How do I run non-LoRaWAN code in LMIC


(Sk Lora) #1

Hello.
I am implementing an RFID and LoRa, using the LMIC library.
For this I need to call the os_runloop_once () function to start the transmission.
How do I insert this function elsewhere in the code without being in the loop? I try to use if, for and other loops, but none works, only with while which ends up causing the program to not function normally
thank you


(Arjan) #2

Please edit your post and title to make clear what you want. Also, showing us what you tried might explain what you need. (See also How do I format my forum post?)

Am I right to assume that you want to read the RFID continuously and only start a LoRaWAN uplink for some specific conditions? I was tempted to rename this to “How do I run non-LoRaWAN code in LMIC?” but I really don’t know if that’s what you need.

Above all: did you read the LMIC documentation? See, e.g, https://github.com/mcci-catena/arduino-lmic/tree/master/doc For basic programming questions such as how to use if, for and while https://www.arduino.cc is a much better place to start.


(Sk Lora) #3

really my title is not fit, I have already made the modification.
This, I need to check the rfid continuous and uplink as soon as it has tag change or the presence sensor on


(Sk Lora) #4

what I was able to do is to let rfid work in parallel with the transmission.
but it is bottleneck in one. I would like to make every 70 seconds a transmission, if not read rfid

the code: unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Serial.println(“entrei millis”);
os_runloop_once();
}else{
// rfid();

but in that case, it assembles the packet in time, but does not transmit the tx complete


(Arjan) #5

Please read “Programming model” in the documentation: you always need to call the job scheduler function os_runloop_once() for each invocation of Arduino’s main loop(), even when you don’t need to send an uplink.


(Sk Lora) #6

I did, it’s working.
But when I leave to run the rfid only, the LMIC after about 20 minutes makes the arduino brick.
I still do not know how to solve

system has a PIR Sensor and an RFID rc522.
Operation: tag 1 turns on the system, performs 2 transmissions with a = 1.
After monitoring (); if it moves it does 3 transmissions with d = 1 and it enters readcard2 (), where the tag 2 does the reset returning to monitoring ().

      #include <hal/hal.h>
        #include <SPI.h>
        #include <MFRC522.h>
        int t = 0;
        int a = 0; //variable that informs sensor 0 off 1 on
        int b = 0;
        int analogPin = A5;
        int val = 0;
        int id1 = 111;
        int r = 0;
        int reset1 = 2;
        int d = 0; // 0 off  1 on  2 reset system // 


        int i = 0;
        int NumDisparo = 3; // tx after sensor active

       // 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) { }


static osjob_t initjob, sendjob, blinkjob;

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

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 10,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 3,
  .dio = {2, 6, 7},
};
void do_send(osjob_t* j) {
  digitalWrite(5, LOW);
  delay(500);
  // Check if there is not a current TX/RX job running
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println("OP_TXRXPEND, not sending");
  } else {
    principal();
    // Prepare upstream data transmission at the next possible time.
    LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
    Serial.println("Packet queued");
    Serial.println(LMIC.freq);
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  Serial.print(": ");
  Serial.println(ev);
  switch (ev) {
    case EV_SCAN_TIMEOUT:
      Serial.println("EV_SCAN_TIMEOUT");
      break;
    case EV_BEACON_FOUND:
      Serial.println("EV_BEACON_FOUND");
      break;
    case EV_BEACON_MISSED:
      Serial.println("EV_BEACON_MISSED");
      break;
    case EV_BEACON_TRACKED:
      Serial.println("EV_BEACON_TRACKED");
      break;
    case EV_JOINING:
      Serial.println("EV_JOINING");
      break;
    case EV_JOINED:
      Serial.println("EV_JOINED");
      break;
    case EV_RFU1:
      Serial.println("EV_RFU1");
      break;
    case EV_JOIN_FAILED:
      Serial.println("EV_JOIN_FAILED");
      break;
    case EV_REJOIN_FAILED:
      Serial.println("EV_REJOIN_FAILED");
      break;
    case EV_TXCOMPLETE:
      Serial.println("EV_TXCOMPLETE (includes waiting for RX windows)");
      if (LMIC.dataLen) {
        // data received in rx slot after tx
        Serial.print("Data Received: ");
        Serial.write(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
        Serial.println();
      }
      //faz com que na primeira passada apos resetar não entre no while da porta
      Serial.print("chega aqui");
      if (a == 1) {
        i = i + 1;
      }
      if ((d == 1) && (reset1 == 0)) {
        S
        monitoramento();
      }
        monitoramento();
      }
      if (reset1 == 0) {
        
        while (t == 0 ) {
          lercartao1();
        }
      } else if (reset1 == 2) {
        reset1 = 0;
      }

      
  
Serial.println(a);

      // Schedule next transmission
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;
    case EV_LOST_TSYNC:
      Serial.println("EV_LOST_TSYNC");
      break;
    case EV_RESET:
      Serial.println("EV_RESET");
      break;
    case EV_RXCOMPLETE:
      // data received in ping slot
      Serial.println("EV_RXCOMPLETE");
      break;
    case EV_LINK_DEAD:
      Serial.println("EV_LINK_DEAD");
      break;
    case EV_LINK_ALIVE:
      Serial.println("EV_LINK_ALIVE");
      break;
    default:
      Serial.println("Unknown event");
      break;
  }
}

      void loop(){
          if (((a == 0) || (a == 1)) && (i < NumDisparo)) {
         
    //if the door is open or closed and i <numdisparo calls,  causes the transmission to occur only in such cases
            os_runloop_once();
          } else
            readcard2();// function call rfid 
        }

(Sk Lora) #7

This is the problem that occurs
FAILURE
\Arduino\libraries\arduino-lmic-master\src\lmic\radio.c:545


(Arjan) #8

Some thoughts:

  • Like mentioned before, and as documented: you always need to call the LMIC job scheduler function os_runloop_once() at least once for each invocation of Arduino’s main loop(), even when you don’t need to send any uplink. This function is not only about transmitting data, like your comment “causes the transmission to occur only in such cases” seems to suggest. For example, it also executes an OTAA join if needed, and opens the receive windows RX1 and RX2, when applicable.

  • Many LMIC examples indeed schedule the next measurement and transmission in its EV_TXCOMPLETE event, but that’s only useful when sending on a fixed interval. In your case things depend on some external events, so it doesn’t make much sense to put your code in that place. Even more: relying on EV_TXCOMPLETE will only run your code after each uplink (likely even 2 seconds later as the event is only fired when LMIC is done waiting for an optional downlink; RX1 and possibly RX2). However, when running your own code from loop() (or when having LMIC run an application job for that) it will be run whenever possible, even directly after an uplink while still waiting for RX1 and RX2 (if os_runloop_once() is properly called).

So, to programmatically continuously check the RFID and PIR, I’d remove your code from EV_TXCOMPLETE, and then define something like:

static osjob_t sendjob;

void check_pir() {
  // TODO: handle the sensor data
}

void check_rfid() {
  // TODO: handle the sensor data
} 

void do_send(osjob_t* j) {
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println("OP_TXRXPEND, not sending");
  } else {
    LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
  }
}

void send_if_needed() {
  if (some_condition) {
    // TODO: populate mydata
    os_setCallback(&sendjob, do_send);
  }
}

…and run that using:

void loop() {
  // Allow LMIC to do its housekeeping:
  os_runloop_once();
  check_pir();
  // ...and again, in case check_pir() took some time:
  os_runloop_once();
  check_rfid();
  // ...and again, in case check_rfid() took some time:
  os_runloop_once();
  send_if_needed();
}

To follow LMIC’s documented programming model, one could also use jobs for one’s own tasks:

static osjob_t pirjob, rfidjob, schedulesendjob, sendjob;

void check_pir(osjob_t* j) {
  // TODO: handle the sensor data
  // re-schedule next call
  os_setCallback(&pirjob, check_pir);
}

void check_rfid(osjob_t* j) {
  // TODO: handle the sensor data
  os_setCallback(&rfidjob, check_rfid);
}

void do_send(osjob_t* j) {
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println("OP_TXRXPEND, not sending");
  } else {
    LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
  }
}

void send_if_needed(osjob_t* j) {
  if (some_condition) {
    // TODO: populate mydata
    os_setCallback(&sendjob, do_send);
  }
  os_setCallback(&schedulesendjob, send_if_needed);
}

…and use that with:

void setup() {
  // TODO: existing setup, such as os_init()

  // schedule initial calls of application jobs
  os_setCallback(&pirjob, check_pir);
  os_setCallback(&rfidjob, check_rfid);
  os_setCallback(&schedulesendjob, send_if_needed);
}

void loop() {
  // Allow LMIC to do its housekeeping and run all the jobs:
  os_runloop_once();
}

For your specific use case:

  • The error is thrown by the failing ASSERT in:

    static void rxlora (u1_t rxmode) {
        // select LoRa modem (from sleep mode)
        opmodeLora();
        ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
    

    Looking at opmodeLora() shows that it calls writeReg, which uses the Serial Peripheral Interface (SPI) to communicate with the SX127x module. Next, readReg returns the wrong value, so shows that writeReg or readReg failed. So, the SPI communication apparently fails? Maybe the SX127x module is busy doing other things. Maybe the LMIC state machine is just messed up as you did not call os_runloop_once() as expected. Just to be sure the wiring is okay:

    Does the same hardware (especially: the same lmic_pinmap) work for simple examples?

  • You’re sending the same event multiple times? If you’re doing that to increase chances that your messages arrives at some gateway, then please rethink that; what if everybody would do that…?

  • You’re also transmitting quite often if nothing changes at all? That’s the same problem: what if everyone would do that? You’re using a shared radio spectrum.

  • If the sensors allow for it, then using some hardware interrupts with some sleep will preserve your battery.


Creating a command line version of LMIC
(Sk Lora) #9

Hi, I tried the suggested implementations, but none worked, rang between 689 errors (fixed with reset) and 73 or even gave rxtx not sending.

Yes the SPI fails because the RFID uses the same bus.
is there any command where I can shut down the lmic?


(Ud Lo Ra) #10

Are you sing the same SS pin?


#11

indeed, possibly conflicting library’s… both devices use SPI


(Sk Lora) #12

different ss pins for two devices


(Sk Lora) #13

Problem solved with only board change


(Sk Lora) #14

I would like to do the remote activation of the node, by an external button, sent a command by LoRa. In case it would be an external remote control, not a node in class C, searching with LMIC found raw.ino, where I can “hear” when the command is given. Pórem would like a tx done after the node is activated, but it is not working dando o erro: c\lmic\radio.c:523


(Sk Lora) #15

code:

/*******************************************************************************
 * Copyright (c) 2015 Matthijs Kooijman
 * Copyright (c) 2018 Terry Moore, MCCI Corporation
 *
 * 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 <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

int i=0;

// we formerly would check this configuration; but now there is a flag,
// in the LMIC, LMIC.noRXIQinversion;
// if we set that during init, we get the same effect.  If
// DISABLE_INVERT_IQ_ON_RX is defined, it means that LMIC.noRXIQinversion is
// treated as always set.
//
// #if !defined(DISABLE_INVERT_IQ_ON_RX)
// #error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \
//        lmic_project_config.h in arduino-lmic/project_config 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 
// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the prototype TTN
// network initially.


static uint8_t mydata[9] = {0x01, 0x68, 0x00, 0x02, 0x66, 0x00, 0x03, 0x66, 0x00};

static const PROGMEM u1_t NWKSKEY[16] ={ 0x40, 0xE0, 0xCE, 0xC3, 0x7C, 0xBC, 0x02, 0x06, 0x3F, 0xF1, 0xC1, 0xB2, 0x27, 0x52, 0x57, 0xFF };
// LoRaWAN AppSKey, application session key

// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the prototype TTN
// network initially.
static const u1_t PROGMEM APPSKEY[16] = { 0xAE, 0xFD, 0x9E, 0xA7, 0x65, 0xC4, 0xFC, 0x25, 0x03, 0x01, 0xDE, 0xEA, 0xC8, 0xB4, 0xA6, 0x70 };
// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
static const u4_t DEVADDR =  0x2603165E; // <-- Change this address for every node!
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }





//#define TX_INTERVAL 10000

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 9,
    .dio = {2, 6, 7},
};


// 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 arduino-lmoc/project_config/lmic_project_config.h,
// otherwise the linker will complain).




osjob_t rxjob;
osjob_t timeoutjob;
//static void tx_func (osjob_t* job);

// Transmit the given string and call the given function afterwards


// 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

  


  Serial.print("Got ");
  i=i+1;
  Serial.print(LMIC.dataLen);
  Serial.println(" bytes");
  Serial.write(LMIC.frame, LMIC.dataLen);
  Serial.println();

  // Restart RX
  rx(rx_func);
}
//static uint8_t mydata[] = "Hello, world!";
static osjob_t initjob,sendjob,blinkjob, schedulesendjob;

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


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

void onEvent (ev_t ev) {
    Serial.print(os_getTime());
    Serial.print(": ");
    Serial.println(ev);
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            Serial.println("EV_SCAN_TIMEOUT");
            break;
        case EV_BEACON_FOUND:
            Serial.println("EV_BEACON_FOUND");
            break;
        case EV_BEACON_MISSED:
            Serial.println("EV_BEACON_MISSED");
            break;
        case EV_BEACON_TRACKED:
            Serial.println("EV_BEACON_TRACKED");
            break;
        case EV_JOINING:
            Serial.println("EV_JOINING");
            break;
        case EV_JOINED:
            Serial.println("EV_JOINED");
            break;
        case EV_RFU1:
            Serial.println("EV_RFU1");
            break;
        case EV_JOIN_FAILED:
            Serial.println("EV_JOIN_FAILED");
            break;
        case EV_REJOIN_FAILED:
            Serial.println("EV_REJOIN_FAILED");
            break;
        case EV_TXCOMPLETE:
            Serial.println("EV_TXCOMPLETE (includes waiting for RX windows)");
            if(LMIC.dataLen) {
                // data received in rx slot after tx
                Serial.print("Data Received: ");
                Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen);
                Serial.println();
            }
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            break;
        case EV_LOST_TSYNC:
            Serial.println("EV_LOST_TSYNC");
            break;
        case EV_RESET:
            Serial.println("EV_RESET");
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            Serial.println("EV_RXCOMPLETE");
            break;
        case EV_LINK_DEAD:
            Serial.println("EV_LINK_DEAD");
            break;
        case EV_LINK_ALIVE:
            Serial.println("EV_LINK_ALIVE");
            break;
         default:
            Serial.println("Unknown event");
            break;
    }
}
float principal() {

  Serial.println("lendo os dados");
  mydata[2] = 1 * 2; //canal 1
  mydata[5] = 2; //canal 2
  mydata[8] = 4;
 
}



// 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();
   #ifdef PROGMEM
    // On AVR, these values are stored in flash and only copied to RAM
    // once. Copy them to a temporary buffer here, LMIC_setSession will
    // copy them into a buffer of its own again.
    uint8_t appskey[sizeof(APPSKEY)];
    uint8_t nwkskey[sizeof(NWKSKEY)];
    memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
    memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
    LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
    #else
    // If not running an AVR with PROGMEM, just use the arrays directly 
    LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
    #endif
  // Set up these settings once, and use them for both TX and RX

#if defined(CFG_us915)
  LMIC.freq = 913300000;
#else
  error Region not supported!
#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_SF10;
  // This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250)
  LMIC.rps = updr2rps(LMIC.datarate);

  // disable RX IQ inversion
//  LMIC.noRXIQinversion = true;

  Serial.println("Started");

  //Serial.flush();
  //LMIC.dataLen = 0;

  // setup initial job
  os_setCallback(&rxjob, rx_func);
  //os_setCallback(&sendjob, do_send);
  
  //do_send(&sendjob);

 
}

void loop() {
  // execute scheduled jobs and events
  os_runloop_once();
  if(i==3){
       
    Serial.println("qq");
    
     os_radio(RADIO_RST); // Stop RX first
     delay(1);
     LMIC.dataLen = 0;
      os_setCallback(&sendjob, do_send);
    while(i==3){
       os_radio(RADIO_TX);
      
      do_send(&sendjob);
    
    }
     
      

   
  
  }
}

(system) #16

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.