From 9182c666ea67f56c64c601a538658777436f9651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 6 Apr 2018 11:04:47 +0200 Subject: [PATCH 1/7] now it's possible to read and write SYSTEM.INI using bulk --- comm/interfaces.c | 98 ++++++++++++++++++++----------------- comm/messages.c | 47 ++++++++++++------ framework/system_settings.c | 46 +++++++++++++---- framework/system_settings.h | 3 ++ platform/cfg_utils.c | 43 ++++++++++++++++ platform/cfg_utils.h | 12 +++++ 6 files changed, 181 insertions(+), 68 deletions(-) diff --git a/comm/interfaces.c b/comm/interfaces.c index 13086ec..2772182 100644 --- a/comm/interfaces.c +++ b/comm/interfaces.c @@ -18,7 +18,7 @@ enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the han static uint32_t last_switch_time = 0; // started with USB static bool xfer_verify_done = false; -static void configure_interface(enum ComportSelection iface); +static bool configure_interface(enum ComportSelection iface); /** Switch com transfer if the current one doesnt seem to work */ void com_switch_transfer_if_needed(void) @@ -30,8 +30,8 @@ void com_switch_transfer_if_needed(void) if (gActiveComport == COMPORT_USB) { if (elapsed > 1000) { - // USB may or may not work, depending on whether the module is plugged - - // in or running from a battery/external supply remotely. + // USB may or may not work, depending on whether the module is plugged in + // or running from a battery/external supply remotely. // Check if USB is enumerated @@ -39,19 +39,30 @@ void com_switch_transfer_if_needed(void) if (0 == uadr) { dbg("Not enumerated, assuming USB is dead"); - // Fallback to bare USART - if (SystemSettings.use_comm_uart) { - configure_interface(COMPORT_USART); - } - else if (SystemSettings.use_comm_nordic) { - configure_interface(COMPORT_NORDIC); // this fallbacks to LoRa if LoRa enabled - } - else if (SystemSettings.use_comm_lora) { - configure_interface(COMPORT_LORA); - } - else { - dbg("No alternate com interface configured, leaving USB enabled."); - } + // Fallback to radio or bare USART + do { + if (SystemSettings.use_comm_nordic) { + if (configure_interface(COMPORT_NORDIC)) { + break; + } + } + + if (SystemSettings.use_comm_lora) { + if (configure_interface(COMPORT_LORA)) { + break; + } + } + + if (SystemSettings.use_comm_uart) { + // after nordic/lora + if (configure_interface(COMPORT_USART)) { + break; + } + } + + dbg("No alternate com interface configured."); + gActiveComport = COMPORT_NONE; + } while (0); } else { dbg("USB got address 0x%02x - OK", (int)uadr); } @@ -131,7 +142,7 @@ void com_iface_flush_buffer(void) } } -static void configure_interface(enum ComportSelection iface) +static bool configure_interface(enum ComportSelection iface) { // Teardown if (gActiveComport == COMPORT_USB) { @@ -146,11 +157,17 @@ static void configure_interface(enum ComportSelection iface) __HAL_RCC_USART2_CLK_DISABLE(); irqd_detach(USART2, com_UsartIrqHandler); } - gActiveComport = COMPORT_NONE; + else if (gActiveComport == COMPORT_NORDIC) { + // TODO + } + + + gActiveComport = iface; // Init if (iface == COMPORT_USB) { trap("illegal"); // this never happens + return false; } else if (iface == COMPORT_USART) { dbg("Setting up UART transfer"); @@ -171,37 +188,28 @@ static void configure_interface(enum ComportSelection iface) LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX); LL_USART_Enable(USART2); - } - else { - if (iface == COMPORT_NORDIC) { - // Try to configure nordic - dbg("Setting up nRF transfer"); - - // TODO set up and check nRF transport - // On failure, try setting up LoRa - dbg("nRF failed to init"); - if (SystemSettings.use_comm_lora) { - iface = COMPORT_LORA; - } else { - iface = COMPORT_NONE; // fail - } - } + return true; // always OK (TODO check voltage on Rx if it's 3V3 when idle?) + } + else if (iface == COMPORT_NORDIC) { + // Try to configure nordic + dbg("Setting up nRF transfer"); - if (iface == COMPORT_LORA) { - // Try to configure nordic - dbg("Setting up LoRa transfer"); + // TODO set up and check nRF transport - // TODO set up and check LoRa transport - dbg("LoRa failed to init"); - iface = COMPORT_NONE; // fail - } + // On failure, try setting up LoRa + dbg("nRF failed to init"); + return false; } - - if (iface == COMPORT_NONE) { - dbg("NO COM PORT AVAILABLE!"); + else if (iface == COMPORT_LORA) { + // Try to configure nordic + dbg("Setting up LoRa transfer"); + // TODO set up and check LoRa transport + dbg("LoRa failed to init"); + return false; + } + else { + trap("Bad iface %d", iface); } - - gActiveComport = iface; } diff --git a/comm/messages.c b/comm/messages.c index e1b679a..77c399d 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -58,26 +58,33 @@ static TF_Result lst_list_units(TinyFrame *tf, TF_Msg *msg) // --------------------------------------------------------------------------- -/** Callback for bulk read of the settings file */ -static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer) +/** Callback for bulk read of a settings file */ +static void ini_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer) { // clean-up request if (buffer == NULL) { free_ck(bulk); iw_end(); -// dbg("INI read complete."); return; } if (bulk->offset == 0) iw_begin(); IniWriter iw = iw_init((char *)buffer, bulk->offset, chunk); - iw.tag = 1; - settings_build_units_ini(&iw); + iw.tag = 1; // indicates this is read via the API (affects some comments) + + uint8_t filenum = (uint8_t) (int) bulk->userdata; + + if (filenum == 0) { + settings_build_units_ini(&iw); + } + else if (filenum == 1) { + settings_build_system_ini(&iw); + } } /** - * Listener: Export INI file via TF + * Listener: Export a file via TF */ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg) { @@ -86,14 +93,29 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg) BulkRead *bulk = malloc_ck(sizeof(BulkRead)); assert_param(bulk != NULL); + uint8_t filenum = 0; + + // if any payload, the first byte defines the file to read + // 0 - units + // 1 - system + // (this is optional for backwards compatibility) + if (msg->len > 0) { + filenum = msg->data[0]; + } + bulk->frame_id = msg->frame_id; - bulk->len = iw_measure_total(settings_build_units_ini, 1); - bulk->read = settings_bulkread_cb; - bulk->userdata = NULL; + bulk->read = ini_bulkread_cb; + bulk->userdata = (void *) (int)filenum; + + if (filenum == 0) { + bulk->len = iw_measure_total(settings_build_units_ini, 1); + } + else if (filenum == 1) { + bulk->len = iw_measure_total(settings_build_system_ini, 1); + } bulkread_start(tf, bulk); Indicator_Effect(STATUS_DISK_BUSY_SHORT); - return TF_STAY; } @@ -142,7 +164,7 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg) PayloadParser pp = pp_start(msg->data, msg->len, NULL); uint32_t len = pp_u32(&pp); if (!pp.ok) { - com_respond_error(msg->frame_id, E_PROTOCOL_BREACH); + com_respond_error(msg->frame_id, E_MALFORMED_COMMAND); goto done; } @@ -151,11 +173,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg) settings_load_ini_begin(); ini_parse_begin(iniparser_cb, NULL); - bulkwrite_start(tf, bulk); - Indicator_Effect(STATUS_DISK_BUSY); - done: return TF_STAY; } diff --git a/framework/system_settings.c b/framework/system_settings.c index 8e49142..d8f462c 100644 --- a/framework/system_settings.c +++ b/framework/system_settings.c @@ -2,8 +2,6 @@ // Created by MightyPork on 2017/12/02. // -#include -#include #include "platform.h" #include "system_settings.h" #include "utils/str_utils.h" @@ -11,6 +9,8 @@ #include "cfg_utils.h" #include "resources.h" #include "unit_base.h" +#include "platform/debug_uart.h" +#include "comm/interfaces.h" static void systemsettings_mco_teardown(void); static void systemsettings_mco_init(void); @@ -171,18 +171,34 @@ void systemsettings_build_ini(IniWriter *iw) iw_entry_d(iw, "mco-prediv", (1< 0)"); + iw_entry(iw, "nrf-address", "%02X", + SystemSettings.nrf_address); + // those aren't implement yet, don't tease the user // TODO show pin-out, extra settings if applicable #if 0 - iw_comment(iw, "nRF24L01+"); - iw_entry_s(iw, "com-nordic", str_yn(SystemSettings.use_comm_nrf24l01p)); - iw_comment(iw, "LoRa/GFSK sx127x"); iw_entry_s(iw, "com-lora", str_yn(SystemSettings.use_comm_sx127x)); #endif @@ -241,12 +257,24 @@ bool systemsettings_load_ini(const char *restrict key, const char *restrict valu if (suc) SystemSettings.comm_uart_baud = baud; } -#if 0 - if (streq(key, "com-nordic")) { + if (streq(key, "com-nrf")) { bool yn = cfg_bool_parse(value, &suc); if (suc) SystemSettings.use_comm_nordic = yn; } + if (streq(key, "nrf-channel")) { + SystemSettings.nrf_channel = cfg_u8_parse(value, &suc); + } + + if (streq(key, "nrf-address")) { + cfg_hex_parse(&SystemSettings.nrf_address, 1, value, &suc); + } + + if (streq(key, "nrf-network")) { + cfg_hex_parse(&SystemSettings.nrf_network[0], 4, value, &suc); + } + +#if 0 if (streq(key, "com-lora")) { bool yn = cfg_bool_parse(value, &suc); if (suc) SystemSettings.use_comm_lora = yn; diff --git a/framework/system_settings.h b/framework/system_settings.h index 94cf4da..1f866e9 100644 --- a/framework/system_settings.h +++ b/framework/system_settings.h @@ -27,6 +27,9 @@ struct system_settings { uint32_t comm_uart_baud; // baud rate for the uart transport bool use_comm_lora; // SX1276/8 bool use_comm_nordic; // nRF24L01+ + uint8_t nrf_channel; + uint8_t nrf_network[4]; + uint8_t nrf_address; // Support flags put here for scoping, but not atcually part of the persistent settings volatile bool editable; //!< True if we booted with the LOCK jumper removed diff --git a/platform/cfg_utils.c b/platform/cfg_utils.c index b8bef60..e580e61 100644 --- a/platform/cfg_utils.c +++ b/platform/cfg_utils.c @@ -297,3 +297,46 @@ uint32_t cfg_enum4_parse(const char *value, *suc = false; return na; } + +void cfg_hex_parse(uint8_t *dest, uint32_t count, const char *value, bool *suc) +{ + // discard possible leading 0x + if (value[0] == '0' && value[1] == 'x') { + value += 2; + } + + uint8_t bytebuf = 0; + for (uint32_t digit = 0; digit < count * 2;) { + char v = *value; + if (v != 0) value++; + + uint8_t nibble = 0; + if (v == ' ' || v == '.' || v == '-' || v == ':') { + continue; // junk + } + else if (v >= '0' && v <= '9') { + nibble = (uint8_t) (v - '0'); + } + else if (v >= 'a' && v <= 'f') { + nibble = (uint8_t) (10 + (v - 'a')); + } + else if (v >= 'A' && v <= 'F') { + nibble = (uint8_t) (10 + (v - 'A')); + } + else if (v == 0) { + nibble = 0; // pad with zeros + } + else { + *suc = false; + return; + } + + digit++; + bytebuf <<= 4; + bytebuf |= nibble; + if ((digit % 2 == 0) && digit > 0) { // whole byte + *dest++ = bytebuf; + bytebuf = 0; + } + } +} diff --git a/platform/cfg_utils.h b/platform/cfg_utils.h index 05f8ebe..de34c19 100644 --- a/platform/cfg_utils.h +++ b/platform/cfg_utils.h @@ -116,6 +116,18 @@ uint32_t cfg_enum4_parse(const char *tpl, const char *d, uint32_t nd, bool *suc); +/** + * Parse a hexa string to a byte array. + * Skips 0x prefix, '.', '-', ':', ' '. + * + * @param[out] dest - storage array + * @param[in] count - expected number of bytes + * @param[in] value - parsed string + * @param[out] suc - success flag + */ +void cfg_hex_parse(uint8_t *dest, uint32_t count, + const char *value, bool *suc); + /** Convert bool to a Y or N constant string */ #define str_yn(cond) ((cond) ? ("Y") : ("N")) From 5eec46c0418f7264227044085ec55831cc84dcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 6 Apr 2018 17:29:10 +0200 Subject: [PATCH 2/7] nordic implemented, need testing and fixes --- TinyFrame/TF_Integration.c | 75 +----- comm/iface_nordic.c | 165 +++++++++++++ comm/iface_nordic.h | 20 ++ comm/iface_uart.c | 105 ++++++++ comm/iface_uart.h | 20 ++ comm/iface_usb.c | 73 ++++++ comm/iface_usb.h | 20 ++ comm/interfaces.c | 126 ++-------- comm/nrf.c | 467 +++++++++++++++++++++++++++++++++++ comm/nrf.h | 159 ++++++++++++ comm/nrf_pins.h | 33 +++ framework/system_settings.c | 81 +++--- gex_hooks.c | 11 +- platform/platform.c | 3 + units/digital_in/_din_init.c | 14 +- 15 files changed, 1167 insertions(+), 205 deletions(-) create mode 100644 comm/iface_nordic.c create mode 100644 comm/iface_nordic.h create mode 100644 comm/iface_uart.c create mode 100644 comm/iface_uart.h create mode 100644 comm/iface_usb.c create mode 100644 comm/iface_usb.h create mode 100644 comm/nrf.c create mode 100644 comm/nrf.h create mode 100644 comm/nrf_pins.h diff --git a/TinyFrame/TF_Integration.c b/TinyFrame/TF_Integration.c index 0b660dc..31d982f 100644 --- a/TinyFrame/TF_Integration.c +++ b/TinyFrame/TF_Integration.c @@ -8,6 +8,9 @@ #include "task_main.h" #include "comm/messages.h" #include "comm/interfaces.h" +#include "comm/iface_uart.h" +#include "comm/iface_nordic.h" +#include "comm/iface_usb.h" #include "framework/system_settings.h" #include "USB/usbd_cdc_if.h" @@ -17,76 +20,16 @@ extern osSemaphoreId semVcomTxReadyHandle; extern osMutexId mutTinyFrameTxHandle; -/** - * USB transmit implementation - * - * @param tf - TF - * @param buff - buffer to send (can be longer than the buffers) - * @param len - buffer size - */ -static inline void _USB_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) -{ -#if 1 - const uint32_t real_size = len; - - // Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed - if ((len&0x3F) && !SystemSettings.visible_vcom) { // this corrupts VCOM on Linux for some reason - uint32_t pad = (64 - (len&0x3F)); - memset((void *) (buff + len), 0, pad); - len += pad; // padding to a multiple of 64 (size of the endpoint) - } - - // We bypass the USBD driver library's overhead by using the HAL function directly - assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len)); - - // The buffer is the TF transmit buffer, we can't leave it to work asynchronously because - // the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame) - - // If this is not the last chunk (assuming all but the last use full 512 bytes of the TF buffer), wait now for completion - if (real_size == TF_SENDBUF_LEN) { - // TODO this seems wrong - investigate - if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) { - TF_Error("Tx stalled in WriteImpl"); - return; - } - } -#else - (void) tf; -#define CHUNK 64 // size of the USB packet - int32_t total = (int32_t) len; - while (total > 0) { - const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100); - if (mxStatus != osOK) { - TF_Error("Tx stalled"); - return; - } - - const uint16_t chunksize = (uint16_t) MIN(total, CHUNK); - - // this is an attempt to speed it up a little by removing a couple levels of indirection - assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize)); - -// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize); -// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize)); - - buff += chunksize; - total -= chunksize; - } -#endif -} - void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) { if (gActiveComport == COMPORT_USB) { - _USB_WriteImpl(tf, buff, len); + iface_usb_transmit(buff, len); } else if (gActiveComport == COMPORT_USART) { - // TODO rewrite this to use DMA, then wait for the DMA - for(uint32_t i=0;i 0) { + dbg("NRF RX %d bytes", (int)count); + rxQuePostMsg(rx_buffer, count); + } else { + dbg("IRQ but no Rx"); + } +} + +bool iface_nordic_init(void) +{ + dbg("Setting up Nordic..."); + + hw_periph_clock_enable(NRF_SPI); + + // SPI pins + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_SCK, NRF_SPI_AF)); + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_MOSI, NRF_SPI_AF)); + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_MISO, NRF_SPI_AF)); + + // Manual pins + LL_GPIO_SetPinMode(NRF_NSS_GPIO_Port, NRF_NSS_Pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinMode(NRF_CE_GPIO_Port, NRF_CE_Pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinMode(NRF_IRQ_GPIO_Port, NRF_IRQ_Pin, LL_GPIO_MODE_INPUT); + + LL_SPI_Disable(NRF_SPI); + { + LL_SPI_SetBaudRatePrescaler(NRF_SPI, LL_SPI_BAUDRATEPRESCALER_DIV8); + + LL_SPI_SetClockPolarity(NRF_SPI, LL_SPI_POLARITY_LOW); + LL_SPI_SetClockPhase(NRF_SPI, LL_SPI_PHASE_2EDGE); + LL_SPI_SetTransferDirection(NRF_SPI, LL_SPI_FULL_DUPLEX); + LL_SPI_SetTransferBitOrder(NRF_SPI, LL_SPI_MSB_FIRST); + + LL_SPI_SetNSSMode(NRF_SPI, LL_SPI_NSS_SOFT); + LL_SPI_SetDataWidth(NRF_SPI, LL_SPI_DATAWIDTH_8BIT); + LL_SPI_SetRxFIFOThreshold(NRF_SPI, LL_SPI_RX_FIFO_TH_QUARTER); // trigger RXNE on 1 byte + + LL_SPI_SetMode(NRF_SPI, LL_SPI_MODE_MASTER); + } + LL_SPI_Enable(NRF_SPI); + + + dbg("configure nrf module"); + + // Now configure the radio + NRF_Init(NRF_SPEED_2M); // TODO configurable speed + NRF_SetChannel(SystemSettings.nrf_channel); + NRF_SetBaseAddress(SystemSettings.nrf_network); + NRF_SetRxAddress(RX_PIPE_NUM, SystemSettings.nrf_address); + NRF_ModeRX(); + + dbg("enable exti"); + // EXTI + LL_EXTI_EnableIT_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); + LL_EXTI_EnableFallingTrig_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); + LL_SYSCFG_SetEXTISource(NRF_SYSCFG_EXTI_PORT, LL_SYSCFG_EXTI_LINES[NRF_EXTI_LINENUM]); + irqd_attach(EXTIS[NRF_EXTI_LINENUM], NrfIrqHandler, NULL); + // TODO increase priority in NVIC? + + dbg("nrf setup done"); + return true; +} + +void iface_nordic_deinit(void) +{ + LL_EXTI_DisableIT_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); + LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); + irqd_detach(EXTIS[NRF_EXTI_LINENUM], NrfIrqHandler); + hw_periph_clock_disable(NRF_SPI); + + hw_deinit_pin_rsc(NRF_R_SCK); + hw_deinit_pin_rsc(NRF_R_MOSI); + hw_deinit_pin_rsc(NRF_R_MISO); + hw_deinit_pin_rsc(NRF_R_NSS); + hw_deinit_pin_rsc(NRF_R_CE); + hw_deinit_pin_rsc(NRF_R_IRQ); +} + +#define MAX_RETRY 8 + +void iface_nordic_transmit(const uint8_t *buff, uint32_t len) +{ + bool suc = false; + while (len > 0) { + uint8_t chunk = (uint8_t) MIN(32, len); + + uint16_t delay = 1; + for (int i = 0; i < MAX_RETRY; i++) { + suc = NRF_SendPacket(RX_PIPE_NUM, buff, chunk); // use the pipe to retrieve the address + if (!suc) { + vTaskDelay(delay); + delay += 5; // longer delay next time + } else { + break; + } + } + + if (!suc) { + break; + } + + buff += chunk; + len -= chunk; + } + + if (suc) { + dbg("+ NRF Tx OK!"); + } else { + dbg("- NRF sending failed"); + } + + // give when it's done + xSemaphoreGive(semVcomTxReadyHandle); // similar to how it's done in USB - this is called in the Tx Done handler +} diff --git a/comm/iface_nordic.h b/comm/iface_nordic.h new file mode 100644 index 0000000..c07d739 --- /dev/null +++ b/comm/iface_nordic.h @@ -0,0 +1,20 @@ +// +// Created by MightyPork on 2018/04/06. +// + +#ifndef GEX_F072_IFACE_NORDIC_H +#define GEX_F072_IFACE_NORDIC_H + +#include "platform.h" + +void iface_nordic_claim_resources(void); + +void iface_nordic_free_resources(void); + +void iface_nordic_deinit(void); + +bool iface_nordic_init(void); + +void iface_nordic_transmit(const uint8_t *buff, uint32_t len); + +#endif //GEX_F072_IFACE_NORDIC_H diff --git a/comm/iface_uart.c b/comm/iface_uart.c new file mode 100644 index 0000000..0d4393e --- /dev/null +++ b/comm/iface_uart.c @@ -0,0 +1,105 @@ +// +// Created by MightyPork on 2018/04/06. +// + +#include "platform.h" +#include "iface_uart.h" +#include "resources.h" +#include "hw_utils.h" +#include "irq_dispatcher.h" +#include "task_msg.h" +#include "system_settings.h" + +extern osSemaphoreId semVcomTxReadyHandle; + +static uint32_t usart_rxi = 0; +static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE]; +static uint32_t last_rx_time = 0; + +void iface_uart_claim_resources(void) +{ + assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_USART2)); + assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_PA2)); + assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_PA3)); +} + +void iface_uart_free_resources(void) +{ + rsc_free(&UNIT_SYSTEM, R_USART2); + rsc_free(&UNIT_SYSTEM, R_PA2); + rsc_free(&UNIT_SYSTEM, R_PA3); +} + +/** Handler for the USART transport */ +static void com_UsartIrqHandler(void *arg) +{ + (void)arg; + if (LL_USART_IsActiveFlag_RXNE(USART2)) { + vPortEnterCritical(); + { + usart_rx_buffer[usart_rxi++] = LL_USART_ReceiveData8(USART2); + if (usart_rxi == MSG_QUE_SLOT_SIZE) { + rxQuePostMsg(usart_rx_buffer, MSG_QUE_SLOT_SIZE); // avoid it happening in the irq + usart_rxi = 0; + } + last_rx_time = HAL_GetTick(); + } + vPortExitCritical(); + } +} + +/** this is called from the hal tick irq */ +void com_iface_flush_buffer(void) +{ + if (usart_rxi > 0 && (HAL_GetTick()-last_rx_time)>=2) { + vPortEnterCritical(); + { + rxQuePostMsg(usart_rx_buffer, usart_rxi); + usart_rxi = 0; + } + vPortExitCritical(); + } +} + +bool iface_uart_init(void) +{ + dbg("Setting up UART transfer"); + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA2, LL_GPIO_AF_1)); + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA3, LL_GPIO_AF_1)); + + __HAL_RCC_USART2_CLK_ENABLE(); + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + + LL_USART_Disable(USART2); + + LL_USART_SetBaudRate(USART2, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, SystemSettings.comm_uart_baud); + dbg("baud = %d", (int)SystemSettings.comm_uart_baud); + + irqd_attach(USART2, com_UsartIrqHandler, NULL); + LL_USART_EnableIT_RXNE(USART2); + LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX); + + LL_USART_Enable(USART2); + + return true; // always OK (TODO check voltage on Rx if it's 3V3 when idle?) +} + +void iface_uart_deinit(void) +{ + // this doesn't normally happen + hw_deinit_pin_rsc(R_PA2); + hw_deinit_pin_rsc(R_PA3); + __HAL_RCC_USART2_CLK_DISABLE(); + irqd_detach(USART2, com_UsartIrqHandler); +} + +void iface_uart_transmit(const uint8_t *buff, uint32_t len) +{ + // TODO rewrite this to use DMA, then wait for the DMA + for(uint32_t i=0;iDADDR & USB_DADDR_ADD); +} + +/** + * USB transmit implementation + * + * @param buff - buffer to send (can be longer than the buffers) + * @param len - buffer size + */ +void iface_usb_transmit(const uint8_t *buff, uint32_t len) +{ +#if 1 + const uint32_t real_size = len; + + // Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed + if ((len&0x3F) && !SystemSettings.visible_vcom) { // this corrupts VCOM on Linux for some reason + uint32_t pad = (64 - (len&0x3F)); + memset((void *) (buff + len), 0, pad); + len += pad; // padding to a multiple of 64 (size of the endpoint) + } + + // We bypass the USBD driver library's overhead by using the HAL function directly + assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len)); + + // The buffer is the TF transmit buffer, we can't leave it to work asynchronously because + // the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame) + + // If this is not the last chunk (assuming all but the last use full 512 bytes of the TF buffer), wait now for completion + if (real_size == TF_SENDBUF_LEN) { + // TODO this seems wrong - investigate + if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) { + TF_Error("Tx stalled in WriteImpl"); + return; + } + } +#else + (void) tf; +#define CHUNK 64 // size of the USB packet + int32_t total = (int32_t) len; + while (total > 0) { + const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100); + if (mxStatus != osOK) { + TF_Error("Tx stalled"); + return; + } + + const uint16_t chunksize = (uint16_t) MIN(total, CHUNK); + + // this is an attempt to speed it up a little by removing a couple levels of indirection + assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize)); + +// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize); +// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize)); + + buff += chunksize; + total -= chunksize; + } +#endif +} diff --git a/comm/iface_usb.h b/comm/iface_usb.h new file mode 100644 index 0000000..d83f370 --- /dev/null +++ b/comm/iface_usb.h @@ -0,0 +1,20 @@ +// +// Created by MightyPork on 2018/04/06. +// + +#ifndef GEX_F072_IFACE_USB_H +#define GEX_F072_IFACE_USB_H + +#include "platform.h" + +bool iface_usb_ready(void); + +/** + * USB transmit implementation + * + * @param buff - buffer to send (can be longer than the buffers) + * @param len - buffer size + */ +void iface_usb_transmit(const uint8_t *buff, uint32_t len); + +#endif //GEX_F072_IFACE_USB_H diff --git a/comm/interfaces.c b/comm/interfaces.c index 2772182..595beec 100644 --- a/comm/interfaces.c +++ b/comm/interfaces.c @@ -2,7 +2,6 @@ // Created by MightyPork on 2018/03/23. // -#include #include "platform.h" #include "usbd_core.h" #include "USB/usb_device.h" @@ -12,6 +11,10 @@ #include "framework/resources.h" #include "platform/hw_utils.h" #include "framework/unit_base.h" +#include "nrf_pins.h" +#include "iface_uart.h" +#include "iface_usb.h" +#include "iface_nordic.h" enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the handlers work correctly initially @@ -35,36 +38,31 @@ void com_switch_transfer_if_needed(void) // Check if USB is enumerated - const uint32_t uadr = (USB->DADDR & USB_DADDR_ADD); - if (0 == uadr) { + if (!iface_usb_ready()) { dbg("Not enumerated, assuming USB is dead"); // Fallback to radio or bare USART do { if (SystemSettings.use_comm_nordic) { - if (configure_interface(COMPORT_NORDIC)) { - break; - } + if (configure_interface(COMPORT_NORDIC)) break; } +#if 0 if (SystemSettings.use_comm_lora) { - if (configure_interface(COMPORT_LORA)) { - break; - } + if (configure_interface(COMPORT_LORA)) break; } +#endif if (SystemSettings.use_comm_uart) { // after nordic/lora - if (configure_interface(COMPORT_USART)) { - break; - } + if (configure_interface(COMPORT_USART)) break; } dbg("No alternate com interface configured."); gActiveComport = COMPORT_NONE; } while (0); } else { - dbg("USB got address 0x%02x - OK", (int)uadr); + dbg("USB got address - OK"); } xfer_verify_done = true; @@ -76,24 +74,11 @@ void com_switch_transfer_if_needed(void) void com_claim_resources_for_alt_transfers(void) { if (SystemSettings.use_comm_uart) { - do { - if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_USART2)) { - SystemSettings.use_comm_uart = false; - break; - } + iface_uart_claim_resources(); + } - if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA2)) { - SystemSettings.use_comm_uart = false; - rsc_free(&UNIT_SYSTEM, R_USART2); - break; - } - if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA3)) { - SystemSettings.use_comm_uart = false; - rsc_free(&UNIT_SYSTEM, R_USART2); - rsc_free(&UNIT_SYSTEM, R_PA2); - break; - } - } while (0); + if (SystemSettings.use_comm_nordic) { + iface_nordic_claim_resources(); } } @@ -101,46 +86,14 @@ void com_claim_resources_for_alt_transfers(void) void com_release_resources_for_alt_transfers(void) { if (SystemSettings.use_comm_uart) { - rsc_free(&UNIT_SYSTEM, R_USART2); - rsc_free(&UNIT_SYSTEM, R_PA2); - rsc_free(&UNIT_SYSTEM, R_PA3); + iface_uart_free_resources(); } -} - -static uint32_t usart_rxi = 0; -static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE]; -static uint32_t last_rx_time = 0; -/** Handler for the USART transport */ -static void com_UsartIrqHandler(void *arg) -{ - (void)arg; - if (LL_USART_IsActiveFlag_RXNE(USART2)) { - vPortEnterCritical(); - { - usart_rx_buffer[usart_rxi++] = LL_USART_ReceiveData8(USART2); - if (usart_rxi == MSG_QUE_SLOT_SIZE) { - rxQuePostMsg(usart_rx_buffer, MSG_QUE_SLOT_SIZE); // avoid it happening in the irq - usart_rxi = 0; - } - last_rx_time = HAL_GetTick(); - } - vPortExitCritical(); + if (SystemSettings.use_comm_nordic) { + iface_nordic_free_resources(); } } -/** this is called from the hal tick irq */ -void com_iface_flush_buffer(void) -{ - if (usart_rxi > 0 && (HAL_GetTick()-last_rx_time)>=2) { - vPortEnterCritical(); - { - rxQuePostMsg(usart_rx_buffer, usart_rxi); - usart_rxi = 0; - } - vPortExitCritical(); - } -} static bool configure_interface(enum ComportSelection iface) { @@ -151,14 +104,10 @@ static bool configure_interface(enum ComportSelection iface) __HAL_RCC_USB_CLK_DISABLE(); } else if (gActiveComport == COMPORT_USART) { - // this doesn't normally happen - hw_deinit_pin_rsc(R_PA2); - hw_deinit_pin_rsc(R_PA3); - __HAL_RCC_USART2_CLK_DISABLE(); - irqd_detach(USART2, com_UsartIrqHandler); + iface_uart_deinit(); } else if (gActiveComport == COMPORT_NORDIC) { - // TODO + iface_nordic_deinit(); } @@ -170,45 +119,20 @@ static bool configure_interface(enum ComportSelection iface) return false; } else if (iface == COMPORT_USART) { - dbg("Setting up UART transfer"); - assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA2, LL_GPIO_AF_1)); - assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA3, LL_GPIO_AF_1)); - - __HAL_RCC_USART2_CLK_ENABLE(); - __HAL_RCC_USART2_FORCE_RESET(); - __HAL_RCC_USART2_RELEASE_RESET(); - - LL_USART_Disable(USART2); - - LL_USART_SetBaudRate(USART2, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, SystemSettings.comm_uart_baud); - dbg("baud = %d", (int)SystemSettings.comm_uart_baud); - - irqd_attach(USART2, com_UsartIrqHandler, NULL); - LL_USART_EnableIT_RXNE(USART2); - LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX); - - LL_USART_Enable(USART2); - - return true; // always OK (TODO check voltage on Rx if it's 3V3 when idle?) + return iface_uart_init(); } else if (iface == COMPORT_NORDIC) { - // Try to configure nordic - dbg("Setting up nRF transfer"); - - // TODO set up and check nRF transport - - - // On failure, try setting up LoRa - dbg("nRF failed to init"); - return false; + return iface_nordic_init(); } +#if 0 else if (iface == COMPORT_LORA) { // Try to configure nordic dbg("Setting up LoRa transfer"); // TODO set up and check LoRa transport - dbg("LoRa failed to init"); + dbg("LoRa not impl!"); return false; } +#endif else { trap("Bad iface %d", iface); } diff --git a/comm/nrf.c b/comm/nrf.c new file mode 100644 index 0000000..dd7e5aa --- /dev/null +++ b/comm/nrf.c @@ -0,0 +1,467 @@ +// +// Created by MightyPork on 2018/04/02. +// + +#include "platform.h" +#include "nrf.h" + +/** + * Read a register + * + * @param reg - register number (max 83) + * @return register value + */ +static uint8_t NRF_ReadRegister(uint8_t reg); + +/** + * Write a register + * + * @param reg - register number (max 83) + * @param value - register value + * @return status register value + */ +static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value); + +// Internal use +static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes); + +static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes); + +/** + * Set TX address for next frame + * + * @param SendTo - addr + */ +static void NRF_SetTxAddress(uint8_t ToAddr); + +//---------------------------------------------------------- + +/** Tight asm loop */ +#define __asm_loop(cycles) \ +do { \ + register uint32_t _count asm ("r4") = cycles; \ + asm volatile( \ + ".syntax unified\n" \ + ".thumb\n" \ + "0:" \ + "subs %0, #1\n" \ + "bne 0b\n" \ + : "+r" (_count)); \ +} while(0) + +// 12 for 72 MHz +#define _delay_us(n) __asm_loop((n)*8) + +static inline void CE(bool level) { + if (level) LL_GPIO_SetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin); + else LL_GPIO_ResetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin); +} + +static inline void NSS(bool level) { + if (level) LL_GPIO_SetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin); + else LL_GPIO_ResetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin); +} + +static uint8_t spi(uint8_t tx) { + while (! LL_SPI_IsActiveFlag_TXE(NRF_SPI)); + LL_SPI_TransmitData8(NRF_SPI, tx); + while (! LL_SPI_IsActiveFlag_RXNE(NRF_SPI)); + return LL_SPI_ReceiveData8(NRF_SPI); +} + +//------- + +/* + * from: http://barefootelectronics.com/NRF24L01.aspx + */ + +#define CMD_READ_REG 0x00 // Read command to register +#define CMD_WRITE_REG 0x20 // Write command to register +#define CMD_RD_RX_PLD 0x61 // Read RX payload register address +#define CMD_WR_TX_PLD 0xA0 // Write TX payload register address +#define CMD_FLUSH_TX 0xE1 // Flush TX register command +#define CMD_FLUSH_RX 0xE2 // Flush RX register command +#define CMD_REUSE_TX_PL 0xE3 // Reuse TX payload register command +#define CMD_RD_RX_PL_WIDTH 0x60 // Read RX Payload Width +#define CMD_WR_ACK_PLD 0xA8 // Write ACK payload for Pipe (Add pipe number 0-6) +#define CMD_WR_TX_PLD_NK 0xB0 // Write ACK payload for not ack +#define CMD_NOP 0xFF // No Operation, might be used to read status register + +// SPI(nRF24L01) registers(addresses) +#define RG_CONFIG 0x00 // 'Config' register address +#define RG_EN_AA 0x01 // 'Enable Auto Acknowledgment' register address +#define RG_EN_RXADDR 0x02 // 'Enabled RX addresses' register address +#define RG_SETUP_AW 0x03 // 'Setup address width' register address +#define RG_SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address +#define RG_RF_CH 0x05 // 'RF channel' register address +#define RG_RF_SETUP 0x06 // 'RF setup' register address +#define RG_STATUS 0x07 // 'Status' register address +#define RG_OBSERVE_TX 0x08 // 'Observe TX' register address +#define RG_CD 0x09 // 'Carrier Detect' register address +#define RG_RX_ADDR_P0 0x0A // 'RX address pipe0' register address +#define RG_RX_ADDR_P1 0x0B // 'RX address pipe1' register address +#define RG_RX_ADDR_P2 0x0C // 'RX address pipe2' register address +#define RG_RX_ADDR_P3 0x0D // 'RX address pipe3' register address +#define RG_RX_ADDR_P4 0x0E // 'RX address pipe4' register address +#define RG_RX_ADDR_P5 0x0F // 'RX address pipe5' register address +#define RG_TX_ADDR 0x10 // 'TX address' register address +#define RG_RX_PW_P0 0x11 // 'RX payload width, pipe0' register address +#define RG_RX_PW_P1 0x12 // 'RX payload width, pipe1' register address +#define RG_RX_PW_P2 0x13 // 'RX payload width, pipe2' register address +#define RG_RX_PW_P3 0x14 // 'RX payload width, pipe3' register address +#define RG_RX_PW_P4 0x15 // 'RX payload width, pipe4' register address +#define RG_RX_PW_P5 0x16 // 'RX payload width, pipe5' register address +#define RG_FIFO_STATUS 0x17 // 'FIFO Status Register' register address +#define RG_DYNPD 0x1C // 'Enable dynamic payload length +#define RG_FEATURE 0x1D // 'Feature register + +#define RD_STATUS_TX_FULL 0x01 // tx queue full +#define RD_STATUS_RX_PNO 0x0E // pipe number of the received payload +#define RD_STATUS_MAX_RT 0x10 // max retransmissions +#define RD_STATUS_TX_DS 0x20 // data sent +#define RD_STATUS_RX_DR 0x40 // data ready + +#define RD_CONFIG_PRIM_RX 0x01 // is primary receiver +#define RD_CONFIG_PWR_UP 0x02 // power up +#define RD_CONFIG_CRCO 0x04 // 2-byte CRC +#define RD_CONFIG_EN_CRC 0x08 // enable CRC +#define RD_CONFIG_DISABLE_IRQ_MAX_RT 0x10 +#define RD_CONFIG_DISABLE_IRQ_TX_DS 0x20 +#define RD_CONFIG_DISABLE_IRQ_RX_DR 0x40 + +// Config register bits (excluding the bottom two that are changed dynamically) +// enable only Rx IRQ +#define ModeBits (RD_CONFIG_DISABLE_IRQ_MAX_RT | \ + RD_CONFIG_DISABLE_IRQ_TX_DS | \ + RD_CONFIG_EN_CRC | \ + RD_CONFIG_CRCO) + +#define CEHIGH CE(1) +#define CELOW CE(0) + +static inline uint8_t CS(uint8_t hl) +{ + if (hl == 1) { + NSS(0); + } + else { + NSS(1); + } + return hl; +} + +#define CHIPSELECT for (uint8_t cs = CS(1); cs==1; cs = CS(0)) + +// Base NRF address - byte 4 may be modified before writing to a pipe register, +// the first 4 bytes are shared in the network. Master is always code 0. +static uint8_t nrf_base_address[5]; + +static uint8_t nrf_pipe_addr[6]; +static bool nrf_pipe_enabled[6]; + +static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value) +{ + uint8_t status = 0; + CHIPSELECT { + status = spi(CMD_WRITE_REG | reg); + spi(value); + } + return status; +} + +static uint8_t NRF_ReadRegister(uint8_t reg) +{ + uint8_t reg_val = 0; + CHIPSELECT { + spi(CMD_READ_REG | reg); + reg_val = spi(0); + } + return reg_val; +} + +static uint8_t NRF_ReadStatus(void) +{ + uint8_t reg_val = 0; + CHIPSELECT { + reg_val = spi(CMD_NOP); + } + return reg_val; +} + +static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes) +{ + uint8_t status = 0, i = 0; + CHIPSELECT { + status = spi(CMD_WRITE_REG | reg); + for (i = 0; i < bytes; i++) { + spi(*pBuf++); + } + } + return status; +} + +static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes) +{ + uint8_t status = 0, i; + CHIPSELECT { + status = spi(CMD_READ_REG | reg); + for (i = 0; i < bytes; i++) { + pBuf[i] = spi(0); + } + } + return status; +} + +void NRF_SetBaseAddress(const uint8_t *Bytes4) +{ + memcpy(nrf_base_address, Bytes4, 4); + nrf_base_address[4] = 0; +} + +void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte) +{ + if (pipenum > 5) { + dbg("!! bad pipe %d", pipenum); + return; + } + + nrf_base_address[4] = AddrByte; + + nrf_pipe_addr[pipenum] = AddrByte; + + if (pipenum == 0) { + NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); + } + else if (pipenum == 1) { + NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5); + } + else { + NRF_WriteRegister(RG_RX_ADDR_P2 + (pipenum - 2), AddrByte); + } +} + +bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum) +{ + for (uint8_t i = 0; i < 6; i++) { + if(!nrf_pipe_enabled[i]) { + NRF_SetRxAddress(i, AddrByte); + *PipeNum = i; + NRF_EnablePipe(i); + return true; + } + } + + return false; +} + +uint8_t NRF_PipeNum2Addr(uint8_t pipe_num) +{ + if (pipe_num > 5) return 0; // fail + return nrf_pipe_addr[pipe_num]; +} + +uint8_t NRF_Addr2PipeNum(uint8_t addr) +{ + for (int i = 0; i < 6; i++) { + if (nrf_pipe_addr[i] == addr) return (uint8_t) i; + } + return 0xFF; +} + +void NRF_EnablePipe(uint8_t pipenum) +{ + uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR); + enabled |= 1 << pipenum; + NRF_WriteRegister(RG_EN_RXADDR, enabled); + + nrf_pipe_enabled[pipenum] = 1; +} + +void NRF_DisablePipe(uint8_t pipenum) +{ + uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR); + enabled &= ~(1 << pipenum); + NRF_WriteRegister(RG_EN_RXADDR, enabled); + + nrf_pipe_enabled[pipenum] = 0; +} + +static void NRF_SetTxAddress(uint8_t SendTo) +{ + nrf_base_address[4] = SendTo; + NRF_WriteBuffer(RG_TX_ADDR, nrf_base_address, 5); + NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); // the ACK will come to pipe 0 +} + +void NRF_PowerDown(void) +{ + CELOW; + NRF_WriteRegister(RG_CONFIG, ModeBits); +} + +void NRF_ModeTX(void) +{ + CELOW; + uint8_t m = NRF_ReadRegister(RG_CONFIG); + NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP); + if ((m & RD_CONFIG_PWR_UP) == 0) LL_mDelay(5); +} + +void NRF_ModeRX(void) +{ + NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP | RD_CONFIG_PRIM_RX); + NRF_SetRxAddress(0, nrf_pipe_addr[0]); // set the P0 address - it was changed during Rx for ACK reception + CEHIGH; + + //if ((m&2)==0) LL_mDelay()(5); You don't need to wait. Just nothing will come for 5ms or more +} + +uint8_t NRF_IsModePowerDown(void) +{ + uint8_t ret = 0; + if ((NRF_ReadRegister(RG_CONFIG) & RD_CONFIG_PWR_UP) == 0) ret = 1; + return ret; +} + +uint8_t NRF_IsModeTX(void) +{ + uint8_t m = NRF_ReadRegister(RG_CONFIG); + if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF + if ((m & RD_CONFIG_PRIM_RX) == 0) return 1; + return 0; +} + +uint8_t NRF_IsModeRx(void) +{ + uint8_t m = NRF_ReadRegister(RG_CONFIG); + if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF + if ((m & RD_CONFIG_PRIM_RX) == 0) return 0; + return 1; +} + +void NRF_SetChannel(uint8_t Ch) +{ + NRF_WriteRegister(RG_RF_CH, Ch); +} + +uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum) +{ + uint8_t pw = 0, status; + if (!NRF_IsRxPacket()) return 0; + + CELOW; + CHIPSELECT { + status = spi(CMD_RD_RX_PL_WIDTH); + pw = spi(0); + } + + if (pw > 32) { + CHIPSELECT { + spi(CMD_FLUSH_RX); + } + NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); + return 0; + } + + // Read the reception pipe number + *PipeNum = (status & RD_STATUS_RX_PNO) >> 1; + + CHIPSELECT { + spi(CMD_RD_RX_PLD); + for (uint8_t i = 0; i < pw; i++) Packet[i] = spi(0); + } + NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt + CEHIGH; + return pw; +} + +bool NRF_IsRxPacket(void) +{ + uint8_t ret = NRF_ReadRegister(RG_STATUS) & RD_STATUS_RX_DR; + return 0 != ret; +} + +bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length) +{ + if (!nrf_pipe_enabled[PipeNum]) { + dbg("!! Pipe %d not enabled", PipeNum); + return 0; + } + + const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG); + CELOW; + NRF_ModeTX(); // Make sure in TX mode + NRF_SetTxAddress(nrf_pipe_addr[PipeNum]); + + CHIPSELECT { + spi(CMD_FLUSH_TX); + }; + + CHIPSELECT { + spi(CMD_WR_TX_PLD); + for (uint8_t i = 0; i < Length; i++) spi(Packet[i]); + }; + + CEHIGH; + _delay_us(15); // At least 10 us + CELOW; + + uint8_t st = 0; + while ((st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)) == 0) { + st = NRF_ReadStatus(); // Packet acked or timed out + } + + NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit + + if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { + NRF_PowerDown(); + } + else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { + NRF_ModeRX(); + } + + return 0 != (st & RD_STATUS_TX_DS); // success +} + +void NRF_Reset(void) +{ + NSS(1); + CELOW; + NRF_PowerDown(); + + NRF_WriteRegister(RG_EN_RXADDR, 0); // disable all pipes + + for (int i = 0; i < 6; i++) { + nrf_pipe_addr[i] = 0; + nrf_pipe_enabled[i] = 0; + } +} + +void NRF_Init(uint8_t pSpeed) +{ + // Set the required output pins + NSS(1); + CELOW; + + LL_mDelay(200); + + NRF_WriteRegister(RG_CONFIG, ModeBits); + NRF_WriteRegister(RG_SETUP_AW, 0b11); // 5 byte addresses + + // default +// NRF_EnablePipe(0); + + NRF_WriteRegister(RG_SETUP_RETR, 0x18); // 8 retries + NRF_WriteRegister(RG_RF_CH, 2); // channel 2 NO HIGHER THAN 83 in USA! + + NRF_WriteRegister(RG_RF_SETUP, pSpeed); + + NRF_WriteRegister(RG_DYNPD, 0b111111); // Dynamic packet length + NRF_WriteRegister(RG_FEATURE, 0b100); // Enable dynamic payload, and no payload in the ack. + + for (int i = 0; i < 6; i++) { + NRF_WriteRegister(RG_RX_PW_P0+i, 32); // Receive 32 byte packets - XXX this is probably not needed with dynamic length + } + + //NRFModePowerDown(); // Already in power down mode, dummy +} diff --git a/comm/nrf.h b/comm/nrf.h new file mode 100644 index 0000000..a2e1dc2 --- /dev/null +++ b/comm/nrf.h @@ -0,0 +1,159 @@ +// +// Created by MightyPork on 2018/04/02. +// + +#ifndef GEX_NRF_NRF_H +#define GEX_NRF_NRF_H + +/* + * nordic.h + * + * Created:12/16/2013 3:36:04 PM + * Author: Tom + * + * NRF24L01+ Library II + * + */ + + +#ifndef NORDIC_H_ +#define NORDIC_H_ + +#include "platform.h" +#include "resources.h" +#include "nrf_pins.h" + +// Initialize SPI and the Nordic + +/** + * Initialize the NRF module + * + * @param pSpeed + */ +void NRF_Init(uint8_t pSpeed); + +#define NRF_SPEED_500k 0b00100110 +#define NRF_SPEED_2M 0b00001110 +#define NRF_SPEED_1M 0b00000110 + +/** + * Set reception address + * @param pipenum - pipe to set + * @param AddrByte - byte 0 + */ +void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte); + +/** + * Set communication channel + */ +void NRF_SetChannel(uint8_t Ch) ; // 0 through 83 only! + +/** + * Power down the transceiver + */ +void NRF_PowerDown(void); + +/** + * Selecr RX mode + */ +void NRF_ModeRX(void); + +/** + * Select TX mode + */ +void NRF_ModeTX(void); + +/** + * @return NRF is power down + */ +uint8_t NRF_IsModePowerDown(void); + +/** + * @return NRF in TX mode + */ +uint8_t NRF_IsModeTX(void); + +/** + * @return NRF in RX mode + */ +uint8_t NRF_IsModeRx(void); + +/** + * Add a pipe to the next free slot + * + * @param AddrByte - address byte of the peer + * @param[out] PipeNum - pipe number is written here + * @return success + */ +bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum); + +/** + * Convert pipe number to address byte + * + * @param pipe_num - pipe number + * @return address byte + */ +uint8_t NRF_PipeNum2Addr(uint8_t pipe_num); + +/** + * Convert address to a pipe number + * + * @param addr + * @return + */ +uint8_t NRF_Addr2PipeNum(uint8_t addr); + +/** + * Reset as much as possible (incl. removing pipes) + */ +void NRF_Reset(void); + +/** + * Send a packet (takes care of mode switching etc) + * + * @param PipeNum - pipe number + * @param Packet - packet bytes + * @param Length - packet length + * @return success (ACK'd) + */ +bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length); + +/** + * Receive a packet + * + * @param[out] Packet - the receiuved packet - buffer that is written + * @param[out] PipeNum - pipe number that was received from + * @return packet size, 0 on failure + */ +uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum); + +/** + * Set base address + * @param Bytes4 + */ +void NRF_SetBaseAddress(const uint8_t *Bytes4); + +/** + * Check if there's a packet to be read + * + * @return 1 if any to read + */ +bool NRF_IsRxPacket(void); + +/** + * Enable a pipe + * + * @param pipenum - pipe number 0-5 + */ +void NRF_EnablePipe(uint8_t pipenum); + +/** + * Disable a pipe + * + * @param pipenum - pipe number 0-5 + */ +void NRF_DisablePipe(uint8_t pipenum); + +#endif /* NORDIC_H_ */ + +#endif //GEX_NRF_NRF_H diff --git a/comm/nrf_pins.h b/comm/nrf_pins.h new file mode 100644 index 0000000..c30b4aa --- /dev/null +++ b/comm/nrf_pins.h @@ -0,0 +1,33 @@ +// +// Created by MightyPork on 2018/04/06. +// + +#ifndef GEX_F072_NRF_PINS_H +#define GEX_F072_NRF_PINS_H + +#include "platform.h" + +// TODO move those to plat_compat? +#define NRF_SPI SPI1 +#define NRF_R_SPI R_SPI1 + +#define NRF_IRQ_Pin LL_GPIO_PIN_10 +#define NRF_IRQ_GPIO_Port GPIOB +#define NRF_R_IRQ R_PB10 +#define NRF_EXTI_LINENUM 10 +#define NRF_SYSCFG_EXTI_PORT LL_SYSCFG_EXTI_PORTB + +#define NRF_NSS_Pin LL_GPIO_PIN_11 +#define NRF_NSS_GPIO_Port GPIOB +#define NRF_R_NSS R_PB11 + +#define NRF_CE_Pin LL_GPIO_PIN_12 +#define NRF_CE_GPIO_Port GPIOB +#define NRF_R_CE R_PB12 + +#define NRF_R_SCK R_PA5 +#define NRF_R_MISO R_PA6 +#define NRF_R_MOSI R_PA7 +#define NRF_SPI_AF LL_GPIO_AF_0 + +#endif //GEX_F072_NRF_PINS_H diff --git a/framework/system_settings.c b/framework/system_settings.c index d8f462c..3dbda4a 100644 --- a/framework/system_settings.c +++ b/framework/system_settings.c @@ -49,7 +49,7 @@ void systemsettings_init(void) void systemsettings_save(PayloadBuilder *pb) { pb_char(pb, 'S'); - pb_u8(pb, 2); // settings format version + pb_u8(pb, 3); // settings format version { // system settings pb_bool(pb, SystemSettings.visible_vcom); @@ -63,9 +63,52 @@ void systemsettings_save(PayloadBuilder *pb) pb_bool(pb, SystemSettings.use_comm_lora); pb_u32(pb, SystemSettings.comm_uart_baud); pb_bool(pb, SystemSettings.enable_debug_uart); + // 3 + pb_u8(pb, SystemSettings.nrf_channel); + pb_u8(pb, SystemSettings.nrf_address); + pb_buf(pb, SystemSettings.nrf_network, 4); } // end system settings } + +// from binary +bool systemsettings_load(PayloadParser *pp) +{ + if (pp_char(pp) != 'S') return false; + + systemsettings_begin_load(); + + uint8_t version = pp_u8(pp); + + { // system settings + SystemSettings.visible_vcom = pp_bool(pp); + SystemSettings.ini_comments = pp_bool(pp); + + // conditional fields based on version + if (version >= 1) { + SystemSettings.enable_mco = pp_bool(pp); + SystemSettings.mco_prediv = pp_u8(pp); + } + if (version >= 2) { + SystemSettings.use_comm_uart = pp_bool(pp); + SystemSettings.use_comm_nordic = pp_bool(pp); + SystemSettings.use_comm_lora = pp_bool(pp); + SystemSettings.comm_uart_baud = pp_u32(pp); + SystemSettings.enable_debug_uart = pp_bool(pp); + } + if (version >= 3) { + SystemSettings.nrf_channel = pp_u8(pp); + SystemSettings.nrf_address = pp_u8(pp); + pp_buf(pp, SystemSettings.nrf_network, 4); + } + } // end system settings + + systemsettings_finalize_load(); + + return pp->ok; +} + + void systemsettings_mco_teardown(void) { if (SystemSettings.enable_mco) { @@ -80,8 +123,7 @@ void systemsettings_mco_init(void) assert_param(rsc_claim(&UNIT_SYSTEM, R_PA8) == E_SUCCESS); assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA8, LL_GPIO_AF_0)); - LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK, - SystemSettings.mco_prediv << RCC_CFGR_MCOPRE_Pos); + LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK, SystemSettings.mco_prediv << RCC_CFGR_MCOPRE_Pos); } else { LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_NOCLOCK, 0); } @@ -115,39 +157,6 @@ void systemsettings_finalize_load(void) com_claim_resources_for_alt_transfers(); } -// from binary -bool systemsettings_load(PayloadParser *pp) -{ - if (pp_char(pp) != 'S') return false; - - systemsettings_begin_load(); - - uint8_t version = pp_u8(pp); - - { // system settings - SystemSettings.visible_vcom = pp_bool(pp); - SystemSettings.ini_comments = pp_bool(pp); - - // conditional fields based on version - if (version >= 1) { - SystemSettings.enable_mco = pp_bool(pp); - SystemSettings.mco_prediv = pp_u8(pp); - } - if (version >= 2) { - SystemSettings.use_comm_uart = pp_bool(pp); - SystemSettings.use_comm_nordic = pp_bool(pp); - SystemSettings.use_comm_lora = pp_bool(pp); - SystemSettings.comm_uart_baud = pp_u32(pp); - SystemSettings.enable_debug_uart = pp_bool(pp); - } - } // end system settings - - systemsettings_finalize_load(); - - return pp->ok; -} - - /** * Write system settings to INI (without section) */ diff --git a/gex_hooks.c b/gex_hooks.c index c0a920a..9da2fb5 100644 --- a/gex_hooks.c +++ b/gex_hooks.c @@ -11,13 +11,17 @@ #include "gex_hooks.h" #include "unit_registry.h" #include "comm/interfaces.h" +#include "system_settings.h" /** * This is a systick callback for GEX application logic */ void GEX_MsTick(void) { - com_iface_flush_buffer(); + if (gActiveComport == COMPORT_USART) { + com_iface_flush_buffer(); + } + TF_Tick(comm); Indicator_Tick(); ureg_tick_units(); @@ -28,6 +32,11 @@ void GEX_MsTick(void) */ void GEX_PreInit(void) { + // this is a hack to make logging of the initial messages work + // it's problematic because we shouldn't even enable the debug uart if it's disabled in the system settings + // TODO move system settings load earlier and check the uart flag in advance + SystemSettings.enable_debug_uart = true; + __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); diff --git a/platform/platform.c b/platform/platform.c index 4e1ebf3..b4dda15 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -41,6 +41,9 @@ void plat_init_resources(void) ureg_add_type(&UNIT_TEST); #endif + // EXTI are always available + rsc_free_range(NULL, R_EXTI0, R_EXTI15); + // --- platform specific resource releases and claims --- #if defined(GEX_PLAT_F103_BLUEPILL) diff --git a/units/digital_in/_din_init.c b/units/digital_in/_din_init.c index 7d501ce..ff3edff 100644 --- a/units/digital_in/_din_init.c +++ b/units/digital_in/_din_init.c @@ -54,7 +54,19 @@ error_t DIn_init(Unit *unit) // Claim all needed pins TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins)); - uint16_t mask = 1; + uint16_t mask; + + // claim the needed EXTIs + mask = 1; + for (int i = 0; i < 16; i++, mask <<= 1) { + if (priv->pins & mask) { + if ((priv->trig_rise|priv->trig_fall) & mask) { + TRY(rsc_claim(unit, R_EXTI0+i)); + } + } + } + + mask = 1; for (int i = 0; i < 16; i++, mask <<= 1) { if (priv->pins & mask) { uint32_t ll_pin = hw_pin2ll((uint8_t) i, &suc); From 2f4101a6e0f19d78d6e6126d659946a8ccdce358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 8 Apr 2018 10:45:45 +0200 Subject: [PATCH 3/7] nordic fixes, still not working --- comm/iface_nordic.c | 1 + comm/nrf.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/comm/iface_nordic.c b/comm/iface_nordic.c index 4a307a2..1c152e1 100644 --- a/comm/iface_nordic.c +++ b/comm/iface_nordic.c @@ -98,6 +98,7 @@ bool iface_nordic_init(void) NRF_SetChannel(SystemSettings.nrf_channel); NRF_SetBaseAddress(SystemSettings.nrf_network); NRF_SetRxAddress(RX_PIPE_NUM, SystemSettings.nrf_address); + NRF_EnablePipe(RX_PIPE_NUM); NRF_ModeRX(); dbg("enable exti"); diff --git a/comm/nrf.c b/comm/nrf.c index dd7e5aa..985538d 100644 --- a/comm/nrf.c +++ b/comm/nrf.c @@ -166,6 +166,7 @@ static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value) status = spi(CMD_WRITE_REG | reg); spi(value); } + dbg("Wr[0x%02x] := 0x%02x", (int)reg, (int) value); return status; } @@ -176,6 +177,7 @@ static uint8_t NRF_ReadRegister(uint8_t reg) spi(CMD_READ_REG | reg); reg_val = spi(0); } + dbg("Rd[0x%02x] = 0x%02x", (int)reg, (int) reg_val); return reg_val; } @@ -229,10 +231,13 @@ void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte) nrf_pipe_addr[pipenum] = AddrByte; + dbg("Set Rx addr (pipe %d) = 0x%02x", (int)pipenum, AddrByte); if (pipenum == 0) { + dbg("W ADDR_PA0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); } else if (pipenum == 1) { + dbg("W ADDR_PA1: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5); } else { @@ -289,18 +294,23 @@ void NRF_DisablePipe(uint8_t pipenum) static void NRF_SetTxAddress(uint8_t SendTo) { nrf_base_address[4] = SendTo; + + dbg("W Tx_ADDR + Rx0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); NRF_WriteBuffer(RG_TX_ADDR, nrf_base_address, 5); NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); // the ACK will come to pipe 0 } void NRF_PowerDown(void) { + dbg("PDn"); CELOW; NRF_WriteRegister(RG_CONFIG, ModeBits); } void NRF_ModeTX(void) { + dbg("Tx Mode"); + CELOW; uint8_t m = NRF_ReadRegister(RG_CONFIG); NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP); @@ -309,6 +319,7 @@ void NRF_ModeTX(void) void NRF_ModeRX(void) { + dbg("Rx Mode"); NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP | RD_CONFIG_PRIM_RX); NRF_SetRxAddress(0, nrf_pipe_addr[0]); // set the P0 address - it was changed during Rx for ACK reception CEHIGH; @@ -411,12 +422,16 @@ bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length) st = NRF_ReadStatus(); // Packet acked or timed out } + dbg("Send status: MAX_RT %d, SENT %d", (st&RD_STATUS_MAX_RT) != 0, (st&RD_STATUS_TX_DS) != 0); + NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { + dbg("going back PwrDn"); NRF_PowerDown(); } else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { + dbg("going back PwrUp+Rx"); NRF_ModeRX(); } From e4ae8e23fc3192ab877add5b73ec721b7345b1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 8 Apr 2018 21:23:24 +0200 Subject: [PATCH 4/7] working nordic comm, tested. May need cleaning --- comm/iface_nordic.c | 20 +++--- comm/interfaces.c | 9 +++ comm/interfaces.h | 2 + comm/messages.c | 3 +- comm/nrf.c | 144 +++++++++++++++++++++++++++----------------- comm/nrf.h | 8 +-- gex.mk | 2 +- 7 files changed, 118 insertions(+), 70 deletions(-) diff --git a/comm/iface_nordic.c b/comm/iface_nordic.c index 1c152e1..4b16c14 100644 --- a/comm/iface_nordic.c +++ b/comm/iface_nordic.c @@ -9,10 +9,11 @@ #include "nrf.h" #include "unit_base.h" #include "system_settings.h" +#include "utils/hexdump.h" extern osSemaphoreId semVcomTxReadyHandle; -#define RX_PIPE_NUM 1 +#define RX_PIPE_NUM 0 void iface_nordic_claim_resources(void) { @@ -45,16 +46,18 @@ static uint8_t rx_buffer[32]; static void NrfIrqHandler(void *arg) { LL_EXTI_ClearFlag_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); + dbg_nrf("[EXTI] ---"); uint8_t pipenum; uint8_t count = NRF_ReceivePacket(rx_buffer, &pipenum); if (count > 0) { - dbg("NRF RX %d bytes", (int)count); + dbg_nrf("NRF RX %d bytes", (int)count); rxQuePostMsg(rx_buffer, count); } else { dbg("IRQ but no Rx"); } + dbg_nrf("--- end [EXTI]"); } bool iface_nordic_init(void) @@ -75,10 +78,11 @@ bool iface_nordic_init(void) LL_SPI_Disable(NRF_SPI); { - LL_SPI_SetBaudRatePrescaler(NRF_SPI, LL_SPI_BAUDRATEPRESCALER_DIV8); + LL_SPI_SetBaudRatePrescaler(NRF_SPI, LL_SPI_BAUDRATEPRESCALER_DIV32); + //LL_SPI_BAUDRATEPRESCALER_DIV8 LL_SPI_SetClockPolarity(NRF_SPI, LL_SPI_POLARITY_LOW); - LL_SPI_SetClockPhase(NRF_SPI, LL_SPI_PHASE_2EDGE); + LL_SPI_SetClockPhase(NRF_SPI, LL_SPI_PHASE_1EDGE); LL_SPI_SetTransferDirection(NRF_SPI, LL_SPI_FULL_DUPLEX); LL_SPI_SetTransferBitOrder(NRF_SPI, LL_SPI_MSB_FIRST); @@ -128,7 +132,8 @@ void iface_nordic_deinit(void) hw_deinit_pin_rsc(NRF_R_IRQ); } -#define MAX_RETRY 8 +// FIXME +#define MAX_RETRY 5 void iface_nordic_transmit(const uint8_t *buff, uint32_t len) { @@ -137,11 +142,12 @@ void iface_nordic_transmit(const uint8_t *buff, uint32_t len) uint8_t chunk = (uint8_t) MIN(32, len); uint16_t delay = 1; + //hexDump("Tx chunk", buff, chunk); for (int i = 0; i < MAX_RETRY; i++) { suc = NRF_SendPacket(RX_PIPE_NUM, buff, chunk); // use the pipe to retrieve the address if (!suc) { vTaskDelay(delay); - delay += 5; // longer delay next time + delay *= 2; // longer delay next time } else { break; } @@ -156,7 +162,7 @@ void iface_nordic_transmit(const uint8_t *buff, uint32_t len) } if (suc) { - dbg("+ NRF Tx OK!"); + dbg_nrf("+ NRF Tx OK!"); } else { dbg("- NRF sending failed"); } diff --git a/comm/interfaces.c b/comm/interfaces.c index 595beec..0ab281c 100644 --- a/comm/interfaces.c +++ b/comm/interfaces.c @@ -16,6 +16,15 @@ #include "iface_usb.h" #include "iface_nordic.h" +const char * COMPORT_NAMES[] = { + "NONE", + "USB", + "UART", + "NRF", + "LORA", +}; + + enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the handlers work correctly initially static uint32_t last_switch_time = 0; // started with USB diff --git a/comm/interfaces.h b/comm/interfaces.h index 5d65766..fe56abe 100644 --- a/comm/interfaces.h +++ b/comm/interfaces.h @@ -15,6 +15,8 @@ enum ComportSelection { COMPORT_LORA = 4, }; +extern const char * COMPORT_NAMES[]; + /** * The currently active communication port */ diff --git a/comm/messages.c b/comm/messages.c index 77c399d..170d8b9 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -11,6 +11,7 @@ #include "framework/system_settings.h" #include "utils/malloc_safe.h" #include "platform/status_led.h" +#include "interfaces.h" static TinyFrame tf_; TinyFrame *comm = &tf_; @@ -23,7 +24,7 @@ TinyFrame *comm = &tf_; static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg) { com_respond_snprintf(msg->frame_id, MSG_SUCCESS, - "GEX v%s on %s", GEX_VERSION, GEX_PLATFORM); + "GEX v%s on %s (%s)", GEX_VERSION, GEX_PLATFORM, COMPORT_NAMES[gActiveComport]); return TF_STAY; } diff --git a/comm/nrf.c b/comm/nrf.c index 985538d..97da551 100644 --- a/comm/nrf.c +++ b/comm/nrf.c @@ -53,13 +53,17 @@ do { \ #define _delay_us(n) __asm_loop((n)*8) static inline void CE(bool level) { + __asm_loop(1); if (level) LL_GPIO_SetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin); else LL_GPIO_ResetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin); + __asm_loop(1); } static inline void NSS(bool level) { + __asm_loop(1); if (level) LL_GPIO_SetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin); else LL_GPIO_ResetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin); + __asm_loop(1); } static uint8_t spi(uint8_t tx) { @@ -136,9 +140,6 @@ static uint8_t spi(uint8_t tx) { RD_CONFIG_EN_CRC | \ RD_CONFIG_CRCO) -#define CEHIGH CE(1) -#define CELOW CE(0) - static inline uint8_t CS(uint8_t hl) { if (hl == 1) { @@ -166,7 +167,21 @@ static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value) status = spi(CMD_WRITE_REG | reg); spi(value); } - dbg("Wr[0x%02x] := 0x%02x", (int)reg, (int) value); + dbg_nrf("Wr[0x%02x] := 0x%02x", (int)reg, (int) value); + + + uint8_t reg_val = 0; + CHIPSELECT { + spi(CMD_READ_REG | reg); + reg_val = spi(0); + } + dbg_nrf(" verify 0x%02x", (int)reg_val); + if (reg_val != value) + dbg_nrf(" !!!"); + else + dbg_nrf(" OK"); + + return status; } @@ -177,7 +192,7 @@ static uint8_t NRF_ReadRegister(uint8_t reg) spi(CMD_READ_REG | reg); reg_val = spi(0); } - dbg("Rd[0x%02x] = 0x%02x", (int)reg, (int) reg_val); + dbg_nrf("Rd[0x%02x] = 0x%02x", (int)reg, (int) reg_val); return reg_val; } @@ -218,12 +233,17 @@ void NRF_SetBaseAddress(const uint8_t *Bytes4) { memcpy(nrf_base_address, Bytes4, 4); nrf_base_address[4] = 0; + + // write it to the two full-width address registers + NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); + nrf_base_address[4] = 1;// to be different + NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5); } void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte) { if (pipenum > 5) { - dbg("!! bad pipe %d", pipenum); + dbg_nrf("!! bad pipe %d", pipenum); return; } @@ -231,13 +251,13 @@ void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte) nrf_pipe_addr[pipenum] = AddrByte; - dbg("Set Rx addr (pipe %d) = 0x%02x", (int)pipenum, AddrByte); + dbg_nrf("Set Rx addr (pipe %d) = 0x%02x", (int)pipenum, AddrByte); if (pipenum == 0) { - dbg("W ADDR_PA0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); + dbg_nrf("W ADDR_PA0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); } else if (pipenum == 1) { - dbg("W ADDR_PA1: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); + dbg_nrf("W ADDR_PA1: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5); } else { @@ -275,6 +295,7 @@ uint8_t NRF_Addr2PipeNum(uint8_t addr) void NRF_EnablePipe(uint8_t pipenum) { + dbg_nrf("Enable pipe num %d", (int)pipenum); uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR); enabled |= 1 << pipenum; NRF_WriteRegister(RG_EN_RXADDR, enabled); @@ -295,34 +316,39 @@ static void NRF_SetTxAddress(uint8_t SendTo) { nrf_base_address[4] = SendTo; - dbg("W Tx_ADDR + Rx0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); + dbg_nrf("W Tx_ADDR + Rx0: %02X-%02X-%02X-%02X-%02X", + nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); + NRF_WriteBuffer(RG_TX_ADDR, nrf_base_address, 5); NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); // the ACK will come to pipe 0 } void NRF_PowerDown(void) { - dbg("PDn"); - CELOW; + dbg_nrf("PDn"); + CE(0); NRF_WriteRegister(RG_CONFIG, ModeBits); } void NRF_ModeTX(void) { - dbg("Tx Mode"); + dbg_nrf("Tx Mode"); - CELOW; + CE(0); uint8_t m = NRF_ReadRegister(RG_CONFIG); NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP); - if ((m & RD_CONFIG_PWR_UP) == 0) LL_mDelay(5); + if ((m & RD_CONFIG_PWR_UP) == 0) { + // switching on + LL_mDelay(5); + } } void NRF_ModeRX(void) { - dbg("Rx Mode"); + dbg_nrf("Rx Mode"); NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP | RD_CONFIG_PRIM_RX); NRF_SetRxAddress(0, nrf_pipe_addr[0]); // set the P0 address - it was changed during Rx for ACK reception - CEHIGH; + CE(1); //if ((m&2)==0) LL_mDelay()(5); You don't need to wait. Just nothing will come for 5ms or more } @@ -360,7 +386,9 @@ uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum) uint8_t pw = 0, status; if (!NRF_IsRxPacket()) return 0; - CELOW; + const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG); + CE(0); // quit Rx mode - go idle + CHIPSELECT { status = spi(CMD_RD_RX_PL_WIDTH); pw = spi(0); @@ -370,19 +398,25 @@ uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum) CHIPSELECT { spi(CMD_FLUSH_RX); } - NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); - return 0; + pw = 0; + } else { + // Read the reception pipe number + *PipeNum = ((status & RD_STATUS_RX_PNO) >> 1); + CHIPSELECT { + spi(CMD_RD_RX_PLD); + for (uint8_t i = 0; i < pw; i++) Packet[i] = spi(0); + } } + NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt - // Read the reception pipe number - *PipeNum = (status & RD_STATUS_RX_PNO) >> 1; - - CHIPSELECT { - spi(CMD_RD_RX_PLD); - for (uint8_t i = 0; i < pw; i++) Packet[i] = spi(0); + if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { + dbg_nrf("going back PwrDn"); + NRF_PowerDown(); + } + else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { + dbg_nrf("going back PwrUp+Rx"); + NRF_ModeRX(); } - NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt - CEHIGH; return pw; } @@ -395,14 +429,16 @@ bool NRF_IsRxPacket(void) bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length) { if (!nrf_pipe_enabled[PipeNum]) { - dbg("!! Pipe %d not enabled", PipeNum); + dbg_nrf("!! Pipe %d not enabled", PipeNum); return 0; } + dbg_nrf("Will tx to addr %02x", nrf_pipe_addr[PipeNum]); + const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG); - CELOW; + CE(0); NRF_ModeTX(); // Make sure in TX mode - NRF_SetTxAddress(nrf_pipe_addr[PipeNum]); + NRF_SetTxAddress(nrf_pipe_addr[PipeNum]); // this sets the Tx addr and also pipe 0 addr for ACK CHIPSELECT { spi(CMD_FLUSH_TX); @@ -413,58 +449,56 @@ bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length) for (uint8_t i = 0; i < Length; i++) spi(Packet[i]); }; - CEHIGH; - _delay_us(15); // At least 10 us - CELOW; + // CE pulse + CE(1); + _delay_us(20); // At least 10 us + CE(0); uint8_t st = 0; while ((st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)) == 0) { st = NRF_ReadStatus(); // Packet acked or timed out } - dbg("Send status: MAX_RT %d, SENT %d", (st&RD_STATUS_MAX_RT) != 0, (st&RD_STATUS_TX_DS) != 0); + dbg_nrf("Send status: 0x%02x - MAX_RT %d, SENT %d", (int)st, + (st&RD_STATUS_MAX_RT) != 0, (st&RD_STATUS_TX_DS) != 0); NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { - dbg("going back PwrDn"); + dbg_nrf("going back PwrDn"); NRF_PowerDown(); } else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { - dbg("going back PwrUp+Rx"); + dbg_nrf("going back PwrUp+Rx"); NRF_ModeRX(); } return 0 != (st & RD_STATUS_TX_DS); // success } -void NRF_Reset(void) +void NRF_Init(uint8_t pSpeed) { + // Set the required output pins NSS(1); - CELOW; - NRF_PowerDown(); + CE(0); - NRF_WriteRegister(RG_EN_RXADDR, 0); // disable all pipes + LL_mDelay(200); for (int i = 0; i < 6; i++) { nrf_pipe_addr[i] = 0; nrf_pipe_enabled[i] = 0; } -} -void NRF_Init(uint8_t pSpeed) -{ - // Set the required output pins - NSS(1); - CELOW; - - LL_mDelay(200); + // clear flags etc + NRF_PowerDown(); + CHIPSELECT { spi(CMD_FLUSH_RX); } + CHIPSELECT { spi(CMD_FLUSH_TX); } + NRF_WriteRegister(RG_STATUS, 0x70); NRF_WriteRegister(RG_CONFIG, ModeBits); NRF_WriteRegister(RG_SETUP_AW, 0b11); // 5 byte addresses - // default -// NRF_EnablePipe(0); + NRF_WriteRegister(RG_EN_RXADDR, 0x01); // disable all, enable pipe 0 - this is required for shockburst, despite not being specified in the DS NRF_WriteRegister(RG_SETUP_RETR, 0x18); // 8 retries NRF_WriteRegister(RG_RF_CH, 2); // channel 2 NO HIGHER THAN 83 in USA! @@ -474,9 +508,7 @@ void NRF_Init(uint8_t pSpeed) NRF_WriteRegister(RG_DYNPD, 0b111111); // Dynamic packet length NRF_WriteRegister(RG_FEATURE, 0b100); // Enable dynamic payload, and no payload in the ack. - for (int i = 0; i < 6; i++) { - NRF_WriteRegister(RG_RX_PW_P0+i, 32); // Receive 32 byte packets - XXX this is probably not needed with dynamic length - } - - //NRFModePowerDown(); // Already in power down mode, dummy +// for (int i = 0; i < 6; i++) { +// NRF_WriteRegister(RG_RX_PW_P0+i, 32); // Receive 32 byte packets - XXX this is probably not needed with dynamic length +// } } diff --git a/comm/nrf.h b/comm/nrf.h index a2e1dc2..e671d71 100644 --- a/comm/nrf.h +++ b/comm/nrf.h @@ -23,6 +23,9 @@ #include "resources.h" #include "nrf_pins.h" +#define dbg_nrf(...) do{}while(0) +//#define dbg_nrf(...) dbg(##__VA_ARGS__) + // Initialize SPI and the Nordic /** @@ -103,11 +106,6 @@ uint8_t NRF_PipeNum2Addr(uint8_t pipe_num); */ uint8_t NRF_Addr2PipeNum(uint8_t addr); -/** - * Reset as much as possible (incl. removing pipes) - */ -void NRF_Reset(void); - /** * Send a packet (takes care of mode switching etc) * diff --git a/gex.mk b/gex.mk index 5921c08..8fbd5e4 100644 --- a/gex.mk +++ b/gex.mk @@ -95,7 +95,7 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DDEBUG_VFS=0 \ -DDEBUG_FLASH_WRITE=0 \ -DVERBOSE_HARDFAULT=1 \ - -DUSE_STACK_MONITOR=1 \ + -DUSE_STACK_MONITOR=0 \ -DUSE_DEBUG_UART=1 \ -DDEBUG_MALLOC=0 \ -DDEBUG_RSC=0 From 2bad5d69e60ded76510a8c71863d2c7ee3759490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 9 Apr 2018 21:49:12 +0200 Subject: [PATCH 5/7] possibly improved the rx routine --- comm/iface_nordic.c | 19 +++++++++++-------- comm/nrf.c | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/comm/iface_nordic.c b/comm/iface_nordic.c index 4b16c14..3bef6bf 100644 --- a/comm/iface_nordic.c +++ b/comm/iface_nordic.c @@ -48,15 +48,18 @@ static void NrfIrqHandler(void *arg) LL_EXTI_ClearFlag_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); dbg_nrf("[EXTI] ---"); - uint8_t pipenum; - uint8_t count = NRF_ReceivePacket(rx_buffer, &pipenum); - - if (count > 0) { - dbg_nrf("NRF RX %d bytes", (int)count); - rxQuePostMsg(rx_buffer, count); - } else { - dbg("IRQ but no Rx"); + while (NRF_IsRxPacket()) { + uint8_t pipenum; + uint8_t count = NRF_ReceivePacket(rx_buffer, &pipenum); + if (count > 0) { + dbg_nrf("NRF RX %d bytes", (int) count); + rxQuePostMsg(rx_buffer, count); + } + else { + dbg("IRQ but no Rx"); + } } + dbg_nrf("--- end [EXTI]"); } diff --git a/comm/nrf.c b/comm/nrf.c index 97da551..45670e2 100644 --- a/comm/nrf.c +++ b/comm/nrf.c @@ -133,6 +133,12 @@ static uint8_t spi(uint8_t tx) { #define RD_CONFIG_DISABLE_IRQ_TX_DS 0x20 #define RD_CONFIG_DISABLE_IRQ_RX_DR 0x40 +#define RD_FIFO_STATUS_RX_EMPTY 0x01 +#define RD_FIFO_STATUS_RX_FULL 0x02 +#define RD_FIFO_STATUS_TX_EMPTY 0x10 +#define RD_FIFO_STATUS_TX_FULL 0x20 +#define RD_FIFO_STATUS_TX_REUSE 0x40 + // Config register bits (excluding the bottom two that are changed dynamically) // enable only Rx IRQ #define ModeBits (RD_CONFIG_DISABLE_IRQ_MAX_RT | \ @@ -384,21 +390,29 @@ void NRF_SetChannel(uint8_t Ch) uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum) { uint8_t pw = 0, status; - if (!NRF_IsRxPacket()) return 0; +// if (!NRF_IsRxPacket()) { +// dbg("rx queue empty"); +// return 0; +// } - const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG); - CE(0); // quit Rx mode - go idle +// const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG); +// CE(0); // quit Rx mode - go idle CHIPSELECT { status = spi(CMD_RD_RX_PL_WIDTH); pw = spi(0); } + if (pw == 0) { + dbg("empty pld"); + } + if (pw > 32) { CHIPSELECT { spi(CMD_FLUSH_RX); } pw = 0; + dbg("over 32"); } else { // Read the reception pipe number *PipeNum = ((status & RD_STATUS_RX_PNO) >> 1); @@ -409,21 +423,23 @@ uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum) } NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt - if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { - dbg_nrf("going back PwrDn"); - NRF_PowerDown(); - } - else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { - dbg_nrf("going back PwrUp+Rx"); - NRF_ModeRX(); - } +// if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { +// dbg_nrf("going back PwrDn"); +// NRF_PowerDown(); +// } +// else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { +// dbg_nrf("going back PwrUp+Rx"); +// NRF_ModeRX(); +// } +// CE(1); // back to rx return pw; } bool NRF_IsRxPacket(void) { - uint8_t ret = NRF_ReadRegister(RG_STATUS) & RD_STATUS_RX_DR; - return 0 != ret; + return 0 == (NRF_ReadRegister(RG_FIFO_STATUS) & RD_FIFO_STATUS_RX_EMPTY); +// uint8_t ret = NRF_ReadRegister(RG_STATUS) & RD_STATUS_RX_DR; +// return 0 != ret; } bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length) From dc78c4da41642cdbda018f96bc555054828102fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 9 Apr 2018 22:06:41 +0200 Subject: [PATCH 6/7] add default settings for nordic --- framework/system_settings.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/framework/system_settings.c b/framework/system_settings.c index 3dbda4a..936bc3d 100644 --- a/framework/system_settings.c +++ b/framework/system_settings.c @@ -32,6 +32,15 @@ void systemsettings_loadDefaults(void) SystemSettings.use_comm_nordic = false; SystemSettings.comm_uart_baud = 115200; // TODO + // just a demo, user must change this + SystemSettings.nrf_network[0] = 0x12; + SystemSettings.nrf_network[2] = 0x09; + SystemSettings.nrf_network[3] = 0x4c; + SystemSettings.nrf_network[4] = 0x61; + + SystemSettings.nrf_address = 1; + SystemSettings.nrf_channel = 76; + SystemSettings.enable_debug_uart = true; } @@ -195,14 +204,14 @@ void systemsettings_build_ini(IniWriter *iw) iw_entry_d(iw, "nrf-channel", SystemSettings.nrf_channel); iw_comment(iw, "nRF network ID (hex, 4 bytes, little-endian)"); - iw_entry(iw, "nrf-network", "%02X.%02X.%02X.%02X", + iw_entry(iw, "nrf-network", "%02X-%02X-%02X-%02X", SystemSettings.nrf_network[0], SystemSettings.nrf_network[1], SystemSettings.nrf_network[2], SystemSettings.nrf_network[3]); iw_comment(iw, "nRF node address (hex, 1 byte, > 0)"); - iw_entry(iw, "nrf-address", "%02X", + iw_entry(iw, "nrf-address", "0x%02X", SystemSettings.nrf_address); // those aren't implement yet, don't tease the user From 73e134d0b62c6ad7f9d60a4187bbab112d582bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 9 Apr 2018 22:23:29 +0200 Subject: [PATCH 7/7] cleaned up nordic config --- framework/system_settings.c | 13 ++++++------- platform/cfg_utils.c | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/framework/system_settings.c b/framework/system_settings.c index 936bc3d..affead3 100644 --- a/framework/system_settings.c +++ b/framework/system_settings.c @@ -200,19 +200,18 @@ void systemsettings_build_ini(IniWriter *iw) iw_comment(iw, "nRF24L01+ radio"); iw_entry_s(iw, "com-nrf", str_yn(SystemSettings.use_comm_nordic)); - iw_comment(iw, "nRF channel"); + iw_comment(iw, "Radio channel (0-125)"); iw_entry_d(iw, "nrf-channel", SystemSettings.nrf_channel); - iw_comment(iw, "nRF network ID (hex, 4 bytes, little-endian)"); - iw_entry(iw, "nrf-network", "%02X-%02X-%02X-%02X", + iw_comment(iw, "Network prefix (hex, 4 bytes)"); + iw_entry(iw, "nrf-network", "%02X:%02X:%02X:%02X", SystemSettings.nrf_network[0], SystemSettings.nrf_network[1], SystemSettings.nrf_network[2], SystemSettings.nrf_network[3]); - iw_comment(iw, "nRF node address (hex, 1 byte, > 0)"); - iw_entry(iw, "nrf-address", "0x%02X", - SystemSettings.nrf_address); + iw_comment(iw, "Node address (1-255)"); + iw_entry(iw, "nrf-address", "%d", (int)SystemSettings.nrf_address); // those aren't implement yet, don't tease the user // TODO show pin-out, extra settings if applicable @@ -285,7 +284,7 @@ bool systemsettings_load_ini(const char *restrict key, const char *restrict valu } if (streq(key, "nrf-address")) { - cfg_hex_parse(&SystemSettings.nrf_address, 1, value, &suc); + SystemSettings.nrf_address = cfg_u8_parse(value, &suc); } if (streq(key, "nrf-network")) { diff --git a/platform/cfg_utils.c b/platform/cfg_utils.c index e580e61..83dce48 100644 --- a/platform/cfg_utils.c +++ b/platform/cfg_utils.c @@ -311,7 +311,7 @@ void cfg_hex_parse(uint8_t *dest, uint32_t count, const char *value, bool *suc) if (v != 0) value++; uint8_t nibble = 0; - if (v == ' ' || v == '.' || v == '-' || v == ':') { + if (v == ' ' || v == '.' || v == ',' || v == '-' || v == ':') { continue; // junk } else if (v >= '0' && v <= '9') {