/******************************************************************************* * Copyright (c) 2015 Matthijs Kooijman * * Permission is hereby granted, free of charge, to anyone * obtaining a copy of this document and accompanying files, * to do whatever they want with them without any restriction, * including, but not limited to, copying, modification and redistribution. * NO WARRANTY OF ANY KIND IS PROVIDED. * * This example transmits data on hardcoded channel and receives data * when not transmitting. Running this sketch on two nodes should allow * them to communicate. *******************************************************************************/ #include #include #include #if !defined(DISABLE_INVERT_IQ_ON_RX) #error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \ config.h in the lmic library to set it. #endif // How often to send a packet. Note that this sketch bypasses the normal // LMIC duty cycle limiting, so when you change anything in this sketch // (payload length, frequency, spreading factor), be sure to check if // this interval should not also be increased. // See this spreadsheet for an easy airtime and duty cycle calculator: // https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc #define TX_INTERVAL 2000 // Pin mapping const lmic_pinmap lmic_pins = { .nss = 6, .rxtx = LMIC_UNUSED_PIN, .rst = 5, .dio = {2, 3, 4}, }; // These callbacks are only used in over-the-air activation, so they are // left empty here (we cannot leave them out completely unless // DISABLE_JOIN is set in config.h, otherwise the linker will complain). void os_getArtEui (u1_t* buf) { } void os_getDevEui (u1_t* buf) { } void os_getDevKey (u1_t* buf) { } void onEvent (ev_t ev) { } osjob_t txjob; osjob_t timeoutjob; static void tx_func (osjob_t* job); // Transmit the given string and call the given function afterwards void tx(const char *str, osjobcb_t func) { os_radio(RADIO_RST); // Stop RX first delay(1); // Wait a bit, without this os_radio below asserts, apparently because the state hasn't changed yet LMIC.dataLen = 0; while (*str) LMIC.frame[LMIC.dataLen++] = *str++; LMIC.osjob.func = func; os_radio(RADIO_TX); Serial.println("TX"); } // Enable rx mode and call func when a packet is received void rx(osjobcb_t func) { LMIC.osjob.func = func; LMIC.rxtime = os_getTime(); // RX _now_ // Enable "continuous" RX (e.g. without a timeout, still stops after // receiving a packet) os_radio(RADIO_RXON); Serial.println("RX"); } static void rxtimeout_func(osjob_t *job) { digitalWrite(LED_BUILTIN, LOW); // off } static void rx_func (osjob_t* job) { // Blink once to confirm reception and then keep the led on digitalWrite(LED_BUILTIN, LOW); // off delay(10); digitalWrite(LED_BUILTIN, HIGH); // on // Timeout RX (i.e. update led status) after 3 periods without RX os_setTimedCallback(&timeoutjob, os_getTime() + ms2osticks(3*TX_INTERVAL), rxtimeout_func); // Reschedule TX so that it should not collide with the other side's // next TX os_setTimedCallback(&txjob, os_getTime() + ms2osticks(TX_INTERVAL/2), tx_func); Serial.print("Got "); Serial.print(LMIC.dataLen); Serial.println(" bytes"); Serial.write(LMIC.frame, LMIC.dataLen); Serial.println(); // Restart RX rx(rx_func); } static void txdone_func (osjob_t* job) { rx(rx_func); } // log text to USART and toggle LED static void tx_func (osjob_t* job) { // say hello tx("Hello, world!", txdone_func); // reschedule job every TX_INTERVAL (plus a bit of random to prevent // systematic collisions), unless packets are received, then rx_func // will reschedule at half this time. os_setTimedCallback(job, os_getTime() + ms2osticks(TX_INTERVAL + random(500)), tx_func); } // application entry point void setup() { Serial.begin(115200); Serial.println("Starting"); #ifdef VCC_ENABLE // For Pinoccio Scout boards pinMode(VCC_ENABLE, OUTPUT); digitalWrite(VCC_ENABLE, HIGH); delay(1000); #endif pinMode(LED_BUILTIN, OUTPUT); // initialize runtime env os_init(); // Set up these settings once, and use them for both TX and RX #if defined(CFG_eu868) // Use a frequency in the g3 which allows 10% duty cycling. LMIC.freq = 869525000; #elif defined(CFG_us915) LMIC.freq = 902300000; #endif // Maximum TX power LMIC.txpow = 27; // Use a medium spread factor. This can be increased up to SF12 for // better range, but then the interval should be (significantly) // lowered to comply with duty cycle limits as well. LMIC.datarate = DR_SF9; // This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250) LMIC.rps = updr2rps(LMIC.datarate); Serial.println("Started"); Serial.flush(); // setup initial job os_setCallback(&txjob, tx_func); } void loop() { // execute scheduled jobs and events os_runloop_once(); }