diff --git a/tracker/hardware/10b/.gitignore b/tracker/hardware/10b/.gitignore new file mode 100644 index 00000000..46f586da --- /dev/null +++ b/tracker/hardware/10b/.gitignore @@ -0,0 +1 @@ +/pecanpico10-rescue.lib diff --git a/tracker/software/ChibiOS/os/various/shell/shell.c b/tracker/software/ChibiOS/os/various/shell/shell.c index 418b1300..9b382115 100644 --- a/tracker/software/ChibiOS/os/various/shell/shell.c +++ b/tracker/software/ChibiOS/os/various/shell/shell.c @@ -354,7 +354,7 @@ THD_FUNCTION(shellThread, p) { chprintf(chp, SHELL_NEWLINE_STR); chprintf(chp, "ChibiOS/RT Shell" SHELL_NEWLINE_STR); - while (true) { + while (!chThdShouldTerminateX()) { chprintf(chp, SHELL_PROMPT_STR); if (shellGetLine(scfg, line, sizeof(line), shp)) { #if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_) diff --git a/tracker/software/config.c b/tracker/software/config.c index e04ad840..8e34cecf 100644 --- a/tracker/software/config.c +++ b/tracker/software/config.c @@ -8,10 +8,10 @@ conf_t conf_sram; const conf_t conf_flash_default = { - // Primary position transmission thread + // Primary position node .pos_pri = { .thread_conf = { - .active = true, + .active = false, .cycle = TIME_S2I(60*30), .init_delay = TIME_S2I(30) }, @@ -21,16 +21,16 @@ const conf_t conf_flash_default = { .mod = MOD_AFSK, .rssi = 0x4F, }, - + // Node identity .call = "VK2GJ-12", .path = "WIDE2-1", - .symbol = SYM_DIGIPEATER, + .symbol = SYM_ANTENNA, .aprs_msg = true, .tel_enc_cycle = TIME_S2I(10800) }, - // Secondary position transmission thread + // Secondary position node .pos_sec = { .thread_conf = { .active = false, @@ -43,7 +43,7 @@ const conf_t conf_flash_default = { .mod = MOD_AFSK, .rssi = 0x4F }, - + // Node identity .call = "DL7AD-14", .path = "WIDE1-1", .symbol = SYM_BALLOON, @@ -52,11 +52,11 @@ const conf_t conf_flash_default = { .tel_enc_cycle = TIME_S2I(10800) }, - // Primary image transmission thread + // Primary image node .img_pri = { .thread_conf = { .active = false, - .cycle = TIME_S2I(60*5), + .cycle = TIME_S2I(60*10), .init_delay = TIME_S2I(60*5), .send_spacing = TIME_S2I(5) }, @@ -67,21 +67,21 @@ const conf_t conf_flash_default = { .rssi = 0x4F, .redundantTx = false }, - + // Node identity .call = "VK2GJ-15", .path = "", .res = RES_VGA, .quality = 4, - .buf_size = 64*1024 + .buf_size = 40*1024 }, - // Secondary image transmission thread + // Secondary image node .img_sec = { .thread_conf = { - .active = true, - .cycle = TIME_S2I(300), - .init_delay = TIME_S2I(60), + .active = false, + .cycle = TIME_S2I(60*5), + .init_delay = TIME_S2I(60*1), .send_spacing = TIME_S2I(30) }, .radio_conf = { @@ -90,16 +90,16 @@ const conf_t conf_flash_default = { .mod = MOD_AFSK, .rssi = 0x4F }, - - .call = "VK2GJ-15", + // Node identity + .call = "VK2GJ-14", .path = "", .res = RES_QVGA, .quality = 4, - .buf_size = 64*1024 + .buf_size = 15*1024 }, - // Log transmission thread + // Log node .log = { .thread_conf = { .active = false, @@ -112,13 +112,13 @@ const conf_t conf_flash_default = { .mod = MOD_AFSK, .rssi = 0x4F }, - + // Node identity .call = "VK2GJ-13", .path = "WIDE1-1", .density = 10 }, - // APRS system control + // APRS node .aprs = { .thread_conf = { .active = true, @@ -130,6 +130,7 @@ const conf_t conf_flash_default = { .mod = MOD_AFSK, .rssi = 0x3F }, + // Node rx identity .call = "VK2GJ-4" }, .tx = { // The transmit identity for digipeat transmit and messages responses @@ -139,6 +140,7 @@ const conf_t conf_flash_default = { .mod = MOD_AFSK, .rssi = 0x4F }, + // Node tx identity .call = "VK2GJ-5", .path = "WIDE2-1", .symbol = SYM_DIGIPEATER, @@ -147,7 +149,8 @@ const conf_t conf_flash_default = { .lon = 1511143478, .alt = 144 }, - .base = { // The base station parameters - how and where tracker originated messages are sent + .base = { + // The base station identity - how and where tracker originated messages are sent .enabled = true, .call = "VK2GJ-7", .path = "WIDE2-1", diff --git a/tracker/software/config.h b/tracker/software/config.h index 22660d11..e266727b 100644 --- a/tracker/software/config.h +++ b/tracker/software/config.h @@ -8,7 +8,7 @@ * 3V, because USB would not work at 1.8V. Note that the transmission power is increased * too when operating at 3V. This option will also run the STM32 at 48MHz (AHB) permanently * because USB needs that speed, otherwise it is running at 6MHz which saves a lot of power. */ -#define ENABLE_EXTERNAL_I2C TRUE /* The external port can be used for bit bang I2C. */ +#define ENABLE_EXTERNAL_I2C FALSE /* The external port can be used for bit bang I2C. */ #include "types.h" @@ -18,5 +18,4 @@ extern conf_t conf_sram; extern const conf_t conf_flash_default; -#endif - +#endif /* __CONFIG_H__ */ diff --git a/tracker/software/drivers/usb/usb.c b/tracker/software/drivers/usb/usb.c index 4cf206f5..8a269b45 100644 --- a/tracker/software/drivers/usb/usb.c +++ b/tracker/software/drivers/usb/usb.c @@ -6,60 +6,137 @@ #include "pktconf.h" static thread_t *shelltp; -static bool usb_initialized; +sdu_term_t sdu_chn_state; -event_listener_t shell_el; +event_listener_t sdu1_el; static const ShellConfig shell_cfg = { (BaseSequentialStream*)&SDU1, commands }; +/* + * + */ void startUSB(void) { - if(usb_initialized) - return; // Avoid duplicate initialization + usbObjectInit(&USBD1); - /* Initialize USB. */ - sduObjectInit(&SDU1); + usbStart(&USBD1, &usbcfg); /* Currently does nothing. */ - usbDisconnectBus(serusbcfg.usbp); + usbDisconnectBus(&USBD1); + chThdSleep(TIME_MS2I(100)); - usbStart(serusbcfg.usbp, &usbcfg); - /* Currently does nothing. */ - usbConnectBus(serusbcfg.usbp); + usbConnectBus(&USBD1); - sduStart(&SDU1, &serusbcfg); - - // Initialize shell - shelltp = NULL; - shellInit(); - - usb_initialized = true; + sdu_chn_state = TERM_SDU_INIT; } -void manageShell(void) { - if(shelltp == NULL && isUSBactive()) { - - shelltp = chThdCreateFromHeap(NULL, - THD_WORKING_AREA_SIZE(4*1024), - "shell", NORMALPRIO + 1, - shellThread, - (void*)&shell_cfg); - - - chEvtRegister(&shell_terminated, &shell_el, USB_SHELL_EVT); - } - chEvtWaitAnyTimeout(EVENT_MASK(USB_SHELL_EVT), TIME_S2I(1)); - if(chThdTerminatedX(shelltp)) { - chThdWait(shelltp); - shelltp = NULL; - chEvtUnregister(&shell_terminated, &shell_el); - } +/* + * + */ +void startSDU(void) { + if(sdu_chn_state != TERM_SDU_INIT) + return; + sduObjectInit(&SDU1); + chEvtRegister(chnGetEventSource(&SDU1), &sdu1_el, USB_SDU1_EVT); + sduStart(&SDU1, &serusbcfg); + sdu_chn_state = TERM_SDU_IDLE; } +/** + * @brief Manage trace output and shell on Serial Over USB. + * @notes TRACE output is sent to USB serial. + * @notes TRACE output is suspended when any key is pressed on terminal. + * @notes A new shell is invoked and remains active until logout. + * @notes TRACE output is then resotored. + * + * @api + */ +void manageTraceAndShell(void) { + + if(chEvtGetAndClearEvents(EVENT_MASK(USB_SDU1_EVT)) == 0) + return; + + BaseSequentialStream *chp = (BaseSequentialStream *)&SDU1; + + eventflags_t evtf = chEvtGetAndClearFlags(&sdu1_el); + + switch(sdu_chn_state) { + case TERM_SDU_INIT: + return; + + case TERM_SDU_IDLE: { + if(evtf == 0) + return; + if(evtf & CHN_CONNECTED) { + sdu_chn_state = TERM_SDU_OUT; + chprintf(chp, "\r\n*** Trace output enabled ***\r\n"); + break; + } + break; + } /* End case TERM_SDU_IDLE */ + + case TERM_SDU_OUT: { + if(evtf & CHN_DISCONNECTED) { + sdu_chn_state = TERM_SDU_IDLE; + return; + } + if(evtf & CHN_INPUT_AVAILABLE) { + /* Flush the input queue. */ + while(chnGetTimeout((SerialUSBDriver *)chp, TIME_MS2I(100)) != STM_TIMEOUT); + chprintf(chp, "\r\n*** Trace suspended - type ^D or use the " + "'exit' command to resume trace ***\r\n"); + shellInit(); + shelltp = chThdCreateFromHeap(NULL, + THD_WORKING_AREA_SIZE(4*1024), + "shell", NORMALPRIO + 1, + shellThread, + (void*)&shell_cfg); + if(shelltp == NULL) { + chprintf(chp, "\r\n*** Failed to open shell ***\r\n"); + break; + } + sdu_chn_state = TERM_SDU_SHELL; + } + break; + } /* End case TERM_SDU_OUT */ + + case TERM_SDU_SHELL: { + /* USB disconnect. */ + if(evtf & CHN_DISCONNECTED) { + chThdTerminate(shelltp); + sdu_chn_state = TERM_SDU_EXIT; + break; + } + /* Was shell terminated from CLI? */ + if(chThdTerminatedX(shelltp)) { + chThdWait(shelltp); + shelltp = NULL; + sdu_chn_state = TERM_SDU_OUT; + chprintf(chp, "\r\n*** Trace resumed by user ***\r\n"); + } + break; + } /* End case TERM_SDU_SHELL */ + + case TERM_SDU_EXIT: { + chThdWait(shelltp); + shelltp = NULL; + sdu_chn_state = TERM_SDU_IDLE; + break; + } /* End case TERM_SDU_EXIT */ + + default: + break; + } /* End switch. */ +} + +/* + * + */ bool isSDUAvailable(void) { - return usb_initialized; + /* Return channel connection status of SDU. */ + return (bool)(sdu_chn_state == TERM_SDU_OUT); } diff --git a/tracker/software/drivers/usb/usb.h b/tracker/software/drivers/usb/usb.h index 52f1c183..194d0194 100644 --- a/tracker/software/drivers/usb/usb.h +++ b/tracker/software/drivers/usb/usb.h @@ -4,10 +4,19 @@ #include "ch.h" #include "hal.h" +typedef enum sduTermStates { + TERM_SDU_INIT = 0, + TERM_SDU_IDLE, + TERM_SDU_OUT, + TERM_SDU_SHELL, + TERM_SDU_EXIT +} sdu_term_t; + #define isUSBactive() (SDU1.config->usbp->state == USB_ACTIVE) void startUSB(void); -void manageShell(void); +void startSDU(void); +void manageTraceAndShell(void); bool isSDUAvailable(void); #endif diff --git a/tracker/software/drivers/usb/usbcfg.c b/tracker/software/drivers/usb/usbcfg.c index f2f2d237..0ebf18de 100644 --- a/tracker/software/drivers/usb/usbcfg.c +++ b/tracker/software/drivers/usb/usbcfg.c @@ -1,344 +1,344 @@ -/* - ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include "hal.h" -#include "config.h" - -/* Virtual serial port over USB.*/ -SerialUSBDriver SDU1; - -/* - * Endpoints to be used for USBD1. - */ -#define USBD1_DATA_REQUEST_EP 1 -#define USBD1_DATA_AVAILABLE_EP 1 -#define USBD1_INTERRUPT_REQUEST_EP 2 - -/* - * USB Device Descriptor. - */ -static const uint8_t vcom_device_descriptor_data[18] = { - USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ - 0x02, /* bDeviceClass (CDC). */ - 0x00, /* bDeviceSubClass. */ - 0x00, /* bDeviceProtocol. */ - 0x40, /* bMaxPacketSize. */ - 0x0483, /* idVendor (ST). */ - 0x5740, /* idProduct. */ - 0x0200, /* bcdDevice. */ - 1, /* iManufacturer. */ - 2, /* iProduct. */ - 3, /* iSerialNumber. */ - 1) /* bNumConfigurations. */ -}; - -/* - * Device Descriptor wrapper. - */ -static const USBDescriptor vcom_device_descriptor = { - sizeof vcom_device_descriptor_data, - vcom_device_descriptor_data -}; - -/* Configuration Descriptor tree for a CDC.*/ -static const uint8_t vcom_configuration_descriptor_data[67] = { - /* Configuration Descriptor.*/ - USB_DESC_CONFIGURATION(67, /* wTotalLength. */ - 0x02, /* bNumInterfaces. */ - 0x01, /* bConfigurationValue. */ - 0, /* iConfiguration. */ - 0xC0, /* bmAttributes (self powered). */ - 50), /* bMaxPower (100mA). */ - /* Interface Descriptor.*/ - USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ - 0x00, /* bAlternateSetting. */ - 0x01, /* bNumEndpoints. */ - 0x02, /* bInterfaceClass (Communications - Interface Class, CDC section - 4.2). */ - 0x02, /* bInterfaceSubClass (Abstract - Control Model, CDC section 4.3). */ - 0x01, /* bInterfaceProtocol (AT commands, - CDC section 4.4). */ - 0), /* iInterface. */ - /* Header Functional Descriptor (CDC section 5.2.3).*/ - USB_DESC_BYTE (5), /* bLength. */ - USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ - USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header - Functional Descriptor. */ - USB_DESC_BCD (0x0110), /* bcdCDC. */ - /* Call Management Functional Descriptor. */ - USB_DESC_BYTE (5), /* bFunctionLength. */ - USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ - USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management - Functional Descriptor). */ - USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ - USB_DESC_BYTE (0x01), /* bDataInterface. */ - /* ACM Functional Descriptor.*/ - USB_DESC_BYTE (4), /* bFunctionLength. */ - USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ - USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract - Control Management Descriptor). */ - USB_DESC_BYTE (0x02), /* bmCapabilities. */ - /* Union Functional Descriptor.*/ - USB_DESC_BYTE (5), /* bFunctionLength. */ - USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ - USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union - Functional Descriptor). */ - USB_DESC_BYTE (0x00), /* bMasterInterface (Communication - Class Interface). */ - USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class - Interface). */ - /* Endpoint 2 Descriptor.*/ - USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80, - 0x03, /* bmAttributes (Interrupt). */ - 0x0008, /* wMaxPacketSize. */ - 0xFF), /* bInterval. */ - /* Interface Descriptor.*/ - USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ - 0x00, /* bAlternateSetting. */ - 0x02, /* bNumEndpoints. */ - 0x0A, /* bInterfaceClass (Data Class - Interface, CDC section 4.5). */ - 0x00, /* bInterfaceSubClass (CDC section - 4.6). */ - 0x00, /* bInterfaceProtocol (CDC section - 4.7). */ - 0x00), /* iInterface. */ - /* Endpoint 3 Descriptor.*/ - USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ - 0x02, /* bmAttributes (Bulk). */ - 0x0040, /* wMaxPacketSize. */ - 0x00), /* bInterval. */ - /* Endpoint 1 Descriptor.*/ - USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ - 0x02, /* bmAttributes (Bulk). */ - 0x0040, /* wMaxPacketSize. */ - 0x00) /* bInterval. */ -}; - -/* - * Configuration Descriptor wrapper. - */ -static const USBDescriptor vcom_configuration_descriptor = { - sizeof vcom_configuration_descriptor_data, - vcom_configuration_descriptor_data -}; - -/* - * U.S. English language identifier. - */ -static const uint8_t vcom_string0[] = { - USB_DESC_BYTE(4), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ -}; - -/* - * Vendor string. - */ -static const uint8_t vcom_string1[] = { - USB_DESC_BYTE(38), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, - 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, - 'c', 0, 's', 0 -}; - -/* - * Device Description string. - */ -static const uint8_t vcom_string2[] = { - USB_DESC_BYTE(56), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, - 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, - 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, - 'o', 0, 'r', 0, 't', 0 -}; - -/* - * Serial Number string. - */ -static const uint8_t vcom_string3[] = { - USB_DESC_BYTE(8), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - '0' + CH_KERNEL_MAJOR, 0, - '0' + CH_KERNEL_MINOR, 0, - '0' + CH_KERNEL_PATCH, 0 -}; - -/* - * Strings wrappers array. - */ -static const USBDescriptor vcom_strings[] = { - {sizeof vcom_string0, vcom_string0}, - {sizeof vcom_string1, vcom_string1}, - {sizeof vcom_string2, vcom_string2}, - {sizeof vcom_string3, vcom_string3} -}; - -/* - * Handles the GET_DESCRIPTOR callback. All required descriptors must be - * handled here. - */ -static const USBDescriptor *get_descriptor(USBDriver *usbp, - uint8_t dtype, - uint8_t dindex, - uint16_t lang) { - - (void)usbp; - (void)lang; - switch (dtype) { - case USB_DESCRIPTOR_DEVICE: - return &vcom_device_descriptor; - case USB_DESCRIPTOR_CONFIGURATION: - return &vcom_configuration_descriptor; - case USB_DESCRIPTOR_STRING: - if (dindex < 4) - return &vcom_strings[dindex]; - } - return NULL; -} - -/** - * @brief IN EP1 state. - */ -static USBInEndpointState ep1instate; - -/** - * @brief OUT EP1 state. - */ -static USBOutEndpointState ep1outstate; - -/** - * @brief EP1 initialization structure (both IN and OUT). - */ -static const USBEndpointConfig ep1config = { - USB_EP_MODE_TYPE_BULK, - NULL, - sduDataTransmitted, - sduDataReceived, - 0x0040, - 0x0040, - &ep1instate, - &ep1outstate, - 2, - NULL -}; - -/** - * @brief IN EP2 state. - */ -static USBInEndpointState ep2instate; - -/** - * @brief EP2 initialization structure (IN only). - */ -static const USBEndpointConfig ep2config = { - USB_EP_MODE_TYPE_INTR, - NULL, - sduInterruptTransmitted, - NULL, - 0x0010, - 0x0000, - &ep2instate, - NULL, - 1, - NULL -}; - -/* - * Handles the USB driver global events. - */ -static void usb_event(USBDriver *usbp, usbevent_t event) { - extern SerialUSBDriver SDU1; - - switch (event) { - case USB_EVENT_ADDRESS: - return; - case USB_EVENT_CONFIGURED: - chSysLockFromISR(); - - /* Enables the endpoints specified into the configuration. - Note, this callback is invoked from an ISR so I-Class functions - must be used.*/ - usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); - usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config); - - /* Resetting the state of the CDC subsystem.*/ - sduConfigureHookI(&SDU1); - - chSysUnlockFromISR(); - return; - case USB_EVENT_RESET: - /* Falls into.*/ - case USB_EVENT_UNCONFIGURED: - /* Falls into.*/ - case USB_EVENT_SUSPEND: - chSysLockFromISR(); - - /* Disconnection event on suspend.*/ - sduSuspendHookI(&SDU1); - - chSysUnlockFromISR(); - return; - case USB_EVENT_WAKEUP: - chSysLockFromISR(); - - /* Disconnection event on suspend.*/ - sduWakeupHookI(&SDU1); - - chSysUnlockFromISR(); - return; - case USB_EVENT_STALLED: - return; - } - return; -} - -/* - * Handles the USB driver global events. - */ -static void sof_handler(USBDriver *usbp) { - - (void)usbp; - - osalSysLockFromISR(); - sduSOFHookI(&SDU1); - osalSysUnlockFromISR(); -} - -/* - * USB driver configuration. - */ -const USBConfig usbcfg = { - usb_event, - get_descriptor, - sduRequestsHook, - sof_handler -}; - -/* - * Serial over USB driver configuration. - */ -const SerialUSBConfig serusbcfg = { - &USBD1, - USBD1_DATA_REQUEST_EP, - USBD1_DATA_AVAILABLE_EP, - USBD1_INTERRUPT_REQUEST_EP -}; - +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "config.h" + +/* Virtual serial port over USB.*/ +SerialUSBDriver SDU1; + +/* + * Endpoints to be used for USBD1. + */ +#define USBD1_DATA_REQUEST_EP 1 +#define USBD1_DATA_AVAILABLE_EP 1 +#define USBD1_INTERRUPT_REQUEST_EP 2 + +/* + * USB Device Descriptor. + */ +static const uint8_t vcom_device_descriptor_data[18] = { + USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ + 0x02, /* bDeviceClass (CDC). */ + 0x00, /* bDeviceSubClass. */ + 0x00, /* bDeviceProtocol. */ + 0x40, /* bMaxPacketSize. */ + 0x0483, /* idVendor (ST). */ + 0x5740, /* idProduct. */ + 0x0200, /* bcdDevice. */ + 1, /* iManufacturer. */ + 2, /* iProduct. */ + 3, /* iSerialNumber. */ + 1) /* bNumConfigurations. */ +}; + +/* + * Device Descriptor wrapper. + */ +static const USBDescriptor vcom_device_descriptor = { + sizeof vcom_device_descriptor_data, + vcom_device_descriptor_data +}; + +/* Configuration Descriptor tree for a CDC.*/ +static const uint8_t vcom_configuration_descriptor_data[67] = { + /* Configuration Descriptor.*/ + USB_DESC_CONFIGURATION(67, /* wTotalLength. */ + 0x02, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0xC0, /* bmAttributes (self powered). */ + 50), /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x01, /* bNumEndpoints. */ + 0x02, /* bInterfaceClass (Communications + Interface Class, CDC section + 4.2). */ + 0x02, /* bInterfaceSubClass (Abstract + Control Model, CDC section 4.3). */ + 0x01, /* bInterfaceProtocol (AT commands, + CDC section 4.4). */ + 0), /* iInterface. */ + /* Header Functional Descriptor (CDC section 5.2.3).*/ + USB_DESC_BYTE (5), /* bLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header + Functional Descriptor. */ + USB_DESC_BCD (0x0110), /* bcdCDC. */ + /* Call Management Functional Descriptor. */ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ + USB_DESC_BYTE (0x01), /* bDataInterface. */ + /* ACM Functional Descriptor.*/ + USB_DESC_BYTE (4), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract + Control Management Descriptor). */ + USB_DESC_BYTE (0x02), /* bmCapabilities. */ + /* Union Functional Descriptor.*/ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bMasterInterface (Communication + Class Interface). */ + USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class + Interface). */ + /* Endpoint 2 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80, + 0x03, /* bmAttributes (Interrupt). */ + 0x0008, /* wMaxPacketSize. */ + 0xFF), /* bInterval. */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x0A, /* bInterfaceClass (Data Class + Interface, CDC section 4.5). */ + 0x00, /* bInterfaceSubClass (CDC section + 4.6). */ + 0x00, /* bInterfaceProtocol (CDC section + 4.7). */ + 0x00), /* iInterface. */ + /* Endpoint 3 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00), /* bInterval. */ + /* Endpoint 1 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00) /* bInterval. */ +}; + +/* + * Configuration Descriptor wrapper. + */ +static const USBDescriptor vcom_configuration_descriptor = { + sizeof vcom_configuration_descriptor_data, + vcom_configuration_descriptor_data +}; + +/* + * U.S. English language identifier. + */ +static const uint8_t vcom_string0[] = { + USB_DESC_BYTE(4), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ +}; + +/* + * Vendor string. + */ +static const uint8_t vcom_string1[] = { + USB_DESC_BYTE(38), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, + 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, + 'c', 0, 's', 0 +}; + +/* + * Device Description string. + */ +static const uint8_t vcom_string2[] = { + USB_DESC_BYTE(56), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, + 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, + 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, + 'o', 0, 'r', 0, 't', 0 +}; + +/* + * Serial Number string. + */ +static const uint8_t vcom_string3[] = { + USB_DESC_BYTE(8), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + '0' + CH_KERNEL_MAJOR, 0, + '0' + CH_KERNEL_MINOR, 0, + '0' + CH_KERNEL_PATCH, 0 +}; + +/* + * Strings wrappers array. + */ +static const USBDescriptor vcom_strings[] = { + {sizeof vcom_string0, vcom_string0}, + {sizeof vcom_string1, vcom_string1}, + {sizeof vcom_string2, vcom_string2}, + {sizeof vcom_string3, vcom_string3} +}; + +/* + * Handles the GET_DESCRIPTOR callback. All required descriptors must be + * handled here. + */ +static const USBDescriptor *get_descriptor(USBDriver *usbp, + uint8_t dtype, + uint8_t dindex, + uint16_t lang) { + + (void)usbp; + (void)lang; + switch (dtype) { + case USB_DESCRIPTOR_DEVICE: + return &vcom_device_descriptor; + case USB_DESCRIPTOR_CONFIGURATION: + return &vcom_configuration_descriptor; + case USB_DESCRIPTOR_STRING: + if (dindex < 4) + return &vcom_strings[dindex]; + } + return NULL; +} + +/** + * @brief IN EP1 state. + */ +static USBInEndpointState ep1instate; + +/** + * @brief OUT EP1 state. + */ +static USBOutEndpointState ep1outstate; + +/** + * @brief EP1 initialization structure (both IN and OUT). + */ +static const USBEndpointConfig ep1config = { + USB_EP_MODE_TYPE_BULK, + NULL, + sduDataTransmitted, + sduDataReceived, + 0x0040, + 0x0040, + &ep1instate, + &ep1outstate, + 2, + NULL +}; + +/** + * @brief IN EP2 state. + */ +static USBInEndpointState ep2instate; + +/** + * @brief EP2 initialization structure (IN only). + */ +static const USBEndpointConfig ep2config = { + USB_EP_MODE_TYPE_INTR, + NULL, + sduInterruptTransmitted, + NULL, + 0x0010, + 0x0000, + &ep2instate, + NULL, + 1, + NULL +}; + +/* + * Handles the USB driver global events. + */ +static void usb_event(USBDriver *usbp, usbevent_t event) { + extern SerialUSBDriver SDU1; + + switch (event) { + case USB_EVENT_ADDRESS: + return; + case USB_EVENT_CONFIGURED: + chSysLockFromISR(); + + /* Enables the endpoints specified into the configuration. + Note, this callback is invoked from an ISR so I-Class functions + must be used.*/ + usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); + usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config); + + /* Resetting the state of the CDC subsystem.*/ + sduConfigureHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_RESET: + /* Falls into.*/ + case USB_EVENT_UNCONFIGURED: + /* Falls into.*/ + case USB_EVENT_SUSPEND: + chSysLockFromISR(); + + /* Disconnection event on suspend.*/ + sduSuspendHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_WAKEUP: + chSysLockFromISR(); + + /* Wake up event.*/ + sduWakeupHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_STALLED: + return; + } + return; +} + +/* + * Handles the USB driver global events. + */ +static void sof_handler(USBDriver *usbp) { + + (void)usbp; + + osalSysLockFromISR(); + sduSOFHookI(&SDU1); + osalSysUnlockFromISR(); +} + +/* + * USB driver configuration. + */ +const USBConfig usbcfg = { + usb_event, + get_descriptor, + sduRequestsHook, + sof_handler +}; + +/* + * Serial over USB driver configuration. + */ +const SerialUSBConfig serusbcfg = { + &USBD1, + USBD1_DATA_REQUEST_EP, + USBD1_DATA_AVAILABLE_EP, + USBD1_INTERRUPT_REQUEST_EP +}; + diff --git a/tracker/software/main.c b/tracker/software/main.c index 6f234acb..9f986de3 100644 --- a/tracker/software/main.c +++ b/tracker/software/main.c @@ -4,7 +4,6 @@ #include "debug.h" #include "threads.h" -#include "padc.h" /** * Main routine is starting up system, runs the software watchdog (module monitoring), controls LEDs @@ -27,6 +26,9 @@ int main(void) { chDbgAssert(pkt == true, "failed to init packet system"); + /* Start Serial Over USB. */ + startSDU(); + /* Start serial channels if selected. */ pktSerialStart(); @@ -37,10 +39,6 @@ int main(void) { pktEnableEventTrace(); } - #if ACTIVATE_USB - startUSB(); - #endif - TRACE_INFO("MAIN > Startup"); // Startup threads @@ -48,15 +46,12 @@ int main(void) { start_user_threads(); // Startup optional modules (eg. POSITION, LOG, ...) while(true) { - #if ACTIVATE_USB - if(isUSBactive()) { - manageShell(); - pktTraceEvents(); - continue; - } - #endif /* ACTIVATE_USB */ - /* Wait in a loop if nothing to do. */ - chThdSleep(TIME_S2I(1)); + #if ACTIVATE_USB + manageTraceAndShell(); + pktTraceEvents(); + #endif /* ACTIVATE_USB */ + /* Wait in a loop if nothing to do. */ + chThdSleep(TIME_MS2I(200)); } } diff --git a/tracker/software/pkt/channels/rxafsk.c b/tracker/software/pkt/channels/rxafsk.c index d781d381..7b99bc4e 100644 --- a/tracker/software/pkt/channels/rxafsk.c +++ b/tracker/software/pkt/channels/rxafsk.c @@ -761,8 +761,11 @@ THD_FUNCTION(pktAFSKDecoder, arg) { TIME_MS2I(100)); if(myPktBuffer == NULL) { + /* Decrease ref count on AX25 FIFO and stop PWM. */ + chFactoryReleaseObjectsFIFO(pkt_fifo); pktAddEventFlags(myHandler, EVT_AX25_NO_BUFFER); - myDriver->active_demod_object->status |= EVT_AX25_NO_BUFFER; + myDriver->active_demod_object->status |= + EVT_AX25_NO_BUFFER | EVT_PWM_QUEUE_LOCK; myDriver->decoder_state = DECODER_ERROR; break; } diff --git a/tracker/software/pkt/channels/rxpwm.c b/tracker/software/pkt/channels/rxpwm.c index b2f94883..66efd720 100644 --- a/tracker/software/pkt/channels/rxpwm.c +++ b/tracker/software/pkt/channels/rxpwm.c @@ -206,7 +206,7 @@ void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt, pwm_code_t reason) icuDisableNotificationsI(myICU); if(myDemod->active_radio_object != NULL) { myDemod->active_radio_object->status |= (EVT_PWM_QUEUE_LOCK | evt); - pktAddEventFlagsI(myHandler, (EVT_PWM_QUEUE_LOCK | evt)); + pktAddEventFlagsI(myHandler, evt); input_queue_t *myQueue = &myDemod->active_radio_object->radio_pwm_queue; /* End of data flag. */ #if USE_12_BIT_PWM == TRUE diff --git a/tracker/software/pkt/managers/pktservice.c b/tracker/software/pkt/managers/pktservice.c index fbd46557..0d77c7c6 100644 --- a/tracker/software/pkt/managers/pktservice.c +++ b/tracker/software/pkt/managers/pktservice.c @@ -661,7 +661,6 @@ eventflags_t pktDispatchReceivedBuffer(pkt_data_object_t *pkt_buffer) { /* Increase outstanding callback count. */ handler->cb_count++; } - } return flags; } diff --git a/tracker/software/pkt/managers/pktservice.h b/tracker/software/pkt/managers/pktservice.h index 615ed0f6..d9eedfb7 100644 --- a/tracker/software/pkt/managers/pktservice.h +++ b/tracker/software/pkt/managers/pktservice.h @@ -477,6 +477,23 @@ static inline bool pktIsBufferValidAX25Frame(pkt_data_object_t *object) { && (frame_size >= PKT_MIN_FRAME)); } +/** + * @brief Gets status of frame. + * @note This returns validity (size) and CRC result. + * @details This function is called from thread level. + * + * @param[in] object pointer to a @p objects FIFO. + * + * @return The operation status. + * @retval true if the frame is valid and has good CRC. + * @retval false if the frame is valid and has bad CRC. + * + * @api + */ +static inline bool pktGetAX25FrameStatus(pkt_data_object_t *object) { + chDbgAssert(object != NULL, "no pointer to packet object buffer"); + return !(object->status & (EVT_PKT_INVALID_FRAME | EVT_AX25_CRC_ERROR)); +} /** * @brief Gets service object associated with radio. diff --git a/tracker/software/pkt/pktconf.h b/tracker/software/pkt/pktconf.h index 4016bb1b..bcb0ca5c 100644 --- a/tracker/software/pkt/pktconf.h +++ b/tracker/software/pkt/pktconf.h @@ -53,7 +53,7 @@ #define EVT_PRIORITY_BASE 0 /* - * Decoder global system events. + * Decoder global system event masks. * The packet channel object holds the global events. * Events are broadcast to any listeners. */ @@ -98,7 +98,8 @@ #define EVT_PKT_CBK_MGR_FAIL EVENT_MASK(EVT_PRIORITY_BASE + 31) -/* Decoder thread events (sent from initiator to decoder). */ +/* Decoder thread event IDs (sent from initiator to decoder). */ +/*TODO: These needs to be values and NOT bit shifted masks. */ #define DEC_COMMAND_START EVENT_MASK(EVT_PRIORITY_BASE + 0) #define DEC_COMMAND_STOP EVENT_MASK(EVT_PRIORITY_BASE + 1) @@ -107,8 +108,9 @@ #define DEC_SUSPEND_EXIT EVENT_MASK(EVT_PRIORITY_BASE + 4) -/* Reserved system thread events (in user threads level). */ -#define USB_SHELL_EVT EVENT_MASK(EVT_PRIORITY_BASE + 0) +/* Reserved system event broadcast IDs (set mask in user threads level). */ +#define USB_SHELL_EVT EVT_PRIORITY_BASE + 0 +#define USB_SDU1_EVT EVT_PRIORITY_BASE + 16 /* Response thread events (from decoder to initiator). */ #define DEC_OPEN_EXEC EVENT_MASK(EVT_PRIORITY_BASE + 15) diff --git a/tracker/software/pkt/protocols/aprs2/ax25_pad.c b/tracker/software/pkt/protocols/aprs2/ax25_pad.c index 6c58d40d..fae22e7e 100644 --- a/tracker/software/pkt/protocols/aprs2/ax25_pad.c +++ b/tracker/software/pkt/protocols/aprs2/ax25_pad.c @@ -1180,43 +1180,54 @@ void ax25_remove_addr (packet_t this_p, int n) * *------------------------------------------------------------------------------*/ -int ax25_get_num_addr (packet_t this_p) -{ - //unsigned char *pf; - int a; - int addr_bytes; +int ax25_get_num_addr (packet_t this_p) { + int a; + //int addr_bytes; - if(this_p->magic1 != MAGIC || this_p->magic2 != MAGIC) { - TRACE_ERROR("PKT > Buffer overflow"); - return 0; - } + if(this_p->magic1 != MAGIC || this_p->magic2 != MAGIC) { + TRACE_ERROR("PKT > Buffer overflow"); + return 0; + } -/* Use cached value if already set. */ + /* Use cached value if already set. */ - if (this_p->num_addr >= 0) { - return (this_p->num_addr); - } + if (this_p->num_addr >= 0) { + return (this_p->num_addr); + } -/* Otherwise, determine the number of addresses. */ + /* + * Otherwise, determine the number of addresses. + * Start with assumption of zero. + */ - this_p->num_addr = 0; /* Number of addresses extracted. */ - - addr_bytes = 0; - for (a = 0; a < this_p->frame_len && addr_bytes == 0; a++) { - if (this_p->frame_data[a] & SSID_LAST_MASK) { - addr_bytes = a + 1; - } - } + this_p->num_addr = 0; - if (addr_bytes % 7 == 0) { - int addrs = addr_bytes / 7; - if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) { - this_p->num_addr = addrs; - } - } - - return (this_p->num_addr); + /* Check that address characters are valid. */ + + for(a = 0; + a < this_p->frame_len && a < (AX25_MAX_ADDRS * AX25_ADDR_LEN); + a++) { + /* + * Check the call sign characters with isgraph + * Could be more strict and accept upper case alpha & numeric only. + */ + if(a % 7 != 6) { + if(isgraph(this_p->frame_data[a] >> 1)) + continue; + } + if((this_p->frame_data[a] & SSID_LAST_MASK)) + break; + } /* End for. */ + + /* Check if last happened on an address boundary. */ + if (++a % 7 == 0) { + int addrs = a / 7; + if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) { + this_p->num_addr = addrs; + } + } + return (this_p->num_addr); } @@ -1401,7 +1412,7 @@ int ax25_get_ssid (packet_t this_p, int n) } if (n >= 0 && n < this_p->num_addr) { - return ((this_p->frame_data[n*7+6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT); + return ((this_p->frame_data[n * AX25_ADDR_LEN + 6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT); } else { TRACE_ERROR ("Internal error: ax25_get_ssid(%d), num_addr=%d", n, this_p->num_addr); @@ -1437,7 +1448,8 @@ void ax25_set_ssid (packet_t this_p, int n, int ssid) if (n >= 0 && n < this_p->num_addr) { - this_p->frame_data[n*7+6] = (this_p->frame_data[n*7+6] & ~ SSID_SSID_MASK) | + this_p->frame_data[n * AX25_ADDR_LEN + 6] = + (this_p->frame_data[n * AX25_ADDR_LEN + 6] & ~ SSID_SSID_MASK) | ((ssid << SSID_SSID_SHIFT) & SSID_SSID_MASK) ; } else { @@ -1476,7 +1488,7 @@ int ax25_get_h (packet_t this_p, int n) } if (n >= 0 && n < this_p->num_addr) { - return ((this_p->frame_data[n*7+6] & SSID_H_MASK) >> SSID_H_SHIFT); + return ((this_p->frame_data[n * AX25_ADDR_LEN + 6] & SSID_H_MASK) >> SSID_H_SHIFT); } else { TRACE_ERROR ("PKT > Internal error: ax25_get_h(%d), num_addr=%d", n, this_p->num_addr); @@ -1511,7 +1523,7 @@ void ax25_set_h (packet_t this_p, int n) } if (n >= 0 && n < this_p->num_addr) { - this_p->frame_data[n*7+6] |= SSID_H_MASK; + this_p->frame_data[n * AX25_ADDR_LEN + 6] |= SSID_H_MASK; } else { TRACE_ERROR ("PKT > Internal error: ax25_set_hd(%d), num_addr=%d", n, this_p->num_addr); @@ -1921,15 +1933,13 @@ void ax25_format_addrs (packet_t this_p, char *result, int8_t size) } *result = '\0'; - /* New in 0.9. */ - /* Don't get upset if no addresses. */ - /* This will allow packets that do not comply to AX.25 format. */ + /* There must be at least two addresses. */ - if (this_p->num_addr == 0) { + if (this_p->num_addr < 2) { return; } - /* TODO: Make a safe strcat function. */ + /* TODO: Refactor this to use a single loop and safe write to buffer. */ ax25_get_addr_with_ssid (this_p, AX25_SOURCE, stemp); if(size - (strlen(stemp) + 1) < 2) diff --git a/tracker/software/pkt/protocols/aprs2/ax25_pad.h b/tracker/software/pkt/protocols/aprs2/ax25_pad.h index 79223614..a8e95999 100644 --- a/tracker/software/pkt/protocols/aprs2/ax25_pad.h +++ b/tracker/software/pkt/protocols/aprs2/ax25_pad.h @@ -37,6 +37,9 @@ /* to be safe. */ #define AX25_MAX_ADDR_LEN 12 +/* The length of an address field in an AX25 header. */ +#define AX25_ADDR_LEN 7 + /* Previously 1 when considering only APRS. */ #define AX25_MIN_INFO_LEN 0U @@ -61,9 +64,9 @@ /* The more general case. */ /* An AX.25 frame can have a control byte and no protocol. */ -#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 ) +#define AX25_MIN_PACKET_LEN ( 2 * AX25_ADDR_LEN + 1 ) -#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN) +#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * AX25_ADDR_LEN + 2 + 3 + AX25_MAX_INFO_LEN) #define AX25_UI_FRAME 3 /* Control field value. */ diff --git a/tracker/software/portab.c b/tracker/software/portab.c index e8719894..71c5ad76 100644 --- a/tracker/software/portab.c +++ b/tracker/software/portab.c @@ -18,6 +18,7 @@ #include "hal.h" #include "chprintf.h" #include "portab.h" +#include "usb.h" #include /*===========================================================================*/ @@ -158,6 +159,10 @@ void sysConfigureCoreIO(void) { palSetLineMode(LINE_I2C_SCL, PAL_MODE_ALTERNATE(4) | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_OTYPE_OPENDRAIN); // SCL + + #if ACTIVATE_USB + startUSB(); + #endif } /** @} */ diff --git a/tracker/software/portab.h b/tracker/software/portab.h index fa35526a..73c08e2d 100644 --- a/tracker/software/portab.h +++ b/tracker/software/portab.h @@ -21,7 +21,7 @@ #define USE_SPI_ATTACHED_RADIO TRUE -#define DUMP_PACKET_TO_SERIAL TRUE +#define DUMP_PACKET_TO_SERIAL FALSE /* * TODO: Need to use radio unit ID to set assigned GPIO & SPI. @@ -67,7 +67,7 @@ #endif //#define LINE_PWM_MIRROR PAL_LINE(GPIOA, 8U) -#define LINE_GPIO_PIN PAL_LINE(GPIOA, 8U) +#define LINE_GPIO_PIN PAL_LINE(GPIOA, 8U) /** * ICU related definitions. @@ -124,7 +124,7 @@ extern "C" { void pktSetLineModeICU(void); void pktSerialStart(void); void dbgWrite(uint8_t level, uint8_t *buf, uint32_t len); - int dbgPrintf(uint8_t level, const char *format, ...); + int dbgPrintf(uint8_t level, const char *format, ...); void pktWrite(uint8_t *buf, uint32_t len); void pktPowerUpRadio(radio_unit_t radio); void pktPowerDownRadio(radio_unit_t radio); diff --git a/tracker/software/protocols/packet/aprs.c b/tracker/software/protocols/packet/aprs.c index a6d768e3..c0260398 100644 --- a/tracker/software/protocols/packet/aprs.c +++ b/tracker/software/protocols/packet/aprs.c @@ -45,7 +45,6 @@ static bool dedupe_initialized; const conf_command_t command_list[] = { {TYPE_INT, "pos_pri.active", sizeof(conf_sram.pos_pri.thread_conf.active), &conf_sram.pos_pri.thread_conf.active }, {TYPE_TIME, "pos_pri.init_delay", sizeof(conf_sram.pos_pri.thread_conf.init_delay), &conf_sram.pos_pri.thread_conf.init_delay }, -/* {TYPE_TIME, "pos_pri.send_spacing", sizeof(conf_sram.pos_pri.thread_conf.send_spacing), &conf_sram.pos_pri.thread_conf.send_spacing },*/ {TYPE_INT, "pos_pri.sleep_conf.type", sizeof(conf_sram.pos_pri.thread_conf.sleep_conf.type), &conf_sram.pos_pri.thread_conf.sleep_conf.type }, {TYPE_INT, "pos_pri.sleep_conf.vbat_thres", sizeof(conf_sram.pos_pri.thread_conf.sleep_conf.vbat_thres), &conf_sram.pos_pri.thread_conf.sleep_conf.vbat_thres}, {TYPE_INT, "pos_pri.sleep_conf.vsol_thres", sizeof(conf_sram.pos_pri.thread_conf.sleep_conf.vsol_thres), &conf_sram.pos_pri.thread_conf.sleep_conf.vsol_thres}, @@ -54,8 +53,6 @@ const conf_command_t command_list[] = { {TYPE_INT, "pos_pri.freq", sizeof(conf_sram.pos_pri.radio_conf.freq), &conf_sram.pos_pri.radio_conf.freq }, {TYPE_INT, "pos_pri.mod", sizeof(conf_sram.pos_pri.radio_conf.mod), &conf_sram.pos_pri.radio_conf.mod }, {TYPE_INT, "pos_pri.rssi", sizeof(conf_sram.pos_pri.radio_conf.rssi), &conf_sram.pos_pri.radio_conf.rssi }, -/* {TYPE_INT, "pos_pri.speed", sizeof(conf_sram.pos_pri.radio_conf.speed), &conf_sram.pos_pri.radio_conf.speed },*/ -/* {TYPE_INT, "pos_pri.redundantTx", sizeof(conf_sram.pos_pri.radio_conf.redundantTx), &conf_sram.pos_pri.radio_conf.redundantTx },*/ {TYPE_STR, "pos_pri.call", sizeof(conf_sram.pos_pri.call), &conf_sram.pos_pri.call }, {TYPE_STR, "pos_pri.path", sizeof(conf_sram.pos_pri.path), &conf_sram.pos_pri.path }, {TYPE_INT, "pos_pri.symbol", sizeof(conf_sram.pos_pri.symbol), &conf_sram.pos_pri.symbol }, @@ -64,7 +61,6 @@ const conf_command_t command_list[] = { {TYPE_INT, "pos_sec.active", sizeof(conf_sram.pos_sec.thread_conf.active), &conf_sram.pos_sec.thread_conf.active }, {TYPE_TIME, "pos_sec.init_delay", sizeof(conf_sram.pos_sec.thread_conf.init_delay), &conf_sram.pos_sec.thread_conf.init_delay }, -/* {TYPE_TIME, "pos_sec.send_spacing", sizeof(conf_sram.pos_sec.thread_conf.send_spacing), &conf_sram.pos_sec.thread_conf.send_spacing },*/ {TYPE_INT, "pos_sec.sleep_conf.type", sizeof(conf_sram.pos_sec.thread_conf.sleep_conf.type), &conf_sram.pos_sec.thread_conf.sleep_conf.type }, {TYPE_INT, "pos_sec.sleep_conf.vbat_thres", sizeof(conf_sram.pos_sec.thread_conf.sleep_conf.vbat_thres), &conf_sram.pos_sec.thread_conf.sleep_conf.vbat_thres}, {TYPE_INT, "pos_sec.sleep_conf.vsol_thres", sizeof(conf_sram.pos_sec.thread_conf.sleep_conf.vsol_thres), &conf_sram.pos_sec.thread_conf.sleep_conf.vsol_thres}, @@ -73,8 +69,6 @@ const conf_command_t command_list[] = { {TYPE_INT, "pos_sec.freq", sizeof(conf_sram.pos_sec.radio_conf.freq), &conf_sram.pos_sec.radio_conf.freq }, {TYPE_INT, "pos_sec.mod", sizeof(conf_sram.pos_sec.radio_conf.mod), &conf_sram.pos_sec.radio_conf.mod }, {TYPE_INT, "pos_sec.rssi", sizeof(conf_sram.pos_sec.radio_conf.rssi), &conf_sram.pos_sec.radio_conf.rssi }, -/* {TYPE_INT, "pos_sec.speed", sizeof(conf_sram.pos_sec.radio_conf.speed), &conf_sram.pos_sec.radio_conf.speed },*/ -/* {TYPE_INT, "pos_sec.redundantTx", sizeof(conf_sram.pos_sec.radio_conf.redundantTx), &conf_sram.pos_sec.radio_conf.redundantTx },*/ {TYPE_STR, "pos_sec.call", sizeof(conf_sram.pos_sec.call), &conf_sram.pos_sec.call }, {TYPE_STR, "pos_sec.path", sizeof(conf_sram.pos_sec.path), &conf_sram.pos_sec.path }, {TYPE_INT, "pos_sec.symbol", sizeof(conf_sram.pos_sec.symbol), &conf_sram.pos_sec.symbol }, @@ -138,13 +132,7 @@ const conf_command_t command_list[] = { {TYPE_INT, "aprs.active", sizeof(conf_sram.aprs.thread_conf.active), &conf_sram.aprs.thread_conf.active }, {TYPE_TIME, "aprs.init_delay", sizeof(conf_sram.aprs.thread_conf.init_delay), &conf_sram.aprs.thread_conf.init_delay }, - /* - {TYPE_TIME, "aprs.packet_spacing", sizeof(conf_sram.aprs.rx.thread_conf.packet_spacing), &conf_sram.aprs.rx.thread_conf.packet_spacing }, - {TYPE_INT, "aprs.sleep_conf.type", sizeof(conf_sram.aprs.rx.thread_conf.sleep_conf.type), &conf_sram.aprs.rx.thread_conf.sleep_conf.type }, - {TYPE_INT, "aprs.sleep_conf.vbat_thres", sizeof(conf_sram.aprs.rx.thread_conf.sleep_conf.vbat_thres), &conf_sram.aprs.rx.thread_conf.sleep_conf.vbat_thres}, - {TYPE_INT, "aprs.sleep_conf.vsol_thres", sizeof(conf_sram.aprs.rx.thread_conf.sleep_conf.vsol_thres), &conf_sram.aprs.rx.thread_conf.sleep_conf.vsol_thres}, - {TYPE_TIME, "aprs.rx.cycle", sizeof(conf_sram.aprs.rx.thread_conf.cycle), &conf_sram.aprs.rx.thread_conf.cycle }, - */ + {TYPE_INT, "aprs.rx.freq", sizeof(conf_sram.aprs.rx.radio_conf.freq), &conf_sram.aprs.rx.radio_conf.freq }, {TYPE_INT, "aprs.rx.mod", sizeof(conf_sram.aprs.rx.radio_conf.mod), &conf_sram.aprs.rx.radio_conf.mod }, {TYPE_INT, "aprs.rx.speed", sizeof(conf_sram.aprs.rx.radio_conf.speed), &conf_sram.aprs.tx.radio_conf.speed }, @@ -179,7 +167,7 @@ const APRSCommand aprs_commands[] = { {"?aprsd", aprs_send_aprsd_message}, {"?aprsh", aprs_send_aprsh_message}, {"?aprsp", aprs_send_position_beacon}, - {"?gpio", aprs_handle_gpio_command}, + {"?gpio", aprs_execute_gpio_command}, {"?gps", aprs_handle_gps_command}, {"?reset", aprs_execute_system_reset}, {"?save", aprs_execute_config_save}, @@ -188,7 +176,7 @@ const APRSCommand aprs_commands[] = { {NULL, NULL} }; -/* +/** * @brief parse arguments from a command string. * * @return pointer to next element in string. @@ -227,7 +215,7 @@ static char *aprs_parse_arguments(char *str, char **saveptr) { return *p != '\0' ? p : NULL; } -/* +/** * @brief Execute a command in an APRS message. * @notes Known commands are in APRS command table. * @notes Commands themselves return only MSG_OK or MSG_ERROR. @@ -252,7 +240,7 @@ static msg_t aprs_cmd_exec(const APRSCommand *acp, return MSG_TIMEOUT; } -/* +/** * */ void aprs_debug_getPacket(packet_t pp, char* buf, uint32_t len) @@ -286,7 +274,7 @@ void aprs_debug_getPacket(packet_t pp, char* buf, uint32_t len) * @notes - Number of satellites being used * @notes - Number of cycles where GPS has been lost (if applicable in cycle) * - * @param[in] callsign originator calls sign + * @param[in] callsign origination call sign * @param[in] path path to use * @param[in] symbol symbol for originator * @param[in] dataPoint position data object @@ -547,7 +535,7 @@ msg_t aprs_send_aprsh_message(aprs_identity_t *id, * @retval MSG_OK if the command completed. * @retval MSG_ERROR if there was an error. */ -msg_t aprs_handle_gpio_command(aprs_identity_t *id, +msg_t aprs_execute_gpio_command(aprs_identity_t *id, int argc, char *argv[]) { if(argc != 1) return MSG_ERROR; @@ -1018,14 +1006,15 @@ static bool aprs_decode_message(packet_t pp) { msg_t msg = aprs_cmd_exec(aprs_commands, cmd, &identity, n, args); if(msg == MSG_TIMEOUT) { - TRACE_INFO("RX > Command not found by parser"); + TRACE_INFO("RX > No command found in message"); } if(msg_id_rx[0]) { /* Incoming message ID exists so an ACK or REJ has to be sent. */ char buf[16]; chsnprintf(buf, sizeof(buf), "%s%s", - (msg == MSG_OK) ? "ack" : "rej", msg_id_rx); + (msg == MSG_OK || msg == MSG_TIMEOUT) ? + "ack" : "rej", msg_id_rx); /* * Use the receiving node identity as sender. @@ -1050,31 +1039,33 @@ static bool aprs_decode_message(packet_t pp) { return false; } -/* +/** * Transmit failure will release the packet memory. */ static void aprs_digipeat(packet_t pp) { - if(!dedupe_initialized) { - dedupe_init(TIME_S2I(10)); - dedupe_initialized = true; - } + if(!dedupe_initialized) { + dedupe_init(TIME_S2I(10)); + dedupe_initialized = true; + } - if(!dedupe_check(pp, 0)) { // Last identical packet older than 10 seconds - packet_t result = digipeat_match(0, pp, conf_sram.aprs.rx.call, - conf_sram.aprs.tx.call, alias_re, - wide_re, 0, preempt, NULL); - if(result != NULL) { // Should be digipeated - dedupe_remember(result, 0); - /* If transmit fails the packet is freed. */ - transmitOnRadio(result, - conf_sram.aprs.tx.radio_conf.freq, - 0, - 0, - conf_sram.aprs.tx.radio_conf.pwr, - conf_sram.aprs.tx.radio_conf.mod, - conf_sram.aprs.tx.radio_conf.rssi); - } - } + if(!dedupe_check(pp, 0)) { // Last identical packet older than 10 seconds + packet_t result = digipeat_match(0, pp, conf_sram.aprs.rx.call, + conf_sram.aprs.tx.call, alias_re, + wide_re, 0, preempt, NULL); + if(result != NULL) { // Should be digipeated + dedupe_remember(result, 0); + /* If transmit fails the packet buffer is released. */ + if(!transmitOnRadio(result, + conf_sram.aprs.tx.radio_conf.freq, + 0, + 0, + conf_sram.aprs.tx.radio_conf.pwr, + conf_sram.aprs.tx.radio_conf.mod, + conf_sram.aprs.tx.radio_conf.rssi)) { + TRACE_INFO("RX > Failed to digipeat packet"); + } /* TX failed. */ + } /* Should be digipteated. */ + } /* Duplicate check. */ } /** @@ -1106,7 +1097,8 @@ void aprs_decode_packet(packet_t pp) { do { v++; ax25_get_addr_with_ssid(pp, ax25_get_heard(pp)-v, call); - } while(ax25_get_heard(pp) - v >= AX25_SOURCE && (!strncmp("WIDE", call, 4) || !strncmp("TRACE", call, 5))); + } while(((ax25_get_heard(pp) - v) >= AX25_SOURCE) + && (!strncmp("WIDE", call, 4) || !strncmp("TRACE", call, 5))); // Fill/Update direct list sysinterval_t first_time = 0xFFFFFFFF; // Timestamp of oldest heard list entry @@ -1142,7 +1134,9 @@ void aprs_decode_packet(packet_t pp) { * Execute any command found in the message. * If not then digipeat it. */ - if(pinfo[0] == ':') digipeat = aprs_decode_message(pp); // ax25_get_dti(pp) + if(pinfo[0] == ':') { + digipeat = aprs_decode_message(pp); // ax25_get_dti(pp) + } // Digipeat packet if(conf_sram.aprs.dig_active && digipeat) { diff --git a/tracker/software/protocols/packet/aprs.h b/tracker/software/protocols/packet/aprs.h index 57e62886..059666e1 100644 --- a/tracker/software/protocols/packet/aprs.h +++ b/tracker/software/protocols/packet/aprs.h @@ -49,6 +49,7 @@ #define SYM_CAR 0x2F3E #define SYM_SHIP 0x2F73 #define SYM_DIGIPEATER 0x2F23 +#define SYM_ANTENNA 0x2F72 #define APRS_HEARD_LIST_SIZE 20 @@ -104,7 +105,7 @@ extern "C" { int argc, char *argv[]); msg_t aprs_send_aprsh_message(aprs_identity_t *id, int argc, char *argv[]); - msg_t aprs_handle_gpio_command(aprs_identity_t *id, + msg_t aprs_execute_gpio_command(aprs_identity_t *id, int argc, char *argv[]); msg_t aprs_handle_gps_command(aprs_identity_t *id, int argc, char *argv[]); diff --git a/tracker/software/threads/collector.c b/tracker/software/threads/collector.c index 0dc6d8e9..3438d697 100644 --- a/tracker/software/threads/collector.c +++ b/tracker/software/threads/collector.c @@ -27,16 +27,14 @@ static bool threadStarted = false; /** * Returns most recent data point which is complete. */ -dataPoint_t* getLastDataPoint(void) -{ +dataPoint_t* getLastDataPoint(void) { return lastDataPoint; } /* * */ -void waitForNewDataPoint(void) -{ +void waitForNewDataPoint(void) { uint32_t old_id = getLastDataPoint()->id; while(old_id == getLastDataPoint()->id) chThdSleep(TIME_S2I(1)); @@ -45,8 +43,8 @@ void waitForNewDataPoint(void) /* * */ -static void aquirePosition(dataPoint_t* tp, dataPoint_t* ltp, sysinterval_t timeout) -{ +static void aquirePosition(dataPoint_t* tp, dataPoint_t* ltp, + sysinterval_t timeout) { sysinterval_t start = chVTGetSystemTime(); gpsFix_t gpsFix; @@ -62,7 +60,7 @@ static void aquirePosition(dataPoint_t* tp, dataPoint_t* ltp, sysinterval_t time bool status = GPS_Init(); if(status) { - // Search for lock as long enough power is available + // Search for lock as long as enough power is available do { batt = stm32_get_vbat(); gps_get_fix(&gpsFix); @@ -185,7 +183,7 @@ static void getSensors(dataPoint_t* tp) tp->sen_e1_press = 0; tp->sen_e1_hum = 0; tp->sen_e1_temp = 0; - bme280_error |= 0x2; + bme280_error |= 0x4; } // External BME280 Sensor 2 @@ -199,8 +197,11 @@ static void getSensors(dataPoint_t* tp) tp->sen_e2_press = 0; tp->sen_e2_hum = 0; tp->sen_e2_temp = 0; - bme280_error |= 0x4; + bme280_error |= 0x10; } +#else + /* Set status to "not installed". */ + bme280_error |= 0x28; #endif // Measure various temperature sensors tp->stm32_temp = stm32_get_temp(); @@ -214,7 +215,19 @@ static void getSensors(dataPoint_t* tp) * */ static void setSystemStatus(dataPoint_t* tp) { - // Set system errors + + /* + * Set system errors. + * + * Bit usage: + * - 0:1 I2C status + * - 2:2 GPS status + * - 3:4 pac1720 status + * - 5:7 OV5640 status + * - 8:9 BMEi1 status (0 = OK, 1 = Fail, 2 = Not fitted) + * - 9:10 BMEe1 status (0 = OK, 1 = Fail, 2 = Not fitted) + * - 10:11 BMEe2 status (0 = OK, 1 = Fail, 2 = Not fitted) + */ tp->sys_error = 0; tp->sys_error |= (I2C_hasError() & 0x1) << 0; @@ -222,7 +235,7 @@ static void setSystemStatus(dataPoint_t* tp) { tp->sys_error |= (pac1720_hasError() & 0x3) << 3; tp->sys_error |= (OV5640_hasError() & 0x7) << 5; - tp->sys_error |= (bme280_error & 0x7) << 8; + tp->sys_error |= (bme280_error & 0x3F) << 8; // Set system time tp->sys_time = TIME_I2S(chVTGetSystemTime()); @@ -320,7 +333,7 @@ THD_FUNCTION(collectorThread, arg) { "%s Pos %d.%05d %d.%05d Alt %dm\r\n" "%s Sats %d TTFF %dsec\r\n" "%s ADC Vbat=%d.%03dV Vsol=%d.%03dV Pbat=%dmW\r\n" - "%s AIR p=%6d.%01dPa T=%2d.%02ddegC phi=%2d.%01d%%", + "%s AIR p=%d.%01dPa T=%d.%02ddegC phi=%d.%01d%%", tp->id, TRACE_TAB, time.year, time.month, time.day, time.hour, time.minute, time.day, TRACE_TAB, tp->gps_lat/10000000, (tp->gps_lat > 0 ? 1:-1)*(tp->gps_lat/100)%100000, tp->gps_lon/10000000, (tp->gps_lon > 0 ? 1:-1)*(tp->gps_lon/100)%100000, tp->gps_alt, @@ -345,9 +358,9 @@ THD_FUNCTION(collectorThread, arg) { */ void init_data_collector(void) { - if(!threadStarted) - { - threadStarted = true; + if(!threadStarted) { + + threadStarted = true; TRACE_INFO("COLL > Startup data collector thread"); thread_t *th = chThdCreateFromHeap(NULL, diff --git a/tracker/software/threads/rxtx/image.c b/tracker/software/threads/rxtx/image.c index aec2804c..ac9d4fe6 100644 --- a/tracker/software/threads/rxtx/image.c +++ b/tracker/software/threads/rxtx/image.c @@ -648,14 +648,14 @@ THD_FUNCTION(imgThread, arg) { chThdSleep(TIME_S2I(60)); continue; } - + uint32_t my_image_id = gimage_id++; /* Create image capture buffer. */ uint8_t *buffer = chHeapAllocAligned(NULL, conf->buf_size, DMA_FIFO_BURST_ALIGN); if(buffer == NULL) { /* Could not get a capture buffer. */ TRACE_WARN("IMG > Unable to get capture buffer for image %i", - gimage_id); + my_image_id); /* Allow time for other threads. */ chThdSleep(TIME_MS2I(10)); /* Try again at next run time. */ @@ -668,11 +668,11 @@ THD_FUNCTION(imgThread, arg) { /* Nothing captured? */ if(size_sampled == 0) { TRACE_INFO("IMG > Encode/Transmit SSDV (camera error) ID=%d", - gimage_id); + my_image_id); if(!transmit_image_packets(noCameraFound, sizeof(noCameraFound), - conf, (uint8_t)(gimage_id))) { + conf, (uint8_t)(my_image_id))) { TRACE_ERROR("IMG > Error in encoding dummy image %i" - " - discarded", gimage_id); + " - discarded", my_image_id); } /* Return the buffer to the heap. */ chHeapFree(buffer); @@ -699,7 +699,7 @@ THD_FUNCTION(imgThread, arg) { chsnprintf(filename, sizeof(filename), "r%02xi%04x.jpg", getLastDataPoint()->reset % 0xFF, - (gimage_id - 1) % 0xFFFF); + (my_image_id) % 0xFFFF); writeBufferToFile(filename, &buffer[soi], size_sampled - soi); } /* End initSD() */ @@ -710,13 +710,12 @@ THD_FUNCTION(imgThread, arg) { } /* Encode and transmit picture. */ - TRACE_INFO("IMG > Encode/Transmit SSDV ID=%d", gimage_id); + TRACE_INFO("IMG > Encode/Transmit SSDV ID=%d", my_image_id); if(!transmit_image_packets(buffer, size_sampled, conf, - (uint8_t)(gimage_id))) { + (uint8_t)(my_image_id))) { TRACE_ERROR("IMG > Error in encoding snapshot image" - " %i - discarded", gimage_id); + " %i - discarded", my_image_id); } - gimage_id++; break; } /* End if SOI in buffer. */ } /* End while soi < size_sampled - 1. */ diff --git a/tracker/software/threads/rxtx/radio.c b/tracker/software/threads/rxtx/radio.c index 61a01b14..403dfddd 100644 --- a/tracker/software/threads/rxtx/radio.c +++ b/tracker/software/threads/rxtx/radio.c @@ -69,11 +69,12 @@ void mapCallback(pkt_data_object_t *pkt_buff) { pktDiagnosticOutput(pkt_buff->handler, pkt_buff); #endif */ -if(pktIsBufferValidAX25Frame(pkt_buff)) { +if(pktGetAX25FrameStatus(pkt_buff)) { + /* Perform the callback. */ processPacket(frame_buffer, frame_size); } else { - TRACE_INFO("RX > Invalid frame - dropped"); + TRACE_INFO("RX > Frame has bad CRC - dropped"); } }