|
- /*-
- * 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 "stm32l1xx.h"
- #include "stm32l1xx_hal.h"
-
- /* LoRaMac headers */
- #include <board.h>
- #include <adc.h>
- #include <radio.h>
- #include <delay.h>
-
- /* lora-irr headers */
- #include <misc.h>
- #include <strobe_rng_init.h>
- #include <comms.h>
-
- #include <sysinit.h>
-
- enum {
- CMD_TERMINATE = 1,
- CMD_WAITFOR = 2,
- CMD_RUNFOR = 3,
- CMD_PING = 4,
- CMD_SETUNSET = 5,
- CMD_ADV = 6,
- CMD_CLEAR = 7,
- };
-
- /*
- * rxpktavail is initialized to true meaning that the data in rxpkt
- * can be over written. When a packet is received, the data is copied
- * to rxpkt, and then rxpktavail is set to false. Once the packet has
- * been processed, it is set back to true.
- */
- static uint8_t rxpkt[128];
- static struct pktbuf rxpktbuf;
- static volatile bool rxpktavail;
-
- #include <shared_key.h>
-
- static struct comms_state cs;
-
- void
- txdone(void)
- {
-
- /* restart Rx when Tx done */
- Radio.Rx(0);
- }
-
- void
- txtimeout(void)
- {
-
- /* restart Rx when Tx done */
- Radio.Rx(0);
- }
-
- void
- rxdone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
- {
-
- if (rxpktavail && size <= sizeof rxpkt) {
- memcpy(rxpkt, payload, size);
- rxpktbuf = (struct pktbuf){
- .pkt = rxpkt,
- .pktlen = size,
- };
- rxpktavail = false;
- }
- Radio.Rx(0);
- }
-
- void
- rxtimeout(void)
- {
-
- Radio.Rx(0);
- }
-
- void
- rxerr(void)
- {
-
- Radio.Rx(0);
- }
-
- RadioEvents_t revents = {
- .TxDone = txdone,
- .TxTimeout = txtimeout,
- .RxDone = rxdone,
- .RxTimeout = rxtimeout,
- .RxError = rxerr,
- };
-
- /*
- * Seed the randomness from the radio. This is not a great
- * seed, and is hard to gauge how much randomness is really
- * there. Assuming about 1 bit per 8 bits looks pretty safe,
- * so add 256 * 8 / 32 words.
- */
- static void
- radio_seed_rng(void)
- {
- #if 1
- uint32_t v;
- int i;
-
- for (i = 0; i < 256 * 8 / 32; i++) {
- v = Radio.Random();
- strobe_seed_prng((uint8_t *)&v, sizeof v);
- }
- #endif
- }
- SYSINIT_VF(radio_seed_rng, SI_SUB_STANDARD, SI_ORDER_ANY, radio_seed_rng);
-
- static void
- analog_seed_rng(void)
- {
- #if 1
- uint16_t v;
- int i;
-
- for (i = 0; i < 256 / 2; i++) {
- /*
- * Capture some ADC data. If pin is floating, 0xfff
- * happens frequently, if pin is grounded, 0 happens
- * frequently, filter these values out.
- */
- do {
- v = AdcReadChannel(&Adc, ADC_CHANNEL_21);
- } while (v == 0 || v == 0xfff);
- strobe_seed_prng((uint8_t *)&v, sizeof v);
- }
- #endif
- }
- SYSINIT_VF(analog_seed_rng, SI_SUB_STANDARD, SI_ORDER_ANY, analog_seed_rng);
-
- static inline uint32_t
- letoh_32(uint8_t *v)
- {
- return v[0] | (v[1] << 8) | (v[2] << 16) | ((unsigned)v[3] << 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()
- {
- 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_HAL, SI_ORDER_LAST, 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];
- int i, apos, cnt;
-
- i = 1;
- apos = 0;
- while (i < inbuf.pktlen) {
- if (i + 4 <= inbuf.pktlen) {
- args[apos++] = letoh_32(&inbuf.pkt[i]);
- i += 4;
- }
- }
-
- outbuf->pkt[0] = inbuf.pkt[0];
-
- 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;
-
- default:
- outbuf->pkt[0] = 0;
- break;
- }
-
- outbuf->pktlen = 1;
- }
-
- void
- radio_init(void)
- {
-
- Radio.Init(&revents);
- }
-
- SYSINIT_VF(radio_init, SI_SUB_HAL, SI_ORDER_MIDDLE, radio_init);
-
- int
- main()
- {
-
- /* turn on LED */
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
-
- Radio.SetModem(MODEM_LORA);
- Radio.SetChannel(914350 * 1000);
-
- /* RX/TX parameters */
- const uint8_t modem = MODEM_LORA;
- const uint8_t bandwidth = 0 /* 128 kHz */;
- const uint8_t datarate = 7 /* 128 chips */;
- const uint8_t coderate = 1 /* 4/5 */;
- const uint8_t preambleLen = 8 /* symbols */;
- const uint8_t fixLen = 0 /* variable */;
- const uint8_t crcOn = 1 /* on */;
- const uint8_t freqHopOn = 0 /* off */;
- const bool iqInverted = false /* not inverted */;
-
- Radio.SetRxConfig(modem, bandwidth, datarate, coderate, 0/*afc*/,
- preambleLen, 5/*symTimeout*/, fixLen, 0/*payloadlen*/, crcOn,
- freqHopOn, 0/*hopPeriod*/, iqInverted, true/*rxcont*/);
- Radio.SetTxConfig(modem, 11/*power*/, 0/*fdev*/, bandwidth, datarate,
- coderate, preambleLen, fixLen, crcOn, freqHopOn, 0/*hopPeriod*/,
- iqInverted, 1000/*timeout*/);
-
- /* blink led */
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
- DelayMs(300);
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
-
- Radio.Rx(0);
-
- comms_init(&cs, procmsg, &shared_key_buf, NULL, NULL);
-
- uint8_t txbuf[128] = "i'mhere";
- struct pktbuf txpktbuf;
-
- txpktbuf = (struct pktbuf){
- .pkt = txbuf,
- .pktlen = 8,
- };
- Radio.Send(txpktbuf.pkt, txpktbuf.pktlen);
-
- rxpktavail = true;
-
- //Radio.Rx(0);
-
- loop:
- while (canproc_sched())
- process_sched();
-
- BoardLowPowerHandler();
- if (Radio.IrqProcess != NULL)
- Radio.IrqProcess();
-
- if (!rxpktavail) {
- txpktbuf = (struct pktbuf){
- .pkt = txbuf,
- .pktlen = sizeof txbuf,
- };
- /* process available packet */
- comms_process(&cs, rxpktbuf, &txpktbuf);
-
- rxpktavail = true;
-
- if (txpktbuf.pktlen) {
- int i;
- for (i = 0; i < 1; i++) {
- DelayMs(20);
- Radio.Send(txpktbuf.pkt, txpktbuf.pktlen);
- }
-
- #if 0
- /* blink led */
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
- DelayMs(300);
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
- DelayMs(300);
- #endif
- }
-
- #if 0
- /* blink led */
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
- DelayMs(300);
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
- #endif
- }
- goto loop;
- }
|