295 lines
6.3 KiB
C
295 lines
6.3 KiB
C
#include <msp430.h>
|
|
#include <msp430xgeneric.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "mw_main.h"
|
|
|
|
#include "mw_uart.h"
|
|
#include "mw_bt.h"
|
|
#include "bt_hci.h"
|
|
#include "bt_l2cap.h"
|
|
|
|
#include "bluetooth_init_cc256x.h"
|
|
|
|
|
|
static char bt_rx_buf[BT_RX_MAX_SIZE];
|
|
static unsigned char bt_rx_buf_wpos = 0;
|
|
static unsigned char bt_rx_buf_rpos = 0;
|
|
static uint8_t mw_bt_enabled = 0;
|
|
|
|
int mw_bt_get_rxbuf_len(void)
|
|
{
|
|
if (bt_rx_buf_rpos > bt_rx_buf_wpos)
|
|
return (BT_RX_MAX_SIZE - bt_rx_buf_rpos) + bt_rx_buf_wpos;
|
|
else
|
|
return bt_rx_buf_wpos - bt_rx_buf_rpos;
|
|
}
|
|
|
|
const unsigned char *mw_bt_get_rx_buf(unsigned char **rpos, unsigned char *len)
|
|
{
|
|
*rpos = &bt_rx_buf_rpos;
|
|
|
|
if (bt_rx_buf_rpos > bt_rx_buf_wpos)
|
|
*len = (BT_RX_MAX_SIZE - bt_rx_buf_rpos) + bt_rx_buf_wpos;
|
|
else
|
|
*len = bt_rx_buf_wpos - bt_rx_buf_rpos;
|
|
|
|
// if we reach high water mark raise RTS to stop more data
|
|
if (*len > (BT_RX_MAX_SIZE-(BT_RX_MAX_SIZE/10))) {
|
|
debug_uart_tx("BT UART RTS\n");
|
|
BT_IO_POUT |= BT_IO_RTS; // low == ready, high == !ready
|
|
} else {
|
|
BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready
|
|
}
|
|
|
|
return (unsigned char *)bt_rx_buf;
|
|
}
|
|
|
|
#pragma vector=USCI_A1_VECTOR
|
|
__interrupt void UCA1_ISR (void)
|
|
{
|
|
switch (UCA1IV) {
|
|
case 2: // RXIFG
|
|
/* clear IRQ flag */
|
|
//UCA1IFG &= ~UCRXIFG;
|
|
/* wake up to handle the received char */
|
|
if (UCA1STAT & UCRXERR) {
|
|
debug_uart_tx("BT UART RXERR: ");
|
|
if (UCA1STAT & UCOE)
|
|
debug_uart_tx("overrun ");
|
|
if (UCA1STAT & UCPE)
|
|
debug_uart_tx("parity err ");
|
|
if (UCA1STAT & UCFE)
|
|
debug_uart_tx("frm-err ");
|
|
debug_uart_tx("\n");
|
|
}
|
|
bt_rx_buf[bt_rx_buf_wpos++] = UCA1RXBUF;
|
|
bt_rx_buf_wpos %= BT_RX_MAX_SIZE;
|
|
// LPM3_EXIT;
|
|
LPM3_EXIT_ISR();
|
|
_event_src |= BT_UART_RCV_EVENT;
|
|
break;
|
|
case 4: // TXIFG
|
|
debug_uart_tx("BT UART TX IRQ - huh?\n");
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
}
|
|
|
|
void mw_init_bt_uart(const bt_uart_baud_t baud)
|
|
{
|
|
UCA1CTL1 = UCSWRST;
|
|
|
|
UCA1CTL1 |= UCSSEL__SMCLK;
|
|
|
|
switch (baud) {
|
|
case BT_UART_BD115200:
|
|
default:
|
|
UCA1BR0 = 138;
|
|
UCA1MCTL = UCBRS_7 + UCBRF_0;
|
|
break;
|
|
};
|
|
UCA1STAT = 0;
|
|
// UCA1CTL0 = UCMODE_0; // UART mode
|
|
// UCA1CTL0 &= ~UC7BIT; // 8bit char
|
|
//UCA1CTL0 |= UCRXEIE;
|
|
|
|
UCA1CTL1 &= ~UCSWRST;
|
|
|
|
/* clear interrup flags */
|
|
UCA1IFG = 0;
|
|
UCA1IE = UCRXIE;
|
|
}
|
|
|
|
#if 0 // Does never finish, presumably trigger does not trigger, unknown :(
|
|
void mw_bt_uart_tx(const void *buf, const unsigned int len)
|
|
{
|
|
UCA1IE &= UCTXIE;
|
|
|
|
DMACTL0 = DMA0TSEL_21;
|
|
|
|
DMA0DA = (unsigned int) &UCA1TXBUF;
|
|
DMA0SA = (uint32_t) buf;
|
|
DMA0SZ = len;
|
|
|
|
//DMA0CTL = 0x03F0;
|
|
DMA0CTL = DMADT_1 | DMASRCINCR_3 | DMASBDB | DMALEVEL | DMAIE;
|
|
UCA1IFG &= ~UCTXIFG;
|
|
DMA0CTL |= DMAEN;
|
|
|
|
while ((DMA0CTL & DMAIFG) == 0 && (DMA0CTL & DMAABORT) == 0)
|
|
nop();
|
|
}
|
|
#else
|
|
int mw_bt_uart_tx(const void *buf, const unsigned int len)
|
|
{
|
|
unsigned int pos, i;
|
|
// char txstr[8];
|
|
|
|
pos = 0;
|
|
// debug_uart_tx("BT tx: ");
|
|
while (pos < len) {
|
|
// watch for CTS to be low
|
|
i = 0;
|
|
while ((BT_IO_PIN & BT_IO_CTS) && (i < 1000)) {
|
|
__delay_cycles(16000);
|
|
i++;
|
|
if (i >= 1000)
|
|
return -1;
|
|
// nop();
|
|
}
|
|
|
|
// do not start a transfer if UART is busy, e.g. rx-ing
|
|
while (UCA1STAT & UCBUSY)
|
|
nop();
|
|
|
|
UCA1TXBUF = *(unsigned char *) (buf+pos);
|
|
// debug_uart_tx_char(*(unsigned char *) (buf+pos));
|
|
// snprintf(txstr, 8, "0x%02x ", *(unsigned char *) (buf+pos));
|
|
// debug_uart_tx(txstr);
|
|
pos++;
|
|
while ((UCA1IFG & UCTXIFG) == 0)
|
|
nop();
|
|
}
|
|
while (UCA1STAT & UCBUSY)
|
|
nop();
|
|
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
static int load_cc256x_init_script(void)
|
|
{
|
|
uint32_t pos;
|
|
unsigned char *tptr;
|
|
int tlen;
|
|
|
|
pos = 0;
|
|
while (pos < cc256x_init_script_size) {
|
|
if (_event_src != 0)
|
|
handle_event();
|
|
tptr = (unsigned char *)(cc256x_init_script + pos);
|
|
tlen = mw_bt_uart_tx(tptr, 4 + tptr[3]);
|
|
if (tlen < 0)
|
|
return -1;
|
|
pos += tlen /*4 + tptr[3]*/;
|
|
// each init script part is one HCI command so wait for reply
|
|
if (_event_src != 0)
|
|
handle_event();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mw_enable_bt(void)
|
|
{
|
|
int i;
|
|
|
|
/* make sure it resets */
|
|
BT_SHUTDOWN();
|
|
__delay_cycles(16000);
|
|
|
|
/* enable 32kHz ACLK output to BT module */
|
|
P11DIR |= BIT0;
|
|
P11SEL |= BIT0;
|
|
|
|
// wait for clock to stabilize
|
|
__delay_cycles(16000);
|
|
|
|
// disable the IRQ on CTS, later used to get a wakeup IRQ from eHCILL
|
|
// will be enabled when going to sleep
|
|
P1IE &= ~BT_IO_CTS;
|
|
P1IES &= ~BT_IO_CTS;
|
|
|
|
BT_IO_PDIR &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
|
|
BT_IO_PDIR |= BT_IO_RTS;
|
|
|
|
BT_IO_POUT &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
|
|
BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready
|
|
|
|
BT_IO_REN |= BT_IO_CTS; // enable pull-down on CTS, POUT-CTS is 0 already
|
|
|
|
/* setup UART pins */
|
|
BT_UART_PSEL |= BT_UART_TX_PIN | BT_UART_RX_PIN;
|
|
// P5OUT |= BT_UART_TX_PIN | BT_UART_RX_PIN;
|
|
// P5REN |= BT_UART_TX_PIN | BT_UART_RX_PIN;
|
|
|
|
mw_init_bt_uart(BT_UART_BD115200);
|
|
|
|
bt_rx_buf_wpos = 0;
|
|
bt_rx_buf_rpos = 0;
|
|
|
|
/* release BT reset pin */
|
|
BT_ENABLE();
|
|
|
|
for (i=0; i<1000; i++) {
|
|
__delay_cycles(16000);
|
|
if ((BT_IO_PIN & BT_IO_CTS) == 0) // when CTS goes low module is ready
|
|
break;
|
|
}
|
|
if (i>=1000) {
|
|
debug_uart_tx("Timeout waiting for CC256x to lower CTS\n");
|
|
mw_bt_enabled = 0;
|
|
} else {
|
|
debug_uart_tx("CC256x CTS low - uploading init\n");
|
|
|
|
// the init script consists of HCI cmds so HCI must be setup before
|
|
bt_hci_init();
|
|
|
|
// give it some more time before anyone sends data
|
|
for (i=0; i<10; i++) {
|
|
__delay_cycles(16000);
|
|
}
|
|
if (load_cc256x_init_script() < 0) {
|
|
debug_uart_tx("init upload failed!\n");
|
|
return;
|
|
}
|
|
|
|
__delay_cycles(32000);
|
|
|
|
debug_uart_tx("init uploaded\n");
|
|
|
|
init_l2cap();
|
|
|
|
if (_event_src != 0)
|
|
handle_event();
|
|
|
|
mw_bt_enabled = 1;
|
|
}
|
|
}
|
|
|
|
void mw_disable_bt(void)
|
|
{
|
|
mw_bt_enabled = 0;
|
|
|
|
// disable the IRQ on CTS
|
|
P1IE &= ~BT_IO_CTS;
|
|
P1IES &= ~BT_IO_CTS;
|
|
// BT_IO_REN &= ~BT_IO_CTS; // disable pull-down on CTS
|
|
P1IFG &= ~BT_IO_CTS;
|
|
|
|
/* disable UART RX interrupt */
|
|
UCA1IE &= ~UCRXIE;
|
|
|
|
/* disable UART pins */
|
|
BT_UART_PSEL &= ~(BT_UART_TX_PIN | BT_UART_RX_PIN);
|
|
|
|
/* set BT reset pin */
|
|
BT_SHUTDOWN();
|
|
|
|
/* disable 32kHz ACLK output to BT module */
|
|
P11DIR &= ~BIT0;
|
|
P11SEL &= ~BIT0;
|
|
|
|
/* make all I/O Pins inputs so we do not drive against a "deaf" module */
|
|
BT_IO_PDIR &= ~(BT_IO_RTS | BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
|
|
BT_IO_POUT &= ~(BT_IO_RTS | BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
|
|
}
|
|
|
|
uint8_t mw_bt_is_enabled(void)
|
|
{
|
|
return mw_bt_enabled;
|
|
}
|
|
|