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...main
| @@ -18,7 +18,8 @@ These are the device that are under conideration for the project: | |||||
| ### STM32F103C8 | ### 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. | Currently looking at USART3, B0 for DE, B1 for RE. | ||||
| @@ -55,3 +56,64 @@ D - Driver | |||||
| R - Receiver | R - Receiver | ||||
| RO Receiver output | RO Receiver output | ||||
| /RE Receiver enable (low enable) | /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. | |||||
| @@ -0,0 +1,41 @@ | |||||
| #include <board/simpflash.h> | |||||
| #include <stm32f1xx.h> | |||||
| #include <stm32f1xx_hal_flash.h> | |||||
| #include <strobe_rng_init.h> /* 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); | |||||
| } | |||||
| @@ -0,0 +1,5 @@ | |||||
| #include <stm32f1xx_hal.h> | |||||
| #include <sysinit.h> | |||||
| SYSINIT(hal_init, SI_SUB_HAL, SI_ORDER_FIRST, (void (*)(const void *))HAL_Init, NULL); | |||||
| @@ -0,0 +1 @@ | |||||
| void doflash(const void *dst, void *src, int bytes); | |||||
| @@ -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 <stm32f1xx_hal_flash.h> | |||||
| #include <stm32f1xx_hal_rcc.h> | |||||
| #include <sysinit.h> | |||||
| /* | |||||
| * 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); | |||||
| @@ -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 <strobe.h> | |||||
| #include <board/simpflash.h> | |||||
| #include <strobe_rng_init.h> | |||||
| #include "stm32f1xx.h" | |||||
| #include "stm32f1xx_hal.h" | |||||
| #include <stm32f1xx_hal_adc.h> | |||||
| #include <sysinit.h> | |||||
| #include <unistd.h> | |||||
| #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); | |||||
| @@ -23,10 +23,12 @@ | |||||
| # | # | ||||
| import asyncio | import asyncio | ||||
| import codecs | |||||
| import contextlib | import contextlib | ||||
| import functools | import functools | ||||
| import itertools | import itertools | ||||
| import os | import os | ||||
| import pathlib | |||||
| import sys | import sys | ||||
| import unittest | 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_SETUNSET = 5 # arg: (chan, val): sets chan to val | ||||
| CMD_ADV = 6 # arg: ([cnt]): advances to the next cnt (default 1) command | 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_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): | class LORANode(object): | ||||
| '''Implement a LORANode initiator. | '''Implement a LORANode initiator. | ||||
| @@ -140,7 +180,10 @@ class LORANode(object): | |||||
| def _encodeargs(*args): | def _encodeargs(*args): | ||||
| r = [] | r = [] | ||||
| for i in args: | 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) | return b''.join(r) | ||||
| @@ -153,6 +196,10 @@ class LORANode(object): | |||||
| 'response does not match, got: %s, expected: %s' % | 'response does not match, got: %s, expected: %s' % | ||||
| (repr(resp[0:1]), repr(cmdbyte))) | (repr(resp[0:1]), repr(cmdbyte))) | ||||
| r = resp[1:] | |||||
| if r: | |||||
| return r | |||||
| async def waitfor(self, length): | async def waitfor(self, length): | ||||
| return await self._sendcmd(CMD_WAITFOR, length) | return await self._sendcmd(CMD_WAITFOR, length) | ||||
| @@ -165,6 +212,14 @@ class LORANode(object): | |||||
| async def ping(self): | async def ping(self): | ||||
| return await self._sendcmd(CMD_PING) | 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): | async def adv(self, cnt=None): | ||||
| args = () | args = () | ||||
| if cnt is not None: | if cnt is not None: | ||||
| @@ -267,23 +322,52 @@ async def main(): | |||||
| from loraserv import DEFAULT_MADDR as maddr | 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, | parser.add_argument('-f', dest='schedfile', metavar='filename', type=str, | ||||
| help='Use commands from the file. One command per line.') | 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, | 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.') | 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='*', | parser.add_argument('args', metavar='CMD_ARG', type=str, nargs='*', | ||||
| help='Various commands to send to the device.') | help='Various commands to send to the device.') | ||||
| args = parser.parse_args() | 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: | if args.client: | ||||
| # Run a client | # Run a client | ||||
| mr = await multicast.create_multicast_receiver(maddr) | mr = await multicast.create_multicast_receiver(maddr) | ||||
| mt = await multicast.create_multicast_transmitter(maddr) | mt = await multicast.create_multicast_transmitter(maddr) | ||||
| @@ -313,16 +397,20 @@ async def main(): | |||||
| cb = syote_comms.process_msgfunc_t(client_call) | cb = syote_comms.process_msgfunc_t(client_call) | ||||
| # Initialize everything | # Initialize everything | ||||
| syote_comms.comms_init(commstate, cb, make_pktbuf(shared_key)) | |||||
| syote_comms.comms_init(commstate, cb, *commsinitargs) | |||||
| try: | try: | ||||
| while True: | while True: | ||||
| pkt = await mr.recv() | pkt = await mr.recv() | ||||
| msg = pkt[0] | msg = pkt[0] | ||||
| #_debprint('procmsg:', repr(msg)) | |||||
| out = syote_comms.comms_process_wrap( | out = syote_comms.comms_process_wrap( | ||||
| commstate, msg) | commstate, msg) | ||||
| #_debprint('resp:', repr(out)) | |||||
| if out: | if out: | ||||
| await mt.send(out) | await mt.send(out) | ||||
| finally: | finally: | ||||
| @@ -333,13 +421,13 @@ async def main(): | |||||
| msd = MulticastSyncDatagram(maddr) | msd = MulticastSyncDatagram(maddr) | ||||
| await msd.start() | await msd.start() | ||||
| l = LORANode(msd, shared=shared_key) | |||||
| l = LORANode(msd, **lorakwargs) | |||||
| await l.start() | await l.start() | ||||
| valid_cmds = { | valid_cmds = { | ||||
| 'waitfor', 'setunset', 'runfor', 'ping', 'adv', 'clear', | 'waitfor', 'setunset', 'runfor', 'ping', 'adv', 'clear', | ||||
| 'terminate', | |||||
| 'terminate', 'type', | |||||
| } | } | ||||
| if args.args and args.schedfile: | if args.args and args.schedfile: | ||||
| @@ -364,7 +452,10 @@ async def main(): | |||||
| fun = getattr(l, cmd) | 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__': | if __name__ == '__main__': | ||||
| asyncio.run(main()) | asyncio.run(main()) | ||||
| @@ -1096,7 +1187,7 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): | |||||
| @timeout(2) | @timeout(2) | ||||
| async def test_ccode(self): | async def test_ccode(self): | ||||
| _self = self | _self = self | ||||
| from ctypes import c_uint8 | |||||
| from ctypes import c_uint8, memmove | |||||
| # seed the RNG | # seed the RNG | ||||
| prngseed = b'abc123' | prngseed = b'abc123' | ||||
| @@ -1111,28 +1202,40 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): | |||||
| (CMD_WAITFOR, [ 30 ]), | (CMD_WAITFOR, [ 30 ]), | ||||
| (CMD_RUNFOR, [ 1, 50 ]), | (CMD_RUNFOR, [ 1, 50 ]), | ||||
| (CMD_PING, [ ]), | (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, [ ]), | (CMD_TERMINATE, [ ]), | ||||
| ] | ] | ||||
| def procmsg(msg, outbuf): | def procmsg(msg, outbuf): | ||||
| msgbuf = msg._from() | msgbuf = msg._from() | ||||
| cmd = msgbuf[0] | 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) | exptmsgs.pop(0) | ||||
| outbuf[0].pkt[0] = cmd | |||||
| outbuf[0].pktlen = 1 | |||||
| else: #pragma: no cover | 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 | # wrap the callback function | ||||
| cb = syote_comms.process_msgfunc_t(procmsg) | cb = syote_comms.process_msgfunc_t(procmsg) | ||||
| class CCodeSD(MockSyncDatagram): | class CCodeSD(MockSyncDatagram): | ||||
| async def runner(self): | 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 | # get message | ||||
| inmsg = await self.get() | inmsg = await self.get() | ||||
| @@ -1176,6 +1279,8 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): | |||||
| await l.ping() | await l.ping() | ||||
| await l.type('sHt') | |||||
| await l.terminate() | await l.terminate() | ||||
| await tsd.drain() | await tsd.drain() | ||||
| @@ -16,8 +16,14 @@ CFLAGS+= -Wall -Werror | |||||
| .include <$(.PARSEDIR)/mu.opts.mk> | .include <$(.PARSEDIR)/mu.opts.mk> | ||||
| .if ${MK_HAL_INIT} == "yes" | |||||
| .PATH: $(SRCTOP)/board | |||||
| SRCS+= hal_init.c | |||||
| .endif | |||||
| .if ${MK_SYSINIT} == "yes" | .if ${MK_SYSINIT} == "yes" | ||||
| .PATH: $(SRCTOP) | .PATH: $(SRCTOP) | ||||
| CFLAGS+= -I$(SRCTOP) | |||||
| SRCS+= sysinit.c | SRCS+= sysinit.c | ||||
| .endif | .endif | ||||
| @@ -29,6 +35,11 @@ STROBE_SRCS+= strobe.c \ | |||||
| x25519.c | x25519.c | ||||
| .endif | .endif | ||||
| .if ${MK_STROBE} == "yes" && ${MK_STM32F103} == "yes" | |||||
| .PATH: $(SRCTOP)/board | |||||
| STROBE_SRCS+= strobe_f1_rng_init.c | |||||
| .endif | |||||
| # LoRamac (SX1276) radio code | # LoRamac (SX1276) radio code | ||||
| .if ${MK_SX1276} == "yes" | .if ${MK_SX1276} == "yes" | ||||
| LORAMAC_SRC = $(SRCTOP)/loramac/src | 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 | ARMTARGET?= -mcpu=cortex-m3 -mthumb | ||||
| .PATH: $(STM32)/f103c8t6 | .PATH: $(STM32)/f103c8t6 | ||||
| .PATH: $(SRCTOP)/board | |||||
| LINKER_SCRIPT=$(STM32)/f103c8t6/STM32F103C8T6_FLASH.ld | LINKER_SCRIPT=$(STM32)/f103c8t6/STM32F103C8T6_FLASH.ld | ||||
| SRCS+= \ | SRCS+= \ | ||||
| misc.c \ | |||||
| f1_flash.c \ | |||||
| hal_generic.c \ | hal_generic.c \ | ||||
| startup_stm32f103xb.s \ | startup_stm32f103xb.s \ | ||||
| stm32_bluepill.c \ | |||||
| stm32f1xx_hal.c \ | stm32f1xx_hal.c \ | ||||
| stm32f1xx_hal_adc.c \ | |||||
| stm32f1xx_hal_adc_ex.c \ | |||||
| stm32f1xx_hal_cortex.c \ | stm32f1xx_hal_cortex.c \ | ||||
| stm32f1xx_hal_dma.c \ | stm32f1xx_hal_dma.c \ | ||||
| stm32f1xx_hal_flash.c \ | |||||
| stm32f1xx_hal_flash_ex.c \ | |||||
| stm32f1xx_hal_gpio.c \ | stm32f1xx_hal_gpio.c \ | ||||
| stm32f1xx_hal_pcd.c \ | stm32f1xx_hal_pcd.c \ | ||||
| stm32f1xx_hal_pcd_ex.c \ | stm32f1xx_hal_pcd_ex.c \ | ||||
| @@ -65,7 +82,6 @@ SRCS+= \ | |||||
| stm32f1xx_hal_rcc.c \ | stm32f1xx_hal_rcc.c \ | ||||
| stm32f1xx_hal_rcc_ex.c \ | stm32f1xx_hal_rcc_ex.c \ | ||||
| stm32f1xx_hal_uart.c \ | stm32f1xx_hal_uart.c \ | ||||
| stm32f1xx_ll_usb.c \ | |||||
| system_stm32f1xx.c | system_stm32f1xx.c | ||||
| CFLAGS+= -I$(STM32) | CFLAGS+= -I$(STM32) | ||||
| @@ -123,8 +139,8 @@ CFLAGS+= -I$(SRCTOP)/rs485hid | |||||
| # USB CDC | # USB CDC | ||||
| .if ${MK_USB_CDC} == "yes" | .if ${MK_USB_CDC} == "yes" | ||||
| .PATH: $(STM32)/usb | .PATH: $(STM32)/usb | ||||
| SRCS+= \ | |||||
| si_usb.c \ | |||||
| SRCS.USB_CDC+= \ | |||||
| misc.c \ | |||||
| usb_device.c \ | usb_device.c \ | ||||
| usbd_cdc.c \ | usbd_cdc.c \ | ||||
| usbd_cdc_if.c \ | usbd_cdc_if.c \ | ||||
| @@ -137,7 +153,28 @@ SRCS+= \ | |||||
| CFLAGS+= -I$(STM32)/usb | CFLAGS+= -I$(STM32)/usb | ||||
| .endif | .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 | stm32l1xx_ll_usb.c | ||||
| .endif | .endif | ||||
| @@ -2,6 +2,32 @@ | |||||
| # code. | # code. | ||||
| # | # | ||||
| # See bsd.mkopt.mk for more information. | # 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 \ | __DEFAULT_YES_OPTIONS = STROBE \ | ||||
| SYSINIT | SYSINIT | ||||
| @@ -11,8 +37,12 @@ __DEFAULT_NO_OPTIONS = \ | |||||
| RS485FRAME \ | RS485FRAME \ | ||||
| STM32F103 \ | STM32F103 \ | ||||
| SX1276 \ | 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> | .include <$(.PARSEDIR)/bsd.mkopt.mk> | ||||
| @@ -31,20 +31,14 @@ | |||||
| PROGEXT = .elf | PROGEXT = .elf | ||||
| DEPENDS += .arm_deps | |||||
| .for i in $(PROGS) | .for i in $(PROGS) | ||||
| ALLTGTS+= $(i)$(PROGEXT) $(i).list | ALLTGTS+= $(i)$(PROGEXT) $(i).list | ||||
| ASRCS.$(i) = $(SRCS) $(SRCS.$(i)) | ASRCS.$(i) = $(SRCS) $(SRCS.$(i)) | ||||
| OBJS.$(i) = $(ASRCS.$(i):C/.c$/.o/) | 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)) | $(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 | $(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) | $(ARMOBJDUMP) -h -S $(.ALLSRC) > $@ || (rm -f $@ && false) | ||||
| .endfor | .endfor | ||||
| .PHONY: depend | |||||
| depend: $(DEPENDS) | |||||
| .arm_deps: $(ARM_DEP_SRCS) | |||||
| .arm_deps: | |||||
| $(ARMCC) $(ARMTARGET) $(CFLAGS) $(.ALLSRC) -MM > $@ || (rm -f $@ && false) | |||||
| .for i in $(DEPENDS) | .for i in $(DEPENDS) | ||||
| .sinclude "$i" | .sinclude "$i" | ||||
| .endfor | .endfor | ||||
| @@ -61,7 +63,7 @@ all: $(ALLTGTS) | |||||
| .PHONY: runbuild | .PHONY: runbuild | ||||
| runbuild: $(SRCS) Makefile mk/*.mk | 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 | # native objects | ||||
| .SUFFIXES: .no | .SUFFIXES: .no | ||||
| @@ -1,2 +1,3 @@ | |||||
| coverage | coverage | ||||
| strobe/python | strobe/python | ||||
| git+https://www.funkthat.com/gitea/jmg/python-usb-protocol.git | |||||
| @@ -22,20 +22,64 @@ | |||||
| # SUCH DAMAGE. | # SUCH DAMAGE. | ||||
| # | # | ||||
| PROGS = rs485gw # lora.irr | |||||
| PROGS = rs485gw rs485hid | |||||
| SRCS.rs485gw = rs485gw.c | 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)/.. | .PATH: $(.CURDIR)/.. | ||||
| CFLAGS += -g | CFLAGS += -g | ||||
| CFLAGS += -I$(.CURDIR)/.. | |||||
| WITH_RS485FRAME = yes | |||||
| WITH_STM32F103 = yes | WITH_STM32F103 = yes | ||||
| WITH_USB_CDC = yes | WITH_USB_CDC = yes | ||||
| WITH_RS485FRAME = yes | |||||
| WITH_USB_HID = yes | |||||
| .include <../mk/boards.mk> | .include <../mk/boards.mk> | ||||
| EXTRA_DEPENDS+= $(STM32)/usb/usb_gen.py | |||||
| .include <../mk/mu.progs.mk> | .include <../mk/mu.progs.mk> | ||||
| usb_hid_base.c: $(STM32)/usb/usb_gen.py | |||||
| @@ -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 <misc.h> | |||||
| #include <sys/param.h> | |||||
| #include <stdarg.h> | |||||
| #include <stdint.h> | |||||
| #include <stdio.h> | |||||
| #include <string.h> | |||||
| #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 | |||||
| @@ -18,7 +18,7 @@ | |||||
| const char *rs485err = NULL; | const char *rs485err = NULL; | ||||
| static uint8_t rxbuf[1024]; | |||||
| static uint8_t rxbuf[128]; | |||||
| static txdone_fn_t txdone; | static txdone_fn_t txdone; | ||||
| static rxdone_fn_t rxdone; | static rxdone_fn_t rxdone; | ||||
| static txdone_fn_t errcb; | static txdone_fn_t errcb; | ||||
| @@ -62,7 +62,7 @@ settx(bool tx) | |||||
| else | else | ||||
| s = GPIO_PIN_RESET; | 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_0, s); | ||||
| HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, s); | HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, s); | ||||
| } | } | ||||
| @@ -71,11 +71,19 @@ void | |||||
| rs485_starttx(uint8_t *pkt, size_t len) | 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 */ | /* 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) { | if (doingrx) { | ||||
| HAL_UART_AbortReceive_IT(&rs485uart); | HAL_UART_AbortReceive_IT(&rs485uart); | ||||
| } | } | ||||
| #endif | |||||
| settx(true); | settx(true); | ||||
| @@ -99,6 +107,8 @@ HAL_UART_TxCpltCallback(UART_HandleTypeDef *phuart) | |||||
| if (phuart != &rs485uart || txdone == NULL) | if (phuart != &rs485uart || txdone == NULL) | ||||
| return; | return; | ||||
| for (int x = 0; x < 1000000; x++); | |||||
| settx(false); | settx(false); | ||||
| doingtx = 0; | doingtx = 0; | ||||
| @@ -140,12 +150,13 @@ HAL_UART_MspInit(UART_HandleTypeDef *huart) | |||||
| /* UM1850 § 38.1.2 Page 550 */ | /* UM1850 § 38.1.2 Page 550 */ | ||||
| /* 2.a */ | /* 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(); | __HAL_RCC_USART3_CLK_ENABLE(); | ||||
| /* 2.b */ | /* 2.b */ | ||||
| __HAL_RCC_GPIOB_CLK_ENABLE(); | __HAL_RCC_GPIOB_CLK_ENABLE(); | ||||
| /* TX pin */ | /* TX pin */ | ||||
| GPIO_InitStruct = (GPIO_InitTypeDef){ | GPIO_InitStruct = (GPIO_InitTypeDef){ | ||||
| .Pin = GPIO_PIN_10, | .Pin = GPIO_PIN_10, | ||||
| @@ -197,10 +208,17 @@ rs485_startrx() | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| doingrx = 1; | |||||
| r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf); | r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf); | ||||
| if (r == HAL_BUSY) { | if (r == HAL_BUSY) { | ||||
| rs485err = "already"; | |||||
| return 1; | |||||
| #if 0 | |||||
| /* This appears to corrupt state and break things */ | |||||
| HAL_UART_AbortReceive_IT(&rs485uart); | HAL_UART_AbortReceive_IT(&rs485uart); | ||||
| r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf); | r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf); | ||||
| #endif | |||||
| } | } | ||||
| rs485err = statustostr(r); | rs485err = statustostr(r); | ||||
| @@ -209,14 +227,16 @@ rs485_startrx() | |||||
| } | } | ||||
| static void | static void | ||||
| rs485frame_init(const void *v) | |||||
| rs485frame_init(void) | |||||
| { | { | ||||
| GPIO_InitTypeDef GPIO_InitStruct; | GPIO_InitTypeDef GPIO_InitStruct; | ||||
| __HAL_RCC_GPIOB_CLK_ENABLE(); | |||||
| /* setup DE/RE */ | /* setup DE/RE */ | ||||
| GPIO_InitStruct = (GPIO_InitTypeDef){ | GPIO_InitStruct = (GPIO_InitTypeDef){ | ||||
| .Pin = GPIO_PIN_0|GPIO_PIN_1, | .Pin = GPIO_PIN_0|GPIO_PIN_1, | ||||
| .Mode = GPIO_MODE_OUTPUT_OD, | |||||
| .Mode = GPIO_MODE_OUTPUT_PP, | |||||
| .Pull = GPIO_NOPULL, | .Pull = GPIO_NOPULL, | ||||
| .Speed = GPIO_SPEED_FREQ_LOW, /* 2 MHz */ | .Speed = GPIO_SPEED_FREQ_LOW, /* 2 MHz */ | ||||
| }; | }; | ||||
| @@ -240,4 +260,4 @@ rs485frame_init(const void *v) | |||||
| /* 4 */ | /* 4 */ | ||||
| HAL_UART_Init(&rs485uart); | 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); | |||||
| @@ -36,7 +36,18 @@ | |||||
| #include <sysinit.h> | #include <sysinit.h> | ||||
| SYSINIT(hal_init, SI_SUB_HAL, SI_ORDER_FIRST, (void (*)(const void *))HAL_Init, NULL); | |||||
| #include <usb_device.h> | |||||
| 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 int dorx = 0; | ||||
| static uint8_t rxbuf[128]; | static uint8_t rxbuf[128]; | ||||
| @@ -71,51 +82,6 @@ SYSINIT(c13led, SI_SUB_HAL, SI_ORDER_SECOND, c13led, NULL); | |||||
| #define usb_printf debug_printf | #define usb_printf debug_printf | ||||
| #endif | #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 * | char * | ||||
| findeol(char *pos, size_t len) | findeol(char *pos, size_t len) | ||||
| { | { | ||||
| @@ -167,19 +133,6 @@ rxdone(const uint8_t *payload, size_t size) | |||||
| gotrxdone = 1; | gotrxdone = 1; | ||||
| } | } | ||||
| void | |||||
| rxtimeout(void) | |||||
| { | |||||
| usb_printf("rxtimeout\r\n"); | |||||
| } | |||||
| void | |||||
| rxerr(void) | |||||
| { | |||||
| usb_printf("rxerr\r\n"); | |||||
| } | |||||
| static uint8_t | static uint8_t | ||||
| hexchartonib(char s) | hexchartonib(char s) | ||||
| { | { | ||||
| @@ -278,7 +231,7 @@ main(void) | |||||
| debug_printf("starting...\n"); | debug_printf("starting...\n"); | ||||
| #if 1 | |||||
| #if 0 | |||||
| int i; | int i; | ||||
| for (i = 0; i < 5; i++) { | for (i = 0; i < 5; i++) { | ||||
| HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); | HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); | ||||
| @@ -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 <stdbool.h> | |||||
| #include <comms.h> | |||||
| #include <misc.h> | |||||
| #include <rs485frame.h> | |||||
| #include <strobe_rng_init.h> | |||||
| #include <strobe_pki.h> | |||||
| #include <cycle.h> | |||||
| #include <sysinit.h> | |||||
| 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; | |||||
| } | |||||
| @@ -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 <stdint.h> | |||||
| #include <x25519.h> | |||||
| #include <board/simpflash.h> | |||||
| #include <strobe_rng_init.h> /* roundup */ | |||||
| #include <strobe_pki.h> | |||||
| 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 <public_key.h> | |||||
| 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; | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| #include <comms.h> | |||||
| struct strobepkikey { | |||||
| struct pktbuf privkey; | |||||
| struct pktbuf pubkey; | |||||
| }; | |||||
| struct strobepkikey get_key(void); | |||||
| void get_pubkey(uint8_t pubkey[EC_PUBLIC_BYTES]); | |||||
| @@ -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('<H', len(report_desc)) | |||||
| # add HID Descriptor after interface, but before | |||||
| # endpoint descriptors per HID v1.11 § 7.1 | |||||
| i.add_subordinate_descriptor(hid_desc) | |||||
| # No OUT endpoint. Use the SET_REPORT via the control EP | |||||
| with i.EndpointDescriptor() as e: | |||||
| e.bEndpointAddress = 0x81 | |||||
| e.bmAttributes = USBTransferType.INTERRUPT | |||||
| # it'd be good to adjust based upon FS vs LS | |||||
| e.bInterval = 10 # polling interval (LS/FS in ms) | |||||
| # Full-speed max size | |||||
| e.wMaxPacketSize = 64 | |||||
| @@ -0,0 +1,328 @@ | |||||
| /*- | |||||
| * 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. | |||||
| * | |||||
| */ | |||||
| #include "usb_hid_def.h" | |||||
| #include <misc.h> /* debug_printf */ | |||||
| #include <stdbool.h> | |||||
| #include <usb_hid_base.h> | |||||
| 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; | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| #include <stdint.h> | |||||
| #define REPORT_SIZE 8 | |||||
| void report_process(void); | |||||
| int report_insert(uint8_t rep[REPORT_SIZE]); | |||||
| @@ -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 <sysinit.h> | #include <sysinit.h> | ||||
| #include <stm32f1xx_hal_gpio.h> | #include <stm32f1xx_hal_gpio.h> | ||||
| #include <stm32f1xx_hal_pcd.h> | |||||
| #include <usb_device.h> | #include <usb_device.h> | ||||
| static void | static void | ||||
| usb_cdc_init(const void *foo) | |||||
| usb_reset(void) | |||||
| { | { | ||||
| /* | /* | ||||
| * pretend that the device was newly plugged in | * 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_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET); | ||||
| HAL_Delay(10); | 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); | |||||
| @@ -55,6 +55,8 @@ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ | |||||
| _Min_Heap_Size = 0x200 ; /* required amount of heap */ | _Min_Heap_Size = 0x200 ; /* required amount of heap */ | ||||
| _Min_Stack_Size = 0x400 ; /* required amount of stack */ | _Min_Stack_Size = 0x400 ; /* required amount of stack */ | ||||
| _flash_page_size = 0x400 ; /* size of a flash page */ | |||||
| /* Memories definition */ | /* Memories definition */ | ||||
| MEMORY | MEMORY | ||||
| { | { | ||||
| @@ -100,7 +102,6 @@ SECTIONS | |||||
| __start_set_sysinit_set = .; | __start_set_sysinit_set = .; | ||||
| KEEP(*(set_sysinit_set)) /* sysinit linker sets */ | KEEP(*(set_sysinit_set)) /* sysinit linker sets */ | ||||
| __stop_set_sysinit_set = .; | __stop_set_sysinit_set = .; | ||||
| . = ALIGN(4); | |||||
| } >FLASH | } >FLASH | ||||
| .ARM.extab : { | .ARM.extab : { | ||||
| @@ -162,6 +163,20 @@ SECTIONS | |||||
| } >RAM AT> FLASH | } >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 */ | /* Uninitialized data section into "RAM" Ram type memory */ | ||||
| . = ALIGN(4); | . = ALIGN(4); | ||||
| .bss : | .bss : | ||||
| @@ -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 <usbd_core.h> | |||||
| 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 <sysinit.h> | |||||
| #include <usbd_core.h> | |||||
| /* #include <usbd_desc.h> */ | |||||
| /* #include <usbd_conf.h> */ | |||||
| 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') | |||||
| @@ -0,0 +1,853 @@ | |||||
| /** | |||||
| ****************************************************************************** | |||||
| * @file usbd_req.c | |||||
| * @author MCD Application Team | |||||
| * @brief This file provides the standard USB requests following chapter 9. | |||||
| ****************************************************************************** | |||||
| * @attention | |||||
| * | |||||
| * <h2><center>© Copyright (c) 2015 STMicroelectronics. | |||||
| * All rights reserved.</center></h2> | |||||
| * | |||||
| * 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****/ | |||||
| @@ -31,8 +31,6 @@ | |||||
| #include <stm32l1xx.h> | #include <stm32l1xx.h> | ||||
| #include <stm32l1xx_hal_flash_ex.h> | #include <stm32l1xx_hal_flash_ex.h> | ||||
| #include <utilities.h> | |||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #define nitems(x) (sizeof(x) / sizeof *(x)) | #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)]; | rng_word_t tmp[sizeof rng_save / sizeof(rng_word_t)]; | ||||
| size_t i; | size_t i; | ||||
| uint32_t primask; | |||||
| int r; | int r; | ||||
| /* | /* | ||||
| @@ -74,7 +73,8 @@ strobe_rng_save(void) | |||||
| r = strobe_randomize((uint8_t *)tmp, sizeof tmp); | r = strobe_randomize((uint8_t *)tmp, sizeof tmp); | ||||
| (void)r; | (void)r; | ||||
| CRITICAL_SECTION_BEGIN(); | |||||
| primask = __get_PRIMASK(); | |||||
| __disable_irq( ); | |||||
| HAL_FLASHEx_DATAEEPROM_Unlock(); | HAL_FLASHEx_DATAEEPROM_Unlock(); | ||||
| @@ -83,5 +83,5 @@ strobe_rng_save(void) | |||||
| HAL_FLASHEx_DATAEEPROM_Lock(); | HAL_FLASHEx_DATAEEPROM_Lock(); | ||||
| CRITICAL_SECTION_END(); | |||||
| __set_PRIMASK(primask); | |||||
| } | } | ||||
| @@ -3,10 +3,6 @@ | |||||
| #define roundup(x, y) ((((x) + (y) - 1) / (y)) * (y)) | #define roundup(x, y) ((((x) + (y) - 1) / (y)) * (y)) | ||||
| typedef uint32_t rng_word_t; | 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 | static inline void | ||||
| bare_strobe_randomize(uint8_t *ptr, ssize_t len) | bare_strobe_randomize(uint8_t *ptr, ssize_t len) | ||||