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 */