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

Files at this revision

API Documentation at this revision

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();
+}
+