From 2245d9e3178404a49a6787656319fa13f0cc1a51 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 27 Apr 2017 23:51:21 -0700 Subject: altos/ms5607: Allow applications to not use the normal data ring and thread MicroPeak V2 has tasks, but doesn't want to use another thread just for the MS5607. Signed-off-by: Keith Packard --- src/drivers/ao_ms5607.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_ms5607.c b/src/drivers/ao_ms5607.c index 261df67f..0afdf012 100644 --- a/src/drivers/ao_ms5607.c +++ b/src/drivers/ao_ms5607.c @@ -191,9 +191,13 @@ ao_ms5607_sample(__xdata struct ao_ms5607_sample *sample) #include "ao_ms5607_convert.c" #endif -#if HAS_TASK +#ifndef HAS_MS5607_TASK +#define HAS_MS5607_TASK HAS_TASK +#endif + __xdata struct ao_ms5607_sample ao_ms5607_current; +#if HAS_MS5607_TASK static void ao_ms5607(void) { @@ -209,7 +213,9 @@ ao_ms5607(void) } __xdata struct ao_task ao_ms5607_task; +#endif +#if HAS_TASK void ao_ms5607_info(void) { @@ -248,6 +254,8 @@ ao_ms5607_init(void) #if HAS_TASK ao_cmd_register(&ao_ms5607_cmds[0]); +#endif +#if HAS_MS5607_TASK ao_add_task(&ao_ms5607_task, ao_ms5607, "ms5607"); #endif -- cgit v1.2.3 From 6442e2ad6af4b337348aa2ce25abc91c05765826 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 May 2017 15:17:41 -0700 Subject: altos: Add RN4678 Bluetooth module driver This works much like the old BTM module, but supports both bluetooth and bluetooth LE. I've poked at it briefly over BTLE to see that it appears to have the right name, but haven't attempted to communicate over BTLE yet. Signed-off-by: Keith Packard --- src/drivers/ao_rn4678.c | 583 ++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_rn4678.h | 98 ++++++++ 2 files changed, 681 insertions(+) create mode 100644 src/drivers/ao_rn4678.c create mode 100644 src/drivers/ao_rn4678.h (limited to 'src/drivers') diff --git a/src/drivers/ao_rn4678.c b/src/drivers/ao_rn4678.c new file mode 100644 index 00000000..f5b50459 --- /dev/null +++ b/src/drivers/ao_rn4678.c @@ -0,0 +1,583 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include + +static uint8_t ao_rn_connected; + +#define AO_RN_DEBUG 0 + +#if AO_RN_DEBUG +static void ao_rn_dbg(char *format, ...) { + va_list a; + uint32_t irq = ao_arch_irqsave(); + ao_arch_release_interrupts(); + va_start(a, format); + vprintf(format, a); + va_end(a); + flush(); + ao_arch_irqrestore(irq); +} + +static char ao_rn_dir; + +static void +ao_rn_log_char(char c, char dir) +{ + if (dir != ao_rn_dir) { + putchar(dir); + ao_rn_dir = dir; + } + switch (c) { + case '\r': + putchar('\\'); putchar('r'); + break; + case '\n': + putchar('\\'); putchar('n'); + break; + default: + putchar(c); + } + flush(); +} + +static void +ao_rn_log_out_char(char c) +{ + ao_rn_log_char(c, '}'); +} + +static void +ao_rn_log_in_char(char c) +{ + ao_rn_log_char(c, '{'); +} + +static inline void +ao_rn_putchar(char c) +{ + ao_rn_log_out_char(c); + ao_serial_rn_putchar(c); +} + +static inline int +_ao_rn_pollchar(void) +{ + int c = _ao_serial_rn_pollchar(); + + if (c != AO_READ_AGAIN) { + ao_arch_release_interrupts(); + ao_rn_log_in_char((char) c); + ao_arch_block_interrupts(); + } + return c; +} +#else +#define ao_rn_dbg(fmt, ...) +#define ao_rn_putchar(c) ao_serial_rn_putchar(c) +#define _ao_rn_pollchar() _ao_serial_rn_pollchar() +#endif + +/* For stdio, this skips all status messages *sigh* */ + +#define STATUS_CHAR '%' + +static const char *status_strings[] = { + "RFCOMM_CLOSE", + "RFCOMM_OPEN", + "CONNECT", + "DISCONN", + "BONDED", +}; + +#define NUM_STATUS_STRING (sizeof status_strings/sizeof status_strings[0]) + +int +_ao_wrap_rn_pollchar(void) +{ + static char buffer[64]; + static int buf_cnt, buf_ptr; + static int draining; + int c = AO_READ_AGAIN; + unsigned i; + int done = 0; + + while (!done && !draining) { + c = _ao_serial_rn_pollchar(); + + if (c == AO_READ_AGAIN) + return AO_READ_AGAIN; + + if (buf_cnt) { + /* buffering chars */ + + if (c == STATUS_CHAR) { + /* End of status string, drop it and carry on */ + buffer[buf_cnt] = '\0'; + ao_rn_dbg("discard %s\n", buffer); + buf_cnt = 0; + } else if (buf_cnt == sizeof(buffer)) { + /* If we filled the buffer, just give up */ + draining = 1; + } else { + buffer[buf_cnt++] = c; + for (i = 0; i < NUM_STATUS_STRING; i++) { + int cmp = strlen(status_strings[i]); + if (cmp >= buf_cnt) + cmp = buf_cnt-1; + if (memcmp(buffer+1, status_strings[i], cmp) == 0) + break; + } + if (i == NUM_STATUS_STRING) + draining = 1; + } + } else if (c == STATUS_CHAR) { + buffer[0] = c; + buf_cnt = 1; + buf_ptr = 0; + } else + done = 1; + } + if (draining) { + c = buffer[buf_ptr++] & 0xff; + if (buf_ptr == buf_cnt) { + buf_ptr = buf_cnt = 0; + draining = 0; + } + } +#if AO_RN_DEBUG + ao_arch_release_interrupts(); + ao_usb_putchar(c); ao_usb_flush(); + ao_arch_block_interrupts(); +#endif + return c; +} + +#if AO_RN_DEBUG +static void +ao_wrap_rn_putchar(char c) +{ + ao_usb_putchar(c); ao_usb_flush(); + ao_serial_rn_putchar(c); +} +#else +#define ao_wrap_rn_putchar ao_serial_rn_putchar +#endif + +static void +ao_rn_puts(char *s) +{ + char c; + + while ((c = *s++)) + ao_rn_putchar(c); +} + +static void +ao_rn_drain(void) +{ + int timeout = 0; + + ao_rn_dbg("drain...\n"); + ao_serial_rn_drain(); + while (!timeout) { + ao_arch_block_interrupts(); + while (_ao_rn_pollchar() == AO_READ_AGAIN) { + if (_ao_serial_rn_sleep_for(AO_MS_TO_TICKS(10))) { + timeout = 1; + break; + } + } + ao_arch_release_interrupts(); + } + ao_rn_dbg("drain done\n"); +} + +static void +ao_rn_send_cmd(char *cmd, char *param) +{ + ao_rn_dbg("send_cmd %s%s\n", cmd, param ? param : ""); + ao_rn_drain(); + ao_rn_puts(cmd); + if (param) + ao_rn_puts(param); + ao_rn_putchar('\r'); +} + +static int +ao_rn_wait_char(AO_TICK_TYPE giveup_time) +{ + int c; + + ao_arch_block_interrupts(); + while ((c = _ao_rn_pollchar()) == AO_READ_AGAIN) { + AO_TICK_SIGNED delay = (AO_TICK_SIGNED) (giveup_time - ao_time()); + if (delay < 0) { + ao_arch_release_interrupts(); + return AO_READ_AGAIN; + } + _ao_serial_rn_sleep_for(delay); + } + ao_arch_release_interrupts(); + return c; +} + +static int +ao_rn_wait_for(int timeout, char *match) +{ + char reply[AO_RN_MAX_REPLY_LEN + 1]; + int match_len = strlen(match); + AO_TICK_TYPE giveup_time = ao_time() + timeout; + int c; + + ao_rn_dbg("wait for %d, \"%s\"\n", timeout, match); + memset(reply, ' ', sizeof(reply)); + while (memcmp(reply, match, match_len) != 0) { + c = ao_rn_wait_char(giveup_time); + if (c == AO_READ_AGAIN) { + ao_rn_dbg("\twait for timeout\n"); + return AO_RN_TIMEOUT; + } + reply[match_len] = (char) c; + memmove(reply, reply+1, match_len); + reply[match_len] = '\0'; + ao_rn_dbg("\tmatch now \"%s\"\n", reply); + } + ao_rn_dbg("\twait for ok\n"); + return AO_RN_OK; +} + +static int +ao_rn_wait_line(AO_TICK_TYPE giveup_time, char *line, int len) +{ + char *l = line; + + ao_rn_dbg("wait line\n"); + for (;;) { + int c = ao_rn_wait_char(giveup_time); + + /* timeout */ + if (c == AO_READ_AGAIN) { + ao_rn_dbg("\twait line timeout\n"); + return AO_RN_TIMEOUT; + } + + /* done */ + if (c == '\r') { + *l = '\0'; + ao_rn_dbg("\twait line \"%s\"\n", line); + return AO_RN_OK; + } + + if (c == '\n') + continue; + + /* buffer overrun */ + if (len <= 1) + return AO_RN_ERROR; + + *l++ = (char) c; + len--; + } +} + +static int +ao_rn_wait_status(void) +{ + char message[AO_RN_MAX_REPLY_LEN]; + AO_TICK_TYPE giveup_time = ao_time() + AO_RN_CMD_TIMEOUT; + int status; + + ao_rn_dbg("wait status\n"); + status = ao_rn_wait_line(giveup_time, message, sizeof (message)); + if (status == AO_RN_OK) + if (strncmp(message, "AOK", 3) != 0) + status = AO_RN_ERROR; + return status; +} + +static int +ao_rn_set_name(void) +{ + char sn[8]; + char *s = sn + 8; + char c; + int n; + + ao_rn_dbg("set name...\n"); + ao_rn_send_cmd(AO_RN_SET_NAME_CMD, "TeleBT-"); + *--s = '\0'; + *--s = '\r'; + n = ao_serial_number; + do { + *--s = '0' + n % 10; + } while (n /= 10); + while ((c = *s++)) + ao_rn_putchar(c); + return ao_rn_wait_status(); +} + +static int +ao_rn_get_name(char *name, int len) +{ + ao_rn_dbg("get name...\n"); + ao_rn_send_cmd(AO_RN_GET_NAME_CMD, NULL); + return ao_rn_wait_line(ao_time() + AO_RN_CMD_TIMEOUT, name, len); +} + +static void +ao_rn_check_link(void) +{ + ao_rn_connected = 1 - ao_gpio_get(AO_RN_CONNECTED_PORT, AO_RN_CONNECTED_PIN, foo); +} + +static void +ao_rn_isr(void) +{ + ao_rn_check_link(); + ao_wakeup(&ao_rn_connected); +} + +static void +ao_bt_panic(int where) +{ + int i; + for (;;) { + for (i = 0; i < 50; i++) { + ao_led_toggle(AO_BT_LED); + ao_delay(AO_MS_TO_TICKS(10)); + } + ao_led_off(AO_BT_LED); + ao_delay(AO_MS_TO_TICKS(500)); + for (i = 0; i < where; i++) { + ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(200)); + ao_delay(AO_MS_TO_TICKS(200)); + } + } +} + +static uint8_t ao_rn_stdio; + +/* + * Set the stdio echo for the bluetooth link + */ +void +ao_rn_echo(uint8_t echo) +{ + ao_stdios[ao_rn_stdio].echo = echo; +} + +static void +ao_rn(void) +{ + int status = AO_RN_ERROR; + char name[17]; + int i; + + ao_rn_dbg("ao_rn top\n"); + + /* Select CMD mode after the device gets out of reset */ + ao_gpio_set(AO_RN_CMD_PORT, AO_RN_CMD_PIN, foo, AO_RN_CMD_CMD); + + for (i = 0; i < 3; i++) { + ao_rn_dbg("reset device\n"); + + ao_gpio_set(AO_RN_RST_N_PORT, AO_RN_RST_N_PIN, foo, 0); + ao_delay(AO_MS_TO_TICKS(100)); + + /* Reboot the RN4678 and wait for it to start talking */ + ao_rn_drain(); + ao_gpio_set(AO_RN_RST_N_PORT, AO_RN_RST_N_PIN, foo, 1); + status = ao_rn_wait_for(AO_RN_REBOOT_TIMEOUT, AO_RN_REBOOT_MSG); + if (status != AO_RN_OK) { + ao_rn_dbg("reboot failed\n"); + continue; + } + + /* After it reboots, it can take a moment before it responds + * to commands + */ + (void) ao_rn_wait_for(AO_RN_REBOOT_TIMEOUT, "CMD> "); + + /* Check to see if the name is already set and assume + * that the device is ready to go + */ + status = ao_rn_get_name(name, sizeof (name)); + if (status != AO_RN_OK) { + ao_rn_dbg("get name failed\n"); + continue; + } + + if (strncmp(name, "TeleBT", 6) == 0) { + ao_rn_dbg("name is set\n"); + status = AO_RN_OK; + break; + } + + /* Make the command pin control command/data mode */ + ao_rn_send_cmd(AO_RN_SET_COMMAND_PIN, NULL); + if (ao_rn_wait_status() != AO_RN_OK) { + ao_rn_dbg("set command pin failed\n"); + continue; + } + + /* Select 'fast' mode to ignore command sequence (more or less) */ + ao_rn_send_cmd(AO_RN_SET_FAST_MODE, NULL); + if (ao_rn_wait_status() != AO_RN_OK) { + ao_rn_dbg("set fast mode failed\n"); + continue; + } + + /* Finally, set the name. Doing this last makes it possible to check + * if the whole sequence has been done + */ + if (ao_rn_set_name() != AO_RN_OK) { + ao_rn_dbg("set name failed\n"); + continue; + } + + /* After we've configured the device, go back around and reboot it + * as that's how we get the new configuration to take effect + */ + } + ao_rn_dbg("ao_rn status %d\n", status); + + if (status != AO_RN_OK) + ao_bt_panic(4); + + ao_gpio_set(AO_RN_CMD_PORT, AO_RN_CMD_PIN, foo, AO_RN_CMD_DATA); + + /* Wait for the hardware to finish sending messages, then clear the queue */ + ao_delay(AO_MS_TO_TICKS(200)); + ao_rn_drain(); + + ao_exti_enable(AO_RN_CONNECTED_PORT, AO_RN_CONNECTED_PIN); + +#if 1 + ao_rn_stdio = ao_add_stdio(_ao_wrap_rn_pollchar, + ao_wrap_rn_putchar, + NULL); + + ao_rn_echo(0); + + ao_rn_check_link(); + + ao_rn_dbg("RN running\n"); + + /* + * Now just hang around and flash the blue LED when we've got + * a connection + */ + for (;;) { + ao_arch_block_interrupts(); + while (!ao_rn_connected) + ao_sleep(&ao_rn_connected); + ao_arch_release_interrupts(); + while (ao_rn_connected) { + ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(20)); + ao_delay(AO_SEC_TO_TICKS(3)); + } + } +#else + + /* + * Separate debug code when things aren't working. Just dump + * inbound bluetooth characters to stdout + */ + for (;;) { + int c; + + while (rn_cmd_running) + ao_delay(AO_MS_TO_TICKS(1000)); + + ao_arch_block_interrupts(); + while ((c = _ao_wrap_rn_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_serial_rn_rx_fifo); + ao_arch_release_interrupts(); + putchar(c); flush(); + } +#endif +} + +static struct ao_task ao_rn_task; + +static void +ao_rn_factory(void) +{ + int i; + int v = 0; + + /* + * Factory reset. Flip pin P3_1 5 times within the first five + * seconds of power-on + */ + + /* Select our target output pin */ + ao_enable_output(AO_RN_P3_1_PORT, AO_RN_P3_1_PIN, foo, v); + + /* Turn off the BT device using the SW_BTN pin */ + printf("Power down BT\n"); flush(); + ao_gpio_set(AO_RN_SW_BTN_PORT, AO_RN_SW_BTN_PIN, foo, 0); + ao_delay(AO_MS_TO_TICKS(1000)); + + /* And turn it back on */ + printf("Power up BT\n"); flush(); + ao_gpio_set(AO_RN_SW_BTN_PORT, AO_RN_SW_BTN_PIN, foo, 1); + + /* Right after power on, poke P3_1 five times to force a + * factory reset + */ + for (i = 0; i < 10; i++) { + v = 1-v; + ao_delay(AO_MS_TO_TICKS(100)); + ao_gpio_set(AO_RN_P3_1_PORT, AO_RN_P3_1_PIN, foo, v); + ao_led_toggle(AO_BT_LED); + } + + /* And let P3_1 float again */ + ao_enable_input(AO_RN_P3_1_PORT, AO_RN_P3_1_PIN, AO_EXTI_MODE_PULL_NONE); +} + +static const struct ao_cmds rn_cmds[] = { + { ao_rn_factory, "F\0Factory reset rn4678" }, + { 0 }, +}; + +void +ao_rn4678_init(void) +{ + (void) ao_rn_set_name; + + ao_serial_rn_set_speed(AO_SERIAL_SPEED_115200); + + /* Reset line */ + ao_enable_output(AO_RN_RST_N_PORT, AO_RN_RST_N_PIN, foo, 0); + + /* SW_BTN */ + ao_enable_output(AO_RN_SW_BTN_PORT, AO_RN_SW_BTN_PIN, foo, 1); + + /* P3_7 command/data selector */ + ao_enable_output(AO_RN_CMD_PORT, AO_RN_CMD_PIN, foo, AO_RN_CMD_CMD); + + ao_enable_input(AO_RN_CONNECTED_PORT, AO_RN_CONNECTED_PIN, AO_EXTI_MODE_PULL_NONE); + ao_exti_setup(AO_RN_CONNECTED_PORT, AO_RN_CONNECTED_PIN, + AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_LOW, + ao_rn_isr); + + ao_cmd_register(rn_cmds); + ao_add_task(&ao_rn_task, ao_rn, "bluetooth"); +} diff --git a/src/drivers/ao_rn4678.h b/src/drivers/ao_rn4678.h new file mode 100644 index 00000000..d6fea23a --- /dev/null +++ b/src/drivers/ao_rn4678.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_RN4678_H_ +#define _AO_RN4678_H_ + +/* From the rn4678 pictail board + + 1 SW_BTN 0-off/1-on 2 P2_0 1-app/0-test (boot time) + 3 P2_4 1-app/0-WF 4 EAN 0-app/1-WF (reboots) + 5 6 RTS 0 + 7 8 P3_2 1 (NC) + 9 TXD 10 P3_3 1 (NC) + 11 RXD 12 P3_4 1 (NC) + 13 14 + 15 16 P3_7 1 (NC) + 17 P0_5 1 (NC) 18 RST_N 1 run/0 reset + 19 WAKE_UP 1 run/0 btn 20 + 21 P0_4 0 (NC) 22 + 23 P1_5 1 (NC) 24 P3_1 1 (NC) + 25 CTS 0 26 3.3V + 27 28 GND + + + Interesting pins: + + Not connected to microcontroller: + + SW_BTN 0-off 1-on + P2_4 0 write-flash 1-app + WAKE_UP 0-stop 1-run + P2_0 0 test 1-run + EAN 1-WF (reboots) 0-run + RST_N 0 reset 1 run + + Connected to microcontroller: + + CTS mostly 0 + RTS mostly 1 + + TXD + RXD + + Other connections -- LDO33_O to VDD_IO + +*/ + +#define AO_RN_REBOOT_MSG "%REBOOT%" + +#define AO_RN_CMD_TIMEOUT AO_MS_TO_TICKS(200) + +#define AO_RN_REBOOT_TIMEOUT AO_MS_TO_TICKS(2000) + +#define AO_RN_MAX_REPLY_LEN 10 + +#define AO_RN_SET_NAME_CMD "SN," +#define AO_RN_GET_NAME_CMD "GN" + +#define AO_RN_SET_STATUS_STRING "SO," +#define AO_RN_STATUS_STRING_DISABLE " " + +#define AO_RN_REBOOT_CMD "R,1" + +#define AO_RN_TIMEOUT -1 +#define AO_RN_ERROR 0 +#define AO_RN_OK 1 + +#define AO_RN_SET_COMMAND_PIN "SX,07,0B" + +#define AO_RN_SET_AUTH_JUST_WORKS "SA,2" +#define AO_RN_SET_FAST_MODE "SQ,9000" + +/* This pin is configured to control cmd/data mode */ +#define AO_RN_CMD_PORT AO_RN_P3_7_PORT +#define AO_RN_CMD_PIN AO_RN_P3_7_PIN + +#define AO_RN_CMD_CMD 0 +#define AO_RN_CMD_DATA 1 + +/* This pin indicates BT connection status */ +#define AO_RN_CONNECTED_PORT AO_RN_P1_5_PORT +#define AO_RN_CONNECTED_PIN AO_RN_P1_5_PIN + +void +ao_rn4678_init(void); + +#endif /* _AO_RN_H_ */ -- cgit v1.2.3 From ab50a1467bac0234062bc8c0a17783f1730aa981 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 15 May 2017 08:59:52 -0700 Subject: altos/ao_rn4678: Send '$$$' for new devices. Fix name setting code. New devices won't respond to the cmd pin we have configured, so get them to command mode by sending the $$$ string. Somehow I'd botched the name setting code and hadn't caught it as I hadn't tried a new device... Signed-off-by: Keith Packard --- src/drivers/ao_rn4678.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_rn4678.c b/src/drivers/ao_rn4678.c index f5b50459..4e3d12cb 100644 --- a/src/drivers/ao_rn4678.c +++ b/src/drivers/ao_rn4678.c @@ -315,19 +315,15 @@ ao_rn_set_name(void) { char sn[8]; char *s = sn + 8; - char c; int n; ao_rn_dbg("set name...\n"); - ao_rn_send_cmd(AO_RN_SET_NAME_CMD, "TeleBT-"); *--s = '\0'; - *--s = '\r'; n = ao_serial_number; do { *--s = '0' + n % 10; } while (n /= 10); - while ((c = *s++)) - ao_rn_putchar(c); + ao_rn_send_cmd(AO_RN_SET_NAME_CMD "TeleBT-", s); return ao_rn_wait_status(); } @@ -408,6 +404,8 @@ ao_rn(void) continue; } + ao_rn_puts("$$$"); + /* After it reboots, it can take a moment before it responds * to commands */ @@ -422,7 +420,7 @@ ao_rn(void) continue; } - if (strncmp(name, "TeleBT", 6) == 0) { + if (strncmp(name, "TeleBT-", 7) == 0) { ao_rn_dbg("name is set\n"); status = AO_RN_OK; break; -- cgit v1.2.3 From fed48732828c85ae56106cd72c5aeaaad47c552f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 11 Jun 2017 22:31:17 -0700 Subject: altos: Update sensor data atomically Read data into a temp variable, block interrupts, then update the published value. The bug is easy to see with the HMC5883 which has to byte-swap the output of the chip, and hence can occasionally get caught with the wrong byte order data. Signed-off-by: Keith Packard --- src/drivers/ao_hmc5883.c | 12 +++++++----- src/drivers/ao_mpu6000.c | 39 +++++++++++++++++++-------------------- src/drivers/ao_ms5607.c | 4 +++- 3 files changed, 29 insertions(+), 26 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_hmc5883.c b/src/drivers/ao_hmc5883.c index f668fb66..9f1131d6 100644 --- a/src/drivers/ao_hmc5883.c +++ b/src/drivers/ao_hmc5883.c @@ -126,13 +126,15 @@ struct ao_hmc5883_sample ao_hmc5883_current; static void ao_hmc5883(void) { + struct ao_hmc5883_sample sample; ao_hmc5883_setup(); for (;;) { - ao_hmc5883_sample(&ao_hmc5883_current); - ao_arch_critical( - AO_DATA_PRESENT(AO_DATA_HMC5883); - AO_DATA_WAIT(); - ); + ao_hmc5883_sample(&sample); + ao_arch_block_interrupts(); + ao_hmc5883_current = sample; + AO_DATA_PRESENT(AO_DATA_HMC5883); + AO_DATA_WAIT(); + ao_arch_release_interrupts(); } } diff --git a/src/drivers/ao_mpu6000.c b/src/drivers/ao_mpu6000.c index 650407ad..81d3c16c 100644 --- a/src/drivers/ao_mpu6000.c +++ b/src/drivers/ao_mpu6000.c @@ -192,7 +192,7 @@ _ao_mpu6000_setup(void) _ao_mpu6000_wait_alive(); /* Reset the whole chip */ - + _ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1, (1 << MPU6000_PWR_MGMT_1_DEVICE_RESET)); @@ -292,7 +292,7 @@ _ao_mpu6000_setup(void) ao_delay(AO_MS_TO_TICKS(200)); _ao_mpu6000_sample(&normal_mode); - + errors += ao_mpu6000_accel_check(normal_mode.accel_x, test_mode.accel_x); errors += ao_mpu6000_accel_check(normal_mode.accel_y, test_mode.accel_y); errors += ao_mpu6000_accel_check(normal_mode.accel_z, test_mode.accel_z); @@ -315,7 +315,7 @@ _ao_mpu6000_setup(void) /* Set sample rate divider to sample at 200Hz (v = gyro/rate - 1) */ _ao_mpu6000_reg_write(MPU6000_SMPRT_DIV, 1000 / 200 - 1); - + ao_delay(AO_MS_TO_TICKS(100)); ao_mpu6000_configured = 1; } @@ -325,6 +325,7 @@ struct ao_mpu6000_sample ao_mpu6000_current; static void ao_mpu6000(void) { + struct ao_mpu6000_sample sample; /* ao_mpu6000_init already grabbed the SPI bus and mutex */ _ao_mpu6000_setup(); #if AO_MPU6000_SPI @@ -335,14 +336,15 @@ ao_mpu6000(void) #if AO_MPU6000_SPI ao_mpu6000_spi_get(); #endif - _ao_mpu6000_sample(&ao_mpu6000_current); + _ao_mpu6000_sample(&sample); #if AO_MPU6000_SPI ao_mpu6000_spi_put(); -#endif - ao_arch_critical( - AO_DATA_PRESENT(AO_DATA_MPU6000); - AO_DATA_WAIT(); - ); +#endif + ao_arch_block_interrupts(); + ao_mpu6000_current = sample; + AO_DATA_PRESENT(AO_DATA_MPU6000); + AO_DATA_WAIT(); + ao_arch_release_interrupts(); } } @@ -351,16 +353,13 @@ static struct ao_task ao_mpu6000_task; static void ao_mpu6000_show(void) { - struct ao_data sample; - - ao_data_get(&sample); printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d\n", - sample.mpu6000.accel_x, - sample.mpu6000.accel_y, - sample.mpu6000.accel_z, - sample.mpu6000.gyro_x, - sample.mpu6000.gyro_y, - sample.mpu6000.gyro_z); + ao_mpu6000_current.accel_x, + ao_mpu6000_current.accel_y, + ao_mpu6000_current.accel_z, + ao_mpu6000_current.gyro_x, + ao_mpu6000_current.gyro_y, + ao_mpu6000_current.gyro_z); } static const struct ao_cmds ao_mpu6000_cmds[] = { @@ -374,7 +373,7 @@ ao_mpu6000_init(void) ao_mpu6000_configured = 0; ao_add_task(&ao_mpu6000_task, ao_mpu6000, "mpu6000"); - + #if AO_MPU6000_SPI ao_spi_init_cs(AO_MPU6000_SPI_CS_PORT, (1 << AO_MPU6000_SPI_CS_PIN)); @@ -386,7 +385,7 @@ ao_mpu6000_init(void) ao_cur_task = &ao_mpu6000_task; ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz); ao_cur_task = NULL; -#endif +#endif ao_cmd_register(&ao_mpu6000_cmds[0]); } diff --git a/src/drivers/ao_ms5607.c b/src/drivers/ao_ms5607.c index 0afdf012..914e0c1b 100644 --- a/src/drivers/ao_ms5607.c +++ b/src/drivers/ao_ms5607.c @@ -201,11 +201,13 @@ __xdata struct ao_ms5607_sample ao_ms5607_current; static void ao_ms5607(void) { + struct ao_ms5607_sample sample; ao_ms5607_setup(); for (;;) { - ao_ms5607_sample(&ao_ms5607_current); + ao_ms5607_sample(&sample); ao_arch_block_interrupts(); + ao_ms5607_current = sample; AO_DATA_PRESENT(AO_DATA_MS5607); AO_DATA_WAIT(); ao_arch_release_interrupts(); -- cgit v1.2.3 From 2a05849c3bf8c1617409237be48802dd6fc6255b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 11 Jun 2017 22:34:11 -0700 Subject: altos: HMC5883 output order is X Z Y Re-label everything to have the correct names. This doesn't actually change the code at all, so the eeprom and telemetry is all compatible. Matching changes on the host side will be required to actually process the data correctly, of course. Signed-off-by: Keith Packard --- src/drivers/ao_hmc5883.c | 6 ++---- src/drivers/ao_hmc5883.h | 2 +- src/kernel/ao_log.h | 4 ++-- src/kernel/ao_log_mega.c | 2 +- src/kernel/ao_telemetry.c | 2 +- src/kernel/ao_telemetry.h | 4 ++-- 6 files changed, 9 insertions(+), 11 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_hmc5883.c b/src/drivers/ao_hmc5883.c index 9f1131d6..c33aa536 100644 --- a/src/drivers/ao_hmc5883.c +++ b/src/drivers/ao_hmc5883.c @@ -143,10 +143,8 @@ static struct ao_task ao_hmc5883_task; static void ao_hmc5883_show(void) { - struct ao_data sample; - ao_data_get(&sample); - printf ("X: %d Y: %d Z: %d missed irq: %lu\n", - sample.hmc5883.x, sample.hmc5883.y, sample.hmc5883.z, ao_hmc5883_missed_irq); + printf ("X: %d Z: %d Y: %d missed irq: %lu\n", + ao_hmc5883_current.x, ao_hmc5883_current.z, ao_hmc5883_current.y, ao_hmc5883_missed_irq); } static const struct ao_cmds ao_hmc5883_cmds[] = { diff --git a/src/drivers/ao_hmc5883.h b/src/drivers/ao_hmc5883.h index 78637b02..b90733df 100644 --- a/src/drivers/ao_hmc5883.h +++ b/src/drivers/ao_hmc5883.h @@ -77,7 +77,7 @@ #define HMC5883_ID_C 12 struct ao_hmc5883_sample { - int16_t x, y, z; + int16_t x, z, y; }; extern struct ao_hmc5883_sample ao_hmc5883_current; diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h index 5c568c99..241ba7d7 100644 --- a/src/kernel/ao_log.h +++ b/src/kernel/ao_log.h @@ -252,8 +252,8 @@ struct ao_log_mega { int16_t gyro_y; /* 20 */ int16_t gyro_z; /* 22 */ int16_t mag_x; /* 24 */ - int16_t mag_y; /* 26 */ - int16_t mag_z; /* 28 */ + int16_t mag_z; /* 26 */ + int16_t mag_y; /* 28 */ int16_t accel; /* 30 */ } sensor; /* 32 */ /* AO_LOG_TEMP_VOLT */ diff --git a/src/kernel/ao_log_mega.c b/src/kernel/ao_log_mega.c index a0212198..b86abe7a 100644 --- a/src/kernel/ao_log_mega.c +++ b/src/kernel/ao_log_mega.c @@ -135,8 +135,8 @@ ao_log(void) #endif #if HAS_HMC5883 log.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].hmc5883.x; - log.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].hmc5883.y; log.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].hmc5883.z; + log.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].hmc5883.y; #endif log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]); ao_log_mega(&log); diff --git a/src/kernel/ao_telemetry.c b/src/kernel/ao_telemetry.c index a4c73a86..2ae1e41b 100644 --- a/src/kernel/ao_telemetry.c +++ b/src/kernel/ao_telemetry.c @@ -160,8 +160,8 @@ ao_send_mega_sensor(void) #if HAS_HMC5883 telemetry.mega_sensor.mag_x = packet->hmc5883.x; - telemetry.mega_sensor.mag_y = packet->hmc5883.y; telemetry.mega_sensor.mag_z = packet->hmc5883.z; + telemetry.mega_sensor.mag_y = packet->hmc5883.y; #endif ao_telemetry_send(); diff --git a/src/kernel/ao_telemetry.h b/src/kernel/ao_telemetry.h index 45aaeb07..23e3ed7d 100644 --- a/src/kernel/ao_telemetry.h +++ b/src/kernel/ao_telemetry.h @@ -198,8 +198,8 @@ struct ao_telemetry_mega_sensor { int16_t gyro_z; /* 24 */ int16_t mag_x; /* 26 */ - int16_t mag_y; /* 28 */ - int16_t mag_z; /* 30 */ + int16_t mag_z; /* 28 */ + int16_t mag_y; /* 30 */ /* 32 */ }; -- cgit v1.2.3 From cd8b22bef0a88ed6881036b4c6718a4e33c55d41 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 13 Jun 2017 10:34:03 -0700 Subject: altos: Add timeout to RN4678 status message code If we see the start of an RN4678 status message, but then output pauses, assume that this isn't the start of a status message and flush the pending data. Signed-off-by: Keith Packard --- src/drivers/ao_rn4678.c | 178 +++++++++++++++++++++++++----------------------- src/drivers/ao_rn4678.h | 7 +- 2 files changed, 99 insertions(+), 86 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_rn4678.c b/src/drivers/ao_rn4678.c index 4e3d12cb..ba25e70d 100644 --- a/src/drivers/ao_rn4678.c +++ b/src/drivers/ao_rn4678.c @@ -39,7 +39,7 @@ static void ao_rn_log_char(char c, char dir) { if (dir != ao_rn_dir) { - putchar(dir); + putchar(dir); putchar('\n'); ao_rn_dir = dir; } switch (c) { @@ -106,78 +106,74 @@ static const char *status_strings[] = { #define NUM_STATUS_STRING (sizeof status_strings/sizeof status_strings[0]) +static char ao_rn_buffer[64]; +static int ao_rn_buf_cnt, ao_rn_buf_ptr; +static int ao_rn_draining; +static AO_TICK_TYPE ao_rn_buf_time; + +/* Well, this is annoying. The status strings from the RN4678 can't be + * disabled due to a firmware bug. So, this code finds those in the + * input and strips them out. + */ int _ao_wrap_rn_pollchar(void) { - static char buffer[64]; - static int buf_cnt, buf_ptr; - static int draining; int c = AO_READ_AGAIN; unsigned i; int done = 0; - while (!done && !draining) { + while (!done && !ao_rn_draining) { c = _ao_serial_rn_pollchar(); - if (c == AO_READ_AGAIN) + if (c == AO_READ_AGAIN) { + if (ao_rn_buf_cnt && (ao_time() - ao_rn_buf_time) > AO_MS_TO_TICKS(1000)) { + ao_rn_draining = 1; + continue; + } return AO_READ_AGAIN; + } - if (buf_cnt) { + if (ao_rn_buf_cnt) { /* buffering chars */ if (c == STATUS_CHAR) { /* End of status string, drop it and carry on */ - buffer[buf_cnt] = '\0'; - ao_rn_dbg("discard %s\n", buffer); - buf_cnt = 0; - } else if (buf_cnt == sizeof(buffer)) { + ao_rn_buffer[ao_rn_buf_cnt] = '\0'; +// ao_rn_dbg("discard %s\n", ao_rn_buffer); + ao_rn_buf_cnt = 0; + } else if (ao_rn_buf_cnt == sizeof(ao_rn_buffer)) { /* If we filled the buffer, just give up */ - draining = 1; + ao_rn_draining = 1; } else { - buffer[buf_cnt++] = c; + ao_rn_buffer[ao_rn_buf_cnt++] = c; for (i = 0; i < NUM_STATUS_STRING; i++) { int cmp = strlen(status_strings[i]); - if (cmp >= buf_cnt) - cmp = buf_cnt-1; - if (memcmp(buffer+1, status_strings[i], cmp) == 0) + if (cmp >= ao_rn_buf_cnt) + cmp = ao_rn_buf_cnt-1; + if (memcmp(ao_rn_buffer+1, status_strings[i], cmp) == 0) break; } if (i == NUM_STATUS_STRING) - draining = 1; + ao_rn_draining = 1; } } else if (c == STATUS_CHAR) { - buffer[0] = c; - buf_cnt = 1; - buf_ptr = 0; + ao_rn_buffer[0] = c; + ao_rn_buf_cnt = 1; + ao_rn_buf_ptr = 0; + ao_rn_buf_time = ao_time(); } else done = 1; } - if (draining) { - c = buffer[buf_ptr++] & 0xff; - if (buf_ptr == buf_cnt) { - buf_ptr = buf_cnt = 0; - draining = 0; + if (ao_rn_draining) { + c = ao_rn_buffer[ao_rn_buf_ptr++] & 0xff; + if (ao_rn_buf_ptr == ao_rn_buf_cnt) { + ao_rn_buf_ptr = ao_rn_buf_cnt = 0; + ao_rn_draining = 0; } } -#if AO_RN_DEBUG - ao_arch_release_interrupts(); - ao_usb_putchar(c); ao_usb_flush(); - ao_arch_block_interrupts(); -#endif return c; } -#if AO_RN_DEBUG -static void -ao_wrap_rn_putchar(char c) -{ - ao_usb_putchar(c); ao_usb_flush(); - ao_serial_rn_putchar(c); -} -#else -#define ao_wrap_rn_putchar ao_serial_rn_putchar -#endif - static void ao_rn_puts(char *s) { @@ -192,7 +188,7 @@ ao_rn_drain(void) { int timeout = 0; - ao_rn_dbg("drain...\n"); +// ao_rn_dbg("drain...\n"); ao_serial_rn_drain(); while (!timeout) { ao_arch_block_interrupts(); @@ -204,13 +200,13 @@ ao_rn_drain(void) } ao_arch_release_interrupts(); } - ao_rn_dbg("drain done\n"); +// ao_rn_dbg("drain done\n"); } static void ao_rn_send_cmd(char *cmd, char *param) { - ao_rn_dbg("send_cmd %s%s\n", cmd, param ? param : ""); +// ao_rn_dbg("send_cmd %s%s\n", cmd, param ? param : ""); ao_rn_drain(); ao_rn_puts(cmd); if (param) @@ -244,20 +240,20 @@ ao_rn_wait_for(int timeout, char *match) AO_TICK_TYPE giveup_time = ao_time() + timeout; int c; - ao_rn_dbg("wait for %d, \"%s\"\n", timeout, match); +// ao_rn_dbg("wait for %d, \"%s\"\n", timeout, match); memset(reply, ' ', sizeof(reply)); while (memcmp(reply, match, match_len) != 0) { c = ao_rn_wait_char(giveup_time); if (c == AO_READ_AGAIN) { - ao_rn_dbg("\twait for timeout\n"); +// ao_rn_dbg("\twait for timeout\n"); return AO_RN_TIMEOUT; } reply[match_len] = (char) c; memmove(reply, reply+1, match_len); reply[match_len] = '\0'; - ao_rn_dbg("\tmatch now \"%s\"\n", reply); +// ao_rn_dbg("\tmatch now \"%s\"\n", reply); } - ao_rn_dbg("\twait for ok\n"); +// ao_rn_dbg("\twait for ok\n"); return AO_RN_OK; } @@ -266,20 +262,20 @@ ao_rn_wait_line(AO_TICK_TYPE giveup_time, char *line, int len) { char *l = line; - ao_rn_dbg("wait line\n"); +// ao_rn_dbg("wait line\n"); for (;;) { int c = ao_rn_wait_char(giveup_time); /* timeout */ if (c == AO_READ_AGAIN) { - ao_rn_dbg("\twait line timeout\n"); +// ao_rn_dbg("\twait line timeout\n"); return AO_RN_TIMEOUT; } /* done */ if (c == '\r') { *l = '\0'; - ao_rn_dbg("\twait line \"%s\"\n", line); +// ao_rn_dbg("\twait line \"%s\"\n", line); return AO_RN_OK; } @@ -302,7 +298,7 @@ ao_rn_wait_status(void) AO_TICK_TYPE giveup_time = ao_time() + AO_RN_CMD_TIMEOUT; int status; - ao_rn_dbg("wait status\n"); +// ao_rn_dbg("wait status\n"); status = ao_rn_wait_line(giveup_time, message, sizeof (message)); if (status == AO_RN_OK) if (strncmp(message, "AOK", 3) != 0) @@ -317,7 +313,7 @@ ao_rn_set_name(void) char *s = sn + 8; int n; - ao_rn_dbg("set name...\n"); +// ao_rn_dbg("set name...\n"); *--s = '\0'; n = ao_serial_number; do { @@ -330,7 +326,7 @@ ao_rn_set_name(void) static int ao_rn_get_name(char *name, int len) { - ao_rn_dbg("get name...\n"); +// ao_rn_dbg("get name...\n"); ao_rn_send_cmd(AO_RN_GET_NAME_CMD, NULL); return ao_rn_wait_line(ao_time() + AO_RN_CMD_TIMEOUT, name, len); } @@ -404,12 +400,18 @@ ao_rn(void) continue; } - ao_rn_puts("$$$"); - /* After it reboots, it can take a moment before it responds * to commands */ - (void) ao_rn_wait_for(AO_RN_REBOOT_TIMEOUT, "CMD> "); + status = ao_rn_wait_for(AO_RN_REBOOT_TIMEOUT, "CMD> "); + + if (status == AO_RN_TIMEOUT) { + ao_rn_puts("$$$"); + (void) ao_rn_wait_for(AO_RN_REBOOT_TIMEOUT, "CMD> "); + } + + ao_rn_send_cmd(AO_RN_VERSION_CMD, NULL); + (void) ao_rn_wait_status(); /* Check to see if the name is already set and assume * that the device is ready to go @@ -417,7 +419,9 @@ ao_rn(void) status = ao_rn_get_name(name, sizeof (name)); if (status != AO_RN_OK) { ao_rn_dbg("get name failed\n"); - continue; + status = ao_rn_get_name(name, sizeof (name)); + if (status != AO_RN_OK) + continue; } if (strncmp(name, "TeleBT-", 7) == 0) { @@ -433,6 +437,12 @@ ao_rn(void) continue; } + ao_rn_send_cmd(AO_RN_SET_STATUS_STRING, AO_RN_STATUS_STRING_ENABLE); + if (ao_rn_wait_status() != AO_RN_OK) { + ao_rn_dbg("set status string\n"); + continue; + } + /* Select 'fast' mode to ignore command sequence (more or less) */ ao_rn_send_cmd(AO_RN_SET_FAST_MODE, NULL); if (ao_rn_wait_status() != AO_RN_OK) { @@ -465,17 +475,27 @@ ao_rn(void) ao_exti_enable(AO_RN_CONNECTED_PORT, AO_RN_CONNECTED_PIN); -#if 1 +#if AO_RN_DEBUG + + /* + * Separate debug code when things aren't working. Just dump + * inbound bluetooth characters to stdout + */ + for (;;) { + int c; + + ao_arch_block_interrupts(); + while ((c = _ao_rn_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_serial_rn_rx_fifo); + ao_arch_release_interrupts(); + } +#else ao_rn_stdio = ao_add_stdio(_ao_wrap_rn_pollchar, - ao_wrap_rn_putchar, + ao_serial_rn_putchar, NULL); ao_rn_echo(0); - ao_rn_check_link(); - - ao_rn_dbg("RN running\n"); - /* * Now just hang around and flash the blue LED when we've got * a connection @@ -487,27 +507,11 @@ ao_rn(void) ao_arch_release_interrupts(); while (ao_rn_connected) { ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(20)); + if (ao_rn_buf_cnt != 0) + ao_wakeup(&ao_stdin_ready); ao_delay(AO_SEC_TO_TICKS(3)); } } -#else - - /* - * Separate debug code when things aren't working. Just dump - * inbound bluetooth characters to stdout - */ - for (;;) { - int c; - - while (rn_cmd_running) - ao_delay(AO_MS_TO_TICKS(1000)); - - ao_arch_block_interrupts(); - while ((c = _ao_wrap_rn_pollchar()) == AO_READ_AGAIN) - ao_sleep(&ao_serial_rn_rx_fifo); - ao_arch_release_interrupts(); - putchar(c); flush(); - } #endif } @@ -539,15 +543,21 @@ ao_rn_factory(void) /* Right after power on, poke P3_1 five times to force a * factory reset */ - for (i = 0; i < 10; i++) { + for (i = 0; i < 20; i++) { v = 1-v; - ao_delay(AO_MS_TO_TICKS(100)); + ao_delay(AO_MS_TO_TICKS(50)); ao_gpio_set(AO_RN_P3_1_PORT, AO_RN_P3_1_PIN, foo, v); ao_led_toggle(AO_BT_LED); } /* And let P3_1 float again */ ao_enable_input(AO_RN_P3_1_PORT, AO_RN_P3_1_PIN, AO_EXTI_MODE_PULL_NONE); + + printf("Reboot BT\n"); flush(); + ao_delay(AO_MS_TO_TICKS(100)); + ao_gpio_set(AO_RN_RST_N_PORT, AO_RN_RST_N_PIN, foo, 0); + ao_delay(AO_MS_TO_TICKS(100)); + ao_gpio_set(AO_RN_RST_N_PORT, AO_RN_RST_N_PIN, foo, 1); } static const struct ao_cmds rn_cmds[] = { diff --git a/src/drivers/ao_rn4678.h b/src/drivers/ao_rn4678.h index d6fea23a..a4dcea38 100644 --- a/src/drivers/ao_rn4678.h +++ b/src/drivers/ao_rn4678.h @@ -56,7 +56,7 @@ */ -#define AO_RN_REBOOT_MSG "%REBOOT%" +#define AO_RN_REBOOT_MSG "REBOOT" #define AO_RN_CMD_TIMEOUT AO_MS_TO_TICKS(200) @@ -67,11 +67,14 @@ #define AO_RN_SET_NAME_CMD "SN," #define AO_RN_GET_NAME_CMD "GN" -#define AO_RN_SET_STATUS_STRING "SO," +#define AO_RN_SET_STATUS_STRING "so," #define AO_RN_STATUS_STRING_DISABLE " " +#define AO_RN_STATUS_STRING_ENABLE "%,%" #define AO_RN_REBOOT_CMD "R,1" +#define AO_RN_VERSION_CMD "V" + #define AO_RN_TIMEOUT -1 #define AO_RN_ERROR 0 #define AO_RN_OK 1 -- cgit v1.2.3 From ea7e236e75452e27f3af6730a0542850851eb23d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 20 Jun 2017 11:19:40 -0700 Subject: altos/rn4678: Add BLE support This just means ignoring the BLE connect status message. Signed-off-by: Keith Packard --- src/drivers/ao_rn4678.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/ao_rn4678.c b/src/drivers/ao_rn4678.c index ba25e70d..98dc35b5 100644 --- a/src/drivers/ao_rn4678.c +++ b/src/drivers/ao_rn4678.c @@ -100,6 +100,7 @@ static const char *status_strings[] = { "RFCOMM_CLOSE", "RFCOMM_OPEN", "CONNECT", + "LCONNECT", "DISCONN", "BONDED", }; @@ -560,8 +561,22 @@ ao_rn_factory(void) ao_gpio_set(AO_RN_RST_N_PORT, AO_RN_RST_N_PIN, foo, 1); } +#if AO_RN_DEBUG +static void +ao_rn_send(void) +{ + int c; + + while ((c = getchar()) != '~') + ao_rn_putchar(c); +} +#endif + static const struct ao_cmds rn_cmds[] = { { ao_rn_factory, "F\0Factory reset rn4678" }, +#if AO_RN_DEBUG + { ao_rn_send, "B\0Send data to rn4678. End with ~" }, +#endif { 0 }, }; -- cgit v1.2.3