Browse Source

Added a command shell and storage functions

The command shell is based on the ChibiOS-provided one, but modified to
not run in a new thread and generally be a bit simpler, while also
having PD Buddy branding.  The storage functions work with the STM32
flash registers directly, taking over the last page of flash.  A new
linker script is used to ensure that program code can't end up using
that page.  The DPM has been updated to use the saved settings rather
than hardcoded ones.  Now what's needed is real commands for editing the
configuration.

Added commands to edit configuration

We now have commands to load the current settings into RAM, edit the
settings in RAM, and write them back to flash.  The only settings
currently supported are current and fixed voltage, because the rest of
the code doesn't support GiveBack or variable/battery PDOs yet.

Short help messages were added for each command.  Nothing too exciting,
but it should be a great help for someone poking around in the PD Buddy
Sink configuration shell for the first time.

Wrote new usage information for the firmware

Now that we have a command shell, the README should indicate how to use
it.
Clara Hobbs 5 years ago
parent
commit
417444167b
15 changed files with 1282 additions and 50 deletions
  1. 5
    4
      Makefile
  2. 31
    4
      README.md
  3. 6
    6
      chconf.h
  4. 2
    2
      halconf.h
  5. 53
    0
      ld/STM32F072xB.ld
  6. 4
    4
      mcuconf.h
  7. 41
    28
      src/device_policy_manager.c
  8. 1
    1
      src/led.c
  9. 20
    1
      src/main.c
  10. 341
    0
      src/shell.c
  11. 63
    0
      src/shell.h
  12. 231
    0
      src/storage.c
  13. 86
    0
      src/storage.h
  14. 352
    0
      src/usbcfg.c
  15. 46
    0
      src/usbcfg.h

+ 5
- 4
Makefile View File

@@ -30,7 +30,7 @@ endif
30 30
 
31 31
 # Enable this if you want link time optimizations (LTO)
32 32
 ifeq ($(USE_LTO),)
33
-  USE_LTO = yes
33
+  USE_LTO = no
34 34
 endif
35 35
 
36 36
 # If enabled, this option allows to compile the application in THUMB mode.
@@ -96,7 +96,7 @@ include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v6m.mk
96 96
 include $(CHIBIOS)/test/rt/test.mk
97 97
 
98 98
 # Define linker script file here
99
-LDSCRIPT= $(STARTUPLD)/STM32F072xB.ld
99
+LDSCRIPT=$(CHIBIOS)/../ld/STM32F072xB.ld
100 100
 
101 101
 # C sources that can be compiled in ARM or THUMB mode depending on the global
102 102
 # setting.
@@ -108,6 +108,7 @@ CSRC = $(STARTUPSRC) \
108 108
        $(PLATFORMSRC) \
109 109
        $(BOARDSRC) \
110 110
        $(TESTSRC) \
111
+       $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
111 112
        $(wildcard src/*.c)
112 113
 
113 114
 # C++ sources that can be compiled in ARM or THUMB mode depending on the global
@@ -139,7 +140,7 @@ ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
139 140
 
140 141
 INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
141 142
          $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
142
-         $(CHIBIOS)/os/various \
143
+         $(CHIBIOS)/os/hal/lib/streams $(CHIBIOS)/os/various \
143 144
 	 config
144 145
 
145 146
 #
@@ -190,7 +191,7 @@ CPPWARN = -Wall -Wextra -Wundef
190 191
 #
191 192
 
192 193
 # List all user C define here, like -D_DEBUG=1
193
-UDEFS =
194
+UDEFS = -DPDB_CONFIG_BASE=0x0801F800
194 195
 
195 196
 # Define ASM defines here
196 197
 UADEFS =

+ 31
- 4
README.md View File

@@ -59,7 +59,34 @@ OpenOCD can also be used to flash the firmware.  For example:
59 59
 
60 60
 ## Usage
61 61
 
62
-Currently, there isn't much to say here.  Plug it into your power supply, and
63
-the PD Buddy Sink will negotiate 2.25 A at 20 V.  This can be configured by
64
-editing `dpm_desired_v` and `dpm_desired_i` in `src/device_policy_manager.c`,
65
-then recompiling and reflashing.
62
+After first flashing the PD Buddy Sink, the device has no configuration.  To
63
+configure it, plug it into your computer while holding the "Setup" button.  The
64
+LED should blink once per second to indicate that the device is in
65
+configuration mode.  The Sink provides a virtual serial port for editing its
66
+configuration.
67
+
68
+### Configuration with the Serial Terminal
69
+
70
+Connect to the PD Buddy Sink with your favorite serial console program, such as
71
+GNU Screen, Minicom, or PuTTY.  Press Enter, and you should be greeted with a
72
+`PDBS)` prompt.  The `help` command gives brief summaries of each of the
73
+available commands.
74
+
75
+To configure the PD Buddy Sink to request 2.25 A at 20 V, run the following
76
+commands:
77
+
78
+    PDBS) set_v 20000
79
+    PDBS) set_i 2250
80
+    PDBS) write
81
+
82
+When `write` is run, the chosen settings are written to flash.  You can then
83
+simply disconnect the Sink from your computer.
84
+
85
+### Using the configured PD Buddy Sink
86
+
87
+Once the Sink has been configured, just plug it into your USB PD power supply.
88
+If the supply is capable of putting out the configured current at the
89
+configured voltage, the Sink will negotiate it, then turn on its output and
90
+blink the LED three times to indicate success.  If the supply cannot output
91
+enough power, the Sink will turn its LED on solid to indicate failure, and
92
+leave its output turned off.

+ 6
- 6
chconf.h View File

@@ -352,7 +352,7 @@
352 352
  *
353 353
  * @note    The default is @p FALSE.
354 354
  */
355
-#define CH_DBG_SYSTEM_STATE_CHECK           TRUE
355
+#define CH_DBG_SYSTEM_STATE_CHECK           FALSE
356 356
 
357 357
 /**
358 358
  * @brief   Debug option, parameters checks.
@@ -361,7 +361,7 @@
361 361
  *
362 362
  * @note    The default is @p FALSE.
363 363
  */
364
-#define CH_DBG_ENABLE_CHECKS                TRUE
364
+#define CH_DBG_ENABLE_CHECKS                FALSE
365 365
 
366 366
 /**
367 367
  * @brief   Debug option, consistency checks.
@@ -371,7 +371,7 @@
371 371
  *
372 372
  * @note    The default is @p FALSE.
373 373
  */
374
-#define CH_DBG_ENABLE_ASSERTS               TRUE
374
+#define CH_DBG_ENABLE_ASSERTS               FALSE
375 375
 
376 376
 /**
377 377
  * @brief   Debug option, trace buffer.
@@ -380,7 +380,7 @@
380 380
  *
381 381
  * @note    The default is @p FALSE.
382 382
  */
383
-#define CH_DBG_ENABLE_TRACE                 TRUE
383
+#define CH_DBG_ENABLE_TRACE                 FALSE
384 384
 
385 385
 /**
386 386
  * @brief   Debug option, stack checks.
@@ -392,7 +392,7 @@
392 392
  * @note    The default failure mode is to halt the system with the global
393 393
  *          @p panic_msg variable set to @p NULL.
394 394
  */
395
-#define CH_DBG_ENABLE_STACK_CHECK           TRUE
395
+#define CH_DBG_ENABLE_STACK_CHECK           FALSE
396 396
 
397 397
 /**
398 398
  * @brief   Debug option, stacks initialization.
@@ -402,7 +402,7 @@
402 402
  *
403 403
  * @note    The default is @p FALSE.
404 404
  */
405
-#define CH_DBG_FILL_THREADS                 TRUE
405
+#define CH_DBG_FILL_THREADS                 FALSE
406 406
 
407 407
 /**
408 408
  * @brief   Debug option, threads profiling.

+ 2
- 2
halconf.h View File

@@ -157,7 +157,7 @@
157 157
  * @brief   Enables the SERIAL over USB subsystem.
158 158
  */
159 159
 #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
160
-#define HAL_USE_SERIAL_USB          FALSE
160
+#define HAL_USE_SERIAL_USB          TRUE
161 161
 #endif
162 162
 
163 163
 /**
@@ -178,7 +178,7 @@
178 178
  * @brief   Enables the USB subsystem.
179 179
  */
180 180
 #if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
181
-#define HAL_USE_USB                 FALSE
181
+#define HAL_USE_USB                 TRUE
182 182
 #endif
183 183
 
184 184
 /**

+ 53
- 0
ld/STM32F072xB.ld View File

@@ -0,0 +1,53 @@
1
+/*
2
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
3
+
4
+    Licensed under the Apache License, Version 2.0 (the "License");
5
+    you may not use this file except in compliance with the License.
6
+    You may obtain a copy of the License at
7
+
8
+        http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+    Unless required by applicable law or agreed to in writing, software
11
+    distributed under the License is distributed on an "AS IS" BASIS,
12
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+    See the License for the specific language governing permissions and
14
+    limitations under the License.
15
+*/
16
+
17
+/*
18
+ * STM32F072xB memory setup.
19
+ *
20
+ * Flash is defined as 2k smaller than it really is to reserve the last page
21
+ * for configuration.
22
+ */
23
+MEMORY
24
+{
25
+    flash : org = 0x08000000, len = 126k
26
+    ram0  : org = 0x20000000, len = 16k
27
+    ram1  : org = 0x00000000, len = 0
28
+    ram2  : org = 0x00000000, len = 0
29
+    ram3  : org = 0x00000000, len = 0
30
+    ram4  : org = 0x00000000, len = 0
31
+    ram5  : org = 0x00000000, len = 0
32
+    ram6  : org = 0x00000000, len = 0
33
+    ram7  : org = 0x00000000, len = 0
34
+}
35
+
36
+/* RAM region to be used for Main stack. This stack accommodates the processing
37
+   of all exceptions and interrupts*/
38
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
39
+
40
+/* RAM region to be used for the process stack. This is the stack used by
41
+   the main() function.*/
42
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
43
+
44
+/* RAM region to be used for data segment.*/
45
+REGION_ALIAS("DATA_RAM", ram0);
46
+
47
+/* RAM region to be used for BSS segment.*/
48
+REGION_ALIAS("BSS_RAM", ram0);
49
+
50
+/* RAM region to be used for the default heap.*/
51
+REGION_ALIAS("HEAP_RAM", ram0);
52
+
53
+INCLUDE rules.ld

+ 4
- 4
mcuconf.h View File

@@ -59,11 +59,11 @@
59 59
 #define STM32_PLS                           STM32_PLS_LEV0
60 60
 #define STM32_HSI_ENABLED                   TRUE
61 61
 #define STM32_HSI14_ENABLED                 TRUE
62
-#define STM32_HSI48_ENABLED                 TRUE
62
+#define STM32_HSI48_ENABLED                 FALSE
63 63
 #define STM32_LSI_ENABLED                   TRUE
64 64
 #define STM32_HSE_ENABLED                   FALSE
65 65
 #define STM32_LSE_ENABLED                   FALSE
66
-#define STM32_SW                            STM32_SW_HSI48
66
+#define STM32_SW                            STM32_SW_PLL
67 67
 #define STM32_PLLSRC                        STM32_PLLSRC_HSI_DIV2
68 68
 #define STM32_PREDIV_VALUE                  1
69 69
 #define STM32_PLLMUL_VALUE                  12
@@ -209,7 +209,7 @@
209 209
 /*
210 210
  * SERIAL driver system settings.
211 211
  */
212
-#define STM32_SERIAL_USE_USART1             TRUE
212
+#define STM32_SERIAL_USE_USART1             FALSE
213 213
 #define STM32_SERIAL_USE_USART2             FALSE
214 214
 #define STM32_SERIAL_USART1_PRIORITY        3
215 215
 #define STM32_SERIAL_USART2_PRIORITY        3
@@ -253,7 +253,7 @@
253 253
 /*
254 254
  * USB driver system settings.
255 255
  */
256
-#define STM32_USB_USE_USB1                  FALSE
256
+#define STM32_USB_USE_USB1                  TRUE
257 257
 #define STM32_USB_LOW_POWER_ON_SUSPEND      FALSE
258 258
 #define STM32_USB_USB1_LP_IRQ_PRIORITY      3
259 259
 

+ 41
- 28
src/device_policy_manager.c View File

@@ -23,19 +23,17 @@
23 23
 #include <hal.h>
24 24
 
25 25
 #include "led.h"
26
+#include "storage.h"
26 27
 #include "pd.h"
27 28
 
28 29
 
29
-/* The voltage and current we want */
30
-/* XXX In the future, these won't be *quite* so convenient to access */
31
-static uint16_t dpm_desired_v = 400; /* 0.05 V increments */
32
-static uint16_t dpm_desired_i = 225; /* 0.01 A increments */
33
-
34 30
 /* Whether or not the power supply is unconstrained */
35 31
 static uint8_t dpm_unconstrained_power;
36 32
 
37 33
 bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg *request)
38 34
 {
35
+    /* Get the current configuration */
36
+    struct pdb_config *cfg = pdb_config_flash_read();
39 37
     /* Get the number of PDOs */
40 38
     uint8_t numobj = PD_NUMOBJ_GET(capabilities);
41 39
 
@@ -49,24 +47,27 @@ bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg
49 47
         dpm_unconstrained_power = 0;
50 48
     }
51 49
 
52
-    /* Look at the PDOs to see if one matches our desires */
53
-    for (uint8_t i = 0; i < numobj; i++) {
54
-        /* Fixed Supply PDOs come first, so when we see a PDO that isn't a
55
-         * Fixed Supply, stop reading. */
56
-        if ((capabilities->obj[i] & PD_PDO_TYPE) != PD_PDO_TYPE_FIXED) {
57
-            break;
58
-        }
59
-        /* If the V from the PDO equals our desired V and the I is at least our
60
-         * desired I */
61
-        if (PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities, i) == dpm_desired_v
62
-                && PD_PDO_SRC_FIXED_CURRENT_GET(capabilities, i) >= dpm_desired_i) {
63
-            /* We got what we wanted, so build a request for that */
64
-            request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
65
-                PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
66
-            request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(dpm_desired_i)
67
-                | PD_RDO_FV_CURRENT_SET(dpm_desired_i)
68
-                | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
69
-            return true;
50
+    /* Make sure we have configuration */
51
+    if (cfg != NULL) {
52
+        /* Look at the PDOs to see if one matches our desires */
53
+        for (uint8_t i = 0; i < numobj; i++) {
54
+            /* Fixed Supply PDOs come first, so when we see a PDO that isn't a
55
+             * Fixed Supply, stop reading. */
56
+            if ((capabilities->obj[i] & PD_PDO_TYPE) != PD_PDO_TYPE_FIXED) {
57
+                break;
58
+            }
59
+            /* If the V from the PDO equals our desired V and the I is at least
60
+             * our desired I */
61
+            if (PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities, i) == cfg->v
62
+                    && PD_PDO_SRC_FIXED_CURRENT_GET(capabilities, i) >= cfg->i) {
63
+                /* We got what we wanted, so build a request for that */
64
+                request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
65
+                    PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
66
+                request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(cfg->i)
67
+                    | PD_RDO_FV_CURRENT_SET(cfg->i)
68
+                    | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
69
+                return true;
70
+            }
70 71
         }
71 72
     }
72 73
     /* Nothing matched, so get 5 V */
@@ -81,15 +82,27 @@ bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg
81 82
 
82 83
 void pdb_dpm_get_sink_capability(union pd_msg *cap)
83 84
 {
85
+    /* Get the current configuration */
86
+    struct pdb_config *cfg = pdb_config_flash_read();
87
+
88
+    /* If we have no configuration, request 0.1 A at 5 V. */
89
+    if (cfg == NULL) {
90
+        /* Sink_Capabilities message */
91
+        cap->hdr = PD_MSGTYPE_SINK_CAPABILITIES | PD_DATAROLE_UFP
92
+            | PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
93
+        /* vSafe5V at the desired current. */
94
+        cap->obj[0] = PD_PDO_TYPE_FIXED
95
+            | PD_PDO_SNK_FIXED_VOLTAGE_SET(100)
96
+            | PD_PDO_SNK_FIXED_CURRENT_SET(10);
84 97
     /* If we want 5 V, we need to send only one PDO */
85
-    if (dpm_desired_v == 100) {
98
+    } else if (cfg->v == 100) {
86 99
         /* Sink_Capabilities message */
87 100
         cap->hdr = PD_MSGTYPE_SINK_CAPABILITIES | PD_DATAROLE_UFP
88 101
             | PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
89 102
         /* vSafe5V at the desired current. */
90 103
         cap->obj[0] = PD_PDO_TYPE_FIXED
91
-            | PD_PDO_SNK_FIXED_VOLTAGE_SET(dpm_desired_v)
92
-            | PD_PDO_SNK_FIXED_CURRENT_SET(dpm_desired_i);
104
+            | PD_PDO_SNK_FIXED_VOLTAGE_SET(cfg->v)
105
+            | PD_PDO_SNK_FIXED_CURRENT_SET(cfg->i);
93 106
     /* Otherwise, send two PDOs, one for 5 V and one for the desired power. */
94 107
     } else {
95 108
         /* Sink_Capabilities message */
@@ -101,8 +114,8 @@ void pdb_dpm_get_sink_capability(union pd_msg *cap)
101 114
             | PD_PDO_SNK_FIXED_CURRENT_SET(10);
102 115
         /* Next, desired_v and desired_i */
103 116
         cap->obj[1] = PD_PDO_TYPE_FIXED
104
-            | PD_PDO_SNK_FIXED_VOLTAGE_SET(dpm_desired_v)
105
-            | PD_PDO_SNK_FIXED_CURRENT_SET(dpm_desired_i);
117
+            | PD_PDO_SNK_FIXED_VOLTAGE_SET(cfg->v)
118
+            | PD_PDO_SNK_FIXED_CURRENT_SET(cfg->i);
106 119
     }
107 120
 
108 121
     /* Set the unconstrained power flag. */

+ 1
- 1
src/led.c View File

@@ -47,7 +47,7 @@ static THD_FUNCTION(LED, arg) {
47 47
      * modes. */
48 48
     systime_t timeout = TIME_INFINITE;
49 49
     /* Counter for blinking modes */
50
-    int i;
50
+    int i = 0;
51 51
 
52 52
     while (true) {
53 53
         /* Wait for any event except the last one we saw */

+ 20
- 1
src/main.c View File

@@ -35,6 +35,11 @@
35 35
 #include <ch.h>
36 36
 #include <hal.h>
37 37
 
38
+#include "chprintf.h"
39
+
40
+#include "shell.h"
41
+#include "usbcfg.h"
42
+
38 43
 #include "priorities.h"
39 44
 #include "led.h"
40 45
 #include "policy_engine.h"
@@ -61,9 +66,23 @@ static void setup(void)
61 66
     chEvtSignal(pdb_led_thread, PDB_EVT_LED_SLOW_BLINK);
62 67
 
63 68
     /* TODO: implement the configuration mode */
69
+    usbDisconnectBus(serusbcfg.usbp);
70
+
71
+    sduObjectInit(&SDU1);
72
+    sduStart(&SDU1, &serusbcfg);
73
+
74
+    chThdSleepMilliseconds(100);
75
+    usbStart(serusbcfg.usbp, &usbcfg);
76
+    usbConnectBus(serusbcfg.usbp);
77
+
78
+    //char text[] = "Hello, world!\r\n";
64 79
 
65 80
     while (true) {
66
-        chThdSleepMilliseconds(1000);
81
+        //sdWrite(&SDU1, (uint8_t *) text, 15);
82
+        //obqWriteTimeout(&SDU1.obqueue, (uint8_t *) text, 15, TIME_INFINITE);
83
+        //chprintf(&SDU1, "Hello, world! %d\r\n", ST2S(chVTGetSystemTime()));
84
+        pdb_shell();
85
+        chThdSleepMilliseconds(100);
67 86
     }
68 87
 }
69 88
 

+ 341
- 0
src/shell.c View File

@@ -0,0 +1,341 @@
1
+/*
2
+ * PD Buddy - USB Power Delivery for everyone
3
+ * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+/*
20
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
21
+
22
+    Licensed under the Apache License, Version 2.0 (the "License");
23
+    you may not use this file except in compliance with the License.
24
+    You may obtain a copy of the License at
25
+
26
+        http://www.apache.org/licenses/LICENSE-2.0
27
+
28
+    Unless required by applicable law or agreed to in writing, software
29
+    distributed under the License is distributed on an "AS IS" BASIS,
30
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
+    See the License for the specific language governing permissions and
32
+    limitations under the License.
33
+*/
34
+
35
+#include "shell.h"
36
+
37
+#include <stdlib.h>
38
+#include <string.h>
39
+
40
+#include <ch.h>
41
+
42
+#include "chprintf.h"
43
+
44
+#include "usbcfg.h"
45
+#include "storage.h"
46
+
47
+
48
+/* Buffer for unwritten configuration */
49
+static struct pdb_config tmpcfg = {
50
+    .status = PDB_CONFIG_STATUS_EMPTY
51
+};
52
+
53
+static void cmd_erase(BaseSequentialStream *chp, int argc, char *argv[])
54
+{
55
+    (void) argv;
56
+    if (argc > 0) {
57
+        chprintf(chp, "Usage: erase\r\n");
58
+        return;
59
+    }
60
+
61
+    pdb_config_flash_erase();
62
+}
63
+
64
+static void cmd_write(BaseSequentialStream *chp, int argc, char *argv[])
65
+{
66
+    (void) argv;
67
+    if (argc > 0) {
68
+        chprintf(chp, "Usage: write\r\n");
69
+        return;
70
+    }
71
+
72
+    pdb_config_flash_update(&tmpcfg);
73
+}
74
+
75
+static void cmd_load(BaseSequentialStream *chp, int argc, char *argv[])
76
+{
77
+    (void) argv;
78
+    if (argc > 0) {
79
+        chprintf(chp, "Usage: load\r\n");
80
+        return;
81
+    }
82
+
83
+    /* Get the current configuration */
84
+    struct pdb_config *cfg = pdb_config_flash_read();
85
+    if (cfg == NULL) {
86
+        chprintf(chp, "No configuration\r\n");
87
+        return;
88
+    }
89
+
90
+    /* Load the current configuration into tmpcfg */
91
+    tmpcfg.status = cfg->status;
92
+    tmpcfg.flags = cfg->flags;
93
+    tmpcfg.v = cfg->v;
94
+    tmpcfg.i = cfg->i;
95
+    tmpcfg.v_min = cfg->v_min;
96
+    tmpcfg.v_max = cfg->v_max;
97
+}
98
+
99
+static void cmd_get_cfg(BaseSequentialStream *chp, int argc, char *argv[])
100
+{
101
+    struct pdb_config *cfg = NULL;
102
+
103
+    if (argc > 1) {
104
+        chprintf(chp, "Usage: get_cfg [index]\r\n");
105
+        return;
106
+    }
107
+
108
+    /* With no arguments, find the current configuration */
109
+    if (argc == 0) {
110
+        cfg = pdb_config_flash_read();
111
+        if (cfg == NULL) {
112
+            chprintf(chp, "No configuration\r\n");
113
+            return;
114
+        }
115
+    /* With an argument, get a particular configuration array index */
116
+    } else if (argc == 1) {
117
+        char *endptr;
118
+        long i = strtol(argv[0], &endptr, 0);
119
+        if (i >= 0 && i < PDB_CONFIG_ARRAY_LEN && endptr > argv[0]) {
120
+            cfg = &pdb_config_array[i];
121
+        } else {
122
+            chprintf(chp, "Invalid index\r\n");
123
+            return;
124
+        }
125
+    }
126
+    /* Print the configuration */
127
+    pdb_config_print(chp, cfg);
128
+}
129
+
130
+static void cmd_get_tmpcfg(BaseSequentialStream *chp, int argc, char *argv[])
131
+{
132
+    (void) argv;
133
+    if (argc > 0) {
134
+        chprintf(chp, "Usage: get_tmpcfg [index]\r\n");
135
+        return;
136
+    }
137
+
138
+    pdb_config_print(chp, &tmpcfg);
139
+}
140
+
141
+static void cmd_set_v(BaseSequentialStream *chp, int argc, char *argv[])
142
+{
143
+    if (argc != 1) {
144
+        chprintf(chp, "Usage: set_v voltage_in_mV\r\n");
145
+        return;
146
+    }
147
+
148
+    char *endptr;
149
+    long i = strtol(argv[0], &endptr, 0);
150
+    if (i >= 0 && i <= UINT16_MAX && endptr > argv[0]) {
151
+        tmpcfg.status = PDB_CONFIG_STATUS_VALID;
152
+        /* Convert mV to the unit used by USB PD */
153
+        /* XXX this could use a macro */
154
+        tmpcfg.v = i / 50;
155
+    } else {
156
+        chprintf(chp, "Invalid voltage\r\n");
157
+        return;
158
+    }
159
+}
160
+
161
+static void cmd_set_i(BaseSequentialStream *chp, int argc, char *argv[])
162
+{
163
+    if (argc != 1) {
164
+        chprintf(chp, "Usage: set_i current_in_mA\r\n");
165
+        return;
166
+    }
167
+
168
+    char *endptr;
169
+    long i = strtol(argv[0], &endptr, 0);
170
+    if (i >= 0 && i <= UINT16_MAX && endptr > argv[0]) {
171
+        tmpcfg.status = PDB_CONFIG_STATUS_VALID;
172
+        /* Convert mA to the unit used by USB PD */
173
+        /* XXX this could use a macro */
174
+        tmpcfg.i = i / 10;
175
+    } else {
176
+        chprintf(chp, "Invalid current\r\n");
177
+        return;
178
+    }
179
+}
180
+
181
+static const struct pdb_shell_cmd commands[] = {
182
+    {"erase", cmd_erase, "Erase all stored configuration"},
183
+    {"write", cmd_write, "Write the changes to flash"},
184
+    {"load", cmd_load, "Load the stored configuration into RAM"},
185
+    {"get_cfg", cmd_get_cfg, "Print the stored configuration"},
186
+    {"get_tmpcfg", cmd_get_tmpcfg, "Print the configuration buffer"},
187
+    /* TODO {"toggle_giveback", cmd_toggle_giveback, "Toggle the GiveBack flag"},*/
188
+    /* TODO {"toggle_var_bat", cmd_toggle_var_bat, "Toggle the Var/Bat flag"},*/
189
+    {"set_v", cmd_set_v, "Set the voltage in millivolts"},
190
+    {"set_i", cmd_set_i, "Set the current in milliamps"},
191
+    /* TODO {"set_v_range", cmd_set_v_range, "Set the minimum and maximum voltage in millivolts"},*/
192
+    {NULL, NULL, NULL}
193
+};
194
+
195
+const struct pdb_shell_cfg shell_cfg = {
196
+    (BaseSequentialStream *)&SDU1,
197
+    commands
198
+};
199
+
200
+/*
201
+ * Utility functions for the shell
202
+ */
203
+static char *_strtok(char *str, const char *delim, char **saveptr)
204
+{
205
+    char *token;
206
+    if (str)
207
+        *saveptr = str;
208
+    token = *saveptr;
209
+
210
+    if (!token)
211
+        return NULL;
212
+
213
+    token += strspn(token, delim);
214
+    *saveptr = strpbrk(token, delim);
215
+    if (*saveptr)
216
+        *(*saveptr)++ = '\0';
217
+
218
+    return *token ? token : NULL;
219
+}
220
+
221
+static void list_commands(BaseSequentialStream *chp, const struct pdb_shell_cmd *scp)
222
+{
223
+    while (scp->cmd != NULL) {
224
+        chprintf(chp, "\t%s: %s\r\n", scp->cmd, scp->desc);
225
+        scp++;
226
+    }
227
+}
228
+
229
+static bool cmdexec(const struct pdb_shell_cmd *scp, BaseSequentialStream *chp,
230
+        char *name, int argc, char *argv[])
231
+{
232
+    while (scp->cmd != NULL) {
233
+        if (strcmp(scp->cmd, name) == 0) {
234
+            scp->func(chp, argc, argv);
235
+            return false;
236
+        }
237
+        scp++;
238
+    }
239
+    return true;
240
+}
241
+
242
+/*
243
+ * PD Buddy configuration shell
244
+ *
245
+ * p: The configuration for the shell itself
246
+ */
247
+void pdb_shell(void)
248
+{
249
+    int n;
250
+    BaseSequentialStream *chp = shell_cfg.io;
251
+    const struct pdb_shell_cmd *scp = shell_cfg.commands;
252
+    char *lp, *cmd, *tokp, line[PDB_SHELL_MAX_LINE_LENGTH];
253
+    char *args[PDB_SHELL_MAX_ARGUMENTS + 1];
254
+
255
+    while (true) {
256
+        chprintf(chp, "PDBS) ");
257
+        if (shellGetLine(chp, line, sizeof(line))) {
258
+            chprintf(chp, "\r\n");
259
+            continue;
260
+        }
261
+        lp = _strtok(line, " \t", &tokp);
262
+        cmd = lp;
263
+        n = 0;
264
+        while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) {
265
+            if (n >= PDB_SHELL_MAX_ARGUMENTS) {
266
+                chprintf(chp, "too many arguments\r\n");
267
+                cmd = NULL;
268
+                break;
269
+            }
270
+            args[n++] = lp;
271
+        }
272
+        args[n] = NULL;
273
+        if (cmd != NULL) {
274
+            if (strcmp(cmd, "help") == 0) {
275
+                if (n > 0) {
276
+                    chprintf(chp, "Usage: help\r\n");
277
+                    continue;
278
+                }
279
+                chprintf(chp, "PD Buddy Sink configuration shell\r\n");
280
+                chprintf(chp, "Commands:\r\n");
281
+                chprintf(chp, "\thelp: Print this message\r\n");
282
+                if (scp != NULL)
283
+                    list_commands(chp, scp);
284
+            }
285
+            else if ((scp == NULL) || cmdexec(scp, chp, cmd, n, args)) {
286
+                chprintf(chp, "%s", cmd);
287
+                chprintf(chp, " ?\r\n");
288
+            }
289
+        }
290
+    }
291
+    return;
292
+}
293
+
294
+
295
+/**
296
+ * @brief   Reads a whole line from the input channel.
297
+ *
298
+ * @param[in] chp       pointer to a @p BaseSequentialStream object
299
+ * @param[in] line      pointer to the line buffer
300
+ * @param[in] size      buffer maximum length
301
+ * @return              The operation status.
302
+ * @retval true         the channel was reset or CTRL-D pressed.
303
+ * @retval false        operation successful.
304
+ *
305
+ * @api
306
+ */
307
+bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size)
308
+{
309
+    char *p = line;
310
+
311
+    while (true) {
312
+        char c;
313
+
314
+        if (chSequentialStreamRead(chp, (uint8_t *)&c, 1) == 0)
315
+            return true;
316
+        if (c == 4) {
317
+            chprintf(chp, "^D");
318
+            return true;
319
+        }
320
+        if ((c == 8) || (c == 127)) {
321
+            if (p != line) {
322
+                chSequentialStreamPut(chp, 0x08);
323
+                chSequentialStreamPut(chp, 0x20);
324
+                chSequentialStreamPut(chp, 0x08);
325
+                p--;
326
+            }
327
+            continue;
328
+        }
329
+        if (c == '\r') {
330
+            chprintf(chp, "\r\n");
331
+            *p = 0;
332
+            return false;
333
+        }
334
+        if (c < 0x20)
335
+            continue;
336
+        if (p < line + size - 1) {
337
+            chSequentialStreamPut(chp, c);
338
+            *p++ = (char)c;
339
+        }
340
+    }
341
+}

+ 63
- 0
src/shell.h View File

@@ -0,0 +1,63 @@
1
+/*
2
+ * PD Buddy - USB Power Delivery for everyone
3
+ * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+/*
20
+   ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
21
+
22
+   Licensed under the Apache License, Version 2.0 (the "License");
23
+   you may not use this file except in compliance with the License.
24
+   You may obtain a copy of the License at
25
+
26
+        http://www.apache.org/licenses/LICENSE-2.0
27
+
28
+    Unless required by applicable law or agreed to in writing, software
29
+    distributed under the License is distributed on an "AS IS" BASIS,
30
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
+    See the License for the specific language governing permissions and
32
+    limitations under the License.
33
+*/
34
+
35
+#ifndef PDB_SHELL_H
36
+#define PDB_SHELL_H
37
+
38
+#include <ch.h>
39
+
40
+#define PDB_SHELL_MAX_LINE_LENGTH 64
41
+#define PDB_SHELL_MAX_ARGUMENTS 2
42
+
43
+
44
+/* Structure for PD Buddy shell commands */
45
+struct pdb_shell_cmd {
46
+    char *cmd;
47
+    void (*func)(BaseSequentialStream *chp, int argc, char *argv[]);
48
+    char *desc;
49
+};
50
+
51
+/* Structure for PD Buddy shell configuration */
52
+struct pdb_shell_cfg {
53
+    BaseSequentialStream *io;
54
+    const struct pdb_shell_cmd *commands;
55
+};
56
+
57
+
58
+void pdb_shell(void);
59
+
60
+bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size);
61
+
62
+
63
+#endif /* PDB_SHELL_H */

+ 231
- 0
src/storage.c View File

@@ -0,0 +1,231 @@
1
+/*
2
+ * PD Buddy - USB Power Delivery for everyone
3
+ * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#include "storage.h"
20
+
21
+#include "chprintf.h"
22
+
23
+
24
+struct pdb_config *pdb_config_array = (struct pdb_config *) PDB_CONFIG_BASE;
25
+
26
+
27
+void pdb_config_print(BaseSequentialStream *chp, const struct pdb_config *cfg)
28
+{
29
+    /* Print the status */
30
+    chprintf(chp, "status: ");
31
+    switch (cfg->status) {
32
+        case PDB_CONFIG_STATUS_INVALID:
33
+            chprintf(chp, "in");
34
+            /* fall-through */
35
+        case PDB_CONFIG_STATUS_VALID:
36
+            chprintf(chp, "valid\r\n");
37
+            break;
38
+        case PDB_CONFIG_STATUS_EMPTY:
39
+            chprintf(chp, "empty\r\n");
40
+            /* Stop early because the rest of the information is meaningless in
41
+             * this case. */
42
+            return;
43
+        default:
44
+            chprintf(chp, "%04X\r\n", cfg->status);
45
+            break;
46
+    }
47
+
48
+    /* Print the flags */
49
+    chprintf(chp, "flags: ");
50
+    if (cfg->flags == 0) {
51
+        chprintf(chp, "(none)");
52
+    }
53
+    if (cfg->flags & PDB_CONFIG_FLAGS_GIVEBACK) {
54
+        chprintf(chp, "GiveBack ");
55
+    }
56
+    if (cfg->flags & PDB_CONFIG_FLAGS_VAR_BAT) {
57
+        chprintf(chp, "Var/Bat ");
58
+    }
59
+    chprintf(chp, "\r\n");
60
+
61
+    /* Print voltages and current */
62
+    chprintf(chp, "v: %d.%02d V\r\n", cfg->v/20, 5*(cfg->v%20));
63
+    chprintf(chp, "i: %d.%02d A\r\n", cfg->i/100, cfg->i%100);
64
+    if (cfg->flags & PDB_CONFIG_FLAGS_VAR_BAT) {
65
+        chprintf(chp, "v_min: %d.%02d V\r\n", cfg->v_min/20, 5*(cfg->v_min%20));
66
+        chprintf(chp, "v_max: %d.%02d V\r\n", cfg->v_max/20, 5*(cfg->v_max%20));
67
+    }
68
+}
69
+
70
+/*
71
+ * Unlock the flash interface
72
+ */
73
+static void flash_unlock(void)
74
+{
75
+    /* Wait till no operation is on going */
76
+    while ((FLASH->SR & FLASH_SR_BSY) != 0) {
77
+        /* Note: we might want a timeout here */
78
+    }
79
+
80
+    /* Check that the Flash is locked */
81
+    if ((FLASH->CR & FLASH_CR_LOCK) != 0) {
82
+        /* Perform unlock sequence */
83
+        FLASH->KEYR = FLASH_KEY1;
84
+        FLASH->KEYR = FLASH_KEY2;
85
+    }
86
+}
87
+
88
+/*
89
+ * Lock the flash interface
90
+ */
91
+static void flash_lock(void)
92
+{
93
+    /* Wait till no operation is on going */
94
+    while ((FLASH->SR & FLASH_SR_BSY) != 0) {
95
+        /* Note: we might want a timeout here */
96
+    }
97
+
98
+    /* Check that the Flash is unlocked */
99
+    if ((FLASH->CR & FLASH_CR_LOCK) == 0) {
100
+        /* Lock the flash */
101
+        FLASH->CR |= FLASH_CR_LOCK;
102
+    }
103
+}
104
+
105
+/*
106
+ * Write one halfword to flash
107
+ */
108
+static void flash_write_halfword(uint16_t *addr, uint16_t data)
109
+{
110
+    /* Set the PG bit in the FLASH_CR register to enable programming */
111
+    FLASH->CR |= FLASH_CR_PG;
112
+    /* Perform the data write (half-word) at the desired address */
113
+    *(__IO uint16_t*)(addr) = data;
114
+    /* Wait until the BSY bit is reset in the FLASH_SR register */
115
+    while ((FLASH->SR & FLASH_SR_BSY) != 0) {
116
+        /* For robust implementation, add here time-out management */
117
+    }
118
+    /* Check the EOP flag in the FLASH_SR register */
119
+    if ((FLASH->SR & FLASH_SR_EOP) != 0) {
120
+        /* clear it by software by writing it at 1 */
121
+        FLASH->SR = FLASH_SR_EOP;
122
+    } else {
123
+        /* Manage the error cases */
124
+    }
125
+    /* Reset the PG Bit to disable programming */
126
+    FLASH->CR &= ~FLASH_CR_PG;
127
+}
128
+
129
+/*
130
+ * Erase the configuration page, without any locking
131
+ */
132
+static void flash_erase(void)
133
+{
134
+    /* Set the PER bit in the FLASH_CR register to enable page erasing */
135
+    FLASH->CR |= FLASH_CR_PER;
136
+    /* Program the FLASH_AR register to select a page to erase */
137
+    FLASH->AR = (int) pdb_config_array;
138
+    /* Set the STRT bit in the FLASH_CR register to start the erasing */
139
+    FLASH->CR |= FLASH_CR_STRT;
140
+    /* Wait till no operation is on going */
141
+    while ((FLASH->SR & FLASH_SR_BSY) != 0) {
142
+        /* Note: we might want a timeout here */
143
+    }
144
+    /* Check the EOP flag in the FLASH_SR register */
145
+    if ((FLASH->SR & FLASH_SR_EOP) != 0) {
146
+        /* Clear EOP flag by software by writing EOP at 1 */
147
+        FLASH->SR = FLASH_SR_EOP;
148
+    } else {
149
+        /* Manage the error cases */
150
+    }
151
+    /* Reset the PER Bit to disable the page erase */
152
+    FLASH->CR &= ~FLASH_CR_PER;
153
+}
154
+
155
+void pdb_config_flash_erase(void)
156
+{
157
+    /* Enter a critical zone */
158
+    chSysLock();
159
+
160
+    flash_unlock();
161
+
162
+    /* Erase the flash page */
163
+    flash_erase();
164
+
165
+    flash_lock();
166
+
167
+    /* Exit the critical zone */
168
+    chSysUnlock();
169
+}
170
+
171
+void pdb_config_flash_update(const struct pdb_config *cfg)
172
+{
173
+    /* Enter a critical zone */
174
+    chSysLock();
175
+
176
+    flash_unlock();
177
+
178
+    /* If there is an old entry, invalidate it. */
179
+    struct pdb_config *old = pdb_config_flash_read();
180
+    if (old != NULL) {
181
+        flash_write_halfword(&(old->status), PDB_CONFIG_STATUS_INVALID);
182
+    }
183
+
184
+    /* Find the first empty entry */
185
+    struct pdb_config *empty = NULL;
186
+    for (int i = 0; i < PDB_CONFIG_ARRAY_LEN; i++) {
187
+        /* If we've found it, return it. */
188
+        if (pdb_config_array[i].status == PDB_CONFIG_STATUS_EMPTY) {
189
+            empty = &pdb_config_array[i];
190
+            break;
191
+        }
192
+    }
193
+    /* If empty is still NULL, the page is full.  Erase it. */
194
+    if (empty == NULL) {
195
+        flash_erase();
196
+        /* Write to the first element */
197
+        empty = &pdb_config_array[0];
198
+    }
199
+
200
+    /* Write the new configuration */
201
+    flash_write_halfword(&(empty->status), cfg->status);
202
+    flash_write_halfword(&(empty->flags), cfg->flags);
203
+    flash_write_halfword(&(empty->v), cfg->v);
204
+    flash_write_halfword(&(empty->i), cfg->i);
205
+    flash_write_halfword(&(empty->v_min), cfg->v_min);
206
+    flash_write_halfword(&(empty->v_max), cfg->v_max);
207
+
208
+    flash_lock();
209
+
210
+    /* Exit the critical zone */
211
+    chSysUnlock();
212
+}
213
+
214
+struct pdb_config *pdb_config_flash_read(void)
215
+{
216
+    /* If the first element is empty, there is no valid structure. */
217
+    if (pdb_config_array[0].status == PDB_CONFIG_STATUS_EMPTY) {
218
+        return NULL;
219
+    }
220
+
221
+    /* Find the valid structure, if there is one. */
222
+    for (int i = 0; i < PDB_CONFIG_ARRAY_LEN; i++) {
223
+        /* If we've found it, return it. */
224
+        if (pdb_config_array[i].status == PDB_CONFIG_STATUS_VALID) {
225
+            return &pdb_config_array[i];
226
+        }
227
+    }
228
+
229
+    /* If we got to the end, none of the structures is valid. */
230
+    return NULL;
231
+}

+ 86
- 0
src/storage.h View File

@@ -0,0 +1,86 @@
1
+/*
2
+ * PD Buddy - USB Power Delivery for everyone
3
+ * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#ifndef PDB_STORAGE_H
20
+#define PDB_STORAGE_H
21
+
22
+#include <stdint.h>
23
+
24
+#include <ch.h>
25
+
26
+
27
+/*
28
+ * PD Buddy Sink configuration structure
29
+ */
30
+struct pdb_config {
31
+    uint16_t status;
32
+    uint16_t flags;
33
+    uint16_t v;
34
+    uint16_t i;
35
+    uint16_t v_min;
36
+    uint16_t v_max;
37
+    uint16_t _reserved[2];
38
+} __attribute__((packed));
39
+
40
+/* Status for configuration structures.  The empty status indicates that the
41
+ * struct is ready to be written, including an update to the valid status.
42
+ * Once the struct is no longer needed, the status is updated to invalid.
43
+ * Erasing the flash page resets all structures to the empty status. */
44
+#define PDB_CONFIG_STATUS_INVALID 0x0000
45
+#define PDB_CONFIG_STATUS_VALID 0xBEEF
46
+#define PDB_CONFIG_STATUS_EMPTY 0xFFFF
47
+
48
+/* Flags for configuration structures. */
49
+/* GiveBack supported */
50
+#define PDB_CONFIG_FLAGS_GIVEBACK 0x0001
51
+/* Variable and battery PDOs supported (v_min and v_max valid) */
52
+#define PDB_CONFIG_FLAGS_VAR_BAT 0x0002
53
+
54
+
55
+/* Flash configuration array */
56
+extern struct pdb_config *pdb_config_array;
57
+
58
+/* The number of elements in the pdb_config_array */
59
+#define PDB_CONFIG_ARRAY_LEN 128
60
+
61
+
62
+/*
63
+ * Print a struct pdb_config to the given BaseSequentialStream
64
+ */
65
+void pdb_config_print(BaseSequentialStream *chp, const struct pdb_config *cfg);
66
+
67
+/*
68
+ * Erase the flash page used for configuration
69
+ */
70
+void pdb_config_flash_erase(void);
71
+
72
+/*
73
+ * Write a configuration structure to flash, invalidating the previous
74
+ * configuration.  If necessary, the flash page is erased before writing the
75
+ * new structure.
76
+ */
77
+void pdb_config_flash_update(const struct pdb_config *cfg);
78
+
79
+/*
80
+ * Get the first valid configuration strucure.  If the flash page is empty,
81
+ * return NULL instead.
82
+ */
83
+struct pdb_config *pdb_config_flash_read(void);
84
+
85
+
86
+#endif /* PDB_STORAGE_H */

+ 352
- 0
src/usbcfg.c View File

@@ -0,0 +1,352 @@
1
+/*
2
+ * PD Buddy - USB Power Delivery for everyone
3
+ * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+/*
20
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
21
+
22
+    Licensed under the Apache License, Version 2.0 (the "License");
23
+    you may not use this file except in compliance with the License.
24
+    You may obtain a copy of the License at
25
+
26
+        http://www.apache.org/licenses/LICENSE-2.0
27
+
28
+    Unless required by applicable law or agreed to in writing, software
29
+    distributed under the License is distributed on an "AS IS" BASIS,
30
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
+    See the License for the specific language governing permissions and
32
+    limitations under the License.
33
+*/
34
+
35
+#include "usbcfg.h"
36
+
37
+
38
+/* Virtual serial port over USB.*/
39
+SerialUSBDriver SDU1;
40
+
41
+/*
42
+ * Endpoints to be used for USBD1.
43
+ */
44
+#define USBD1_DATA_REQUEST_EP           1
45
+#define USBD1_DATA_AVAILABLE_EP         1
46
+#define USBD1_INTERRUPT_REQUEST_EP      2
47
+
48
+/*
49
+ * USB Device Descriptor.
50
+ */
51
+static const uint8_t vcom_device_descriptor_data[18] = {
52
+    USB_DESC_DEVICE       (0x0110,        /* bcdUSB (1.1).                    */
53
+            0x02,          /* bDeviceClass (CDC).              */
54
+            0x00,          /* bDeviceSubClass.                 */
55
+            0x00,          /* bDeviceProtocol.                 */
56
+            0x40,          /* bMaxPacketSize.                  */
57
+            0x1209,        /* idVendor (pid.codes).            */
58
+            0x0001,        /* idProduct.                       */
59
+            0x0200,        /* bcdDevice.                       */
60
+            1,             /* iManufacturer.                   */
61
+            2,             /* iProduct.                        */
62
+            3,             /* iSerialNumber.                   */
63
+            1)             /* bNumConfigurations.              */
64
+};
65
+
66
+/*
67
+ * Device Descriptor wrapper.
68
+ */
69
+static const USBDescriptor vcom_device_descriptor = {
70
+    sizeof vcom_device_descriptor_data,
71
+    vcom_device_descriptor_data
72
+};
73
+
74
+/* Configuration Descriptor tree for a CDC.*/
75
+static const uint8_t vcom_configuration_descriptor_data[67] = {
76
+    /* Configuration Descriptor.*/
77
+    USB_DESC_CONFIGURATION(67,            /* wTotalLength.                    */
78
+            0x02,          /* bNumInterfaces.                  */
79
+            0x01,          /* bConfigurationValue.             */
80
+            0,             /* iConfiguration.                  */
81
+            0xC0,          /* bmAttributes (self powered).     */
82
+            50),           /* bMaxPower (100mA).               */
83
+    /* Interface Descriptor.*/
84
+    USB_DESC_INTERFACE    (0x00,          /* bInterfaceNumber.                */
85
+            0x00,          /* bAlternateSetting.               */
86
+            0x01,          /* bNumEndpoints.                   */
87
+            0x02,          /* bInterfaceClass (Communications
88
+                              Interface Class, CDC section
89
+                              4.2).                            */
90
+            0x02,          /* bInterfaceSubClass (Abstract
91
+                              Control Model, CDC section 4.3).   */
92
+            0x01,          /* bInterfaceProtocol (AT commands,
93
+                              CDC section 4.4).                */
94
+            0),            /* iInterface.                      */
95
+    /* Header Functional Descriptor (CDC section 5.2.3).*/
96
+    USB_DESC_BYTE         (5),            /* bLength.                         */
97
+    USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
98
+    USB_DESC_BYTE         (0x00),         /* bDescriptorSubtype (Header
99
+                                             Functional Descriptor.           */
100
+    USB_DESC_BCD          (0x0110),       /* bcdCDC.                          */
101
+    /* Call Management Functional Descriptor. */
102
+    USB_DESC_BYTE         (5),            /* bFunctionLength.                 */
103
+    USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
104
+    USB_DESC_BYTE         (0x01),         /* bDescriptorSubtype (Call Management
105
+                                             Functional Descriptor).          */
106
+    USB_DESC_BYTE         (0x00),         /* bmCapabilities (D0+D1).          */
107
+    USB_DESC_BYTE         (0x01),         /* bDataInterface.                  */
108
+    /* ACM Functional Descriptor.*/
109
+    USB_DESC_BYTE         (4),            /* bFunctionLength.                 */
110
+    USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
111
+    USB_DESC_BYTE         (0x02),         /* bDescriptorSubtype (Abstract
112
+                                             Control Management Descriptor).  */
113
+    USB_DESC_BYTE         (0x02),         /* bmCapabilities.                  */
114
+    /* Union Functional Descriptor.*/
115
+    USB_DESC_BYTE         (5),            /* bFunctionLength.                 */
116
+    USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
117
+    USB_DESC_BYTE         (0x06),         /* bDescriptorSubtype (Union
118
+                                             Functional Descriptor).          */
119
+    USB_DESC_BYTE         (0x00),         /* bMasterInterface (Communication
120
+                                             Class Interface).                */
121
+    USB_DESC_BYTE         (0x01),         /* bSlaveInterface0 (Data Class
122
+                                             Interface).                      */
123
+    /* Endpoint 2 Descriptor.*/
124
+    USB_DESC_ENDPOINT     (USBD1_INTERRUPT_REQUEST_EP|0x80,
125
+            0x03,          /* bmAttributes (Interrupt).        */
126
+            0x0008,        /* wMaxPacketSize.                  */
127
+            0xFF),         /* bInterval.                       */
128
+    /* Interface Descriptor.*/
129
+    USB_DESC_INTERFACE    (0x01,          /* bInterfaceNumber.                */
130
+            0x00,          /* bAlternateSetting.               */
131
+            0x02,          /* bNumEndpoints.                   */
132
+            0x0A,          /* bInterfaceClass (Data Class
133
+                              Interface, CDC section 4.5).     */
134
+            0x00,          /* bInterfaceSubClass (CDC section
135
+                              4.6).                            */
136
+            0x00,          /* bInterfaceProtocol (CDC section
137
+                              4.7).                            */
138
+            0x00),         /* iInterface.                      */
139
+    /* Endpoint 3 Descriptor.*/
140
+    USB_DESC_ENDPOINT     (USBD1_DATA_AVAILABLE_EP,       /* bEndpointAddress.*/
141
+            0x02,          /* bmAttributes (Bulk).             */
142
+            0x0040,        /* wMaxPacketSize.                  */
143
+            0x00),         /* bInterval.                       */
144
+    /* Endpoint 1 Descriptor.*/
145
+    USB_DESC_ENDPOINT     (USBD1_DATA_REQUEST_EP|0x80,    /* bEndpointAddress.*/
146
+            0x02,          /* bmAttributes (Bulk).             */
147
+            0x0040,        /* wMaxPacketSize.                  */
148
+            0x00)          /* bInterval.                       */
149
+};
150
+
151
+/*
152
+ * Configuration Descriptor wrapper.
153
+ */
154
+static const USBDescriptor vcom_configuration_descriptor = {
155
+    sizeof vcom_configuration_descriptor_data,
156
+    vcom_configuration_descriptor_data
157
+};
158
+
159
+/*
160
+ * U.S. English language identifier.
161
+ */
162
+static const uint8_t vcom_string0[] = {
163
+    USB_DESC_BYTE(4),                     /* bLength.                         */
164
+    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
165
+    USB_DESC_WORD(0x0409)                 /* wLANGID (U.S. English).          */
166
+};
167
+
168
+/*
169
+ * Vendor string.
170
+ */
171
+static const uint8_t vcom_string1[] = {
172
+    USB_DESC_BYTE(34),                    /* bLength.                         */
173
+    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
174
+    'C', 0, 'l', 0, 'a', 0, 'y', 0, 't', 0, 'o', 0, 'n', 0, ' ', 0,
175
+    'G', 0, '.', 0, ' ', 0, 'H', 0, 'o', 0, 'b', 0, 'b', 0, 's', 0,
176
+};
177
+
178
+/*
179
+ * Device Description string.
180
+ */
181
+static const uint8_t vcom_string2[] = {
182
+    USB_DESC_BYTE(28),                    /* bLength.                         */
183
+    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
184
+    'P', 0, 'D', 0, ' ', 0, 'B', 0, 'u', 0, 'd', 0, 'd', 0, 'y', 0,
185
+    ' ', 0, 'S', 0, 'i', 0, 'n', 0, 'k', 0
186
+};
187
+
188
+/*
189
+ * Serial Number string.
190
+ */
191
+static const uint8_t vcom_string3[] = {
192
+    USB_DESC_BYTE(8),                     /* bLength.                         */
193
+    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
194
+    '0' + CH_KERNEL_MAJOR, 0,
195
+    '0' + CH_KERNEL_MINOR, 0,
196
+    '0' + CH_KERNEL_PATCH, 0
197
+};
198
+
199
+/*
200
+ * Strings wrappers array.
201
+ */
202
+static const USBDescriptor vcom_strings[] = {
203
+    {sizeof vcom_string0, vcom_string0},
204
+    {sizeof vcom_string1, vcom_string1},
205
+    {sizeof vcom_string2, vcom_string2},
206
+    {sizeof vcom_string3, vcom_string3}
207
+};
208
+
209
+/*
210
+ * Handles the GET_DESCRIPTOR callback. All required descriptors must be
211
+ * handled here.
212
+ */
213
+static const USBDescriptor *get_descriptor(USBDriver *usbp,
214
+        uint8_t dtype,
215
+        uint8_t dindex,
216
+        uint16_t lang) {
217
+
218
+    (void)usbp;
219
+    (void)lang;
220
+    switch (dtype) {
221
+        case USB_DESCRIPTOR_DEVICE:
222
+            return &vcom_device_descriptor;
223
+        case USB_DESCRIPTOR_CONFIGURATION:
224
+            return &vcom_configuration_descriptor;
225
+        case USB_DESCRIPTOR_STRING:
226
+            if (dindex < 4)
227
+                return &vcom_strings[dindex];
228
+    }
229
+    return NULL;
230
+}
231
+
232
+/**
233
+ * @brief   IN EP1 state.
234
+ */
235
+static USBInEndpointState ep1instate;
236
+
237
+/**
238
+ * @brief   OUT EP1 state.
239
+ */
240
+static USBOutEndpointState ep1outstate;
241
+
242
+/**
243
+ * @brief   EP1 initialization structure (both IN and OUT).
244
+ */
245
+static const USBEndpointConfig ep1config = {
246
+    USB_EP_MODE_TYPE_BULK,
247
+    NULL,
248
+    sduDataTransmitted,
249
+    sduDataReceived,
250
+    0x0040,
251
+    0x0040,
252
+    &ep1instate,
253
+    &ep1outstate,
254
+    1,
255
+    NULL
256
+};
257
+
258
+/**
259
+ * @brief   IN EP2 state.
260
+ */
261
+static USBInEndpointState ep2instate;
262
+
263
+/**
264
+ * @brief   EP2 initialization structure (IN only).
265
+ */
266
+static const USBEndpointConfig ep2config = {
267
+    USB_EP_MODE_TYPE_INTR,
268
+    NULL,
269
+    sduInterruptTransmitted,
270
+    NULL,
271
+    0x0010,
272
+    0x0000,
273
+    &ep2instate,
274
+    NULL,
275
+    1,
276
+    NULL
277
+};
278
+
279
+/*
280
+ * Handles the USB driver global events.
281
+ */
282
+static void usb_event(USBDriver *usbp, usbevent_t event) {
283
+    extern SerialUSBDriver SDU1;
284
+
285
+    switch (event) {
286
+        case USB_EVENT_RESET:
287
+            return;
288
+        case USB_EVENT_ADDRESS:
289
+            return;
290
+        case USB_EVENT_CONFIGURED:
291
+            chSysLockFromISR();
292
+
293
+            /* Enables the endpoints specified into the configuration.
294
+               Note, this callback is invoked from an ISR so I-Class functions
295
+               must be used.*/
296
+            usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config);
297
+            usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config);
298
+
299
+            /* Resetting the state of the CDC subsystem.*/
300
+            sduConfigureHookI(&SDU1);
301
+
302
+            chSysUnlockFromISR();
303
+            return;
304
+        case USB_EVENT_UNCONFIGURED:
305
+            return;
306
+        case USB_EVENT_SUSPEND:
307
+            chSysLockFromISR();
308
+
309
+            /* Disconnection event on suspend.*/
310
+            sduDisconnectI(&SDU1);
311
+
312
+            chSysUnlockFromISR();
313
+            return;
314
+        case USB_EVENT_WAKEUP:
315
+            return;
316
+        case USB_EVENT_STALLED:
317
+            return;
318
+    }
319
+    return;
320
+}
321
+
322
+/*
323
+ * Handles the USB driver global events.
324
+ */
325
+static void sof_handler(USBDriver *usbp) {
326
+
327
+    (void)usbp;
328
+
329
+    osalSysLockFromISR();
330
+    sduSOFHookI(&SDU1);
331
+    osalSysUnlockFromISR();
332
+}
333
+
334
+/*
335
+ * USB driver configuration.
336
+ */
337
+const USBConfig usbcfg = {
338
+    usb_event,
339
+    get_descriptor,
340
+    sduRequestsHook,
341
+    sof_handler
342
+};
343
+
344
+/*
345
+ * Serial over USB driver configuration.
346
+ */
347
+const SerialUSBConfig serusbcfg = {
348
+    &USBD1,
349
+    USBD1_DATA_REQUEST_EP,
350
+    USBD1_DATA_AVAILABLE_EP,
351
+    USBD1_INTERRUPT_REQUEST_EP
352
+};

+ 46
- 0
src/usbcfg.h View File

@@ -0,0 +1,46 @@
1
+/*
2
+ * PD Buddy - USB Power Delivery for everyone
3
+ * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+/*
20
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
21
+
22
+    Licensed under the Apache License, Version 2.0 (the "License");
23
+    you may not use this file except in compliance with the License.
24
+    You may obtain a copy of the License at
25
+
26
+        http://www.apache.org/licenses/LICENSE-2.0
27
+
28
+    Unless required by applicable law or agreed to in writing, software
29
+    distributed under the License is distributed on an "AS IS" BASIS,
30
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
+    See the License for the specific language governing permissions and
32
+    limitations under the License.
33
+*/
34
+
35
+#ifndef PDB_USBCFG_H
36
+#define PDB_USBCFG_H
37
+
38
+#include <hal.h>
39
+
40
+
41
+extern const USBConfig usbcfg;
42
+extern const SerialUSBConfig serusbcfg;
43
+extern SerialUSBDriver SDU1;
44
+
45
+
46
+#endif  /* PDB_USBCFG_H */

Loading…
Cancel
Save