0,0 → 1,876 |
/** |
* 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 */ |