From 4d369b95177d2f2add7d5e9c21286f3d52266c9d Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Wed, 30 Mar 2022 18:09:41 -0700 Subject: [PATCH] big drop adding the USB HID part of this project... This refactors out a bunch of code to make better use of the SYSINIT mechanism... Completes the PKI side of things for doing mutual authentication... Uses a python script to generate the USB descriptors, and basic interface code for the STM USB HAL Layer.. This gets ride of a lot of the glue code that was previously written, allowing the glue code to be easily changed/update... break out the memory debug function into it's own file... Minor fixes to the rs485 framing code... Finally found the bug where aborting a receive would corrupt the RX state for some reason... Add back RNG seeding, and make it generic... --- RS485HID.md | 64 +- board/f1_flash.c | 41 ++ board/hal_init.c | 5 + board/simpflash.h | 1 + board/stm32_bluepill.c | 62 ++ board/strobe_f1_rng_init.c | 142 +++++ lora.py | 141 ++++- mk/boards.mk | 49 +- mk/mu.opts.mk | 34 +- mk/mu.progs.mk | 22 +- requirements.txt | 1 + rs485hid/Makefile | 52 +- rs485hid/memdebug.c | 65 ++ rs485hid/rs485frame.c | 36 +- rs485hid/rs485gw.c | 73 +-- rs485hid/rs485hid.c | 558 +++++++++++++++++ rs485hid/strobe_pki.c | 87 +++ rs485hid/strobe_pki.h | 9 + rs485hid/usb_hid.py | 62 ++ rs485hid/usb_hid_def.c | 328 ++++++++++ rs485hid/usb_hid_def.h | 6 + si_usb.c | 23 +- stm32/f103c8t6/STM32F103C8T6_FLASH.ld | 17 +- stm32/usb/usb_gen.py | 216 +++++++ stm32/usb/usbd_ctlreq_nodesc.c | 853 ++++++++++++++++++++++++++ strobe_rng_init.c | 8 +- strobe_rng_init.h | 4 - 27 files changed, 2824 insertions(+), 135 deletions(-) create mode 100644 board/f1_flash.c create mode 100644 board/hal_init.c create mode 100644 board/simpflash.h create mode 100644 board/stm32_bluepill.c create mode 100644 board/strobe_f1_rng_init.c create mode 100644 rs485hid/memdebug.c create mode 100644 rs485hid/rs485hid.c create mode 100644 rs485hid/strobe_pki.c create mode 100644 rs485hid/strobe_pki.h create mode 100644 rs485hid/usb_hid.py create mode 100644 rs485hid/usb_hid_def.c create mode 100644 rs485hid/usb_hid_def.h create mode 100644 stm32/usb/usb_gen.py create mode 100755 stm32/usb/usbd_ctlreq_nodesc.c diff --git a/RS485HID.md b/RS485HID.md index 38b2b3a..bd24f31 100644 --- a/RS485HID.md +++ b/RS485HID.md @@ -18,7 +18,8 @@ These are the device that are under conideration for the project: ### STM32F103C8 -64KB flash +64KB flash, but the devices I have seem to have 128KB flash. They +appear to be BluePill clones. Green LED is GPIOC Pin 13. Currently looking at USART3, B0 for DE, B1 for RE. @@ -55,3 +56,64 @@ D - Driver R - Receiver RO Receiver output /RE Receiver enable (low enable) + +Note: Some pre-assembled devices have pull up resistors on the DE/RE +lines. This is a BAD design as it means that it will be driving the +bus by default. This can often be fixed by removing the pull-up +resistors. + + +Programming +----------- + +Command to program the HID device: +``` +sudo openocd -f interface/ftdi/digilent-hs1.cfg -f interface/ftdi/swd-resistor-hack.cfg -f target/stm32f1x.cfg -c "init" -c "reset init" -c "program build/rs485hid.elf verify reset exit" +``` + +Keying +------ + +There are two keys involved, the initiator key, which is made w/ the +Makefile, but issuing the command: +``` +bmake hid_priv_key +``` + +Which creates the private key in the file `.hid_priv_key`. This is +needed for the build process. + +The other key is the device key, which is generated by the USB HID +device at first start. The device will "type" the hex encoded public +key when the A7 pin is grounded. This public key should be saved to +a file, which can then be passed to the `lora.py` initiator program +via the `-p` argument. + +Low level info +-------------- + +Definitions: +Mark: logic 1, B > A +Space: logic 0, B < A + +Idle state: Mark + +Async comms: Space | 8 bits LSB, 0 through 7 | Mark + +As the start of the sequence begins w/ a space, it requires that the +line be "idle" (aka mark) before things start, so any non-mark state +before TX starts should consider the line as busy, and not be ready +to transmit. Additional info on this is in the Wiring section. + +Wiring +------ + +For long runs, it is recommend to have terminating resistors w/ a value +of 120 Ω, the impedence of twisted pair, to prevent reflections. + +Wikipedia recommends to add biasing resistors to help w/ noise +immunity, BUT, care must be done when using them. When the bus is +idle, make sure that the receivers are outputing a hi value (aka +mark), that is 5V if you're using a MAX485 converter. If it is 0V, +then the receiver will not work. I have seen in some cases where +grounding A w/ a 2.2k Ω resistor makes things work. diff --git a/board/f1_flash.c b/board/f1_flash.c new file mode 100644 index 0000000..1a5103d --- /dev/null +++ b/board/f1_flash.c @@ -0,0 +1,41 @@ +#include + +#include +#include + +#include /* roundup */ + +void +doflash(const void *dst, void *src, int bytes) +{ + FLASH_EraseInitTypeDef erase; + const uint32_t *dstp; + uint32_t *srcp; + size_t i; + uint32_t pageerr; + uint32_t primask; + + dstp = dst; + srcp = src; + + primask = __get_PRIMASK(); + __disable_irq(); + + HAL_FLASH_Unlock(); + + erase = (FLASH_EraseInitTypeDef){ + .TypeErase = FLASH_TYPEERASE_PAGES, + .Banks = FLASH_BANK_1, + .PageAddress = (intptr_t)&dstp[0], + .NbPages = roundup(bytes, FLASH_PAGE_SIZE) / FLASH_PAGE_SIZE, + }; + HAL_FLASHEx_Erase(&erase, &pageerr); + + for (i = 0; i < roundup(bytes, sizeof *srcp) / 4; i++) { + HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (intptr_t)&dstp[i], srcp[i]); + } + + HAL_FLASH_Lock(); + + __set_PRIMASK(primask); +} diff --git a/board/hal_init.c b/board/hal_init.c new file mode 100644 index 0000000..26dfde1 --- /dev/null +++ b/board/hal_init.c @@ -0,0 +1,5 @@ +#include + +#include + +SYSINIT(hal_init, SI_SUB_HAL, SI_ORDER_FIRST, (void (*)(const void *))HAL_Init, NULL); diff --git a/board/simpflash.h b/board/simpflash.h new file mode 100644 index 0000000..59cdb5f --- /dev/null +++ b/board/simpflash.h @@ -0,0 +1 @@ +void doflash(const void *dst, void *src, int bytes); diff --git a/board/stm32_bluepill.c b/board/stm32_bluepill.c new file mode 100644 index 0000000..d08b764 --- /dev/null +++ b/board/stm32_bluepill.c @@ -0,0 +1,62 @@ +/* + * More info here: + * https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill.html + * + * And resistor fix: + * https://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html + * + * Note: I didn't have to do this fix, and things seem to work fine. + */ + +#include +#include + +#include + +/* + * Referenced from: + * Projects/STM32F103RB-Nucleo/Applications/USB_Device/HID_Standalone/Src/main.c + */ +static void +oscconfig(const void *none) +{ + RCC_ClkInitTypeDef clkinitstruct; + RCC_OscInitTypeDef oscinitstruct; + RCC_PeriphCLKInitTypeDef rccperiphclkinit; + + __HAL_RCC_PWR_CLK_ENABLE(); + + oscinitstruct = (RCC_OscInitTypeDef){ + .OscillatorType = RCC_OSCILLATORTYPE_HSE, + .HSEState = RCC_HSE_ON, + .HSEPredivValue = RCC_HSE_PREDIV_DIV1, + .PLL.PLLMUL = RCC_PLL_MUL9, + + .PLL.PLLState = RCC_PLL_ON, + .PLL.PLLSource = RCC_PLLSOURCE_HSE, + }; + + HAL_RCC_OscConfig(&oscinitstruct); + + /* USB clock selection */ + rccperiphclkinit = (RCC_PeriphCLKInitTypeDef){ + .PeriphClockSelection = RCC_PERIPHCLK_USB, + .UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5, + }; + HAL_RCCEx_PeriphCLKConfig(&rccperiphclkinit); + + /* + * Select PLL as system clock source and configure the HCLK, + * PCLK1 and PCLK2 clocks dividers + */ + clkinitstruct = (RCC_ClkInitTypeDef){ + .ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | + RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2), + .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK, + .AHBCLKDivider = RCC_SYSCLK_DIV1, + .APB1CLKDivider = RCC_HCLK_DIV2, + .APB2CLKDivider = RCC_HCLK_DIV1, + }; + HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); +} +SYSINIT(oscconfig, SI_SUB_HAL, SI_ORDER_THIRD, oscconfig, NULL); diff --git a/board/strobe_f1_rng_init.c b/board/strobe_f1_rng_init.c new file mode 100644 index 0000000..8a91589 --- /dev/null +++ b/board/strobe_f1_rng_init.c @@ -0,0 +1,142 @@ +/*- + * Copyright 2021 John-Mark Gurney. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include +#include + +#include "stm32f1xx.h" +#include "stm32f1xx_hal.h" + +#include + +#include + +#include + +#define NBYTESENTROPY (256 / 8) +#define DEFINE_RNG_SAVE 1 +#if DEFINE_RNG_SAVE +const rng_word_t rng_save[roundup(NBYTESENTROPY, sizeof(rng_word_t)) / sizeof(rng_word_t)] __attribute__ ((section (".savestate"))); +#endif + +static void +strobe_rng_init(void) +{ + + /* + * Seed RNG + * Seed w/ saved state. + */ + strobe_seed_prng((uint8_t *)rng_save, sizeof rng_save); + + /* + * On first boot, SRAM is uninitialized and randomness from + * it is used. + * + * Note: This depends upon sbrk pointing to uinitalized SRAM. + */ + strobe_seed_prng(sbrk(0), 2*1024); + +} +SYSINIT_VF(rng_init, SI_SUB_HAL, SI_ORDER_LAST, strobe_rng_init); + +uint32_t times[20]; + +static void +analog_seed_rng(void) +{ + ADC_HandleTypeDef ah; + ADC_ChannelConfTypeDef chanconf; + uint16_t v; + int timespos; + int i; + + /* Enable ADC1 Clock */ + __HAL_RCC_ADC1_CLK_ENABLE(); + + /* Configure */ + ah = (ADC_HandleTypeDef){ + .Instance = ADC1, + .Init.DataAlign = ADC_DATAALIGN_RIGHT, + .Init.ScanConvMode = ADC_SCAN_DISABLE, + .Init.ContinuousConvMode = DISABLE, + .Init.NbrOfConversion = 1, + .Init.DiscontinuousConvMode = DISABLE, + .Init.NbrOfDiscConversion = 1, + .Init.ExternalTrigConv = ADC_SOFTWARE_START, + }; + HAL_ADC_Init(&ah); + + chanconf = (ADC_ChannelConfTypeDef){ + .Rank = ADC_REGULAR_RANK_1, + .Channel = ADC_CHANNEL_TEMPSENSOR, /* temp sensor */ + .SamplingTime = ADC_SAMPLETIME_71CYCLES_5, + }; + HAL_ADC_ConfigChannel(&ah, &chanconf); + + HAL_Delay(1); + + timespos = 0; + + /* Capture */ + for (i = 0; i < 256 / 2; i++) { + times[timespos++] = HAL_GetTick(); + timespos %= sizeof times / sizeof *times; + /* + * Capture some ADC data. If pin is floating, 0xfff + * happens frequently, if pin is grounded, 0 happens + * frequently, filter these values out. + */ + do { + HAL_ADC_Start(&ah); + HAL_ADC_PollForConversion(&ah, 1); + v = HAL_ADC_GetValue(&ah); + } while (v == 0 || v == 0xfff); + strobe_seed_prng((uint8_t *)&v, sizeof v); + } + + /* Deinit */ + HAL_ADC_DeInit(&ah); +} +SYSINIT_VF(analog_seed_rng, SI_SUB_HAL, SI_ORDER_LAST, analog_seed_rng); + +static void +strobe_rng_save(void) +{ + rng_word_t tmp[sizeof rng_save / sizeof(rng_word_t)]; + int r; + + /* + * Save entropy for next reset. + */ + r = strobe_randomize((uint8_t *)tmp, sizeof tmp); + (void)r; + + doflash(rng_save, tmp, sizeof(rng_save)); +} +SYSINIT_VF(rng_save, SI_SUB_LAST, SI_ORDER_LAST, strobe_rng_save); diff --git a/lora.py b/lora.py index 9991069..058df08 100644 --- a/lora.py +++ b/lora.py @@ -23,10 +23,12 @@ # import asyncio +import codecs import contextlib import functools import itertools import os +import pathlib import sys import unittest @@ -49,6 +51,44 @@ CMD_PING = 4 # arg: (): a no op command CMD_SETUNSET = 5 # arg: (chan, val): sets chan to val CMD_ADV = 6 # arg: ([cnt]): advances to the next cnt (default 1) command CMD_CLEAR = 7 # arg: (): clears all future commands, but keeps current running +CMD_KEY = 8 # arg: ([key reports]): standard USB HID key reports, return is number added + +_directmap = [ + (40, '\n\x1b\b\t -=[]\\#;\'`,./'), + (40, '\r'), +] +_keymap = { chr(x): x - ord('a') + 4 for x in range(ord('a'), ord('z') + 1) } | \ + { '0': 39 } | \ + { chr(x): x - ord('1') + 30 for x in range(ord('1'), ord('9') + 1) } | \ + { x: i + base for base, keys in _directmap for i, x in enumerate(keys) } +_shiftmaplist = '!1@2#3$4%5^6&7*8(9)0_-+=~`{[}]|\\:;"\'<,>.?/' +_completemap = { x: (False, y) for x, y in _keymap.items() } | \ + { x.upper(): (True, y) for x, y in _keymap.items() if x != x.upper() } | \ + { x: (True, _keymap[y]) for x, y in zip(_shiftmaplist[::2], _shiftmaplist[1::2]) } + + +def makekeybuf(s): + blank = b'\x00' * 8 + + # start clean + ret = [ blank ] + templ = bytearray([ 0 ] * 8) + + for i in s: + shift, key = _completemap[i] + + if ret[-1][2] == key: + ret.append(blank) + + templ[2] = key + templ[0] = 2 if shift else 0 + + ret.append(templ[:]) + + # end clean + ret.append(blank) + + return b''.join(ret) class LORANode(object): '''Implement a LORANode initiator. @@ -140,7 +180,10 @@ class LORANode(object): def _encodeargs(*args): r = [] for i in args: - r.append(i.to_bytes(4, byteorder='little')) + if isinstance(i, bytes): + r.append(i) + else: + r.append(i.to_bytes(4, byteorder='little')) return b''.join(r) @@ -153,6 +196,10 @@ class LORANode(object): 'response does not match, got: %s, expected: %s' % (repr(resp[0:1]), repr(cmdbyte))) + r = resp[1:] + if r: + return r + async def waitfor(self, length): return await self._sendcmd(CMD_WAITFOR, length) @@ -165,6 +212,14 @@ class LORANode(object): async def ping(self): return await self._sendcmd(CMD_PING) + async def type(self, s): + keys = makekeybuf(s) + + while keys: + r = await self._sendcmd(CMD_KEY, keys[:8 * 6]) + r = int.from_bytes(r, byteorder='little') + keys = keys[r * 8:] + async def adv(self, cnt=None): args = () if cnt is not None: @@ -267,23 +322,52 @@ async def main(): from loraserv import DEFAULT_MADDR as maddr - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser(description='This is an implementation of both the server and client implementing syote secure IoT protocol.', + epilog='Both -k and -p MUST be used together. One of either -s or the combone -k & -p MUST be specified.') parser.add_argument('-f', dest='schedfile', metavar='filename', type=str, help='Use commands from the file. One command per line.') + parser.add_argument('-k', dest='privkey', metavar='privfile', type=str, + help='File containing a hex encoded private key.') + parser.add_argument('-p', dest='pubkey', metavar='pubfile', type=str, + help='File containing a hex encoded public key.') parser.add_argument('-r', dest='client', metavar='module:function', type=str, help='Create a respondant instead of sending commands. Commands will be passed to the function.') - parser.add_argument('-s', dest='shared_key', metavar='shared_key', type=str, required=True, - help='The shared key (encoded as UTF-8) to use.') + parser.add_argument('-s', dest='shared_key', metavar='shared_key', type=str, + help='File containing the shared key to use (note, any white space is included).') parser.add_argument('args', metavar='CMD_ARG', type=str, nargs='*', help='Various commands to send to the device.') args = parser.parse_args() - shared_key = args.shared_key.encode('utf-8') + # make sure a key is specified. + if args.privkey is None and args.pubkey is None and \ + args.shared_key is None: + parser.error('a key must be specified (either -k and -p, or -s)') + + # make sure if one is specified, both are. + if (args.privkey is not None or args.pubkey is not None) and \ + (args.privkey is None or args.pubkey is None): + parser.error('both -k and -p MUST be specified if one is.') + + if args.shared_key is not None: + skdata = pathlib.Path(args.shared_key).read_bytes() + lorakwargs = dict(shared_key=skdata) + commsinitargs = (lorakwargs['shared_key'], ) + else: + privkeydata = pathlib.Path(args.privkey).read_text().strip() + privkey = X25519.frombytes(codecs.decode(privkeydata, 'hex')) + + pubkeydata = pathlib.Path(args.pubkey).read_text().strip() + pubkey = codecs.decode(pubkeydata, 'hex') + + lorakwargs = dict(init_key=privkey, resp_pub=pubkey) + commsinitargs = (None, make_pktbuf(privkey.getpriv()), + make_pktbuf(pubkey)) if args.client: # Run a client + mr = await multicast.create_multicast_receiver(maddr) mt = await multicast.create_multicast_transmitter(maddr) @@ -313,16 +397,20 @@ async def main(): cb = syote_comms.process_msgfunc_t(client_call) # Initialize everything - syote_comms.comms_init(commstate, cb, make_pktbuf(shared_key)) + syote_comms.comms_init(commstate, cb, *commsinitargs) try: while True: pkt = await mr.recv() msg = pkt[0] + #_debprint('procmsg:', repr(msg)) + out = syote_comms.comms_process_wrap( commstate, msg) + #_debprint('resp:', repr(out)) + if out: await mt.send(out) finally: @@ -333,13 +421,13 @@ async def main(): msd = MulticastSyncDatagram(maddr) await msd.start() - l = LORANode(msd, shared=shared_key) + l = LORANode(msd, **lorakwargs) await l.start() valid_cmds = { 'waitfor', 'setunset', 'runfor', 'ping', 'adv', 'clear', - 'terminate', + 'terminate', 'type', } if args.args and args.schedfile: @@ -364,7 +452,10 @@ async def main(): fun = getattr(l, cmd) - await fun(*(int(x) for x in args)) + try: + await fun(*(int(x) for x in args)) + except: + await fun(*args) if __name__ == '__main__': asyncio.run(main()) @@ -1096,7 +1187,7 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): @timeout(2) async def test_ccode(self): _self = self - from ctypes import c_uint8 + from ctypes import c_uint8, memmove # seed the RNG prngseed = b'abc123' @@ -1111,28 +1202,40 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): (CMD_WAITFOR, [ 30 ]), (CMD_RUNFOR, [ 1, 50 ]), (CMD_PING, [ ]), + # using big here, because Python is stupid. + (CMD_KEY, b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x00\x00\x02\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', CMD_KEY.to_bytes(1, byteorder='big') + (3).to_bytes(4, byteorder='little')), + (CMD_KEY, b'\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', CMD_KEY.to_bytes(1, byteorder='big') + (2).to_bytes(4, byteorder='little')), (CMD_TERMINATE, [ ]), ] def procmsg(msg, outbuf): msgbuf = msg._from() cmd = msgbuf[0] - args = [ int.from_bytes(msgbuf[x:x + 4], - byteorder='little') for x in range(1, len(msgbuf), - 4) ] + if isinstance(exptmsgs[0][1], bytes): + args = msgbuf[1:] + else: + args = [ int.from_bytes(msgbuf[x:x + 4], + byteorder='little') for x in range(1, len(msgbuf), + 4) ] + + if exptmsgs[0][:2] == (cmd, args): + if len(exptmsgs[0]) > 2: + rmsg = exptmsgs[0][2] + memmove(outbuf[0].pkt, rmsg, len(rmsg)) + outbuf[0].pktlen = len(rmsg) + else: + outbuf[0].pkt[0] = cmd + outbuf[0].pktlen = 1 - if exptmsgs[0] == (cmd, args): exptmsgs.pop(0) - outbuf[0].pkt[0] = cmd - outbuf[0].pktlen = 1 else: #pragma: no cover - raise RuntimeError('cmd not found') + raise RuntimeError('cmd not found, got %d, expected %d' % (cmd, exptmsgs[0][0])) # wrap the callback function cb = syote_comms.process_msgfunc_t(procmsg) class CCodeSD(MockSyncDatagram): async def runner(self): - for expectlen in [ 24, 17, 9, 9, 9, 9 ]: + for expectlen in [ 24, 17, 9, 9, 9, 13, 13, 9 ]: # get message inmsg = await self.get() @@ -1176,6 +1279,8 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): await l.ping() + await l.type('sHt') + await l.terminate() await tsd.drain() diff --git a/mk/boards.mk b/mk/boards.mk index 0e3fcbc..d41e7a3 100644 --- a/mk/boards.mk +++ b/mk/boards.mk @@ -16,8 +16,14 @@ CFLAGS+= -Wall -Werror .include <$(.PARSEDIR)/mu.opts.mk> +.if ${MK_HAL_INIT} == "yes" +.PATH: $(SRCTOP)/board +SRCS+= hal_init.c +.endif + .if ${MK_SYSINIT} == "yes" .PATH: $(SRCTOP) +CFLAGS+= -I$(SRCTOP) SRCS+= sysinit.c .endif @@ -29,6 +35,11 @@ STROBE_SRCS+= strobe.c \ x25519.c .endif +.if ${MK_STROBE} == "yes" && ${MK_STM32F103} == "yes" +.PATH: $(SRCTOP)/board +STROBE_SRCS+= strobe_f1_rng_init.c +.endif + # LoRamac (SX1276) radio code .if ${MK_SX1276} == "yes" LORAMAC_SRC = $(SRCTOP)/loramac/src @@ -49,15 +60,21 @@ SRCS+= adc-board.c delay-board.c gpio-board.c rtc-board.c lpm-board.c sx1276mb1l ARMTARGET?= -mcpu=cortex-m3 -mthumb .PATH: $(STM32)/f103c8t6 +.PATH: $(SRCTOP)/board LINKER_SCRIPT=$(STM32)/f103c8t6/STM32F103C8T6_FLASH.ld SRCS+= \ - misc.c \ + f1_flash.c \ hal_generic.c \ startup_stm32f103xb.s \ + stm32_bluepill.c \ stm32f1xx_hal.c \ + stm32f1xx_hal_adc.c \ + stm32f1xx_hal_adc_ex.c \ stm32f1xx_hal_cortex.c \ stm32f1xx_hal_dma.c \ + stm32f1xx_hal_flash.c \ + stm32f1xx_hal_flash_ex.c \ stm32f1xx_hal_gpio.c \ stm32f1xx_hal_pcd.c \ stm32f1xx_hal_pcd_ex.c \ @@ -65,7 +82,6 @@ SRCS+= \ stm32f1xx_hal_rcc.c \ stm32f1xx_hal_rcc_ex.c \ stm32f1xx_hal_uart.c \ - stm32f1xx_ll_usb.c \ system_stm32f1xx.c CFLAGS+= -I$(STM32) @@ -123,8 +139,8 @@ CFLAGS+= -I$(SRCTOP)/rs485hid # USB CDC .if ${MK_USB_CDC} == "yes" .PATH: $(STM32)/usb -SRCS+= \ - si_usb.c \ +SRCS.USB_CDC+= \ + misc.c \ usb_device.c \ usbd_cdc.c \ usbd_cdc_if.c \ @@ -137,7 +153,28 @@ SRCS+= \ CFLAGS+= -I$(STM32)/usb .endif -.if ${MK_USB_CDC} == "yes" && ${MK_NODE151} == "yes" -SRCS+= \ +# USB HID +.if ${MK_USB_HID} == "yes" +.PATH: $(STM32)/usb +CFLAGS+= -I$(.OBJDIR) +SRCS.USB_HID+= \ + usb_hid_def.c \ + usbd_conf.c \ + usbd_core.c \ + usbd_ctlreq_nodesc.c \ + usbd_ioreq.c + +CFLAGS+= -I$(STM32)/usb +.endif + +.if ${MK_USB} == "yes" && ${MK_STM32F103} == "yes" +SRCS.USB+= \ + si_usb.c \ + stm32f1xx_ll_usb.c +.endif + +.if ${MK_USB} == "yes" && ${MK_NODE151} == "yes" +SRCS.USB_CDC+= \ + si_usb.c \ stm32l1xx_ll_usb.c .endif diff --git a/mk/mu.opts.mk b/mk/mu.opts.mk index aeaf436..e33a378 100644 --- a/mk/mu.opts.mk +++ b/mk/mu.opts.mk @@ -2,6 +2,32 @@ # code. # # See bsd.mkopt.mk for more information. +# +# An option should only be listed in one of the following sections. +# If it's listed as a dependent option, do NOT list it in a default +# section. +# + +# +# If the option doesn't state if it defines a SRCS var, then +# the necessary sources are added to the SRCS var. +# +# Options (by order in this file): +# +# STROBE - The STROBE crypto library. (Defines STROBE_SRCS) +# SYSINIT - The sysinit framework. Needed to run the init code. +# +# NODE151 - Code needed for the Node151 LoRa module +# RS485FRAME - Base code for RS485 framing tx/rx +# STM32F103 - Base code for the BluePill microcontroller module +# SX1276 - LoRa radio code, for Node151 +# USB_CDC - Code implementing the CDC Device mode. (Defines SRCS.USB_CDC) +# USB_HID - Code implementing the HID Device mode. (Defines SRCS.USB_HID) +# +# Dependent options: +# HAL_INIT - Run hal_init via sysinit. +# USB - Turn on generic USB support code. (Defines SRCS.USB) +# __DEFAULT_YES_OPTIONS = STROBE \ SYSINIT @@ -11,8 +37,12 @@ __DEFAULT_NO_OPTIONS = \ RS485FRAME \ STM32F103 \ SX1276 \ - USB_CDC + USB_CDC \ + USB_HID -__DEFAULT_DEPENDENT_OPTIONS = +__DEFAULT_DEPENDENT_OPTIONS = \ + HAL_INIT/STM32F103 \ + USB/USB_CDC \ + USB/USB_HID .include <$(.PARSEDIR)/bsd.mkopt.mk> diff --git a/mk/mu.progs.mk b/mk/mu.progs.mk index b80adbf..75dc553 100644 --- a/mk/mu.progs.mk +++ b/mk/mu.progs.mk @@ -31,20 +31,14 @@ PROGEXT = .elf +DEPENDS += .arm_deps + .for i in $(PROGS) ALLTGTS+= $(i)$(PROGEXT) $(i).list ASRCS.$(i) = $(SRCS) $(SRCS.$(i)) OBJS.$(i) = $(ASRCS.$(i):C/.c$/.o/) -DEPENDS += .arm_deps - -.arm_deps: $(ASRCS.$(i)) - -.arm_deps: - $(ARMCC) $(ARMTARGET) $(CFLAGS) $(.ALLSRC) -MM > $@ || (rm -f $@ && false) - -.PHONY: depend -depend: $(DEPENDS) +ARM_DEP_SRCS+= $(ASRCS.$(i)) $(i)$(PROGEXT) $(i).map: $(OBJS.$(i)) $(ARMCC) $(ARMTARGET) -o $(i)$(PROGEXT) $(.ALLSRC) -T$(LINKER_SCRIPT) --specs=nosys.specs -Wl,-Map="$(i).map" -Wl,--gc-sections -static --specs=nano.specs -Wl,--start-group -lc -lm -Wl,--end-group @@ -53,6 +47,14 @@ $(i).list: $(i)$(PROGEXT) $(ARMOBJDUMP) -h -S $(.ALLSRC) > $@ || (rm -f $@ && false) .endfor +.PHONY: depend +depend: $(DEPENDS) + +.arm_deps: $(ARM_DEP_SRCS) + +.arm_deps: + $(ARMCC) $(ARMTARGET) $(CFLAGS) $(.ALLSRC) -MM > $@ || (rm -f $@ && false) + .for i in $(DEPENDS) .sinclude "$i" .endfor @@ -61,7 +63,7 @@ all: $(ALLTGTS) .PHONY: runbuild runbuild: $(SRCS) Makefile mk/*.mk - for i in $(.MAKEFILE_LIST) $(.ALLSRC) $$(cat $(DEPENDS) | gsed ':x; /\\$$/ { N; s/\\\n//; tx }' | sed -e 's/^[^:]*://'); do if [ "$$i" != ".." ]; then echo $$i; fi; done | sort -u | entr -d sh -c 'echo starting...; cd $(.CURDIR) && $(MAKE) $(.MAKEFLAGS) depend && $(MAKE) $(.MAKEFLAGS) all' + for i in $(EXTRA_DEPENDS) $(.MAKEFILE_LIST) $(.ALLSRC) $$(cat $(DEPENDS) | gsed ':x; /\\$$/ { N; s/\\\n//; tx }' | sed -e 's/^[^:]*://'); do if [ "$$i" != ".." ]; then echo $$i; fi; done | sort -u | entr -d sh -c 'echo starting...; cd $(.CURDIR) && $(MAKE) $(.MAKEFLAGS) depend && $(MAKE) $(.MAKEFLAGS) all' # native objects .SUFFIXES: .no diff --git a/requirements.txt b/requirements.txt index 3683c86..f4a1e2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ coverage strobe/python +git+https://www.funkthat.com/gitea/jmg/python-usb-protocol.git diff --git a/rs485hid/Makefile b/rs485hid/Makefile index 5852219..1472805 100644 --- a/rs485hid/Makefile +++ b/rs485hid/Makefile @@ -22,20 +22,64 @@ # SUCH DAMAGE. # -PROGS = rs485gw # lora.irr +PROGS = rs485gw rs485hid SRCS.rs485gw = rs485gw.c -SRCS.rs485gw+= misc.c +SRCS.rs485gw+= $(SRCS.USB_CDC) +SRCS.rs485gw+= $(SRCS.USB) + +SRCS.rs485hid = rs485hid.c +SRCS.rs485hid+= $(SRCS.USB_HID) +SRCS.rs485hid+= $(SRCS.USB) +SRCS.rs485hid+= $(STROBE_SRCS) +SRCS.rs485hid+= comms.c +SRCS.rs485hid+= memdebug.c +SRCS.rs485hid+= strobe_pki.c + +CFLAGS.rs485hid+= -DEXTERNAL_GET_DESCRIPTOR=1 +CFLAGS.rs485hid+= -I$(.OBJDIR) # for public_key.h +SRCS.rs485hid+= usb_hid_base.c + +.if empty(HID_PRIV_KEY) && exists($(.CURDIR)/.hid_priv_key) +HID_PRIV_KEY!= cat $(.CURDIR)/.hid_priv_key +.endif + +.PHONY: hid_priv_key +hid_priv_key: + @LANG=C tr -c -d a-f0-9 < /dev/urandom | dd bs=1 of=$(.CURDIR)/.hid_priv_key count=64 2>/dev/null + @echo 'Key created and put into .hid_priv_key.' + +# make this a phony target so it's always run +# dependancies will only be made when it's updated +.PHONY: $(.OBJDIR)/public_key.h +$(.OBJDIR)/public_key.h: + @if [ "$(HID_PRIV_KEY)" = "" ]; then echo 'Must provide HID_PRIV_KEY make variable or have a non-empty file ".hid_priv_key". This can be created by the command "$(MAKE) hid_priv_key".'; false; fi + + @echo 'static const uint8_t pubkey[] = {' $$(python3 -c 'import sys; import codecs; from syote_comms import X25519; print(", ".join(hex(x) for x in X25519.frombytes(codecs.decode(sys.argv[1], "hex")).getpub()))' $(HID_PRIV_KEY) ) "};" > public_key.h.tmp + @echo 'static_assert(sizeof pubkey == 32);' >> public_key.h.tmp + + if [ "$$(cat public_key.h.tmp)" = "static uint8_t pubkey[] = { };" -o "$$(cat public_key.h.tmp)" = "" ]; then rm -f "$@"; false; fi + + (cmp public_key.h.tmp public_key.h >/dev/null 2>&1 && rm public_key.h.tmp) || mv public_key.h.tmp public_key.h + +strobe_pki.o: $(.OBJDIR)/public_key.h + +usb_hid_base.c: usb_hid.py + PYTHONPATH=$(.CURDIR) python $(STM32)/usb/usb_gen.py $(.ALLSRC:[1]:T:R) .PATH: $(.CURDIR)/.. CFLAGS += -g -CFLAGS += -I$(.CURDIR)/.. +WITH_RS485FRAME = yes WITH_STM32F103 = yes WITH_USB_CDC = yes -WITH_RS485FRAME = yes +WITH_USB_HID = yes .include <../mk/boards.mk> +EXTRA_DEPENDS+= $(STM32)/usb/usb_gen.py + .include <../mk/mu.progs.mk> + +usb_hid_base.c: $(STM32)/usb/usb_gen.py diff --git a/rs485hid/memdebug.c b/rs485hid/memdebug.c new file mode 100644 index 0000000..cdb2524 --- /dev/null +++ b/rs485hid/memdebug.c @@ -0,0 +1,65 @@ +/*- + * Copyright 2021 John-Mark Gurney. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include +#include +#include + +#if MEM_DEBUG_BUF +static char debugbuf[1024]; +static uint32_t debugpos = 0; + +void +debug_printf(const char *format, ...) +{ + char buf[128]; + char *pos; + va_list args; + uint32_t length; + uint32_t cpy; + + va_start(args, format); + length = vsnprintf(buf, sizeof buf, format, args); + va_end(args); + + pos = &buf[0]; + while (length) { + cpy = MIN(length, sizeof debugbuf - debugpos); + memcpy(&debugbuf[debugpos], pos, cpy); + + debugpos += cpy; + if (debugpos >= sizeof debugbuf) + debugpos = 0; + + pos += cpy; + length -= cpy; + } +} +#endif diff --git a/rs485hid/rs485frame.c b/rs485hid/rs485frame.c index d3745cf..1c05239 100644 --- a/rs485hid/rs485frame.c +++ b/rs485hid/rs485frame.c @@ -18,7 +18,7 @@ const char *rs485err = NULL; -static uint8_t rxbuf[1024]; +static uint8_t rxbuf[128]; static txdone_fn_t txdone; static rxdone_fn_t rxdone; static txdone_fn_t errcb; @@ -62,7 +62,7 @@ settx(bool tx) else s = GPIO_PIN_RESET; - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, s); + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, s); /* XXX - led */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, s); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, s); } @@ -71,11 +71,19 @@ void rs485_starttx(uint8_t *pkt, size_t len) { - /* XXX - make sure not tx'ing */ + /* XXX - make sure not actively rx'ing */ /* XXX - make sure line is idle */ + if (rs485uart.RxState == HAL_UART_STATE_BUSY_RX) { + while (rs485uart.RxXferCount != sizeof rxbuf) { + } + } +#if 0 + /* XXX - as it's full duplex, this shouldn't be needed */ + /* This appears to corrupt state and break things */ if (doingrx) { HAL_UART_AbortReceive_IT(&rs485uart); } +#endif settx(true); @@ -99,6 +107,8 @@ HAL_UART_TxCpltCallback(UART_HandleTypeDef *phuart) if (phuart != &rs485uart || txdone == NULL) return; + for (int x = 0; x < 1000000; x++); + settx(false); doingtx = 0; @@ -140,12 +150,13 @@ HAL_UART_MspInit(UART_HandleTypeDef *huart) /* UM1850 § 38.1.2 Page 550 */ /* 2.a */ - __HAL_RCC_USART3_FORCE_RESET( ); - __HAL_RCC_USART3_RELEASE_RESET( ); + __HAL_RCC_USART3_FORCE_RESET(); + __HAL_RCC_USART3_RELEASE_RESET(); __HAL_RCC_USART3_CLK_ENABLE(); /* 2.b */ __HAL_RCC_GPIOB_CLK_ENABLE(); + /* TX pin */ GPIO_InitStruct = (GPIO_InitTypeDef){ .Pin = GPIO_PIN_10, @@ -197,10 +208,17 @@ rs485_startrx() return 0; } + doingrx = 1; + r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf); if (r == HAL_BUSY) { + rs485err = "already"; + return 1; +#if 0 + /* This appears to corrupt state and break things */ HAL_UART_AbortReceive_IT(&rs485uart); r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf); +#endif } rs485err = statustostr(r); @@ -209,14 +227,16 @@ rs485_startrx() } static void -rs485frame_init(const void *v) +rs485frame_init(void) { GPIO_InitTypeDef GPIO_InitStruct; + __HAL_RCC_GPIOB_CLK_ENABLE(); + /* setup DE/RE */ GPIO_InitStruct = (GPIO_InitTypeDef){ .Pin = GPIO_PIN_0|GPIO_PIN_1, - .Mode = GPIO_MODE_OUTPUT_OD, + .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, /* 2 MHz */ }; @@ -240,4 +260,4 @@ rs485frame_init(const void *v) /* 4 */ HAL_UART_Init(&rs485uart); } -SYSINIT(rs485frame_init, SI_SUB_STANDARD, SI_ORDER_FIRST, rs485frame_init, NULL); +SYSINIT_VF(rs485frame_init, SI_SUB_STANDARD, SI_ORDER_FIRST, rs485frame_init); diff --git a/rs485hid/rs485gw.c b/rs485hid/rs485gw.c index ea8cae9..69a93e0 100644 --- a/rs485hid/rs485gw.c +++ b/rs485hid/rs485gw.c @@ -36,7 +36,18 @@ #include -SYSINIT(hal_init, SI_SUB_HAL, SI_ORDER_FIRST, (void (*)(const void *))HAL_Init, NULL); +#include +SYSINIT_VF(usb_cdc, SI_SUB_USB, SI_ORDER_MIDDLE, MX_USB_DEVICE_Init); + +/* XXX - where's a better place? */ +extern PCD_HandleTypeDef hpcd_USB_FS; + +void +USB_LP_IRQHandler(void) +{ + + HAL_PCD_IRQHandler(&hpcd_USB_FS); +} static int dorx = 0; static uint8_t rxbuf[128]; @@ -71,51 +82,6 @@ SYSINIT(c13led, SI_SUB_HAL, SI_ORDER_SECOND, c13led, NULL); #define usb_printf debug_printf #endif -/* - * Referenced from: - * Projects/STM32F103RB-Nucleo/Applications/USB_Device/HID_Standalone/Src/main.c - */ -static void -oscconfig(const void *none) -{ - RCC_ClkInitTypeDef clkinitstruct; - RCC_OscInitTypeDef oscinitstruct; - RCC_PeriphCLKInitTypeDef rccperiphclkinit; - - __HAL_RCC_PWR_CLK_ENABLE(); - - oscinitstruct = (RCC_OscInitTypeDef){ - .OscillatorType = RCC_OSCILLATORTYPE_HSE, - .HSEState = RCC_HSE_ON, - .HSEPredivValue = RCC_HSE_PREDIV_DIV1, - .PLL.PLLMUL = RCC_PLL_MUL9, - - .PLL.PLLState = RCC_PLL_ON, - .PLL.PLLSource = RCC_PLLSOURCE_HSE, - }; - - HAL_RCC_OscConfig(&oscinitstruct); - - /* USB clock selection */ - rccperiphclkinit = (RCC_PeriphCLKInitTypeDef){ - .PeriphClockSelection = RCC_PERIPHCLK_USB, - .UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5, - }; - HAL_RCCEx_PeriphCLKConfig(&rccperiphclkinit); - - /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 - clocks dividers */ - clkinitstruct = (RCC_ClkInitTypeDef){ - .ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2), - .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK, - .AHBCLKDivider = RCC_SYSCLK_DIV1, - .APB1CLKDivider = RCC_HCLK_DIV2, - .APB2CLKDivider = RCC_HCLK_DIV1, - }; - HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); -} -SYSINIT(oscconfig, SI_SUB_HAL, SI_ORDER_THIRD, oscconfig, NULL); - char * findeol(char *pos, size_t len) { @@ -167,19 +133,6 @@ rxdone(const uint8_t *payload, size_t size) gotrxdone = 1; } -void -rxtimeout(void) -{ - - usb_printf("rxtimeout\r\n"); -} - -void -rxerr(void) -{ - usb_printf("rxerr\r\n"); -} - static uint8_t hexchartonib(char s) { @@ -278,7 +231,7 @@ main(void) debug_printf("starting...\n"); -#if 1 +#if 0 int i; for (i = 0; i < 5; i++) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); diff --git a/rs485hid/rs485hid.c b/rs485hid/rs485hid.c new file mode 100644 index 0000000..17d417b --- /dev/null +++ b/rs485hid/rs485hid.c @@ -0,0 +1,558 @@ +/*- + * Copyright 2021 John-Mark Gurney. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "usb_hid_def.h" + +#include "stm32f1xx.h" +#include "stm32f1xx_hal.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static struct pktbuf rxpktbuf; +static volatile int dorx = 0; +static uint8_t rxbuf[128]; +static volatile int gotrxdone = 0; +static volatile int gottxdone = 0; +static volatile int goterr = 0; +static volatile int rxbufsize = 0; +static volatile int rxbuftrunc = 0; + +enum { + CMD_TERMINATE = 1, + CMD_WAITFOR = 2, + CMD_RUNFOR = 3, + CMD_PING = 4, + CMD_SETUNSET = 5, + CMD_ADV = 6, + CMD_CLEAR = 7, + CMD_KEY = 8, +}; + +static struct comms_state cs; + +static void +c13led(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + + GPIO_InitStruct = (GPIO_InitTypeDef){ + .Pin = GPIO_PIN_13, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); +} +SYSINIT_VF(c13led, SI_SUB_HAL, SI_ORDER_SECOND, c13led); + +void +txdone(void) +{ + + gottxdone = 1; +} + +void +errfunc(void) +{ + + debug_printf("error\n"); + goterr = 1; +} + +struct pktbuf shared_key_buf = { + .pkt = (uint8_t *)"abcd1234", + .pktlen = 8, +}; + +static uint32_t rxts; + +void +rxdone(const uint8_t *payload, size_t size) +{ + + if (size > sizeof rxbuf) { + size = sizeof rxbuf; + rxbuftrunc = 1; + } + + debug_printf("rx: %d: %02x %02x ...\n", size, payload[0], payload[1]); + + memcpy(rxbuf, payload, size); + rxbufsize = size; + gotrxdone = 1; + rxts = HAL_GetTick(); +} + +static inline uint32_t +letoh_32(uint8_t *v) +{ + return v[0] | (v[1] << 8) | (v[2] << 16) | ((unsigned)v[3] << 24); +} + +static inline void +htole_32(uint8_t *d, uint32_t v) +{ + + d[0] = v; + d[1] = v >> 8; + d[2] = v >> 16; + d[3] = v >> 24; +} + +struct chaninfo { + GPIO_TypeDef *bank; + uint16_t pinnum; + bool init; + bool invert; +} chans[] = { + [0] = { .bank = GPIOB, .pinnum = GPIO_PIN_5, .invert = true, }, + [1] = { .bank = GPIOB, .pinnum = GPIO_PIN_6, .invert = true, }, + [2] = { .bank = GPIOB, .pinnum = GPIO_PIN_7, .invert = true, }, + [3] = { .bank = GPIOB, .pinnum = GPIO_PIN_9, .invert = true, }, + /* Turn on LED at start */ + [4] = { .bank = GPIOB, .pinnum = GPIO_PIN_8, .init = true, }, +}; +#define nitems(x) (sizeof(x) / sizeof *(x)) + +static void +set_chan(uint32_t chan, bool val) +{ + struct chaninfo ci; + + if (chan < nitems(chans)) { + ci = chans[chan]; + HAL_GPIO_WritePin(ci.bank, ci.pinnum, val ^ ci.invert ? + GPIO_PIN_SET : GPIO_PIN_RESET); + } +} + +static void +setup_gpio(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + int i; + + for (i = 0; i < nitems(chans); i++) { + GPIO_InitStruct = (GPIO_InitTypeDef){ + .Pin = chans[i].pinnum, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(chans[i].bank, &GPIO_InitStruct); + set_chan(i, chans[i].init); + } +} +SYSINIT_VF(setup_gpio, SI_SUB_STANDARD, SI_ORDER_ANY, setup_gpio); + +static struct sched { + uint32_t cmd; + uint32_t end_wait_tick; /* end if running, otherwise how long to wait */ + uint32_t chan; +} schedule[20]; +static int schedpos; /* position in schedule, % nitems(schedule)*/ +static int schedcnt; /* total items waiting */ + +#define SCHED_ITEM(x) (schedule[(schedpos + x) % nitems(schedule)]) +#define SCHED_HEAD SCHED_ITEM(0) +#define SCHED_TAIL SCHED_ITEM(schedcnt) + +static void +start_sched(struct sched *sched) +{ + + sched->end_wait_tick += uwTick; + + if (sched->cmd == CMD_RUNFOR) + set_chan(sched->chan, 1); +} + +static bool +canproc_sched() +{ + + /* nothing to do? */ + if (schedcnt == 0) + return false; + + /* not yet expired */ + if (uwTick < SCHED_HEAD.end_wait_tick) + return false; + + return true; +} + +static void +process_sched() +{ + + if (!canproc_sched()) + return; + + if (SCHED_HEAD.cmd == CMD_RUNFOR) + set_chan(SCHED_HEAD.chan, 0); + + /* we are done, advance */ + schedpos++; + schedcnt--; + + if (schedcnt) + start_sched(&SCHED_HEAD); +} + +static void +enqueue_sched(uint32_t cmd, uint32_t ticks, uint32_t chan) +{ + + if (schedcnt >= nitems(schedule)) + return; + + SCHED_TAIL = (struct sched){ + .cmd = cmd, + .end_wait_tick = ticks, + .chan = chan, + }; + + if (schedcnt == 0) + start_sched(&SCHED_HEAD); + + schedcnt++; +} + +static void +procmsg(struct pktbuf inbuf, struct pktbuf *outbuf) +{ + uint32_t args[5]; + uint32_t keycnt; + int i, r, apos, cnt; + + i = 1; + apos = 0; + for (i = 1, apos = 0; apos < sizeof args / sizeof *args && i + 4 <= inbuf.pktlen; i += 4, apos++) { + args[apos] = letoh_32(&inbuf.pkt[i]); + } + + outbuf->pkt[0] = inbuf.pkt[0]; + outbuf->pktlen = 1; + + switch (inbuf.pkt[0]) { + case CMD_WAITFOR: + if (apos == 1) + enqueue_sched(CMD_WAITFOR, args[0], -1); + break; + + case CMD_RUNFOR: + if (apos == 2) + enqueue_sched(CMD_RUNFOR, args[0], args[1]); + break; + + case CMD_PING: + break; + + case CMD_SETUNSET: + if (apos == 2) + set_chan(args[0], args[1]); + break; + + case CMD_ADV: + cnt = 1; + if (apos == 1) + cnt = args[0]; + + for (i = 0; i < cnt && i < schedcnt; i++) + SCHED_ITEM(i).end_wait_tick = 0; + break; + + case CMD_CLEAR: + if (schedcnt) + schedcnt = 1; + break; + + case CMD_KEY: + i = 1; + + keycnt = 0; + for (i = 1; i + REPORT_SIZE <= inbuf.pktlen; i += REPORT_SIZE) { + r = report_insert(&inbuf.pkt[i]); + if (!r) + break; + + keycnt++; + } + htole_32(&outbuf->pkt[1], keycnt); + outbuf->pktlen = 5; + break; + + default: + outbuf->pkt[0] = 0; + break; + } +} + +static void +setup_button() +{ + GPIO_InitTypeDef GPIO_InitStruct; + + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitStruct = (GPIO_InitTypeDef){ + .Pin = GPIO_PIN_7, + .Mode = GPIO_MODE_INPUT, + .Pull = GPIO_PULLUP, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); +} +SYSINIT_VF(setup_button, SI_SUB_STANDARD, SI_ORDER_ANY, setup_button); + +/* check if the button has been pushed, returns true once for each "push" */ +static int +button_pushed(void) +{ + static uint32_t lasthightick; + static uint32_t waspushed; + uint32_t tick; + uint8_t pinstate; + + tick = HAL_GetTick(); + pinstate = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); + + if (pinstate) { + /* Reset button state */ + waspushed = 0; + lasthightick = tick; + return 0; + } + + /* only return IF the it's been held for 5ms & wasn't returned before */ + if (tick - lasthightick > 5 && !waspushed) { + waspushed = 1; + return 1; + } + + return 0; +} + +static const uint8_t hexkeymap[] = { + [0] = 0x27, + [1] = 0x1e, + [2] = 0x1f, + [3] = 0x20, + [4] = 0x21, + [5] = 0x22, + [6] = 0x23, + [7] = 0x24, + [8] = 0x25, + [9] = 0x26, + [10] = 0x04, + [11] = 0x05, + [12] = 0x06, + [13] = 0x07, + [14] = 0x08, + [15] = 0x09, +}; +static_assert(sizeof hexkeymap == 16); + +volatile uint32_t v; + +void +report_blocking_insert(uint8_t rep[REPORT_SIZE]) +{ + int inserted; + + do { + report_process(); + + inserted = report_insert(rep); + } while(!inserted); +} + +int +main() +{ + struct strobepkikey keys; + + debug_printf("starting..."); + + sysinit_run(); + +#if 0 + /* turn on LED */ + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); +#endif + + keys = get_key(); + + comms_init(&cs, procmsg, NULL, &keys.privkey, &keys.pubkey); + + /* Clear out pointer to private key. */ + keys.privkey = (struct pktbuf){}; + + rs485_register(txdone, rxdone, errfunc); + + uint8_t txbuf[128] = "i'mhere"; + struct pktbuf txpktbuf; + + txpktbuf = (struct pktbuf){ + .pkt = txbuf, + .pktlen = 7, + }; + //rs485_starttx(txpktbuf.pkt, txpktbuf.pktlen); + dorx = 1; + + int laststartrx = 0; +loop: + while (canproc_sched()) + process_sched(); + +#if 0 + BoardLowPowerHandler(); +#else + //(void)BoardLowPowerHandler; +#endif + + /* process any pending keys */ + report_process(); + + if (button_pushed()) { + /* Send the public key */ + uint8_t pubkey[EC_PUBLIC_BYTES]; + uint8_t reportbuf[REPORT_SIZE]; + const uint8_t *buf; + int remainnibbles; + uint8_t lastkey, key; + + get_pubkey(pubkey); + + buf = pubkey; + remainnibbles = keys.pubkey.pktlen * 2; + + memset(reportbuf, 0, sizeof reportbuf); + + /* clear any previous key presses */ + report_blocking_insert(reportbuf); + + for (remainnibbles = keys.pubkey.pktlen * 2; remainnibbles; remainnibbles--) { + /* top nibble when even, bottom when odd */ + if (remainnibbles & 1) { + key = hexkeymap[buf[0] & 0xf]; + buf++; + } else + key = hexkeymap[buf[0] >> 4]; + + lastkey = reportbuf[2]; + + /* + * if previous key matches, we need to "up" it, to make + * a transition, otherwise, speed things along. + */ + if (key == lastkey) { + reportbuf[2] = 0; + report_blocking_insert(reportbuf); + } + + reportbuf[2] = key; + report_blocking_insert(reportbuf); + + } + + /* clear last key */ + reportbuf[2] = 0; + report_blocking_insert(reportbuf); + } + + if (gottxdone) { + dorx = 1; + gottxdone = 0; + } + + if (gotrxdone) { + rxpktbuf = (struct pktbuf){ + .pkt = rxbuf, + .pktlen = rxbufsize, + }; + txpktbuf = (struct pktbuf){ + .pkt = txbuf, + .pktlen = sizeof txbuf, + }; + /* process available packet */ +#if 1 + uint32_t gt; + gt = HAL_GetTick(); + reset_timer(); + start_timer(); + comms_process(&cs, rxpktbuf, &txpktbuf); + stop_timer(); + debug_printf("comproc: %u cycles, ticks: %u, fromrx: %u\n", getCycles(), HAL_GetTick() - gt, HAL_GetTick() - rxts); +#else + txpktbuf = rxpktbuf; +#endif + + //debug_printf("totx: %d: %02x %02x ...\n", txpktbuf.pktlen, txpktbuf.pkt[0], txpktbuf.pkt[1]); + gotrxdone = false; + + if (txpktbuf.pktlen) { + int i; + + //debug_printf("rx to tx: %d\n", HAL_GetTick() - rxts); + for (i = 0; i < 1; i++) { + //HAL_Delay(20); + rs485_starttx(txpktbuf.pkt, txpktbuf.pktlen); + } + + /* Make sure we don't interrupt tx */ + laststartrx = HAL_GetTick(); + } else { + dorx = 1; + } + } + + if (dorx || goterr || HAL_GetTick() > laststartrx + 1000000) { + //usb_printf("dorx\r\n"); + laststartrx = HAL_GetTick(); + rs485_startrx(); + //usb_printf("startrx res: %s\r\n", rs485err); + dorx = 0; + } + + goto loop; +} diff --git a/rs485hid/strobe_pki.c b/rs485hid/strobe_pki.c new file mode 100644 index 0000000..70f25a5 --- /dev/null +++ b/rs485hid/strobe_pki.c @@ -0,0 +1,87 @@ +/*- + * Copyright 2022 John-Mark Gurney. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include + +#include + +#include /* roundup */ + +#include + +uint8_t keyvalid; + +static const uint8_t privkey[roundup(EC_PRIVATE_BYTES, sizeof(uint8_t)) / sizeof(uint8_t)] __attribute__ ((section (".savekeys"))) = { +#if 1 + 0xae, 0xe7, 0xdd, 0x04, 0x84, 0xb3, 0xcd, 0x3c, + 0xef, 0x25, 0x71, 0x83, 0xc4, 0x6c, 0x5d, 0x3c, + 0xee, 0x98, 0xee, 0x79, 0xf2, 0x97, 0x6a, 0xe8, + 0x39, 0xec, 0x7d, 0xe8, 0x23, 0xe7, 0x20, 0xdb, +#endif +}; +#include + +void +get_pubkey(uint8_t pubkey[EC_PUBLIC_BYTES]) +{ + + x25519_base(pubkey, privkey, 1); +} + +struct strobepkikey +get_key(void) +{ + struct strobepkikey spk; + uint8_t key[sizeof privkey] = {}; + uint8_t keyf[sizeof privkey] = {}; + int r; + + memset(keyf, 0xff, sizeof keyf); + + if (memcmp(key, privkey, sizeof privkey) == 0 || + memcmp(keyf, privkey, sizeof privkey) == 0) { + /* Generate new key */ + do { + r = strobe_randomize((uint8_t *)key, sizeof key); + if (r < 0) + continue; + } while (r != 0); + + /* and write it. */ + doflash(privkey, key, sizeof key); + } + + spk = (struct strobepkikey){ + .privkey.pkt = (void *)(uintptr_t)privkey, + .privkey.pktlen = EC_PRIVATE_BYTES, + .pubkey.pkt = (void *)(uintptr_t)pubkey, + .pubkey.pktlen = EC_PUBLIC_BYTES, + }; + + return spk; +} diff --git a/rs485hid/strobe_pki.h b/rs485hid/strobe_pki.h new file mode 100644 index 0000000..405a0d3 --- /dev/null +++ b/rs485hid/strobe_pki.h @@ -0,0 +1,9 @@ +#include + +struct strobepkikey { + struct pktbuf privkey; + struct pktbuf pubkey; +}; + +struct strobepkikey get_key(void); +void get_pubkey(uint8_t pubkey[EC_PUBLIC_BYTES]); diff --git a/rs485hid/usb_hid.py b/rs485hid/usb_hid.py new file mode 100644 index 0000000..23cc18c --- /dev/null +++ b/rs485hid/usb_hid.py @@ -0,0 +1,62 @@ +import codecs +import struct + +from usb_protocol.types import USBTransferType +from usb_protocol.emitters.descriptors import DeviceDescriptorCollection, get_string_descriptor + + +# Imported defines from usbd_def.h +USBD_IDX_LANGID_STR = 0x00 +USBD_IDX_MFC_STR = 0x01 +USBD_IDX_PRODUCT_STR = 0x02 +USBD_IDX_SERIAL_STR = 0x03 +USBD_IDX_CONFIG_STR = 0x04 +USBD_IDX_INTERFACE_STR = 0x05 + +USB_CLASS_HID = 0x03 +USB_CLASS_HID_NO_BOOT = 0x00 +USB_CLASS_HID_BOOT = 0x01 +USB_PROTOCOL_HID_NONE = 0x00 +USB_PROTOCOL_HID_KEYBOARD = 0x01 +USB_PROTOCOL_HID_MOUSE = 0x02 + +collection = DeviceDescriptorCollection() + +with collection.DeviceDescriptor() as d: + # https://pid.codes/1209/ + d.idVendor = 0x1209 + d.idProduct = 0x001 + d.bNumConfigurations = 1 + + # Hack for ST reference code + d.iProduct = USBD_IDX_PRODUCT_STR + collection.add_descriptor(get_string_descriptor('RS-485 to HID'), d.iProduct) + +with collection.ConfigurationDescriptor() as c: + with c.InterfaceDescriptor() as i: + i.bInterfaceNumber = 0 + i.bInterfaceClass = USB_CLASS_HID + i.bInterfaceSubclass = USB_CLASS_HID_BOOT + i.bInterfaceProtocol = USB_PROTOCOL_HID_KEYBOARD + + report_desc = codecs.decode('05010906a101050719e029e71500250175019508810295017508810195057501050819012905910295017503910195067508150025650507190029658100c0', 'hex') + collection.add_descriptor(report_desc, descriptor_type=0x22) + + hid_desc = codecs.decode('09211101000122', 'hex') + struct.pack(' /* debug_printf */ + +#include + +#include + +static uint8_t Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +static uint8_t DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +static uint8_t Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +static uint8_t DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum); +#if 0 +static uint8_t DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum); +#endif +static uint8_t ep0rxready(USBD_HandleTypeDef *pdev); + +#define USB_HID_EPIN_ADDR 0x81 + +#define REPORT_CNT 10 + +enum hid_state { + IDLE, + BUSY, +}; + +struct usb_hid_softc { + enum hid_state state; + uint8_t led_status[2]; + uint8_t idle_time; + uint8_t report_protocol; +}; + +static USBD_HandleTypeDef *hid_handle; +static uint32_t next_idle_report; + +static uint8_t reports[REPORT_CNT][REPORT_SIZE] = { + /* mod pad keys... */ +#if 0 + [0] = { 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [1] = { 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [2] = { 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [3] = { 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [4] = { 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [5] = { 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [6] = { 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [7] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +#endif +}; +/* + * Ring buffer for reports. + * + * reporthead: next available report + * reporttail: next empty slot + * + * reporthead == reporttail: ring buffer is empty + * reporttail == reporthead - 1: ring buffer is full + */ +static uint8_t reporthead = 0; +static uint8_t reporttail = 0; +static uint32_t reportoverflow; + +/* as -1 % posint == -1, adding REPORT_CNT keeps it positive if x is val - 1 when val is 0 */ +#define MAKE_POS(x) (((x) + REPORT_CNT) % REPORT_CNT) + +static bool +report_is_avail(void) +{ + return reporthead != reporttail; +} + +static uint8_t * +report_next(void) +{ + int oldrep; + + /* no new report, don't advance, return previous */ + if (!report_is_avail()) + return reports[MAKE_POS(reporthead - 1)]; + + oldrep = reporthead; + reporthead = MAKE_POS(reporthead + 1); + + return reports[oldrep]; +} + +void +report_process(void) +{ + struct usb_hid_softc *hid; + uint32_t tick; + + if (hid_handle == NULL) + return; + + hid = (struct usb_hid_softc *)hid_handle->pClassData; + + if (hid_handle->dev_state != USBD_STATE_CONFIGURED || + hid->state != IDLE) { + return; + } + + tick = HAL_GetTick(); + + if (!report_is_avail() && tick < next_idle_report) + return; + + next_idle_report = tick + hid->idle_time; + + hid->state = BUSY; + USBD_LL_Transmit(hid_handle, USB_HID_EPIN_ADDR, report_next(), REPORT_SIZE); +} + +/* + * This could be smarter by collapsing reports. The algorithm to do + * so is a bit tricky, and likely not needed, BUT it does mean for a + * simple algorithm, you could be limited to 50 chars per second assuming + * 10ms report timing (one down, one up). + * + * Return true if successful, false if overflowed. + */ +int +report_insert(uint8_t rep[REPORT_SIZE]) +{ + uint8_t newtail; + + newtail = MAKE_POS(reporttail + 1); + if (newtail == reporthead) { + reportoverflow++; + return 0; + } + + memcpy(reports[reporttail], rep, sizeof reports[reporttail]); + + reporttail = newtail; + + return 1; +} + +enum { + HID_REQ_GET_REPORT = 0x01, + HID_REQ_GET_IDLE = 0x02, + HID_REQ_GET_PROTOCOL = 0x03, + HID_REQ_SET_REPORT = 0x09, + HID_REQ_SET_IDLE = 0x0a, + HID_REQ_SET_PROTOCOL = 0x0b, +}; + +USBD_ClassTypeDef usb_hid_def = { + .Init = Init, + .DeInit = DeInit, + .Setup = Setup, + .EP0_RxReady = ep0rxready, + .DataIn = DataIn, +#if 0 + .DataOut = DataOut, +#endif + /* Get*Desc not used */ +}; + +static uint8_t +Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + struct usb_hid_softc *hid; + int ret; + + ret = 0; + + usb_hid_epopen(pdev); + + /* allocate state data */ + hid = (void *)USBD_malloc(sizeof(struct usb_hid_softc)); + if (hid == NULL) { + ret = 1; + } else { + *hid = (struct usb_hid_softc){ + .idle_time = 10, + }; + + pdev->pClassData = hid; + + hid_handle = pdev; + } + + return ret; +} + +static uint8_t +DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + + usb_hid_epclose(pdev); + + if (pdev->pClassData != NULL) { + USBD_free(pdev->pClassData); + pdev->pClassData = NULL; + hid_handle = NULL; + } + + return 0; +} + +#define MAKE_CASE_REQ(type, req) ((((type) << 8) & USB_REQ_TYPE_MASK) | (req)) +#define USB_CASE_REQ(req) MAKE_CASE_REQ((req)->bmRequest, (req)->bRequest) + +static void +send_ctlresp(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req, const uint8_t *buf, size_t len) +{ + + len = MIN(req->wLength, len); + + USBD_CtlSendData(pdev, (uint8_t *)(uintptr_t)buf, len); +} + +/* + * Handle non-standard control SETUP requests. + * + * This includes requests sent to the interface and other special + * requests. + */ +static uint8_t +Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + struct usb_hid_softc *hid; + uint8_t ret; + + ret = USBD_OK; + hid = (struct usb_hid_softc *)pdev->pClassData; + + switch (USB_CASE_REQ(req)) { + case MAKE_CASE_REQ(USB_REQ_TYPE_STANDARD, USB_REQ_GET_DESCRIPTOR): + USBD_GetDescriptor(pdev, req); + break; + + case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_GET_REPORT): + send_ctlresp(pdev, req, report_next(), REPORT_SIZE); + break; + + case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_SET_REPORT): + break; + + case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_GET_IDLE): + send_ctlresp(pdev, req, &hid->idle_time, sizeof hid->idle_time); + break; + + case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_SET_IDLE): + hid->idle_time = (uint8_t)(req->wValue >> 8); + break; + + case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_GET_PROTOCOL): + send_ctlresp(pdev, req, &hid->report_protocol, sizeof hid->idle_time); + break; + + case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_SET_PROTOCOL): + hid->report_protocol = !!req->wValue; + break; + + default: + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + break; + } + + return ret; +} + +static uint8_t +DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + struct usb_hid_softc *hid; + + hid = (struct usb_hid_softc *)pdev->pClassData; + + /* Previously queued data was sent */ + hid->state = IDLE; + + return USBD_OK; +} + +#if 0 +static uint8_t +DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + + /* received led status */ + + return USBD_OK; +} +#endif + +static uint8_t +ep0rxready(USBD_HandleTypeDef *pdev) +{ + + return USBD_OK; +} diff --git a/rs485hid/usb_hid_def.h b/rs485hid/usb_hid_def.h new file mode 100644 index 0000000..6429c87 --- /dev/null +++ b/rs485hid/usb_hid_def.h @@ -0,0 +1,6 @@ +#include + +#define REPORT_SIZE 8 + +void report_process(void); +int report_insert(uint8_t rep[REPORT_SIZE]); diff --git a/si_usb.c b/si_usb.c index 4e662d6..e8521b8 100644 --- a/si_usb.c +++ b/si_usb.c @@ -1,16 +1,18 @@ /* - * Code for initalizing USB CDC via the SYSINIT mechanism. + * Code for reseting USB via the SYSINIT mechanism. + * + * Note: This works for both Node151 and BluePill (F1) as PA12 is + * USB_DP on both. */ #include #include -#include #include static void -usb_cdc_init(const void *foo) +usb_reset(void) { /* * pretend that the device was newly plugged in @@ -32,18 +34,5 @@ usb_cdc_init(const void *foo) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET); HAL_Delay(10); - - MX_USB_DEVICE_Init(); -} - -extern PCD_HandleTypeDef hpcd_USB_FS; - - -void -USB_LP_IRQHandler(void) -{ - - HAL_PCD_IRQHandler(&hpcd_USB_FS); } - -SYSINIT(usb_cdc_init, SI_SUB_CONSOLE, SI_ORDER_FIRST, usb_cdc_init, NULL); +SYSINIT_VF(usb_reset, SI_SUB_USB, SI_ORDER_FIRST, usb_reset); diff --git a/stm32/f103c8t6/STM32F103C8T6_FLASH.ld b/stm32/f103c8t6/STM32F103C8T6_FLASH.ld index 2d1f0d6..3425e6b 100755 --- a/stm32/f103c8t6/STM32F103C8T6_FLASH.ld +++ b/stm32/f103c8t6/STM32F103C8T6_FLASH.ld @@ -55,6 +55,8 @@ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200 ; /* required amount of heap */ _Min_Stack_Size = 0x400 ; /* required amount of stack */ +_flash_page_size = 0x400 ; /* size of a flash page */ + /* Memories definition */ MEMORY { @@ -100,7 +102,6 @@ SECTIONS __start_set_sysinit_set = .; KEEP(*(set_sysinit_set)) /* sysinit linker sets */ __stop_set_sysinit_set = .; - . = ALIGN(4); } >FLASH .ARM.extab : { @@ -162,6 +163,20 @@ SECTIONS } >RAM AT> FLASH + .savestate : + { + . = ALIGN(_flash_page_size); + *(.savestate) /* save state */ + . = ALIGN(_flash_page_size); + } >FLASH + + .savekeys : + { + . = ALIGN(_flash_page_size); + *(.savekeys) /* save keys */ + . = ALIGN(_flash_page_size); + } >FLASH + /* Uninitialized data section into "RAM" Ram type memory */ . = ALIGN(4); .bss : diff --git a/stm32/usb/usb_gen.py b/stm32/usb/usb_gen.py new file mode 100644 index 0000000..1c719bc --- /dev/null +++ b/stm32/usb/usb_gen.py @@ -0,0 +1,216 @@ +import codecs +import construct +import importlib +import sys + +from usb_protocol.types.descriptors.standard import ConfigurationDescriptor, DescriptorFormat, EndpointDescriptor, InterfaceDescriptor, StandardDescriptorNumbers +from string import Template + +# Note this file is under the following copyright: +copyright = '''/*- + * Copyright 2022 John-Mark Gurney. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. If you are STMicroelectronics N.V., one of it's subsidiaries, a + * subsidiary of an owner of STMicroelectronics N.V., or an employee, + * contractor, or agent of any of the preceeding entities, you are not + * allowed to use this code, in either source or binary forms. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +''' + +UniDesc = DescriptorFormat( + "bLength" / construct.Int8ul, + "bDescriptorType" / construct.Int8ul, +) + +descparsers = { + StandardDescriptorNumbers.INTERFACE: InterfaceDescriptor.parse, + StandardDescriptorNumbers.ENDPOINT: EndpointDescriptor.parse, +} + +def getepdescs(confdesc): + ret = [] + + lastdesc = ConfigurationDescriptor.parse(confdesc) + pos = lastdesc.bLength + + while pos < len(confdesc): + descparser = descparsers.get(confdesc[pos + 1], UniDesc.parse) + desc = descparser(confdesc[pos:]) + + if confdesc[pos + 1] == StandardDescriptorNumbers.ENDPOINT: + ret.append(desc) + + lastdesc = desc + + pos += lastdesc.bLength + + return ret + +if __name__ == '__main__': + usbname = sys.argv[1] + + mod = importlib.import_module(usbname) + collection = mod.collection + + sorteddesc = sorted(collection) + descs = { (x, y): z for x, y, z in collection } + + for value, index, raw in sorteddesc: + print(int(value), repr(index), codecs.encode(raw, 'hex')) + + p = lambda *args, **kwargs: print(*args, **kwargs, file=fp) + + with open('%s_base.h' % usbname, 'w') as fp: + p(Template('''${copyright} + +#include + +extern USBD_ClassTypeDef ${usbname}_def; + +void USBD_GetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + +void ${usbname}_init(void); +void ${usbname}_epopen(USBD_HandleTypeDef *pdev); +void ${usbname}_epclose(USBD_HandleTypeDef *pdev); +''').substitute(locals())) + + with open('%s_base.c' % usbname, 'w') as fp: + descstrings = '\n'.join('const uint8_t desc_%d_%d[] = { %s };' % (x, y, ', '.join(hex(w) for w in z)) for x, y, z in sorteddesc) + descstructs = '\n'.join('\t{ .type = %d, .subnumb = %d, .datalen = %d, .data = desc_%d_%d },' % (x, y, len(z), x, y) for x, y, z in sorteddesc) + + epdescs = getepdescs(descs[(2, 0)]) + print(repr(epdescs)) + epopencode = '\n\t'.join(sum(([ + 'USBD_LL_OpenEP(pdev, %#x, %d, %d);' % (ep.bEndpointAddress, ep.bmAttributes & 0x3, ep.wMaxPacketSize), + 'pdev->%s[%#x & 0xFU].is_used = 1;' % ('ep_in' if ep.bEndpointAddress & 0x80 else 'ep_out', ep.bEndpointAddress) + ] for ep in epdescs), [])) + epclosecode = '\n\t'.join(sum(([ + 'USBD_LL_CloseEP(pdev, %#x);' % (ep.bEndpointAddress), + 'pdev->%s[%#x & 0xFU].is_used = 0;' % ('ep_in' if ep.bEndpointAddress & 0x80 else 'ep_out', ep.bEndpointAddress) + ] for ep in epdescs), [])) + print(repr(epopencode)) + + p(Template('''${copyright} +#include "${usbname}_base.h" + +#include + +#include +/* #include */ +/* #include */ + +static USBD_HandleTypeDef usbd_inst; + +void USBD_GetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + +${descstrings} + +static const struct { + uint8_t type; + uint8_t subnumb; + uint8_t datalen; + const uint8_t *data; +} descriptors[] = { +${descstructs} +}; + +void +USBD_GetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + uint8_t const *buf; + uint8_t buflen; + uint8_t type, subnumb; + int i; + + type = req->wValue >> 8; + subnumb = req->wValue & 0xff; + + for (i = 0; i < sizeof descriptors / sizeof *descriptors; i++) { + if (descriptors[i].type == type && descriptors[i].subnumb == subnumb) { + buf = descriptors[i].data; + buflen = descriptors[i].datalen; + if ((buflen != 0U) && (req->wLength != 0U)) { + buflen = MIN(buflen, req->wLength); + USBD_CtlSendData(pdev, (uint8_t *)(uintptr_t)buf, buflen); + } + + if(req->wLength == 0U) { + USBD_CtlSendStatus(pdev); + } + return; + } + } + + USBD_CtlError(pdev , req); +} + +void +${usbname}_init(void) +{ + + if (USBD_Init(&usbd_inst, NULL/*Desc, not used*/, DEVICE_FS) != USBD_OK) + Error_Handler(); + + if (USBD_RegisterClass(&usbd_inst, &${usbname}_def) != USBD_OK) + Error_Handler(); + + if (USBD_Start(&usbd_inst) != USBD_OK) + Error_Handler(); +} +SYSINIT_VF(${usbname}_init, SI_SUB_USB, SI_ORDER_MIDDLE, ${usbname}_init); + +void +${usbname}_epopen(USBD_HandleTypeDef *pdev) +{ + + ${epopencode} +} + +void +${usbname}_epclose(USBD_HandleTypeDef *pdev) +{ + + ${epclosecode} +} + +extern PCD_HandleTypeDef hpcd_USB_FS; +void +USB_LP_IRQHandler(void) +{ + + HAL_PCD_IRQHandler(&hpcd_USB_FS); +} + +static volatile uint32_t holding; +void +Error_Handler(void) +{ + +#if 0 + debug_printf("error_handler\\n"); +#endif + for (;;) holding++; +}''').substitute(locals())) + + print('enda') diff --git a/stm32/usb/usbd_ctlreq_nodesc.c b/stm32/usb/usbd_ctlreq_nodesc.c new file mode 100755 index 0000000..4d1e831 --- /dev/null +++ b/stm32/usb/usbd_ctlreq_nodesc.c @@ -0,0 +1,853 @@ +/** + ****************************************************************************** + * @file usbd_req.c + * @author MCD Application Team + * @brief This file provides the standard USB requests following chapter 9. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2015 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, 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.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ctlreq.h" +#include "usbd_ioreq.h" + + +/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_REQ + * @brief USB standard requests module + * @{ + */ + +/** @defgroup USBD_REQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Variables + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_FunctionPrototypes + * @{ + */ +#if 0 +static +#endif +void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static uint8_t USBD_GetLen(uint8_t *buf); + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Functions + * @{ + */ + + +/** +* @brief USBD_StdDevReq +* Handle standard usb device requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (req->bmRequest & USB_REQ_TYPE_MASK) + { + case USB_REQ_TYPE_CLASS: + case USB_REQ_TYPE_VENDOR: + pdev->pClass->Setup(pdev, req); + break; + + case USB_REQ_TYPE_STANDARD: + + switch (req->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + + USBD_GetDescriptor (pdev, req); + break; + + case USB_REQ_SET_ADDRESS: + USBD_SetAddress (pdev, req); + break; + + case USB_REQ_SET_CONFIGURATION: + USBD_SetConfig (pdev, req); + break; + + case USB_REQ_GET_CONFIGURATION: + USBD_GetConfig (pdev, req); + break; + + case USB_REQ_GET_STATUS: + USBD_GetStatus (pdev, req); + break; + + + case USB_REQ_SET_FEATURE: + USBD_SetFeature (pdev, req); + break; + + case USB_REQ_CLEAR_FEATURE: + USBD_ClrFeature (pdev, req); + break; + + default: + USBD_CtlError(pdev, req); + break; + } + break; + + default: + USBD_CtlError(pdev, req); + break; + } + + return ret; +} + +/** +* @brief USBD_StdItfReq +* Handle standard usb interface requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (req->bmRequest & USB_REQ_TYPE_MASK) + { + case USB_REQ_TYPE_CLASS: + case USB_REQ_TYPE_VENDOR: + case USB_REQ_TYPE_STANDARD: + switch (pdev->dev_state) + { + case USBD_STATE_DEFAULT: + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + + if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES) + { + ret = (USBD_StatusTypeDef)pdev->pClass->Setup (pdev, req); + + if ((req->wLength == 0U) && (ret == USBD_OK)) + { + USBD_CtlSendStatus(pdev); + } + } + else + { + USBD_CtlError(pdev, req); + } + break; + + default: + USBD_CtlError(pdev, req); + break; + } + break; + + default: + USBD_CtlError(pdev, req); + break; + } + + return USBD_OK; +} + +/** +* @brief USBD_StdEPReq +* Handle standard usb endpoint requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + + uint8_t ep_addr; + USBD_StatusTypeDef ret = USBD_OK; + USBD_EndpointTypeDef *pep; + ep_addr = LOBYTE(req->wIndex); + + switch (req->bmRequest & USB_REQ_TYPE_MASK) + { + + case USB_REQ_TYPE_CLASS: + case USB_REQ_TYPE_VENDOR: + pdev->pClass->Setup (pdev, req); + break; + + case USB_REQ_TYPE_STANDARD: + /* Check if it is a class request */ + if ((req->bmRequest & 0x60U) == 0x20U) + { + ret = (USBD_StatusTypeDef)pdev->pClass->Setup (pdev, req); + + return ret; + } + + switch (req->bRequest) + { + + case USB_REQ_SET_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00U) && (ep_addr != 0x80U)) + { + USBD_LL_StallEP(pdev, ep_addr); + USBD_LL_StallEP(pdev, 0x80U); + } + else + { + USBD_CtlError(pdev, req); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr != 0x00U) && (ep_addr != 0x80U) && (req->wLength == 0x00U)) + { + USBD_LL_StallEP(pdev, ep_addr); + } + } + USBD_CtlSendStatus(pdev); + + break; + + default: + USBD_CtlError(pdev, req); + break; + } + break; + + case USB_REQ_CLEAR_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00U) && (ep_addr != 0x80U)) + { + USBD_LL_StallEP(pdev, ep_addr); + USBD_LL_StallEP(pdev, 0x80U); + } + else + { + USBD_CtlError(pdev, req); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr & 0x7FU) != 0x00U) + { + USBD_LL_ClearStallEP(pdev, ep_addr); + } + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev, req); + break; + } + break; + + case USB_REQ_GET_STATUS: + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00U) && (ep_addr != 0x80U)) + { + USBD_CtlError(pdev, req); + break; + } + pep = ((ep_addr & 0x80U) == 0x80U) ? &pdev->ep_in[ep_addr & 0x7FU]:\ + &pdev->ep_out[ep_addr & 0x7FU]; + + pep->status = 0x0000U; + + USBD_CtlSendData (pdev, (uint8_t *)(void *)&pep->status, 2U); + break; + + case USBD_STATE_CONFIGURED: + if((ep_addr & 0x80U) == 0x80U) + { + if (pdev->ep_in[ep_addr & 0xFU].is_used == 0U) + { + USBD_CtlError(pdev, req); + break; + } + } + else + { + if (pdev->ep_out[ep_addr & 0xFU].is_used == 0U) + { + USBD_CtlError(pdev, req); + break; + } + } + + pep = ((ep_addr & 0x80U) == 0x80U) ? &pdev->ep_in[ep_addr & 0x7FU]:\ + &pdev->ep_out[ep_addr & 0x7FU]; + + if ((ep_addr == 0x00U) || (ep_addr == 0x80U)) + { + pep->status = 0x0000U; + } + else if(USBD_LL_IsStallEP(pdev, ep_addr)) + { + pep->status = 0x0001U; + } + else + { + pep->status = 0x0000U; + } + + USBD_CtlSendData (pdev, (uint8_t *)(void *)&pep->status, 2U); + break; + + default: + USBD_CtlError(pdev, req); + break; + } + break; + + default: + USBD_CtlError(pdev, req); + break; + } + break; + + default: + USBD_CtlError(pdev, req); + break; + } + + return ret; +} +#if 0 +/** +* @brief USBD_GetDescriptor +* Handle Get Descriptor requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint16_t len; + uint8_t *pbuf; + + + switch (req->wValue >> 8) + { +#if (USBD_LPM_ENABLED == 1U) + case USB_DESC_TYPE_BOS: + pbuf = pdev->pDesc->GetBOSDescriptor(pdev->dev_speed, &len); + break; +#endif + case USB_DESC_TYPE_DEVICE: + pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len); + break; + + case USB_DESC_TYPE_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + else + { + pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + break; + + case USB_DESC_TYPE_STRING: + switch ((uint8_t)(req->wValue)) + { + case USBD_IDX_LANGID_STR: + pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_MFC_STR: + pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_PRODUCT_STR: + pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_SERIAL_STR: + pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_CONFIG_STR: + pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len); + break; + + case USBD_IDX_INTERFACE_STR: + pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len); + break; + + default: +#if (USBD_SUPPORT_USER_STRING == 1U) + pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len); + break; +#else + USBD_CtlError(pdev , req); + return; +#endif + } + break; + case USB_DESC_TYPE_DEVICE_QUALIFIER: + + if(pdev->dev_speed == USBD_SPEED_HIGH) + { + pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(&len); + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(&len); + pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + default: + USBD_CtlError(pdev , req); + return; + } + + if((len != 0U) && (req->wLength != 0U)) + { + + len = MIN(len, req->wLength); + + USBD_CtlSendData (pdev, pbuf, len); + } + + if(req->wLength == 0U) + { + USBD_CtlSendStatus(pdev); + } +} +#endif + +/** +* @brief USBD_SetAddress +* Set device address +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint8_t dev_addr; + + if ((req->wIndex == 0U) && (req->wLength == 0U) && (req->wValue < 128U)) + { + dev_addr = (uint8_t)(req->wValue) & 0x7FU; + + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + USBD_CtlError(pdev , req); + } + else + { + pdev->dev_address = dev_addr; + USBD_LL_SetUSBAddress(pdev, dev_addr); + USBD_CtlSendStatus(pdev); + + if (dev_addr != 0U) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + } + else + { + pdev->dev_state = USBD_STATE_DEFAULT; + } + } + } + else + { + USBD_CtlError(pdev, req); + } +} + +/** +* @brief USBD_SetConfig +* Handle Set device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetConfig(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + static uint8_t cfgidx; + + cfgidx = (uint8_t)(req->wValue); + + if (cfgidx > USBD_MAX_NUM_CONFIGURATION) + { + USBD_CtlError(pdev, req); + } + else + { + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if (cfgidx) + { + pdev->dev_config = cfgidx; + pdev->dev_state = USBD_STATE_CONFIGURED; + if(USBD_SetClassConfig(pdev, cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev, req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + case USBD_STATE_CONFIGURED: + if (cfgidx == 0U) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + pdev->dev_config = cfgidx; + USBD_ClrClassConfig(pdev, cfgidx); + USBD_CtlSendStatus(pdev); + } + else if (cfgidx != pdev->dev_config) + { + /* Clear old configuration */ + USBD_ClrClassConfig(pdev, (uint8_t)pdev->dev_config); + + /* set new configuration */ + pdev->dev_config = cfgidx; + if(USBD_SetClassConfig(pdev, cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev, req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev, req); + USBD_ClrClassConfig(pdev, cfgidx); + break; + } + } +} + +/** +* @brief USBD_GetConfig +* Handle Get device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetConfig(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + if (req->wLength != 1U) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state) + { + case USBD_STATE_DEFAULT: + case USBD_STATE_ADDRESSED: + pdev->dev_default_config = 0U; + USBD_CtlSendData (pdev, (uint8_t *)(void *)&pdev->dev_default_config, 1U); + break; + + case USBD_STATE_CONFIGURED: + USBD_CtlSendData (pdev, (uint8_t *)(void *)&pdev->dev_config, 1U); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetStatus +* Handle Get Status request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetStatus(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + switch (pdev->dev_state) + { + case USBD_STATE_DEFAULT: + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + if(req->wLength != 0x2U) + { + USBD_CtlError(pdev, req); + break; + } + +#if ( USBD_SELF_POWERED == 1U) + pdev->dev_config_status = USB_CONFIG_SELF_POWERED; +#else + pdev->dev_config_status = 0U; +#endif + + if (pdev->dev_remote_wakeup) + { + pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; + } + + USBD_CtlSendData (pdev, (uint8_t *)(void *)&pdev->dev_config_status, 2U); + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + + +/** +* @brief USBD_SetFeature +* Handle Set device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 1U; + USBD_CtlSendStatus(pdev); + } + +} + + +/** +* @brief USBD_ClrFeature +* Handle clear device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + switch (pdev->dev_state) + { + case USBD_STATE_DEFAULT: + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 0U; + USBD_CtlSendStatus(pdev); + } + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + +/** +* @brief USBD_ParseSetupRequest +* Copy buffer into setup structure +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata) +{ + req->bmRequest = *(uint8_t *) (pdata); + req->bRequest = *(uint8_t *) (pdata + 1); + req->wValue = SWAPBYTE (pdata + 2); + req->wIndex = SWAPBYTE (pdata + 4); + req->wLength = SWAPBYTE (pdata + 6); + +} + +/** +* @brief USBD_CtlError +* Handle USB low level Error +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_CtlError( USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + USBD_LL_StallEP(pdev , 0x80U); + USBD_LL_StallEP(pdev , 0U); +} + + +/** + * @brief USBD_GetString + * Convert Ascii string into unicode one + * @param desc : descriptor buffer + * @param unicode : Formatted string buffer (unicode) + * @param len : descriptor length + * @retval None + */ +void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0U; + + if (desc != NULL) + { + *len = (uint16_t)USBD_GetLen(desc) * 2U + 2U; + unicode[idx++] = *(uint8_t *)(void *)len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != '\0') + { + unicode[idx++] = *desc++; + unicode[idx++] = 0U; + } + } +} + +/** + * @brief USBD_GetLen + * return the string length + * @param buf : pointer to the ascii string buffer + * @retval string length + */ +static uint8_t USBD_GetLen(uint8_t *buf) +{ + uint8_t len = 0U; + + while (*buf != '\0') + { + len++; + buf++; + } + + return len; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/strobe_rng_init.c b/strobe_rng_init.c index 3576cf2..9009906 100644 --- a/strobe_rng_init.c +++ b/strobe_rng_init.c @@ -31,8 +31,6 @@ #include #include -#include - #include #define nitems(x) (sizeof(x) / sizeof *(x)) @@ -66,6 +64,7 @@ strobe_rng_save(void) { rng_word_t tmp[sizeof rng_save / sizeof(rng_word_t)]; size_t i; + uint32_t primask; int r; /* @@ -74,7 +73,8 @@ strobe_rng_save(void) r = strobe_randomize((uint8_t *)tmp, sizeof tmp); (void)r; - CRITICAL_SECTION_BEGIN(); + primask = __get_PRIMASK(); + __disable_irq( ); HAL_FLASHEx_DATAEEPROM_Unlock(); @@ -83,5 +83,5 @@ strobe_rng_save(void) HAL_FLASHEx_DATAEEPROM_Lock(); - CRITICAL_SECTION_END(); + __set_PRIMASK(primask); } diff --git a/strobe_rng_init.h b/strobe_rng_init.h index 34d391b..a6c0d09 100644 --- a/strobe_rng_init.h +++ b/strobe_rng_init.h @@ -3,10 +3,6 @@ #define roundup(x, y) ((((x) + (y) - 1) / (y)) * (y)) typedef uint32_t rng_word_t; -extern const rng_word_t rng_save[roundup(32, sizeof(rng_word_t)) / sizeof(rng_word_t)]; - -void strobe_rng_init(void); -void strobe_rng_save(void); static inline void bare_strobe_randomize(uint8_t *ptr, ssize_t len)