Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

/**
 * source for the Bluetooth driver
 * @file bluetooth.c
 * @author Linus Lotz<lotz@in.tum.de>
 * @author Salomon Sickert
 */




#include "cpu.h"
#include <string.h>
#include <util/delay.h>
#include "bluetooth.h"
#include "main.h"
#ifdef HWVERSION3_9
#include "uart1.h"
#include "usart.h"
#include "fifo.h"
#include "error.h"
#include "lcd.h"
#include "eeprom.h"
#include "error.h"
#include "setup.h"


//#define SaveMem

//
// Baudrate for the UART-connection to the BTM-222 on SQUIRREL
//

#define SQUIRREL

#ifdef SQUIRREL
#define UART_BAUD_RATE      19200
#endif

#ifdef NUT
#define UART_BAUD_RATE      19200
#endif


typedef enum {
        BT_RAW,
        BT_DATA,
        BT_CMD,
        BT_NOECHO,
        BT_NOANSWER
} communication_mode_t;

#define BT_CMD_TIMEOUT_MS 2000

typedef enum {
        BT_TEST,                                // AT
        BT_CONNECT,                             // ATA
        BT_DISCONNECT,                  // ATH
        BT_CLEAR_ADDRESS,               // ATD0
        BT_SET_ADDRESS,                 // ATD=_____
        BT_FIND_DEVICES,                // ATF?
        BT_DISABLE_AUTOCONNECT, // ATO1
        BT_SET_MASTER,                  // ATR0
        BT_SET_SLAVE,                   // ATR1
        BT_SET_PIN,                             // ATP=1234
        BT_SET_57600,                   // ATL4 Baudrate 57600
        BT_SET_NOANSWER,                // ATQ1 Rückmeldungen aus
        BT_SET_NOECHO,                  // ATE0 ECHO deaktivieren
        BT_SET_ANSWER,                  // ATQ0 Rückmeldungen
        BT_SET_ECHO,                    // ATE1 ECHO aktivieren
        BT_SET_DEFAULT,                 // Defaultwerte setzen
        BT_SET_NAME,                    // Devicename
        BT_SET_DISPWRDOWN               // disable auto Powerdown
} bt_cmd_t;

#ifdef SQUIRREL
#define IN_FIFO_SIZE 100
#endif

#ifdef NUT
#define IN_FIFO_SIZE 65
#endif

static uint8_t bt_buffer[IN_FIFO_SIZE];
static fifo_t in_fifo;

static bt_mode_t bt_mode = BLUETOOTH_SLAVE;
static communication_mode_t comm_mode = BT_CMD;

uint8_t i = 0;
uint8_t NoEcho = 0;
uint8_t NoAnswer = 0;



// Set a timeout of Y ms and a Conditon X, which have to be true while timeout
#define while_timeout(X, Y) for(uint16_t __timeout = 0; __timeout++ <= Y && (X); Delay_MS(Y ? 1 : 0))

//--------------------------------------------------------------
void Delay_MS(int count)
{
        for (int i = 0; i < count; i++)
                _delay_ms(1);
}


//--------------------------------------------------------------
static void uart_receive(void)
{
        unsigned int uart_data;

        while (!fifo_is_full(&in_fifo))
        {
                uart_data = uart1_getc();

//              USART_puts(".");

                switch (uart_data & 0xFF00) {
                        // Framing Error detected, i.e no stop bit detected
                case UART_FRAME_ERROR:
#ifdef DEBUG
                        warn_pgm(PSTR("FRM ERR"));
#endif
                        return;

                        // Overrun, a character already presend in the UART UDR register was
                        // not read by the interrupt handler before the next character arrived,
                        // one or more received characters have been dropped
                        //
                case UART_OVERRUN_ERROR:
#ifdef DEBUG
                        warn_pgm(PSTR("OVR ERR"));
#endif
                        return;

                        // We are not reading the receive buffer fast enough,
                        // one or more received character have been dropped
                        //
                case UART_BUFFER_OVERFLOW:
#ifdef DEBUG
                        warn_pgm(PSTR("BUF ERR"));
#endif
                        return;

                        // UART Inputbuffer empty, nothing to do
                case UART_NO_DATA:
                        return;

                default:
                {
                        fifo_write(&in_fifo, uart_data);
//                      USART_putc(uart_data);
                }
                }
        }
#ifdef DEBUG
        warn_pgm(PSTR("FIFO OVR ERR"));
#endif
}


//--------------------------------------------------------------
static void uart_send(const char *data, const uint8_t length)
{
#ifdef DEBUG
  debug_pgm(PSTR("bt_uart_send"));
#endif

        char echo;

        lcd_printp_at (i++, 1, PSTR("."), 0);
        for (uint8_t i = 0; i < length; i++)
        {

#ifdef DEBUG
                USART_putc((data[i]));    //test
#endif
//              debug_pgm(PSTR("bt_init_S"));

                if (uart1_putc(data[i]) == 0)
                {
#ifdef DEBUG
                        warn_pgm(PSTR("UART: Remote not ready"));
#endif
                        return;
                }

                if (comm_mode == BT_RAW)
                        _delay_ms(50);

                if (comm_mode == BT_DATA)
                        _delay_ms(1);

                if (comm_mode == BT_NOECHO)
                        _delay_ms(1);

                if (comm_mode == BT_CMD)
                {
                        uint8_t x = 0;
                        for (; x < 3; x++)
                        {
//                              //      while_timeout(X, Y) for(uint16_t __timeout = 0; __timeout++ <= Y && (X); _delay_ms(Y ? 1 : 0))
//                              while_timeout(fifo_is_empty(&in_fifo), 200)
                                for(uint16_t __timeout = 0; __timeout++ <= 200 && (fifo_is_empty(&in_fifo)); _delay_ms(200 ? 1 : 0))
                                {
                                        uart_receive();
                                }

                                fifo_read(&in_fifo, &echo);

                                if (echo != data[i]) {
                                        if (uart1_putc(data[i]) == 0)
                                        {
                                                warn_pgm(PSTR ("UART: Remote not ready"));
                                                return;
                                        }
                                }
                                else
                                        break;
                        }

                        if (x == 3)
                        {
                                error_putc(data[i]);
                                error_pgm(PSTR("BT: WRONG ECHO"));
                        }
                }
        }
}


//--------------------------------------------------------------
static uint16_t send_cmd(const bt_cmd_t command, const char *data)
{
        _delay_ms(500);         // org 500 300 zu wenig
        char full_command[20];  // Maximum command size

        switch (command)
        {
        case BT_SET_PIN:
                strcpy_P(full_command, PSTR("ATP="));
                for (uint8_t i = 0; i < bt_pin_length; i++)
                {
                        full_command[i+4] = bt_pin[i];
                }
                full_command[(bt_pin_length+4)] =0;
                break;

        case BT_SET_DEFAULT:
                strcpy_P(full_command, PSTR("ATZ0"));
                break;

        case BT_SET_57600:
                strcpy_P(full_command, PSTR("ATL4"));
                break;

        case BT_SET_NOANSWER:
                strcpy_P(full_command, PSTR("ATQ1"));
                break;

        case BT_SET_NOECHO:
                strcpy_P(full_command, PSTR("ATE0"));
                break;

        case BT_SET_ANSWER:
                strcpy_P(full_command, PSTR("ATQ0"));
                break;

        case BT_SET_ECHO:
                strcpy_P(full_command, PSTR("ATE1"));
                break;

        case BT_TEST:
                strcpy_P(full_command, PSTR("AT"));
                break;

        case BT_CONNECT:
                strcpy_P(full_command, PSTR("ATA"));
                break;

        case BT_DISCONNECT:
                strcpy_P(full_command, PSTR("ATH"));
                break;

        case BT_CLEAR_ADDRESS:
                strcpy_P(full_command, PSTR("ATD0"));
                break;

        case BT_SET_ADDRESS:
                strcpy_P(full_command, PSTR("ATD="));
                memcpy((full_command + strlen(full_command)), data, 12);
                full_command[16] = 0;
                break;

        case BT_FIND_DEVICES:
                strcpy_P(full_command, PSTR("ATF?"));
                break;

        case BT_DISABLE_AUTOCONNECT:
                strcpy_P(full_command, PSTR("ATO1"));
                break;

        case BT_SET_MASTER:
                strcpy_P(full_command, PSTR("ATR0"));
                break;

        case BT_SET_SLAVE:
                strcpy_P(full_command, PSTR("ATR1"));
                break;

        case BT_SET_NAME:
                strcpy_P(full_command, PSTR("ATN="));
                for (uint8_t i = 0; i < bt_name_len; i++)
                {
                        full_command[i + 4] = bt_name[i];
                }
                full_command[(bt_name_len + 4)] = 0;
                break;

        case BT_SET_DISPWRDOWN:
                strcpy_P(full_command, PSTR("ATS1"));
                break;

        default:
                warn_pgm(PSTR("CMD UNK"));
                return false;
        }

        strcat_P(full_command, PSTR("\r"));

        // throw away your television
        uart_receive();
        fifo_clear(&in_fifo);
//      debug_pgm(PSTR("bt_init3"));
        // send command
        uart_send(full_command, strlen(full_command));

        if (command== BT_SET_ECHO)
                return true;

        if (command== BT_SET_ANSWER)
        return true;

        // get response
        while_timeout(true, BT_CMD_TIMEOUT_MS)
        {
                uart_receive();
                if (fifo_strstr_pgm(&in_fifo, PSTR("OK\r\n")))
                {
                        info_pgm(PSTR("CMD SEND: OK"));
                        return true;
                }

                if (fifo_strstr_pgm(&in_fifo, PSTR("ERROR\r\n")))
                {
#ifdef DEBUG
                        info_pgm(PSTR("CMD SEND: Error"));
#endif
                        return false;
                }
        }

#ifdef DEBUG
        if (command != BT_TEST)
                warn_pgm(PSTR("CMD SEND: TIMEOUT"));
#endif


        return false;
}


//--------------------------------------------------------------
void test(void)
{
        comm_mode = BT_RAW;
        for (uint8_t i = 0; i < 3; i++)
                if (send_cmd(BT_TEST, NULL))
                        break;
        comm_mode = BT_CMD;
}


#ifndef SaveMem

//--------------------------------------------------------------
static void clean_line(void)
{
        while_timeout(true, 50)
        uart_receive();
        fifo_strstr_pgm(&in_fifo, PSTR("\r\n"));
}

static communication_mode_t update_comm_mode(uint16_t timeout_ms)
{
        while_timeout(true, timeout_ms)
        {
                uart_receive();

                if (fifo_strstr_pgm(&in_fifo, PSTR("DISCONNECT")))
                {
                        clean_line();
                        test();
                        comm_mode = BT_CMD;
                        return comm_mode;
                }

                if (fifo_strstr_pgm(&in_fifo, PSTR("CONNECT")))
                {
                        _delay_ms(100); //don't delete this, else there will be no success!!!!!!!!!
                        comm_mode = BT_DATA;
                        return comm_mode;
                }

                if (fifo_strstr_pgm (&in_fifo, PSTR("Time out,Fail to connect!")))
                {
                        clean_line();
#ifdef DEBUG
                        debug_pgm(PSTR("CONNECT FAILED"));
#endif
                        test();
                        comm_mode = BT_CMD;
                        return comm_mode;
                }
        }

        return comm_mode;
}
#endif


//--------------------------------------------------------------
uint16_t bt_init(void)
{
        uint8_t init_error = false;
        uint8_t BT_found = 0;
        i = 0;

        set_BTOn();

        lcd_cls();
        lcd_printp_at (0, 0, PSTR("BT initialisieren.."), 0);
        _delay_ms(200);

        for (uint8_t z = (bt_name_length); z > 0; z--)
        {
                if (bt_name[z - 1] != ' ')
                {
                        bt_name_len = z;
                        break;
                }
        }

        uart1_init(UART_BAUD_SELECT(57600, F_CPU));
        fifo_init(&in_fifo, bt_buffer, IN_FIFO_SIZE);
        _delay_ms(100);
//      debug_pgm(PSTR("bt_init"));
        uart_receive();
//      debug_pgm(PSTR("bt_init1"));
        fifo_clear(&in_fifo);
        send_cmd(BT_TEST, NULL);
        comm_mode = BT_NOECHO;
        send_cmd(BT_SET_ECHO, NULL);
        send_cmd(BT_SET_ANSWER, NULL);

//      debug_pgm(PSTR("bt_init2"));
#ifdef DEBUG
        debug_pgm(PSTR("Check with 57600"));
#endif
//      send_cmd(BT_TEST, NULL); // Schrott löschen

        if (send_cmd(BT_TEST, NULL)) // Test mit 57600
        {
#ifdef DEBUG
                debug_pgm(PSTR("BT found 57600 Baud"));
#endif
        BT_found = 1;
        }

        if (BT_found == 0)
        {
#ifdef DEBUG
                debug_pgm(PSTR("Check with 19200"));
#endif
                uart1_init(UART_BAUD_SELECT(19200, F_CPU));// Test mit 19200
                _delay_ms(100);
                send_cmd(BT_TEST, NULL); // Schrott löschen
                send_cmd(BT_SET_ANSWER, NULL);
                send_cmd(BT_SET_ECHO, NULL);

                if (send_cmd(BT_TEST, NULL))
                {
                        debug_pgm(PSTR("19200 OK"));
                        if (send_cmd(BT_TEST, NULL))
                        {
#ifdef DEBUG
                                debug_pgm(PSTR("BT found 19200 Baud"));
#endif
                                BT_found = 2;
                        }
                }
        }

        if (BT_found == 0)
        {
#ifdef DEBUG
                debug_pgm(PSTR("Check with 9600"));
#endif
                uart1_init(UART_BAUD_SELECT(9600, F_CPU));//test mit 9600
                _delay_ms(100);
                send_cmd(BT_TEST, NULL);
                send_cmd(BT_SET_ANSWER, NULL);
                send_cmd(BT_SET_ECHO, NULL);
                if (send_cmd(BT_TEST, NULL));
                {
#ifdef DEBUG
                        debug_pgm(PSTR("9600 OK"));
#endif
                        if (send_cmd(BT_TEST, NULL))
                        {
#ifdef DEBUG
                                debug_pgm(PSTR("BT found 9600 Baud"));
#endif
                                BT_found = 3;
                        }
                }
        }

        if (BT_found > 0)
        {
                /* Set comm_mode to CMD */
                comm_mode = BT_CMD;
//              test();
                /* Set BTM Baudrate */
                if (!(send_cmd(BT_SET_57600, NULL)))
                        init_error = true;
                uart1_init(UART_BAUD_SELECT(57600, F_CPU));
                _delay_ms(100);
//              test();
                /* Clear remote address */
                if(!(send_cmd(BT_CLEAR_ADDRESS, NULL)))
                        init_error = true;
//              test();
                /* Set BTM to SLAVE */
                if (!(send_cmd(BT_SET_SLAVE, NULL)))
                        init_error = true;
//              test();
                /* Set BTM PIN */
                if(!(send_cmd(BT_SET_PIN, NULL)))
                        init_error = true;
//              test();
                /* Set BTM Name */
                if(!(send_cmd(BT_SET_NAME, NULL)))
                        init_error = true;
                _delay_ms(300);
//              test();
                if(!(send_cmd(BT_SET_DISPWRDOWN, NULL)))
                        init_error = true;
//              test();
                /* Set BTM Echo aus */
                send_cmd(BT_SET_NOECHO, NULL);
//              test();
                comm_mode = BT_NOECHO;
                /* Set BTM Answer aus */
                send_cmd(BT_SET_NOANSWER, NULL);
//              test();

                bt_mode = BLUETOOTH_SLAVE;

                set_USBOn();

                if (!init_error)
                {
                        WriteBTInitFlag();  // Init merken
                        return true;
                }
                else
                        return false;
        }
        else
        {
                set_USBOn();
                return false;
        }

}


#ifndef SaveMem

//--------------------------------------------------------------
uint16_t bt_set_mode(const bt_mode_t mode)
{
        if (update_comm_mode(0) == BT_DATA)
                return false;

        if (mode == bt_mode)
                return true;

        if (mode == BLUETOOTH_MASTER)
                if (send_cmd(BT_SET_MASTER, NULL))
                {
                        bt_mode = BLUETOOTH_MASTER;
                        test();
                        send_cmd(BT_DISABLE_AUTOCONNECT, NULL);
                }

        if (mode == BLUETOOTH_SLAVE)
                if (send_cmd(BT_SET_SLAVE, NULL))
                {
                        bt_mode = BLUETOOTH_SLAVE;
                }

        test();
        return mode == bt_mode;
}


//--------------------------------------------------------------
uint16_t bt_receive(void *data, uint8_t length, uint16_t timeout_ms)
{
        uint8_t rec_length = 0;
        uint8_t i = 0;

//      while_timeout(true, timeout_ms);
        for(uint16_t __timeout = 0; __timeout++ <= true && (timeout_ms); _delay_ms(true ? 1 : 0))
        {
                if (i == length)
                        return true;

                uart_receive();

                if (fifo_is_empty(&in_fifo))
                        continue;

                if (update_comm_mode(0) != BT_DATA)
                {
#ifdef DEBUG
                        debug_pgm(PSTR("not connected"));
#endif
                        return false;
                }
                // We have a connection
                if (timeout_ms == 0)
                        timeout_ms += 2000;

                if (fifo_is_empty(&in_fifo))
                        continue;

                // Find starting point of packet
                if (!rec_length)
                {
                        fifo_read(&in_fifo, (char *)&rec_length);

                        if (rec_length != length)
                        {
                                rec_length = 0;
                        }
                        else
                        {
                                // You've got mail!
                                timeout_ms += 2000;
                        }
                }
                else
                {
                        fifo_read(&in_fifo, (char *)data + i);
                        i++;
                }
        }
        return false;
}

#endif

#ifndef SaveMem


//--------------------------------------------------------------
uint16_t bt_send(void *data, const uint8_t length)
{
        if (update_comm_mode(0) == BT_CMD)
                return false;

        uart_send((const char *)&length, 1);
        uart_send((char *)data, length);
        return (update_comm_mode(0) == BT_DATA);
}


#ifdef SQUIRREL

//--------------------------------------------------------------
uint16_t bt_connect(const char *address)
{
        // Maybe we already disconnected???
        if (BT_DATA == update_comm_mode(0))
        {
#ifdef DEBUG
                debug_pgm(PSTR("We are still connected..."));
#endif
                return false;
        }
        test();

        if (!send_cmd(BT_DISABLE_AUTOCONNECT, address))
                return false;

        test();
#ifdef DEBUG
        debug_pgm (PSTR ("SET_ADD"));
#endif

        if (!send_cmd(BT_SET_ADDRESS, address))
                return false;

        test();
#ifdef DEBUG
        debug_pgm (PSTR ("CONNECT"));
#endif

        if (!send_cmd(BT_CONNECT, NULL))
                return false;
#ifdef DEBUG
        debug_pgm (PSTR ("WAIT FOR COMM"));
#endif
        return (BT_DATA == update_comm_mode(60000));
}


//--------------------------------------------------------------
uint16_t bt_disconnect(void)
{
        /* Bluetooth reseten */
//      set_bit(PORTC.DIR, 4);
//      set_bit(PORTC.OUT, 4);
        _delay_ms(500);
//      clear_bit(PORTC.OUT, 4);
//      return bt_init();

#if 1
        if (BT_CMD == update_comm_mode(0))
        {
                fifo_clear(&in_fifo);
                return true;
        }

        // Switch to online cmd mode
        for (uint8_t i = 0; i < 4; i++)
        {
                const char plus = '+';
                uart_send(&plus, 1);
                _delay_ms(1500);
        }

        //comm_mode = BT_CMD;

        if (!send_cmd(BT_DISCONNECT, NULL))
                return false;

        test();
        if (!send_cmd(BT_CLEAR_ADDRESS, NULL))
                return false;
        test();

        if (BT_CMD == update_comm_mode(10000))
        {
                fifo_clear(&in_fifo);
                return true;
        }
#ifdef DEBUG
        debug_pgm(PSTR("Still in DATA??"));
#endif
        return false;
#endif
}


//--------------------------------------------------------------
void copy_address(const char *src, char *dst)
{
        uint8_t off = 0;

        for (uint8_t i = 0; i < 14; i++)
        {
                if (src[i + off] == '-')
                        off++;

                dst[i] = src[i + off];
        }
}


//--------------------------------------------------------------
uint16_t bt_discover(char result[8][12])

// 14.8.2011 ist noch nicht getestet, wird für PKT auch nicht benötigt, Cebra
{
//      update_callback(20);
        test();
        if (!bt_set_mode(BLUETOOTH_MASTER))
                return false;

        if (!send_cmd(BT_FIND_DEVICES, NULL))
                return false;

        char buffer[255];       //oversized, but who cares?
        char *bufferhead = buffer;
        uint8_t pos = 0;
        uint16_t Timeout = 20000;
        uint8_t pos1 = 0;

        do
        {
                uart_receive();
                Timeout--;
                pos1++;
                _delay_ms(1);

        }
        while ((Timeout > 0) ||(!fifo_strstr_pgm(&in_fifo, PSTR("Inquiry Results:\r\n"))));

//      byte_to_hex(Timeout);

        assert_pgm((!fifo_strstr_pgm(&in_fifo, PSTR("Inquiry Results:\r\n"))),PSTR("INQ Result false"));

        info_pgm (PSTR ("Rec1"));

        for (uint16_t i = 0; i < 60000; i++)
        {
                //if ((i % 1000) == 0)
                //update_callback(40 + i / 1000);
                uart_receive();
//              lcd_printp(".", 0);
                _delay_ms(1);
        }

        info_pgm (PSTR ("Rec2"));

        //update_callback(100);

        while (!fifo_is_empty(&in_fifo))
        {
                // Get next line
                while (!fifo_cmp_pgm(&in_fifo, PSTR("\r\n")))
                {
                        fifo_read(&in_fifo, bufferhead);
                        bufferhead++;
                }
                // terminate string
                *bufferhead = 0;

                //reset bufferhead
                bufferhead = buffer;

                if (strlen(buffer) == 0)
                        continue;       //the empty line before end of inquiry

                if (strstr_P(buffer, PSTR("Inquiry End")))
                {
                        fifo_clear(&in_fifo);
                        test();
                        return true;
                }

                if (strncmp_P(PSTR("0012"), &buffer[21], 4))
                {
                        copy_address(&buffer[21], result[pos]);
                        pos++;
                }
        }

        return false;
}

#endif
#endif
#endif                          /* SQUIRREL */