Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: SX127x sx12xx_hal
main.cpp
- Committer:
- dudmuck
- Date:
- 2017-08-11
- Revision:
- 17:763412df6872
- Parent:
- 16:67fa19bc6331
- Child:
- 18:806cf9b7a904
File content as of revision 17:763412df6872:
#include "lorawan.h"
#include "tim.h"
#include "commands.h"
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
//#define TYPE_ABZ
RawSerial pc(USBTX, USBRX);
Timer timer;
//#if defined(TARGET_DISCO_L072CZ_LRWAN1)
#if defined(TARGET_NUCLEO_L073RZ) && defined(TYPE_ABZ)
SPI spi(PA_7, PA_6, PB_3); // mosi, miso, sclk
// dio0, dio1, nss, spi, rst
SX127x radio(PB_4, PB_1, PA_15, spi, PC_0); // sx1276 arduino shield
#define CRF1 PA_1
#define CRF2 PC_2
#define CRF3 PC_1
DigitalOut Vctl1(CRF1);
DigitalOut Vctl2(CRF2);
DigitalOut Vctl3(CRF3);
void rfsw_callback()
{
if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER) {
Vctl1 = 0;
if (radio.RegPaConfig.bits.PaSelect) {
Vctl2 = 0;
Vctl3 = 1;
} else {
Vctl2 = 1;
Vctl3 = 0;
}
} else {
if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE)
Vctl1 = 1;
else
Vctl1 = 0;
Vctl2 = 0;
Vctl3 = 0;
}
}
#else
SPI spi(D11, D12, D13); // mosi, miso, sclk
// dio0, dio1, nss, spi, rst
SX127x radio( D2, D3, D10, spi, A0); // sx1276 arduino shield
DigitalInOut rfsw(A4);
void rfsw_callback()
{
if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER)
rfsw = 1;
else
rfsw = 0;
}
#endif
char pcbuf[64];
int pcbuf_len;
uint8_t beacon_payload[4];
uint32_t tx_ms;
unsigned int skip_beacon_cnt;
SX127x_lora lora(radio);
float starting_bg_rssi;
#define N_SAMPLES 64
void channel_scan()
{
int min_ch, ch;
uint32_t hz = LORAMAC_FIRST_CHANNEL;
int acc[LORA_MAX_NB_CHANNELS];
radio.set_opmode(RF_OPMODE_STANDBY);
for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
int i;
float MHz = (float)hz / 1e6;
radio.set_frf_MHz(MHz);
radio.set_opmode(RF_OPMODE_RECEIVER);
acc[ch] = 0;
for (i = 0; i < N_SAMPLES; i++) {
int rssi = lora.get_current_rssi();
acc[ch] += rssi;
wait(0.01);
}
radio.set_opmode(RF_OPMODE_STANDBY);
printf("ch%u: %f\r\n", ch, acc[ch] / (float)N_SAMPLES);
hz += LORAMAC_STEPWIDTH_CHANNEL;
radio.set_frf_MHz((float)hz/1e6);
}
int min = 0x7fffffff;
min_ch = 0;
for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
if (acc[ch] < min) {
min = acc[ch];
min_ch = ch;
}
}
hz = LORAMAC_FIRST_CHANNEL + (min_ch * LORAMAC_STEPWIDTH_CHANNEL);
printf("using ch%u, %luhz\r\n", min_ch, hz);
radio.set_frf_MHz((float)hz/1e6);
starting_bg_rssi = acc[min_ch] / (float)N_SAMPLES;
}
void measure_ambient()
{
int i, acc = 0;
float bg_rssi;
float diff;
static unsigned cnt = 0;
for (i = 0; i < N_SAMPLES; i++) {
int rssi = lora.get_current_rssi();
acc += rssi;
wait(0.01);
}
bg_rssi = acc / (float)N_SAMPLES;
diff = bg_rssi - starting_bg_rssi;
printf("bg_rssi:%.1fdBm vs %1.fdBm, diff:%.1f, %d\r\n", bg_rssi, starting_bg_rssi, diff, cnt);
if (diff > 10) {
if (++cnt > 3) {
/* find better channel */
channel_scan();
lora.start_rx(RF_OPMODE_RECEIVER);
cnt = 0;
}
} else
cnt = 0;
}
void init_radio()
{
radio.set_opmode(RF_OPMODE_STANDBY);
radio.RegPaConfig.bits.OutputPower = 15;
radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
lora.enable();
lora.setBw_KHz(BANDWIDTH_KHZ);
lora.setSf(LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
channel_scan();
radio.write_reg(REG_LR_SYNC_BYTE, LORA_MAC_PUBLIC_SYNCWORD);
radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, 255);
}
void printLoraIrqs(bool clear)
{
printf("\r\nIrqFlags:");
if (lora.RegIrqFlags.bits.CadDetected)
printf("CadDetected ");
if (lora.RegIrqFlags.bits.FhssChangeChannel) {
printf("FhssChangeChannel:%d ", lora.RegHopChannel.bits.FhssPresentChannel);
}
if (lora.RegIrqFlags.bits.CadDone)
printf("CadDone ");
if (lora.RegIrqFlags.bits.TxDone)
printf("TxDone-dio0:%d ", radio.dio0.read());
if (lora.RegIrqFlags.bits.ValidHeader)
printf("[42mValidHeader[0m ");
if (lora.RegIrqFlags.bits.PayloadCrcError)
printf("[41mPayloadCrcError[0m ");
if (lora.RegIrqFlags.bits.RxDone)
printf("[42mRxDone[0m ");
if (lora.RegIrqFlags.bits.RxTimeout)
printf("RxTimeout ");
printf("\r\n");
if (clear)
radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
}
void printOpMode()
{
radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
switch (radio.RegOpMode.bits.Mode) {
case RF_OPMODE_SLEEP: printf("[7msleep[0m"); break;
case RF_OPMODE_STANDBY: printf("[7mstby[0m"); break;
case RF_OPMODE_SYNTHESIZER_TX: printf("[33mfstx[0m"); break;
case RF_OPMODE_TRANSMITTER: printf("[31mtx[0m"); break;
case RF_OPMODE_SYNTHESIZER_RX: printf("[33mfsrx[0m"); break;
case RF_OPMODE_RECEIVER: printf("[32mrx[0m"); break;
case 6:
if (radio.RegOpMode.bits.LongRangeMode)
printf("[42mrxs[0m");
else
printf("-6-");
break; // todo: different lora/fsk
case 7:
if (radio.RegOpMode.bits.LongRangeMode)
printf("[45mcad[0m");
else
printf("-7-");
break; // todo: different lora/fsk
}
}
//#define GPO_IDX 6
void decrypted_uplink(uint32_t dev_addr, uint8_t* buf, uint8_t buflen, uint8_t port)
{
if (port == SENSOR_PORT) {
uint8_t i = 0;
uint16_t lum = buf[i++] << 8;
lum += buf[i++];
LoRaWan::filtered_printf(dev_addr, "SENSOR lum:%u\r\n", lum);
while (i < buflen) {
uint16_t a_a, a_b, p;
a_a = buf[i++] << 8;
a_a += buf[i++];
a_b = buf[i++] << 8;
a_b += buf[i++];
p = buf[i++];
LoRaWan::filtered_printf(dev_addr, "%x, %u, %u, %u, %u\r\n",
dev_addr,
a_a, /* analog */
a_b, /* analog */
(p & 2) >> 1, /* digital in */
p & 1 /* digital out */
);
}
} else {
int i;
LoRaWan::filtered_printf(dev_addr, "port%u: ", port);
for (i = 0; i < buflen; i++)
LoRaWan::filtered_printf(dev_addr, "%02x ", buf[i]);
LoRaWan::filtered_printf(dev_addr, "\r\n");
}
}
EventQueue queue;
volatile bool get_tx_done;
volatile bool beacon_guard;
bool restore_tx_invert;
bool restore_header_mode;
void send_downlink()
{
if (!beacon_guard && LoRaWan::do_downlink) {
radio.set_opmode(RF_OPMODE_STANDBY);
radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
lora.invert_tx(true);
restore_tx_invert = true;
lora.setRxPayloadCrcOn(false);
lora.start_tx(lora.RegPayloadLength);
LoRaWan::do_downlink = false;
get_tx_done = true;
tx_ms = timer.read_ms();
}
}
void
service_radio()
{
service_action_e act = lora.service();
switch (act) {
case SERVICE_ERROR:
printf("SERVICE_ERROR\r\n");
case SERVICE_TX_DONE:
case SERVICE_NONE:
break;
case SERVICE_READ_FIFO:
LoRaWan::rx_slot = tim_get_current_slot();
LoRaWan::rx_ms = timer.read_ms();
radio.set_opmode(RF_OPMODE_STANDBY);
LoRaWan::parse_receive();
if (!LoRaWan::do_downlink) {
/* if not sending downlink, start receiver now */
lora.start_rx(RF_OPMODE_RECEIVER);
}
break;
} // ..switch (act)
}
volatile float prev_beacon_send_at;
volatile float beacon_send_at;
volatile float beacon_loaded_at;
volatile bool beacon_loaded;
void
send_beacon()
{
prev_beacon_send_at = beacon_send_at;
beacon_send_at = timer.read();
if (!beacon_loaded)
return;
radio.set_opmode(RF_OPMODE_TRANSMITTER);
beacon_loaded = false;
get_tx_done = true;
tx_ms = timer.read_ms();
}
static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
{
// The CRC calculation follows CCITT
const uint16_t polynom = 0x1021;
// CRC initial value
uint16_t crc = 0x0000;
if( buffer == NULL )
{
return 0;
}
for( uint16_t i = 0; i < length; ++i )
{
crc ^= ( uint16_t ) buffer[i] << 8;
for( uint16_t j = 0; j < 8; ++j )
{
crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
}
}
return crc;
}
void
_load_beacon()
{
uint16_t crc;
radio.set_opmode(RF_OPMODE_STANDBY);
// clear any flags which might have been set during beacon_guard
radio.write_reg(REG_LR_IRQFLAGS, 0xff);
lora.RegPayloadLength = BEACON_SIZE;
radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
lora.setHeaderMode(true);
restore_header_mode = true;
if (skip_beacon_cnt > 0) {
//printf("skip_beacon_cnt:%d\r\n", skip_beacon_cnt);
lora.invert_tx(true);
restore_tx_invert = true;
skip_beacon_cnt--;
}
radio.tx_buf[0] = beacon_payload[0];
radio.tx_buf[1] = beacon_payload[1];
radio.tx_buf[2] = beacon_payload[2];
radio.tx_buf[3] = beacon_payload[3];
beacon_payload[0] = CMD_NONE;
crc = beacon_crc(radio.tx_buf, 4);
radio.tx_buf[4] = crc & 0xff;
radio.tx_buf[5] = crc >> 8;
// DIO0 to TxDone
radio.RegDioMapping1.bits.Dio0Mapping = 1;
radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
// set FifoPtrAddr to FifoTxPtrBase
radio.write_reg(REG_LR_FIFOADDRPTR, radio.read_reg(REG_LR_FIFOTXBASEADDR));
// write PayloadLength bytes to fifo
lora.write_fifo(lora.RegPayloadLength);
// prepare for tx to occur in send_beacon()
radio.set_opmode(RF_OPMODE_SYNTHESIZER_TX);
beacon_loaded = true;
beacon_loaded_at = timer.read();
}
void load_beacon()
{
beacon_guard = true;
queue.call_in(200, _load_beacon);
}
void get_time_till_beacon()
{
uint16_t slots = tim_get_current_slot();
printf("slots:%u\r\n", slots);
}
void rx_isr()
{
static uint8_t pcbuf_idx = 0;
static uint8_t prev_len = 0;;
char c = pc.getc();
if (c == 8) {
if (pcbuf_idx > 0) {
pc.putc(8);
pc.putc(' ');
pc.putc(8);
pcbuf_idx--;
}
} else if (c == 3) { // ctrl-C
pcbuf_len = -1;
} else if (c == '\r') {
if (pcbuf_idx == 0) {
pcbuf_len = prev_len;
} else {
pcbuf[pcbuf_idx] = 0; // null terminate
prev_len = pcbuf_idx;
pcbuf_idx = 0;
pcbuf_len = prev_len;
}
} else if (pcbuf_idx < sizeof(pcbuf)) {
pcbuf[pcbuf_idx++] = c;
pc.putc(c);
}
}
void cmd_skip_beacon(uint8_t idx)
{
if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
}
printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
}
void cmd_list_motes(uint8_t idx)
{
int i;
for (i = 0; i < N_MOTES; i++) {
if (motes[i].dev_addr != DEVADDR_NONE) {
LoRaWan::print_octets_rev("", motes[i].dev_eui, LORA_EUI_LENGTH);
printf(" %" PRIx32 "\r\n", motes[i].dev_addr);
}
}
}
void
cmd_beacon_payload(uint8_t idx)
{
uint32_t i;
uint32_t* ptr;
sscanf(pcbuf+idx, "%" PRIx32, &i);
printf("beacon_payload:%08" PRIx32 "\r\n", i);
ptr = (uint32_t*)beacon_payload;
*ptr = i;
}
void
cmd_send_downlink(uint8_t idx)
{
ota_mote_t* mote = NULL;
int i;
unsigned int dev_addr;
sscanf(pcbuf+idx, "%x", &dev_addr);
for (i = 0; i < N_MOTES; i++) {
if (motes[i].dev_addr == dev_addr) {
break;
}
}
if (i == N_MOTES) {
printf("mote %x not found\r\n", dev_addr);
return;
}
mote = &motes[i];
while (pcbuf[idx] != ' ') {
if (pcbuf[++idx] == 0) {
printf("hit end\r\n");
return;
}
}
idx++; // step past space
mote->user_downlink_length = 0;
while (pcbuf[idx] > ' ') {
int o;
sscanf(pcbuf+idx, "%02x", &o);
LoRaWan::user_downlink[mote->user_downlink_length++] = o;
idx += 2;
}
printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
}
void cmd_rx_restart(uint8_t idx)
{
/*radio.set_opmode(RF_OPMODE_STANDBY);
printf("standby\r\n");*/
radio.set_opmode(RF_OPMODE_SLEEP);
printf("sleep\r\n");
wait(0.05);
radio.set_opmode(RF_OPMODE_RECEIVER);
printf("receive\r\n");
}
void cmd_beacon_gpo(uint8_t idx)
{
int gpo;
sscanf(pcbuf+idx, "%d", &gpo);
beacon_payload[0] = CMD_GPIO_OUT;
beacon_payload[1] = gpo;
printf("beacon gpo: %d\r\n", gpo);
}
void cmd_beacon_rgb(uint8_t idx)
{
int r, g ,b;
sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
beacon_payload[0] = CMD_LED_RGB;
beacon_payload[1] = r;
beacon_payload[2] = g;
beacon_payload[3] = b;
printf("beacon rgb: %d %d %d\r\n", r, g, b);
}
void cmd_downlink_rgb(uint8_t idx)
{
ota_mote_t* mote = NULL;
int i, r, g ,b;
unsigned int dev_addr;
sscanf(pcbuf+idx, "%x %d %d %d", &dev_addr, &r, &g, &b);
for (i = 0; i < N_MOTES; i++) {
if (motes[i].dev_addr == dev_addr) {
break;
}
}
if (i == N_MOTES) {
printf("mote %x not found\r\n", dev_addr);
return;
}
mote = &motes[i];
mote->user_downlink_length = 0;
LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_LED_RGB;
LoRaWan::user_downlink[mote->user_downlink_length++] = r;
LoRaWan::user_downlink[mote->user_downlink_length++] = g;
LoRaWan::user_downlink[mote->user_downlink_length++] = b;
printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
}
void cmd_downlink_gpo(uint8_t idx)
{
ota_mote_t* mote = NULL;
int i, gpo;
unsigned int dev_addr;
sscanf(pcbuf+idx, "%x %d", &dev_addr, &gpo);
for (i = 0; i < N_MOTES; i++) {
if (motes[i].dev_addr == dev_addr) {
break;
}
}
if (i == N_MOTES) {
printf("mote %x not found\r\n", dev_addr);
return;
}
mote = &motes[i];
mote->user_downlink_length = 0;
LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_GPIO_OUT;
LoRaWan::user_downlink[mote->user_downlink_length++] = gpo;
printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);
}
void cmd_status(uint8_t idx)
{
radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
if (radio.RegPaConfig.bits.PaSelect)
printf("PA_BOOST ");
else
printf("RFO ");
radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
printf("%.3fMHz sf%ubw%u ", radio.get_frf_MHz(), lora.getSf(), lora.getBw());
printOpMode();
if (!radio.RegOpMode.bits.LongRangeMode) {
printf("FSK\r\n");
return;
}
lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
printLoraIrqs(false);
printf(" do_downlink:%u get_tx_done:%u, ", LoRaWan::do_downlink, get_tx_done);
lora.RegTest33.octet = radio.read_reg(REG_LR_TEST33); // invert_i_q
lora.RegDriftInvert.octet = radio.read_reg(REG_LR_DRIFT_INVERT);
printf("modemstat:%02x, rxinv:%x,%x\r\n", radio.read_reg(REG_LR_MODEMSTAT), lora.RegTest33.octet, lora.RegDriftInvert.octet);
radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), radio.RegDioMapping1.bits.Dio0Mapping);
printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", radio.read_reg(REG_LR_FIFOADDRPTR), radio.read_reg(REG_LR_FIFORXBASEADDR));
}
void cmd_filter(uint8_t idx)
{
if (sscanf(pcbuf+idx, "%lx", &LoRaWan::dev_addr_filter) != 1) {
LoRaWan::dev_addr_filter = 0;
printf("filter off\r\n");
} else
printf("filtering %lx\r\n", LoRaWan::dev_addr_filter);
}
void cmd_op(uint8_t idx)
{
int i, dbm;
RegPdsTrim1_t pds_trim;
uint8_t adr;
if (radio.type == SX1276)
adr = REG_PDSTRIM1_SX1276;
else
adr = REG_PDSTRIM1_SX1272;
pds_trim.octet = radio.read_reg(adr);
if (pcbuf[idx] >= '0' && (pcbuf[idx] <= '9' || pcbuf[idx] == '-')) {
sscanf(pcbuf+idx, "%d", &i);
if (radio.RegPaConfig.bits.PaSelect) {
/* PABOOST used: +2dbm to +17, or +20 */
if (i == 20) {
printf("+20dBm PADAC bias\r\n");
i -= 3;
pds_trim.bits.prog_txdac = 7;
radio.write_reg(adr, pds_trim.octet);
}
if (i > 1)
radio.RegPaConfig.bits.OutputPower = i - 2;
} else {
/* RFO used: -1 to +14dbm */
if (i < 15)
radio.RegPaConfig.bits.OutputPower = i + 1;
}
radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
}
radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
if (radio.RegPaConfig.bits.PaSelect) {
printf("PA_BOOST ");
dbm = radio.RegPaConfig.bits.OutputPower + pds_trim.bits.prog_txdac - 2;
} else {
printf("RFO ");
dbm = radio.RegPaConfig.bits.OutputPower - 1;
}
printf("OutputPower:%ddBm\r\n", dbm);
}
#ifdef TYPE_ABZ
void cmd_pa_select(uint8_t idx)
{
radio.RegPaConfig.bits.PaSelect ^= 1;
radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
if (radio.RegPaConfig.bits.PaSelect)
printf("PA_BOOST\r\n");
else
printf("RFO\r\n");
}
#endif /* TYPE_ABZ */
void cmd_set_time(uint8_t idx)
{
set_time(0);
printf("time:%" PRIu32 "\r\n", time(NULL));
}
void cmd_pwm(uint8_t idx)
{
ota_mote_t* mote;
int i;
unsigned dev_addr, p, d;
if (sscanf(pcbuf+idx, "%x %u %u", &dev_addr, &p, &d) != 3) {
printf("parse fail\r\n");
return;
}
for (i = 0; i < N_MOTES; i++) {
if (motes[i].dev_addr == dev_addr) {
break;
}
}
if (i == N_MOTES) {
printf("mote %x not found\r\n", dev_addr);
return;
}
mote = &motes[i];
mote->user_downlink_length = 0;
LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_PWM;
LoRaWan::user_downlink[mote->user_downlink_length++] = p;
LoRaWan::user_downlink[mote->user_downlink_length++] = d;
printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
}
void cmd_beacon_pwm(uint8_t idx)
{
unsigned p, d;
if (sscanf(pcbuf+idx, "%u %u", &p, &d) != 2) {
printf("parse fail\r\n");
return;
}
beacon_payload[0] = CMD_PWM;
beacon_payload[1] = p;
beacon_payload[2] = d;
printf("period:%u duty:%u\r\n", p, d);
}
void cmd_endnode_txp(uint8_t idx)
{
ota_mote_t* mote;
int i;
unsigned dev_addr, txi;
if (sscanf(pcbuf+idx, "%x %u", &dev_addr, &txi) != 2) {
printf("parse fail\r\n");
return;
}
for (i = 0; i < N_MOTES; i++) {
if (motes[i].dev_addr == dev_addr) {
break;
}
}
if (i == N_MOTES) {
printf("mote %x not found\r\n", dev_addr);
return;
}
mote = &motes[i];
mote->user_downlink_length = 0;
LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_TX_POWER;
LoRaWan::user_downlink[mote->user_downlink_length++] = txi;
printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
}
void cmd_beacon_endnode_txp(uint8_t idx)
{
unsigned txi;
if (sscanf(pcbuf+idx, "%u", &txi) != 1) {
printf("parse fail\r\n");
return;
}
beacon_payload[0] = CMD_TX_POWER;
beacon_payload[1] = txi;
printf("txp index:%u\r\n", txi);
}
void cmd_help(uint8_t);
typedef struct {
const char* const cmd;
void (*handler)(uint8_t args_at);
const char* const arg_descr;
const char* const description;
} menu_item_t;
const menu_item_t menu_items[] =
{ /* after first character, command names must be [A-Za-z] */
{ "?", cmd_help, "","show available commands"},
{ ".", cmd_status, "","read status"},
{ "f", cmd_filter, "%x","set dev_addr print filter"},
{ "b", cmd_beacon_payload, "<%x>","set beacon payload"},
{ "sb", cmd_skip_beacon, "<%d>","skip beacons"},
{ "list", cmd_list_motes, "","list active motes"},
{ "dl", cmd_send_downlink, "[%x %s]","send downlink <mote-hex-dev-addr> <hex-payload>"},
{ "rxr", cmd_rx_restart, "", "restart RX"},
{ "brgb", cmd_beacon_rgb, "%u %u %u", "load RGB command into next beacon" },
{ "rgb", cmd_downlink_rgb, "%x %u %u %u", "load RGB command to mote"},
{ "bgpo", cmd_beacon_gpo, "%d", "load output pin command into next beacon"},
{ "gpo", cmd_downlink_gpo, "%x %d", "load output pin command to mote"},
{ "op", cmd_op, "<dBm>","(TX) get/set TX power"},
#ifdef TYPE_ABZ
{ "pas", cmd_pa_select, "","(TX) toggle PaSelect"},
#endif
{ "tz", cmd_set_time, "", "set seconds to zero"},
{ "p", cmd_pwm, "%x %u %u", "send pwm period, duty to dev_addr"},
{ "bp", cmd_beacon_pwm, "%u %u", "send pwm period, duty on beacon"},
{ "ntxp", cmd_endnode_txp, "%x %u", "send txpower index to dev_addr"},
{ "bntxp", cmd_beacon_endnode_txp, "%u", "send txpower index on beacon"},
{ NULL, NULL, NULL, NULL }
};
void cmd_help(uint8_t args_at)
{
int i;
for (i = 0; menu_items[i].cmd != NULL ; i++) {
printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
}
}
void
console()
{
int i;
uint8_t user_cmd_len;
if (pcbuf_len < 0) { // ctrl-C
//printf("abort\r\n");
return;
}
if (pcbuf_len == 0)
return;
printf("\r\n");
/* get end of user-entered command */
user_cmd_len = 1; // first character can be any character
for (i = 1; i <= pcbuf_len; i++) {
if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
user_cmd_len = i;
break;
}
}
for (i = 0; menu_items[i].cmd != NULL ; i++) {
int mi_len = strlen(menu_items[i].cmd);
if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
while (pcbuf[mi_len] == ' ') // skip past spaces
mi_len++;
menu_items[i].handler(mi_len);
break;
}
}
pcbuf_len = 0;
printf("> ");
fflush(stdout);
}
int main()
{
Thread eventThread;
pc.baud(38400);
printf("\r\nreset %f\r\n", radio.get_frf_MHz());
set_time(0);
radio.hw_reset();
printf("%fMHz\r\n", radio.get_frf_MHz());
#ifndef TYPE_ABZ
/* LoRa arduino shield... */
#ifdef USE_BAND_433
radio.RegPaConfig.bits.PaSelect = 0; // RFO_LF connected
#else
rfsw.input();
if (rfsw.read()) {
printf("LAS\r\n");
/* LAS HF=PA_BOOST LF=RFO */
radio.RegPaConfig.bits.PaSelect = 1;
} else {
printf("MAS\r\n");
radio.RegPaConfig.bits.PaSelect = 0;
}
#endif /* !USE_BAND_433 */
rfsw.output();
/* ...LoRa arduino shield */
#endif
radio.rf_switch = rfsw_callback;
init_radio();
lora.start_rx(RF_OPMODE_RECEIVER);
eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
LoRaWan::init();
timer.start();
tim_init();
pc.attach(&rx_isr);
for (;;) {
console();
if (radio.dio0) {
if (get_tx_done) {
get_tx_done = false;
lora.RegIrqFlags.octet = 0;
lora.RegIrqFlags.bits.TxDone = 1;
radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
if (restore_tx_invert) {
lora.invert_tx(false);
restore_tx_invert = false;
}
if (restore_header_mode) {
lora.setHeaderMode(false);
restore_header_mode = false;
}
lora.start_rx(RF_OPMODE_RECEIVER);
if (beacon_guard) { // beacon done transmitting
measure_ambient();
beacon_guard = false;
}
} else {
if (!beacon_guard)
service_radio();
}
} else if (get_tx_done) {
/* dio0 not yet asserted */
uint32_t since = timer.read_ms() - tx_ms;
if (since > 4000) {
radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
if (radio.RegOpMode.bits.Mode == RF_OPMODE_STANDBY) {
/* done transmitting, but dio0 not asserted */
printf("txDone but no dio0\r\n");
radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
if (radio.RegDioMapping1.bits.Dio0Mapping != 1) {
printf("dio0mapping-fail\r\n");
radio.RegDioMapping1.bits.Dio0Mapping = 1;
radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
}
}
}
}
if (LoRaWan::do_downlink && !beacon_guard) {
uint32_t since = timer.read_ms() - LoRaWan::rx_ms;
if (since > 110)
printf("since-tx:%lu\r\n", since);
if (since > 500) {
LoRaWan::do_downlink = false;
printf("stalled-tx\r\n");
cmd_rx_restart(0);
}
}
} // ..for(;;)
}