Browse Source

implemented fallback to physical usart and basis for wireless support in the future

Ondřej Hruška 1 year ago
parent
commit
102d5f5a4c
Signed by: Ondřej Hruška <ondra@ondrovo.com> GPG key ID: 2C5FD5035250423D

+ 36 - 5
TinyFrame/TF_Integration.c View File

@@ -6,6 +6,9 @@
6 6
 
7 7
 #include "platform.h"
8 8
 #include "task_main.h"
9
+#include "comm/messages.h"
10
+#include "comm/interfaces.h"
11
+#include "framework/system_settings.h"
9 12
 
10 13
 #include "USB/usbd_cdc_if.h"
11 14
 #include "USB/usb_device.h"
@@ -14,13 +17,20 @@
14 17
 extern osSemaphoreId semVcomTxReadyHandle;
15 18
 extern osMutexId mutTinyFrameTxHandle;
16 19
 
17
-void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
20
+/**
21
+ * USB transmit implementation
22
+ *
23
+ * @param tf - TF
24
+ * @param buff - buffer to send (can be longer than the buffers)
25
+ * @param len - buffer size
26
+ */
27
+static inline void _USB_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
18 28
 {
19 29
 #if 1
20 30
     const uint32_t real_size = len;
21 31
 
22 32
     // Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
23
-    if (len&0x3F) {
33
+    if ((len&0x3F) && !SystemSettings.visible_vcom) { // this corrupts VCOM on Linux for some reason
24 34
         uint32_t pad = (64 - (len&0x3F));
25 35
         memset((void *) (buff + len), 0, pad);
26 36
         len += pad; // padding to a multiple of 64 (size of the endpoint)
@@ -32,8 +42,9 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
32 42
     // The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
33 43
     // the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
34 44
 
35
-    // the assumption here is that all until the last chunk use the full buffer capacity
45
+    // If this is not the last chunk (assuming all but the last use full 512 bytes of the TF buffer), wait now for completion
36 46
     if (real_size == TF_SENDBUF_LEN) {
47
+        // TODO this seems wrong - investigate
37 48
         if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
38 49
             TF_Error("Tx stalled in WriteImpl");
39 50
             return;
@@ -41,7 +52,7 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
41 52
     }
42 53
 #else
43 54
     (void) tf;
44
-#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
55
+#define CHUNK 64 // size of the USB packet
45 56
     int32_t total = (int32_t) len;
46 57
     while (total > 0) {
47 58
         const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100);
@@ -64,11 +75,31 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
64 75
 #endif
65 76
 }
66 77
 
78
+void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
79
+{
80
+    if (gActiveComport == COMPORT_USB) {
81
+        _USB_WriteImpl(tf, buff, len);
82
+    }
83
+    else if (gActiveComport == COMPORT_USART) {
84
+        // TODO rewrite this to use DMA, then wait for the DMA
85
+        for(uint32_t i=0;i<len;i++) {
86
+            while(!LL_USART_IsActiveFlag_TXE(USART2));
87
+            LL_USART_TransmitData8(USART2, buff[i]);
88
+        }
89
+        xSemaphoreGive(semVcomTxReadyHandle); // act as if we just finished it and this is perhaps the DMA irq
90
+    }
91
+    else {
92
+        // TODO other transports
93
+        trap("not implemented.");
94
+    }
95
+}
96
+
67 97
 /** Claim the TX interface before composing and sending a frame */
68 98
 bool TF_ClaimTx(TinyFrame *tf)
69 99
 {
70 100
     (void) tf;
71
-//    assert_param(!inIRQ()); // useless delay
101
+    assert_param(!inIRQ());
102
+
72 103
     assert_param(pdTRUE == xSemaphoreTake(mutTinyFrameTxHandle, 5000)); // trips the wd
73 104
 
74 105
     // The last chunk from some previous frame may still be being transmitted,

+ 12 - 0
USB/README.TXT View File

@@ -17,3 +17,15 @@ and processed by the message queue thread. This makes it possible to query hardw
17 17
 also makes it possible to wait on a binary semaphore when sending data back to host. The
18 18
 semaphore is set from the CDC TxComplete callback and taken by the TinyFrame write
19 19
 function, serving as a form of flow control.
20
+
21
+--------------------------------------------
22
+
23
+COMM API:
24
+
25
+GEX supports alternate command interfaces.
26
+
27
+The active interface is set in the global variable gActiveComport
28
+Due to special init procedures, the com_switch_transfer() function must be called to change it.
29
+
30
+The TX function is defined in TF_Integration.c and any RX'd data is sent through rxQuePostMsg()
31
+

+ 1 - 1
USB/usbd_storage_if.c View File

@@ -186,7 +186,7 @@ USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
186 186
 int8_t STORAGE_Init_FS (uint8_t lun)
187 187
 {
188 188
   /* USER CODE BEGIN 2 */
189
-    dbg("Plug In");
189
+  dbg("MSC init request");
190 190
   vfs_mngr_fs_enable(1);
191 191
   return (USBD_OK);
192 192
   /* USER CODE END 2 */ 

+ 207 - 0
comm/interfaces.c View File

@@ -0,0 +1,207 @@
1
+//
2
+// Created by MightyPork on 2018/03/23.
3
+//
4
+
5
+#include <stm32f072xb.h>
6
+#include "platform.h"
7
+#include "usbd_core.h"
8
+#include "USB/usb_device.h"
9
+#include "interfaces.h"
10
+#include "framework/system_settings.h"
11
+#include "framework/unit.h"
12
+#include "framework/resources.h"
13
+#include "platform/hw_utils.h"
14
+#include "framework/unit_base.h"
15
+
16
+enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the handlers work correctly initially
17
+
18
+static uint32_t last_switch_time = 0; // started with USB
19
+static bool xfer_verify_done = false;
20
+
21
+static void configure_interface(enum ComportSelection iface);
22
+
23
+/** Switch com transfer if the current one doesnt seem to work */
24
+void com_switch_transfer_if_needed(void)
25
+{
26
+    if (xfer_verify_done) return;
27
+
28
+    const uint32_t now = HAL_GetTick();
29
+    const uint32_t elapsed = now - last_switch_time;
30
+
31
+    if (gActiveComport == COMPORT_USB) {
32
+        if (elapsed > 1000) {
33
+            // USB may or may not work, depending on whether the module is plugged -
34
+            // in or running from a battery/external supply remotely.
35
+
36
+            // Check if USB is enumerated
37
+
38
+            const uint32_t uadr = (USB->DADDR & USB_DADDR_ADD);
39
+            if (0 == uadr) {
40
+                dbg("Not enumerated, assuming USB is dead");
41
+
42
+                // Fallback to bare USART
43
+                if (SystemSettings.use_comm_uart) {
44
+                    configure_interface(COMPORT_USART);
45
+                }
46
+                else if (SystemSettings.use_comm_nordic) {
47
+                    configure_interface(COMPORT_NORDIC); // this fallbacks to LoRa if LoRa enabled
48
+                }
49
+                else if (SystemSettings.use_comm_lora) {
50
+                    configure_interface(COMPORT_LORA);
51
+                }
52
+                else {
53
+                    dbg("No alternate com interface configured, leaving USB enabled.");
54
+                }
55
+            } else {
56
+                dbg("USB got address 0x%02x - OK", (int)uadr);
57
+            }
58
+
59
+            xfer_verify_done = true;
60
+        }
61
+    }
62
+}
63
+
64
+/** Claim resources that may be needed for alternate transfers */
65
+void com_claim_resources_for_alt_transfers(void)
66
+{
67
+    if (SystemSettings.use_comm_uart) {
68
+        do {
69
+            if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_USART2)) {
70
+                SystemSettings.use_comm_uart = false;
71
+                break;
72
+            }
73
+
74
+            if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA2)) {
75
+                SystemSettings.use_comm_uart = false;
76
+                rsc_free(&UNIT_SYSTEM, R_USART2);
77
+                break;
78
+            }
79
+            if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA3)) {
80
+                SystemSettings.use_comm_uart = false;
81
+                rsc_free(&UNIT_SYSTEM, R_USART2);
82
+                rsc_free(&UNIT_SYSTEM, R_PA2);
83
+                break;
84
+            }
85
+        } while (0);
86
+    }
87
+}
88
+
89
+/** Release resources allocated for alternate transfers */
90
+void com_release_resources_for_alt_transfers(void)
91
+{
92
+    if (SystemSettings.use_comm_uart) {
93
+        rsc_free(&UNIT_SYSTEM, R_USART2);
94
+        rsc_free(&UNIT_SYSTEM, R_PA2);
95
+        rsc_free(&UNIT_SYSTEM, R_PA3);
96
+    }
97
+}
98
+
99
+static uint32_t usart_rxi = 0;
100
+static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE];
101
+static uint32_t last_rx_time = 0;
102
+
103
+/** Handler for the USART transport */
104
+static void com_UsartIrqHandler(void *arg)
105
+{
106
+    (void)arg;
107
+    if (LL_USART_IsActiveFlag_RXNE(USART2)) {
108
+        vPortEnterCritical();
109
+        {
110
+            usart_rx_buffer[usart_rxi++] = LL_USART_ReceiveData8(USART2);
111
+            if (usart_rxi == MSG_QUE_SLOT_SIZE) {
112
+                rxQuePostMsg(usart_rx_buffer, MSG_QUE_SLOT_SIZE); // avoid it happening in the irq
113
+                usart_rxi = 0;
114
+            }
115
+            last_rx_time = HAL_GetTick();
116
+        }
117
+        vPortExitCritical();
118
+    }
119
+}
120
+
121
+/** this is called from the hal tick irq */
122
+void com_iface_flush_buffer(void)
123
+{
124
+    if (usart_rxi > 0 && (HAL_GetTick()-last_rx_time)>=2) {
125
+        vPortEnterCritical();
126
+        {
127
+            rxQuePostMsg(usart_rx_buffer, usart_rxi);
128
+            usart_rxi = 0;
129
+        }
130
+        vPortExitCritical();
131
+    }
132
+}
133
+
134
+static void configure_interface(enum ComportSelection iface)
135
+{
136
+    // Teardown
137
+    if (gActiveComport == COMPORT_USB) {
138
+        // simplest USB disabling (XXX needs porting)
139
+        HAL_PCD_DeInit(&hpcd_USB_FS);
140
+        __HAL_RCC_USB_CLK_DISABLE();
141
+    }
142
+    else if (gActiveComport == COMPORT_USART) {
143
+        // this doesn't normally happen
144
+        hw_deinit_pin_rsc(R_PA2);
145
+        hw_deinit_pin_rsc(R_PA3);
146
+        __HAL_RCC_USART2_CLK_DISABLE();
147
+        irqd_detach(USART2, com_UsartIrqHandler);
148
+    }
149
+    gActiveComport = COMPORT_NONE;
150
+
151
+    // Init
152
+    if (iface == COMPORT_USB) {
153
+        trap("illegal"); // this never happens
154
+    }
155
+    else if (iface == COMPORT_USART) {
156
+        dbg("Setting up UART transfer");
157
+        assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA2, LL_GPIO_AF_1));
158
+        assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA3, LL_GPIO_AF_1));
159
+
160
+        __HAL_RCC_USART2_CLK_ENABLE();
161
+        __HAL_RCC_USART2_FORCE_RESET();
162
+        __HAL_RCC_USART2_RELEASE_RESET();
163
+
164
+        LL_USART_Disable(USART2);
165
+
166
+        LL_USART_SetBaudRate(USART2, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, SystemSettings.comm_uart_baud);
167
+        dbg("baud = %d", (int)SystemSettings.comm_uart_baud);
168
+
169
+        irqd_attach(USART2, com_UsartIrqHandler, NULL);
170
+        LL_USART_EnableIT_RXNE(USART2);
171
+        LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX);
172
+
173
+        LL_USART_Enable(USART2);
174
+    }
175
+    else {
176
+        if (iface == COMPORT_NORDIC) {
177
+            // Try to configure nordic
178
+            dbg("Setting up nRF transfer");
179
+
180
+            // TODO set up and check nRF transport
181
+
182
+            // On failure, try setting up LoRa
183
+            dbg("nRF failed to init");
184
+            if (SystemSettings.use_comm_lora) {
185
+                iface = COMPORT_LORA;
186
+            } else {
187
+                iface = COMPORT_NONE; // fail
188
+            }
189
+        }
190
+
191
+        if (iface == COMPORT_LORA) {
192
+            // Try to configure nordic
193
+            dbg("Setting up LoRa transfer");
194
+
195
+            // TODO set up and check LoRa transport
196
+
197
+            dbg("LoRa failed to init");
198
+            iface = COMPORT_NONE; // fail
199
+        }
200
+    }
201
+
202
+    if (iface == COMPORT_NONE) {
203
+        dbg("NO COM PORT AVAILABLE!");
204
+    }
205
+
206
+    gActiveComport = iface;
207
+}

+ 35 - 0
comm/interfaces.h View File

@@ -0,0 +1,35 @@
1
+//
2
+// Created by MightyPork on 2018/03/23.
3
+//
4
+
5
+#ifndef GEX_F072_COM_INTERFACES_H
6
+#define GEX_F072_COM_INTERFACES_H
7
+
8
+#include "platform.h"
9
+
10
+enum ComportSelection {
11
+    COMPORT_NONE = 0,
12
+    COMPORT_USB = 1,
13
+    COMPORT_USART = 2,
14
+    COMPORT_NORDIC = 3,
15
+    COMPORT_LORA = 4,
16
+};
17
+
18
+/**
19
+ * The currently active communication port
20
+ */
21
+extern enum ComportSelection gActiveComport;
22
+
23
+/** Switch com transfer if the current one doesnt seem to work */
24
+void com_switch_transfer_if_needed(void);
25
+
26
+/** Claim resources that may be needed for alternate transfers */
27
+void com_claim_resources_for_alt_transfers(void);
28
+
29
+/** Release resources allocated for alternate transfers */
30
+void com_release_resources_for_alt_transfers(void);
31
+
32
+/** Flush the rx buffer */
33
+void com_iface_flush_buffer(void);
34
+
35
+#endif //GEX_F072_COM_INTERFACES_H

+ 1 - 1
comm/messages.c View File

@@ -2,7 +2,6 @@
2 2
 // Created by MightyPork on 2017/11/21.
3 3
 //
4 4
 
5
-#include <platform/status_led.h>
6 5
 #include "platform.h"
7 6
 #include "framework/settings.h"
8 7
 #include "utils/ini_parser.h"
@@ -11,6 +10,7 @@
11 10
 #include "comm/messages.h"
12 11
 #include "framework/system_settings.h"
13 12
 #include "utils/malloc_safe.h"
13
+#include "platform/status_led.h"
14 14
 
15 15
 static TinyFrame tf_;
16 16
 TinyFrame *comm = &tf_;

+ 4 - 2
framework/settings.c View File

@@ -2,6 +2,7 @@
2 2
 // Created by MightyPork on 2017/11/26.
3 3
 //
4 4
 
5
+#include <comm/interfaces.h>
5 6
 #include "platform.h"
6 7
 #include "utils/hexdump.h"
7 8
 #include "settings.h"
@@ -9,6 +10,7 @@
9 10
 #include "system_settings.h"
10 11
 #include "utils/str_utils.h"
11 12
 #include "unit_base.h"
13
+#include "platform/debug_uart.h"
12 14
 #include "utils/avrlibc.h"
13 15
 
14 16
 // pre-declarations
@@ -311,7 +313,7 @@ void settings_load_ini_key(const char *restrict section, const char *restrict ke
311 313
     if (streq(section, "SYSTEM")) {
312 314
         if (SystemSettings.loading_inifile == 0) {
313 315
             SystemSettings.loading_inifile = 'S';
314
-            systemsettings_mco_teardown();
316
+            systemsettings_begin_load();
315 317
             systemsettings_loadDefaults();
316 318
         }
317 319
 
@@ -358,6 +360,6 @@ void settings_load_ini_end(void)
358 360
     }
359 361
 
360 362
     if (SystemSettings.loading_inifile == 'S') {
361
-        systemsettings_mco_init();
363
+        systemsettings_finalize_load();
362 364
     }
363 365
 }

+ 106 - 4
framework/system_settings.c View File

@@ -2,6 +2,8 @@
2 2
 // Created by MightyPork on 2017/12/02.
3 3
 //
4 4
 
5
+#include <platform/debug_uart.h>
6
+#include <comm/interfaces.h>
5 7
 #include "platform.h"
6 8
 #include "system_settings.h"
7 9
 #include "utils/str_utils.h"
@@ -10,6 +12,11 @@
10 12
 #include "resources.h"
11 13
 #include "unit_base.h"
12 14
 
15
+static void systemsettings_mco_teardown(void);
16
+static void systemsettings_mco_init(void);
17
+/** Init/deinit debug uart */
18
+static void systemsettings_debug_uart_init_deinit(void);
19
+
13 20
 struct system_settings SystemSettings;
14 21
 
15 22
 /** Load defaults only */
@@ -19,6 +26,13 @@ void systemsettings_loadDefaults(void)
19 26
     SystemSettings.ini_comments = true;
20 27
     SystemSettings.enable_mco = false;
21 28
     SystemSettings.mco_prediv = 7;
29
+
30
+    SystemSettings.use_comm_uart = false; // TODO configure those based on compile flags for a particular platform
31
+    SystemSettings.use_comm_lora = false;
32
+    SystemSettings.use_comm_nordic = false;
33
+    SystemSettings.comm_uart_baud = 115200; // TODO
34
+
35
+    SystemSettings.enable_debug_uart = true;
22 36
 }
23 37
 
24 38
 /** Load defaults and init flags */
@@ -35,14 +49,20 @@ void systemsettings_init(void)
35 49
 void systemsettings_save(PayloadBuilder *pb)
36 50
 {
37 51
     pb_char(pb, 'S');
38
-    pb_u8(pb, 1); // settings format version
52
+    pb_u8(pb, 2); // settings format version
39 53
 
40 54
     { // system settings
41 55
         pb_bool(pb, SystemSettings.visible_vcom);
42 56
         pb_bool(pb, SystemSettings.ini_comments);
43
-
57
+        // 1
44 58
         pb_bool(pb, SystemSettings.enable_mco);
45 59
         pb_u8(pb, SystemSettings.mco_prediv);
60
+        // 2
61
+        pb_bool(pb, SystemSettings.use_comm_uart);
62
+        pb_bool(pb, SystemSettings.use_comm_nordic);
63
+        pb_bool(pb, SystemSettings.use_comm_lora);
64
+        pb_u32(pb, SystemSettings.comm_uart_baud);
65
+        pb_bool(pb, SystemSettings.enable_debug_uart);
46 66
     } // end system settings
47 67
 }
48 68
 
@@ -67,12 +87,40 @@ void systemsettings_mco_init(void)
67 87
     }
68 88
 }
69 89
 
90
+void systemsettings_debug_uart_init_deinit(void)
91
+{
92
+    if (SystemSettings.enable_debug_uart) {
93
+        DebugUart_Init();
94
+    } else {
95
+        DebugUart_Teardown();
96
+    }
97
+}
98
+
99
+/**
100
+ * Begin load of system settings, releasing resources etc
101
+ */
102
+void systemsettings_begin_load(void)
103
+{
104
+    systemsettings_mco_teardown();
105
+    com_release_resources_for_alt_transfers();
106
+}
107
+
108
+/**
109
+ * Claim resources and set up system components based on the loaded settings
110
+ */
111
+void systemsettings_finalize_load(void)
112
+{
113
+    systemsettings_mco_init();
114
+    systemsettings_debug_uart_init_deinit();
115
+    com_claim_resources_for_alt_transfers();
116
+}
117
+
70 118
 // from binary
71 119
 bool systemsettings_load(PayloadParser *pp)
72 120
 {
73 121
     if (pp_char(pp) != 'S') return false;
74 122
 
75
-    systemsettings_mco_teardown();
123
+    systemsettings_begin_load();
76 124
 
77 125
     uint8_t version = pp_u8(pp);
78 126
 
@@ -85,9 +133,16 @@ bool systemsettings_load(PayloadParser *pp)
85 133
             SystemSettings.enable_mco = pp_bool(pp);
86 134
             SystemSettings.mco_prediv = pp_u8(pp);
87 135
         }
136
+        if (version >= 2) {
137
+            SystemSettings.use_comm_uart = pp_bool(pp);
138
+            SystemSettings.use_comm_nordic = pp_bool(pp);
139
+            SystemSettings.use_comm_lora = pp_bool(pp);
140
+            SystemSettings.comm_uart_baud = pp_u32(pp);
141
+            SystemSettings.enable_debug_uart = pp_bool(pp);
142
+        }
88 143
     } // end system settings
89 144
 
90
-    systemsettings_mco_init();
145
+    systemsettings_finalize_load();
91 146
 
92 147
     return pp->ok;
93 148
 }
@@ -106,11 +161,31 @@ void systemsettings_build_ini(IniWriter *iw)
106 161
     iw_comment(iw, "Show comments in INI files (Y, N)");
107 162
     iw_entry_s(iw, "ini-comments", str_yn(SystemSettings.ini_comments));
108 163
 
164
+    iw_comment(iw, "Enable debug UART-Tx on PA9 (Y, N)"); // TODO update if moved to a different pin
165
+    iw_entry_s(iw, "debug-uart", str_yn(SystemSettings.enable_debug_uart));
166
+
109 167
     iw_cmt_newline(iw);
110 168
     iw_comment(iw, "Output core clock on PA8 (Y, N)");
111 169
     iw_entry_s(iw, "mco-enable", str_yn(SystemSettings.enable_mco));
112 170
     iw_comment(iw, "Output clock prediv (1,2,...,128)");
113 171
     iw_entry_d(iw, "mco-prediv", (1<<SystemSettings.mco_prediv));
172
+
173
+    iw_cmt_newline(iw);
174
+    iw_comment(iw, "Allowed fallback communication ports");
175
+
176
+    iw_comment(iw, "UART Tx:PA2, Rx:PA2");
177
+    iw_entry_s(iw, "com-uart", str_yn(SystemSettings.use_comm_uart));
178
+    iw_entry_d(iw, "com-uart-baud", SystemSettings.comm_uart_baud);
179
+
180
+    // those aren't implement yet, don't tease the user
181
+    // TODO show pin-out, extra settings if applicable
182
+#if 0
183
+    iw_comment(iw, "nRF24L01+");
184
+    iw_entry_s(iw, "com-nordic", str_yn(SystemSettings.use_comm_nrf24l01p));
185
+
186
+    iw_comment(iw, "LoRa/GFSK sx127x");
187
+    iw_entry_s(iw, "com-lora", str_yn(SystemSettings.use_comm_sx127x));
188
+#endif
114 189
 }
115 190
 
116 191
 /**
@@ -151,5 +226,32 @@ bool systemsettings_load_ini(const char *restrict key, const char *restrict valu
151 226
         }
152 227
     }
153 228
 
229
+    if (streq(key, "debug-uart")) {
230
+        bool yn = cfg_bool_parse(value, &suc);
231
+        if (suc) SystemSettings.enable_debug_uart = yn;
232
+    }
233
+
234
+    if (streq(key, "com-uart")) {
235
+        bool yn = cfg_bool_parse(value, &suc);
236
+        if (suc) SystemSettings.use_comm_uart = yn;
237
+    }
238
+
239
+    if (streq(key, "com-uart-baud")) {
240
+        uint32_t baud = cfg_u32_parse(value, &suc);
241
+        if (suc) SystemSettings.comm_uart_baud = baud;
242
+    }
243
+
244
+#if 0
245
+    if (streq(key, "com-nordic")) {
246
+        bool yn = cfg_bool_parse(value, &suc);
247
+        if (suc) SystemSettings.use_comm_nordic = yn;
248
+    }
249
+
250
+    if (streq(key, "com-lora")) {
251
+        bool yn = cfg_bool_parse(value, &suc);
252
+        if (suc) SystemSettings.use_comm_lora = yn;
253
+    }
254
+#endif
255
+
154 256
     return suc;
155 257
 }

+ 11 - 2
framework/system_settings.h View File

@@ -20,6 +20,13 @@ struct system_settings {
20 20
     bool ini_comments;
21 21
     bool enable_mco;
22 22
     uint8_t mco_prediv;
23
+    bool enable_debug_uart;
24
+
25
+    // enable alternate communication ports if USB doesn't enumerate (e.g. running from battery / solar cell remotely)
26
+    bool use_comm_uart;
27
+    uint32_t comm_uart_baud; // baud rate for the uart transport
28
+    bool use_comm_lora;   // SX1276/8
29
+    bool use_comm_nordic; // nRF24L01+
23 30
 
24 31
     // Support flags put here for scoping, but not atcually part of the persistent settings
25 32
     volatile bool editable; //!< True if we booted with the LOCK jumper removed
@@ -62,7 +69,9 @@ void systemsettings_build_ini(IniWriter *iw);
62 69
  */
63 70
 bool systemsettings_load_ini(const char *restrict key, const char *restrict value);
64 71
 
65
-void systemsettings_mco_teardown(void);
66
-void systemsettings_mco_init(void);
72
+/** Release system resources before system settings init */
73
+void systemsettings_begin_load(void);
74
+/** Claim system resources and apply system settings */
75
+void systemsettings_finalize_load(void);
67 76
 
68 77
 #endif //GEX_SYSTEM_SETTINGS_H

+ 2 - 0
gex_hooks.c View File

@@ -10,12 +10,14 @@
10 10
 #include "platform/debug_uart.h"
11 11
 #include "gex_hooks.h"
12 12
 #include "unit_registry.h"
13
+#include "comm/interfaces.h"
13 14
 
14 15
 /**
15 16
  * This is a systick callback for GEX application logic
16 17
  */
17 18
 void GEX_MsTick(void)
18 19
 {
20
+    com_iface_flush_buffer();
19 21
     TF_Tick(comm);
20 22
     Indicator_Tick();
21 23
     ureg_tick_units();

+ 36 - 0
platform/debug_uart.c View File

@@ -7,6 +7,7 @@
7 7
 #include "debug_uart.h"
8 8
 #include "plat_compat.h"
9 9
 #include "hw_utils.h"
10
+#include "framework/system_settings.h"
10 11
 
11 12
 #if USE_DEBUG_UART
12 13
 
@@ -52,18 +53,26 @@
52 53
 #endif
53 54
 
54 55
 
56
+static bool debug_uart_inited = false;
57
+static bool debug_uart_preinited = false;
55 58
 
56 59
 /** Init the submodule. */
57 60
 void DebugUart_Init(void)
58 61
 {
62
+    if (debug_uart_inited) return;
63
+    if (!debug_uart_preinited) DebugUart_PreInit();
59 64
     // Debug UART
60 65
     assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, DEBUG_USART_RSC));
61 66
     assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, DEBUG_USART_PORT, DEBUG_USART_PIN));
67
+
68
+    debug_uart_inited = true;
62 69
 }
63 70
 
64 71
 /** Init the hardware peripheral - this is called early in the boot process */
65 72
 void DebugUart_PreInit(void)
66 73
 {
74
+    debug_uart_preinited = true;
75
+
67 76
     // configure AF only if platform uses AF numbers
68 77
 #if !PLAT_NO_AFNUM
69 78
 #pragma GCC diagnostic push
@@ -89,8 +98,35 @@ void DebugUart_PreInit(void)
89 98
     LL_USART_Enable(DEBUG_USART);
90 99
 }
91 100
 
101
+void DebugUart_Teardown(void)
102
+{
103
+    if (!debug_uart_inited) return;
104
+
105
+    dbg("Disabling debug UART!");
106
+
107
+    // TODO wait for Tx (after debug print DMA is implemented)
108
+
109
+    LL_USART_Disable(DEBUG_USART);
110
+    rsc_free(&UNIT_SYSTEM, DEBUG_USART_RSC);
111
+    hw_periph_clock_disable(DEBUG_USART);
112
+
113
+    bool suc = true;
114
+    Resource r = rsc_portpin2rsc(DEBUG_USART_PORT, DEBUG_USART_PIN, &suc);
115
+    rsc_free(&UNIT_SYSTEM, r);
116
+    hw_deinit_pin_rsc(r);
117
+
118
+    debug_uart_preinited = false;
119
+    debug_uart_inited = false;
120
+
121
+    assert_param(suc);
122
+}
123
+
92 124
 void debug_write(const char *buf, uint16_t len)
93 125
 {
126
+    if (!SystemSettings.enable_debug_uart) return;
127
+
128
+    // TODO wait for DMA complete
129
+    // TODO use DMA
94 130
     for (uint16_t i = 0; i < len; i++) {
95 131
         while (!LL_USART_IsActiveFlag_TC(DEBUG_USART));
96 132
         LL_USART_TransmitData8(DEBUG_USART, (uint8_t) *buf++);

+ 9 - 1
platform/debug_uart.h View File

@@ -8,6 +8,8 @@
8 8
 #ifndef GEX_DEBUG_UART_H
9 9
 #define GEX_DEBUG_UART_H
10 10
 
11
+#include "platform.h"
12
+
11 13
 /**
12 14
  * Pre-init the debug uart
13 15
  *
@@ -17,7 +19,13 @@
17 19
 void DebugUart_PreInit(void);
18 20
 
19 21
 /**
20
- * Finalize the init (claim resources)
22
+ * Release the peripheral and deinit pin
23
+ */
24
+void DebugUart_Teardown(void);
25
+
26
+/**
27
+ * Finalize the init (claim resources).
28
+ * If not pre-inited (i.e. Teardown was called before), also pre-init.
21 29
  */
22 30
 void DebugUart_Init(void);
23 31
 

+ 9 - 4
platform/hw_utils.c View File

@@ -99,14 +99,19 @@ void hw_deinit_unit_pins(Unit *unit)
99 99
 {
100 100
     for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
101 101
         if (RSC_IS_HELD(unit->resources, (Resource)rsc)) {
102
-            rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
103
-            GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
104
-            uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
105
-            LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
102
+            hw_deinit_pin_rsc((Resource)rsc);
106 103
         }
107 104
     }
108 105
 }
109 106
 
107
+void hw_deinit_pin_rsc(Resource rsc)
108
+{
109
+    rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
110
+    GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
111
+    uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
112
+    LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
113
+}
114
+
110 115
 /** Configure a pin to alternate function */
111 116
 error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
112 117
 {

+ 2 - 0
platform/hw_utils.h View File

@@ -40,6 +40,8 @@ GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
40 40
  */
41 41
 bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribute__((warn_unused_result));
42 42
 
43
+void hw_deinit_pin_rsc(Resource rsc);
44
+
43 45
 /**
44 46
  * Spread packed port pins using a mask
45 47
  *

+ 3 - 3
platform/plat_compat.h View File

@@ -56,9 +56,9 @@
56 56
 #define IWBUFFER_LEN     80 // Ini writer buffer for sprintf
57 57
 
58 58
 // -------- Timeouts ------------
59
-#define TF_PARSER_TIMEOUT_TICKS 300 // Timeout for receiving & parsing a frame
60
-#define BULK_LST_TIMEOUT_MS     500 // timeout for the bulk transaction to expire
61
-#define MSG_QUE_POST_TIMEOUT    100 // Time to post to the messages / jobs queue
59
+#define TF_PARSER_TIMEOUT_TICKS 100 // Timeout for receiving & parsing a frame
60
+#define BULK_LST_TIMEOUT_MS     2000 // timeout for the bulk transaction to expire
61
+#define MSG_QUE_POST_TIMEOUT    200 // Time to post to the messages / jobs queue
62 62
 
63 63
 // -------- Platform specific includes and defines ---------
64 64
 

+ 4 - 1
platform/platform.c View File

@@ -2,7 +2,6 @@
2 2
 // Created by MightyPork on 2017/11/26.
3 3
 //
4 4
 
5
-#include <units/dac/unit_dac.h>
6 5
 #include "platform.h"
7 6
 #include "usbd_core.h"
8 7
 #include "USB/usb_device.h"
@@ -22,6 +21,8 @@
22 21
 #include "units/fcap/unit_fcap.h"
23 22
 #include "units/touch/unit_touch.h"
24 23
 #include "units/simple_pwm/unit_pwmdim.h"
24
+#include "units/dac/unit_dac.h"
25
+#include "comm/interfaces.h"
25 26
 #include "hw_utils.h"
26 27
 
27 28
 void plat_init_resources(void)
@@ -258,6 +259,8 @@ void plat_init_resources(void)
258 259
  */
259 260
 void plat_usb_reconnect(void)
260 261
 {
262
+    if (gActiveComport != COMPORT_USB) return;
263
+
261 264
     // TODO add better reset methods available on different chips
262 265
 
263 266
     USBD_LL_Reset(&hUsbDeviceFS);

+ 36 - 26
tasks/task_main.c View File

@@ -12,6 +12,7 @@
12 12
 #include "usb_device.h"
13 13
 #include "usbd_msc.h"
14 14
 #include "task_main.h"
15
+#include "comm/interfaces.h"
15 16
 
16 17
 /* TaskUsbEvent function */
17 18
 void TaskMain(void const * argument)
@@ -25,14 +26,16 @@ void TaskMain(void const * argument)
25 26
 
26 27
     Indicator_Effect(STATUS_WELCOME);
27 28
 
28
-    uint32_t startTime = xTaskGetTickCount();
29
+    const uint32_t bootTime = HAL_GetTick();
30
+    uint32_t startTime = bootTime;
29 31
     uint32_t cnt = 1;
32
+    bool waiting_for_usb = true;
30 33
     while(1) {
31 34
         uint32_t msg;
32 35
         xTaskNotifyWait(0, UINT32_MAX, &msg, 100); // time out if nothing happened
33 36
 
34 37
         // periodic updates to the VFS driver
35
-        uint32_t now = xTaskGetTickCount();
38
+        uint32_t now = HAL_GetTick();
36 39
         uint32_t elapsed = now - startTime;
37 40
         if (elapsed >= 100) {
38 41
             // interval 100ms or more - slow periodic
@@ -48,6 +51,9 @@ void TaskMain(void const * argument)
48 51
             Indicator_Heartbeat();
49 52
 
50 53
             wd_restart();
54
+
55
+            // If USB has no signal, set up alternate communication interface
56
+            com_switch_transfer_if_needed();
51 57
         }
52 58
 
53 59
         // if no message and it just timed out, go wait some more...
@@ -61,35 +67,39 @@ void TaskMain(void const * argument)
61 67
             continue;
62 68
         }
63 69
 
64
-        // Endpoint 0 - control messages for the different classes
65
-        if (msg & USBEVT_FLAG_EP0_RX_RDY) {
66
-            USBD_CDC_EP0_RxReady(&hUsbDeviceFS);
67
-        }
70
+        if (gActiveComport == COMPORT_USB) {
71
+            // Endpoint 0 - control messages for the different classes
72
+            if (msg & USBEVT_FLAG_EP0_RX_RDY) {
73
+                USBD_CDC_EP0_RxReady(&hUsbDeviceFS);
74
+            }
68 75
 
69
-        if (msg & USBEVT_FLAG_EP0_TX_SENT) {
70
-            //
71
-        }
76
+            if (msg & USBEVT_FLAG_EP0_TX_SENT) {
77
+                //
78
+            }
72 79
 
73 80
 #ifndef DISABLE_MSC
74
-        // MSC - read/write etc
75
-        if (msg & (USBEVT_FLAG_EPx_IN(MSC_EPIN_ADDR))) {
76
-            USBD_MSC_DataIn(&hUsbDeviceFS, MSC_EPIN_ADDR);
77
-        }
78
-
79
-        if (msg & (USBEVT_FLAG_EPx_OUT(MSC_EPOUT_ADDR))) {
80
-            USBD_MSC_DataOut(&hUsbDeviceFS, MSC_EPOUT_ADDR);
81
-        }
81
+            // MSC - read/write etc
82
+            if (msg & (USBEVT_FLAG_EPx_IN(MSC_EPIN_ADDR))) {
83
+                USBD_MSC_DataIn(&hUsbDeviceFS, MSC_EPIN_ADDR);
84
+            }
85
+
86
+            if (msg & (USBEVT_FLAG_EPx_OUT(MSC_EPOUT_ADDR))) {
87
+                USBD_MSC_DataOut(&hUsbDeviceFS, MSC_EPOUT_ADDR);
88
+            }
82 89
 #endif
83 90
 
84
-        // CDC - config packets and data in/out
85
-//        if (msg & (USBEVT_FLAG_EPx_IN(CDC_IN_EP))) {
86
-//            USBD_CDC_DataIn(&hUsbDeviceFS, CDC_IN_EP);
87
-//        }
88
-        if (msg & (USBEVT_FLAG_EPx_IN(CDC_CMD_EP))) {
89
-            USBD_CDC_DataIn(&hUsbDeviceFS, CDC_CMD_EP);
90
-        }
91
-        if (msg & (USBEVT_FLAG_EPx_OUT(CDC_OUT_EP))) {
92
-            USBD_CDC_DataOut(&hUsbDeviceFS, CDC_OUT_EP);
91
+            // CDC - config packets and data in/out
92
+//          if (msg & (USBEVT_FLAG_EPx_IN(CDC_IN_EP))) {
93
+//              USBD_CDC_DataIn(&hUsbDeviceFS, CDC_IN_EP);
94
+//          }
95
+
96
+            if (msg & (USBEVT_FLAG_EPx_IN(CDC_CMD_EP))) {
97
+                USBD_CDC_DataIn(&hUsbDeviceFS, CDC_CMD_EP);
98
+            }
99
+
100
+            if (msg & (USBEVT_FLAG_EPx_OUT(CDC_OUT_EP))) {
101
+                USBD_CDC_DataOut(&hUsbDeviceFS, CDC_OUT_EP);
102
+            }
93 103
         }
94 104
     }
95 105
 }