simple example of wifi AP scanning, sending scan-results over radio link
Dependencies: lr1110 sx12xx_hal
End device for testing Wifi geolocation.
Use with radio shield for europe
or radio shield for USA
which is programmed with trx
firmware from updater tool.
Press USER_BUTTON
to scan wifi access points and send results over radio link to gateway, which posts to geolocation provider, which then reply's with coordinates.
Long press user button (half second) to only scan wifi, to print out on 9600bps UART, and not transmit scan results for geolocation resolving. Short press and release (under 500ms) will wifi scan and transmit for geolocation resolving.
Use this project with lr1110_wifi_geolocation_gateway to receive the message from this project and resolve the location from geolocation server
notice
This project is not using LoRaWAN, instead just LoRa transceiver directly to geolocation provider
Revision 1:416ed16806fc, committed 2021-02-09
- Comitter:
- Wayne Roberts
- Date:
- Tue Feb 09 10:47:25 2021 -0800
- Parent:
- 0:d8a6a7dfa435
- Commit message:
- add source file
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
diff -r d8a6a7dfa435 -r 416ed16806fc main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Feb 09 10:47:25 2021 -0800 @@ -0,0 +1,323 @@ +#include "radio.h" + +#define TX_DBM 20 +#define BW_KHZ 500 +#define SPREADING_FACTOR 11 +#define CF_HZ 919000000 + +#define HEADER_LENGTH 10 /* for chipEUI and extra reserved */ +#define WIFI_MAX_RESULTS 20 +#define LORA_RX_TIME_MS 20000 /* how long for cloud to reply with resolved location? */ + +/**********************************************************************/ +bool wifiResultFormatBasic; /* false, TODO get basic results functional */ +EventQueue queue(4 * EVENTS_EVENT_SIZE); + +unsigned packet_len; +uint8_t chip_eui[8]; + +InterruptIn ub(USER_BUTTON); /* released = hi, pressed = lo */ +void button_released(void); +int wifi_scan_id, long_press_id; +bool long_pressed; + +uint64_t wifi_start_at, wifi_scan_dur; + +static void cfg_lora() +{ + /* after wifi scan, lora is gone */ + Radio::LoRaModemConfig(BW_KHZ, SPREADING_FACTOR, 1); + Radio::SetChannel(CF_HZ); + + Radio::set_tx_dbm(TX_DBM); + + // preambleLen, fixLen, crcOn, invIQ + Radio::LoRaPacketConfig(8, false, true, false); +} + +void wifi_scan() +{ + uint8_t wifiScan_buf[9]; + + { /* wifi scan defaults, see LR1110 user manual section 10.2 */ + unsigned chanmask = 0x0421; // ch1, ch6, ch11 + unsigned timeout = 105; // in milliseconds, 100 wifi TUs (beacon interval) + + wifiScan_buf[0] = 0x01; // wifi type + wifiScan_buf[2] = chanmask; // chanmask-lo + chanmask >>= 8; + wifiScan_buf[1] = chanmask; // chanmask-hi + wifiScan_buf[3] = 0x02; // acqMode + wifiScan_buf[4] = WIFI_MAX_RESULTS; // NbMaxRes + wifiScan_buf[5] = 0x10; // NbScanPerChan + wifiScan_buf[7] = timeout; // Timeout-lo + timeout >>= 8; + wifiScan_buf[6] = timeout; // Timeout-hi + wifiScan_buf[8] = 0x00; // AbortOnTimeout + } + + Radio::radio.xfer(OPCODE_WIFI_SCAN, 9, 0, wifiScan_buf); + wifi_start_at = Kernel::get_ms_count(); + printf("wifiScan...\r\n"); +} + +void long_press() +{ + long_pressed = true; + wifi_scan(); +} + +void button_pressed() +{ + ub.rise(button_released); + queue.cancel(wifi_scan_id); + long_pressed = false; + long_press_id = queue.call_in(500, long_press); +} + +void button_released() +{ + ub.fall(button_pressed); + if (!long_pressed) { + wifi_scan_id = queue.call_in(20, wifi_scan); + queue.cancel(long_press_id); + } +} + +void txDoneCB() +{ + Radio::Rx(0); + queue.call_in(LORA_RX_TIME_MS, Radio::Standby); +} + +void rxDoneCB(uint8_t size, float rssi, float snr) +{ + unsigned i; + printf("%.1fdBm snr:%.1fdB\t", rssi, snr); + + /* + for (i = 0; i < size; i++) { + printf("%02x ", Radio::radio.rx_buf[i]); + } + printf("\r\n");*/ + + if (memcmp(Radio::radio.rx_buf, chip_eui, 8) == 0) { + /* print resolved coordinates from cloud */ + printf(">> %s\r\n", Radio::radio.rx_buf + HEADER_LENGTH); + } +} + +struct wifidr { + const char *txt; + float Mbps; +}; + +const struct wifidr wifiDatarates[] = { + /* 0 */ { NULL, 0}, + /* 1 */ { "DBPSK", 1}, + /* 2 */ { "DQPSK", 2}, + /* 3 */ { "BPSK", 6}, + /* 4 */ { "BPSK", 9}, + /* 5 */ { "QPSK", 12}, + /* 6 */ { "QPSK", 18}, + /* 7 */ { "16-QAM", 24}, + /* 8 */ { "16-QAM", 36}, + /* 9 */ { "(9)", 0}, + /* 10 */ { "(10)", 0}, + /* 11 */ { "BPSK", 6.5}, + /* 12 */ { "QPSK", 13}, + /* 13 */ { "QPSK", 19.5}, + /* 14 */ { "16-QAM", 26}, + /* 15 */ { "16-QAM", 39}, + /* 16 */ { "(16)", 0}, + /* 17 */ { "(17)", 0}, + /* 18 */ { "(18)", 0}, + /* 19 */ { "BPSK", 7.2}, + /* 20 */ { "QPSK", 14.4}, + /* 21 */ { "QPSK", 21.7}, + /* 22 */ { "16-QAM", 28.9}, + /* 23 */ { "16-QAM", 43.3}, +}; + +void print_wifi_result(const uint8_t *result) +{ + char out[96]; + char str[24]; + unsigned n, macStart; + wifiType_t wt; + wifiChanInfo_t ci; + wt.octet = result[0]; + ci.octet = result[1]; + out[0] = 0; + strcat(out, "802.11"); + switch (wt.bits.signal) { + case 1: strcat(out, "b"); break; + case 2: strcat(out, "g"); break; + case 3: strcat(out, "n"); break; + } + sprintf(str, " %s %.1fMbps", wifiDatarates[wt.bits.datarate].txt, wifiDatarates[wt.bits.datarate].Mbps); + strcat(out, str); + strcat(out, " "); + + sprintf(str, "ch%u ", ci.bits.channelID); + strcat(out, str); + switch (ci.bits.channelID) { + // table 10-5 + } + strcat(out, " "); + sprintf(str, "mv:%u ", ci.bits.macValidationID); + strcat(out, str); + switch (ci.bits.macValidationID) { + case 1: strcat(out, "gateway"); break; + case 2: strcat(out, "phone"); break; + case 3: strcat(out, "?"); break; + // table 10.8 + } + + strcat(out, " "); + + if (wifiResultFormatBasic) { + macStart = 3; + } else { + macStart = 4; + } + for (n = 0; n < 6; n++) { + sprintf(str, "%02x", result[n+macStart]); + strcat(out, str); + if (n < 5) + strcat(out, ":"); + } + + sprintf(str, " rssi:%d ", (int8_t)result[2]); + strcat(out, str); + + if (!wifiResultFormatBasic) { + sprintf(str, "frameCtrl:%02x ", result[3]); + strcat(out, str); + } + printf("%s\r\n", out); +} + +static void service() +{ + irq_t irq; + irq.dword = Radio::radio.service(); + if (irq.bits.WifiDone) { + unsigned n; + stat_t stat; + uint8_t nbResults; + stat.word = Radio::radio.xfer(OPCODE_GET_WIFI_NB_RESULTS, 0, 0, NULL); + stat.word = Radio::radio.xfer(0x0000, 0, 1, &nbResults); + if (stat.bits.cmdStatus != CMD_DAT) { + printf("get-nbResult-fail\r\n"); + return; + } + packet_len = HEADER_LENGTH; + printf("%ums nbResults:%u\r\n", (unsigned)wifi_scan_dur, nbResults); + for (n = 0; n < nbResults; n++) { + uint8_t buf[3]; + uint8_t resultBuf[22]; + buf[0] = n; + buf[1] = 1; // number of results in this read + buf[2] = wifiResultFormatBasic ? 4 : 1; + stat.word = Radio::radio.xfer(OPCODE_WIFI_READ_RESULTS, 3, 0, buf); + // basic = 9byte length + // full = 22byte length + stat.word = Radio::radio.xfer(0x0000, 0, wifiResultFormatBasic ? 9 : 22, resultBuf); + + if (stat.bits.cmdStatus == CMD_DAT) { + unsigned n, macStart; + wifiChanInfo_t ci; + ci.octet = resultBuf[1]; + if (ci.bits.macValidationID == 1) { // gateway (AP) + macStart = wifiResultFormatBasic ? 3 : 4; + for (n = 0; n < 6; n++) { + Radio::radio.tx_buf[packet_len++] = resultBuf[n+macStart]; + printf("%02x", resultBuf[n+macStart]); + if (n < 5) + printf(":"); + } + printf(" rssi:%d\r\n", (int8_t)resultBuf[2]); + Radio::radio.tx_buf[packet_len++] = resultBuf[2]; + } + } else + printf("readResult:%s\r\n", Radio::radio.cmdStatus_toString(stat.bits.cmdStatus)); + } + + if (!long_pressed) { + unsigned n; + cfg_lora(); + for (n = 0; n < 8; n++) + Radio::radio.tx_buf[n] = chip_eui[n]; + + Radio::radio.tx_buf[n++] = 0; // rfu + Radio::radio.tx_buf[n++] = 0; // rfu + printf("pktLen:%u\r\n", packet_len); + Radio::Send(packet_len, 0, 0, 0); /* begin transmission */ + } + } // ..if (irq.bits.WifiDone) + + if (irq.bits.TxDone) { + printf("main-TxDone\r\n"); + } +} + +void radio_irq_callback() +{ + wifi_scan_dur = Kernel::get_ms_count() - wifi_start_at; + queue.call(service); +} + +const RadioEvents_t rev = { + /* DioPin_top_half */ radio_irq_callback, + /* TxDone_topHalf */ NULL, + /* TxDone_botHalf */ txDoneCB, + /* TxTimeout */ NULL, + /* RxDone */ rxDoneCB, + /* RxTimeout */ NULL, + /* RxError */ NULL, + /* FhssChangeChannel */NULL, + /* CadDone */ NULL +}; + +int main() +{ + Radio::Init(&rev); + + Radio::Standby(); + cfg_lora(); + + { + uint8_t buf[9]; + stat_t stat; + stat.word = Radio::radio.xfer(OPCODE_GET_VERSION, 0, 0, NULL); + stat.word = Radio::radio.xfer(0x0000, 0, 4, buf); + if (stat.bits.cmdStatus == CMD_DAT) { + printf("LR1110 chip:%02x use:%02x fw-v%u.%u\r\n", + buf[0], /* silicon rev */ + buf[1], /* use case */ + buf[2], /* firmware major */ + buf[3] /* firmware minor */ + ); + } + + stat.word = Radio::radio.xfer(OPCODE_GET_DEVEUI, 0, 0, NULL); + stat.word = Radio::radio.xfer(0x0000, 0, 9, buf); + memcpy(chip_eui, buf+1, 8); + for (unsigned i = 0; i < 9; i++) + printf("%02x ", buf[i]); + printf("\r\n"); + } + +#ifdef AUTO_TX + queue.call_in(500, tx_test); +#endif /* AUTO_TX */ + + if (ub.read()) + ub.fall(button_pressed); + else + ub.rise(button_released); + + queue.dispatch(); +} +