esp32 TTGO Lora OLED

Links

Getting started

Some code

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <U8x8lib.h>

/**
 *                                       !!! IMPORTANT !!!
 *
 * Make sure to configure ".../Arduino/libraries/MCCI_LoRaWAN_LMIC_library/project_config/lmic_project_config.h"
 *
 */

#define BUILTIN_LED 2

// the OLED used
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16);

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8]={ 0x24, 0xFA, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8]={ 0x35, 0xA1, 0x44, 0x41, 0x89, 0xE1, 0x15, 0x00 };
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = { 0x79, 0x15, 0xDB, 0x3A, 0x1C, 0x37, 0x3E, 0x1E, 0x37, 0x02, 0x1C, 0xCC, 0x49, 0x49, 0x85, 0x53 };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 30;

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 18,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 14,
  .dio = {26, 33, 32},
};

void printHex2(unsigned v) {
    v &= 0xff;
    if (v < 16)
        Serial.print('0');
    Serial.print(v, HEX);
}

void oledPrintf(int col, int row, const char* fmt, ...) {
  char msg[50];
 
  va_list args;
 
  va_start(args, fmt);
  vsprintf(msg, fmt, args);
  va_end(args);

  u8x8.setCursor(col, row);
  Serial.println(msg);
  strcat(msg, "                ");
  msg[16] = 0; // Mark end of string.
  u8x8.print(msg);
}

void onEvent (ev_t ev) {
    long now = os_getTime();
    oledPrintf(0, 5, "Time %lu", now);

    // clear the lines
    oledPrintf(0, 3, "");
    oledPrintf(0, 6, "");
    oledPrintf(0, 7, "");

    switch(ev) {
        case EV_SCAN_TIMEOUT:
            oledPrintf(0, 7, "EV_SCAN_TIMEOUT");
            break;
        case EV_BEACON_FOUND:
            oledPrintf(0, 7, "EV_BEACON_FOUND");
            break;
        case EV_BEACON_MISSED:
            oledPrintf(0, 7, "EV_BEACON_MISSED");
            break;
        case EV_BEACON_TRACKED:
            oledPrintf(0, 7, "EV_BEACON_TRACKED");
            break;
        case EV_JOINING:
            oledPrintf(0, 7, "EV_JOINING");
            break;
        case EV_JOINED:
            oledPrintf(0, 7, "EV_JOINED");
            {
              u4_t netid = 0;
              devaddr_t devaddr = 0;
              u1_t nwkKey[16];
              u1_t artKey[16];
              LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
              Serial.print("netid: ");
              Serial.println(netid, DEC);
              Serial.print("devaddr: ");
              Serial.println(devaddr, HEX);
              Serial.print("AppSKey: ");
              for (size_t i=0; i<sizeof(artKey); ++i) {
                if (i != 0) Serial.print("-");
                printHex2(artKey[i]);
              }
              Serial.println("");
              Serial.print("NwkSKey: ");
              for (size_t i=0; i<sizeof(nwkKey); ++i) {
                      if (i != 0) Serial.print("-");
                      printHex2(nwkKey[i]);
              }
              Serial.println();
            }
            
            // Disable link check validation (automatically enabled
            // during join, but because slow data rates change max TX
              // size, we don't use it in this example.
            LMIC_setLinkCheckMode(0);
            break;
        case EV_RFU1:
            oledPrintf(0, 7, "EV_RFU1");
            break;
        case EV_JOIN_FAILED:
            oledPrintf(0, 7, "EV_JOIN_FAILED");
            break;
        case EV_REJOIN_FAILED:
            oledPrintf(0, 7, "EV_REJOIN_FAILED");
            break;
        case EV_TXCOMPLETE:
            oledPrintf(0, 7, "EV_TXCOMPLETE");
            digitalWrite(BUILTIN_LED, LOW);
            if (LMIC.txrxFlags & TXRX_ACK) {
              oledPrintf(0, 3, "rssi:%d, snr:%1d", LMIC.rssi, LMIC.snr);
              oledPrintf(0, 6, "Received ack");
            }
            if (LMIC.dataLen) {
              oledPrintf(0, 3, "rssi:%d, snr:%1d", LMIC.rssi, LMIC.snr);
              oledPrintf(0, 6, "Received %d", LMIC.dataLen);
              Serial.print("Data:");
              for(size_t i=0; i<LMIC.dataLen; i++) {
                Serial.print(" ");
                printHex2(LMIC.frame[i + LMIC.dataBeg]);
              }
              Serial.println();
            }
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            break;
        case EV_LOST_TSYNC:
            oledPrintf(0, 7, "EV_LOST_TSYNC");
            break;
        case EV_RESET:
            oledPrintf(0, 7, "EV_RESET");
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            oledPrintf(0, 7, "EV_RXCOMPLETE");
            break;
        case EV_LINK_DEAD:
            oledPrintf(0, 7, "EV_LINK_DEAD");
            break;
        case EV_LINK_ALIVE:
            oledPrintf(0, 7, "EV_LINK_ALIVE");
            break;
        case EV_SCAN_FOUND:
            oledPrintf(0, 7, "EV_SCAN_FOUND");
            break;
        case EV_TXSTART:
            oledPrintf(0, 7, "EV_TXSTART");
            break;
        case EV_TXCANCELED:
            oledPrintf(0, 7, "EV_TXCANCELED");
            break;
        case EV_RXSTART:
            oledPrintf(0, 7, "EV_RXSTART");
            break;
        case EV_JOIN_TXCOMPLETE:
            oledPrintf(0, 7, "EV_JOIN_TXCOMPLETE");
            break;
        default:
            oledPrintf(0, 7, "Unknown event %ud", ev);
            break;
    }
}

void do_send(osjob_t* j){
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        // Prepare upstream data transmission at the next possible time.
        u1_t confirmed = 1;
        LMIC_setTxData2(1, mydata, sizeof(mydata)-1, confirmed);
        Serial.println(F("Packet queued"));
        digitalWrite(BUILTIN_LED, HIGH);
    }
    // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
    Serial.begin(115200);
    Serial.println(F("Starting"));

    u8x8.begin();
    u8x8.setFont(u8x8_font_chroma48medium8_r);
    oledPrintf(0, 0, "Milo's OLED 2020");

    // LMIC init
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();
    LMIC_setAdrMode(false);

    // Start job (sending automatically starts OTAA too)
    do_send(&sendjob);

    pinMode(BUILTIN_LED, OUTPUT);
    digitalWrite(BUILTIN_LED, LOW);
}

void loop() {
    os_runloop_once();
}