From b422c02d0e7da274d27e410d3a5ce6ca4bef8c6d Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Thu, 23 May 2019 14:18:29 +0200 Subject: [PATCH 1/5] raspberry pi examples --- examples/raspi/README.txt | 3 + examples/raspi/get_deveui/Makefile | 21 + examples/raspi/get_deveui/get_deveui.c | 118 +++++ examples/raspi/raw/Makefile | 39 ++ examples/raspi/raw/raw.cpp | 158 +++++++ examples/raspi/spi_scan/Makefile | 21 + examples/raspi/spi_scan/spi_scan.c | 106 +++++ examples/raspi/ttn-otaa-sensors/Makefile | 45 ++ examples/raspi/ttn-otaa-sensors/bmp180.cpp | 377 ++++++++++++++++ examples/raspi/ttn-otaa-sensors/bmp180.h | 127 ++++++ examples/raspi/ttn-otaa-sensors/si7021.c | 221 ++++++++++ examples/raspi/ttn-otaa-sensors/si7021.h | 75 ++++ .../ttn-otaa-sensors/ttn-otaa-sensors.cpp | 417 ++++++++++++++++++ examples/raspi/ttn-otaa/Makefile | 39 ++ examples/raspi/ttn-otaa/ttn-otaa.cpp | 261 +++++++++++ 15 files changed, 2028 insertions(+) create mode 100644 examples/raspi/README.txt create mode 100644 examples/raspi/get_deveui/Makefile create mode 100644 examples/raspi/get_deveui/get_deveui.c create mode 100644 examples/raspi/raw/Makefile create mode 100644 examples/raspi/raw/raw.cpp create mode 100644 examples/raspi/spi_scan/Makefile create mode 100644 examples/raspi/spi_scan/spi_scan.c create mode 100644 examples/raspi/ttn-otaa-sensors/Makefile create mode 100644 examples/raspi/ttn-otaa-sensors/bmp180.cpp create mode 100644 examples/raspi/ttn-otaa-sensors/bmp180.h create mode 100644 examples/raspi/ttn-otaa-sensors/si7021.c create mode 100644 examples/raspi/ttn-otaa-sensors/si7021.h create mode 100644 examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp create mode 100644 examples/raspi/ttn-otaa/Makefile create mode 100644 examples/raspi/ttn-otaa/ttn-otaa.cpp diff --git a/examples/raspi/README.txt b/examples/raspi/README.txt new file mode 100644 index 00000000..16292ed1 --- /dev/null +++ b/examples/raspi/README.txt @@ -0,0 +1,3 @@ + +raspberry pi examples +origin: https://github.com/hallard/arduino-lmic/tree/rpi/examples/raspi diff --git a/examples/raspi/get_deveui/Makefile b/examples/raspi/get_deveui/Makefile new file mode 100644 index 00000000..8a622e87 --- /dev/null +++ b/examples/raspi/get_deveui/Makefile @@ -0,0 +1,21 @@ +# Makefile +# Sample for gettting device EUI from MAC address +# +# + +CC = g++ +CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" +LIBS = -lbcm2835 +RADIOHEADBASE = ../../.. +INCLUDE = -I$(RADIOHEADBASE) + +all: get_deveui + +get_deveui.o: get_deveui.c + $(CC) $(CFLAGS) -c $(INCLUDE) $< + +get_deveui: get_deveui.o + $(CC) $^ $(LIBS) -o get_deveui + +clean: + rm -rf *.o get_deveui diff --git a/examples/raspi/get_deveui/get_deveui.c b/examples/raspi/get_deveui/get_deveui.c new file mode 100644 index 00000000..469eb931 --- /dev/null +++ b/examples/raspi/get_deveui/get_deveui.c @@ -0,0 +1,118 @@ +// get_deveui.c +// +// Example program to get LoraWAN device EUI from MAC Address +// Use the Makefile in this directory: +// cd example/raspi/get_deveui +// make +// sudo ./get_deveui +// +// written by Charles-Henri Hallard (hallard.me) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, const char * argv[]) +{ + struct ifaddrs *ifaddr=NULL; + struct ifaddrs *ifa = NULL; + int family = 0; + int i = 0; + int all=0; + + if (argc==2 && !strncasecmp(argv[1],"all", 3) ) { + all=1; + } else { + fprintf(stdout, "Use \"%s all\" to see all interfaces and details\n", __BASEFILE__ ); + } + + // get linked list of the network interfaces + if (getifaddrs(&ifaddr) == -1) { + perror("getifaddrs"); + + } else { + // Loop thru interfaces list + for ( ifa=ifaddr; ifa!=NULL; ifa=ifa->ifa_next) { + // Ethernet + if ( (ifa->ifa_addr) && (ifa->ifa_addr->sa_family==AF_PACKET) ) { + // Not loopback interface + if (! (ifa->ifa_flags & IFF_LOOPBACK)) { + char fname[128]; + int fd; + int up=0; + struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr; + + // Get interface status + // Interface can be up with no cable connected and to be sure + // It's up, active and connected we need to get operstate + // + // if up + cable if up + NO cable if down + cable + // ============= ========== ================== + // carrier:1 carrier:0 carrier:Invalid + // dormant:0 dormant:0 dormant:Invalid + // operstate:up operstate:down operstate :own + sprintf(fname, "/sys/class/net/%s/operstate", ifa->ifa_name); + + if ( (fd = open( fname, O_RDONLY)) > 0 ){ + char buf[2]; + if ( read(fd, buf, 2) > 0 ) { + if ( buf[0]=='u' && buf[1]=='p' ) { + up=1; + } + close(fd); + } else { + perror("read()"); + } + } else { + perror(fname); + } + + //active interface or all wanted + if (all || up) { + char deveui[8]; + char *p = deveui; + // deveui is LSB to we reverse it so TTN display + // will remain the same as MAC address + // MAC is 6 bytes, devEUI 8, set first 2 ones + // with an arbitrary value + *p++ = 0x00; + *p++ = 0x04; + // Then next 6 bytes are mac address still reversed + for ( i=0; i<6 ; i++) { + *p++ = s->sll_addr[5-i]; + } + + // Device Info + fprintf(stdout, "// %s %s %s ", ifa->ifa_name, ifa->ifa_flags&IFF_UP?"Up":"Down", up?"Linked":"No Link"); + // Raw format for ttnctl + p = deveui+8; + fprintf(stdout, "TTN Dashboard DEVEUI format "); + for ( i=0 ; i<8 ; i++) { + fprintf( stdout, "%02X", *--p); + } + + p = deveui; + // LSB format for application code + fprintf(stdout, "\nstatic const u1_t PROGMEM DEVEUI[8]={"); + for ( i=0 ; i<8 ; i++) { + fprintf( stdout, " 0x%02x%c", *p++, i<7?',':' '); + } + fprintf( stdout, "}; // %s\n", ifa->ifa_name); + + } + } + } + } + + // Free our Linked list + freeifaddrs(ifaddr); + } + return 0; +} + diff --git a/examples/raspi/raw/Makefile b/examples/raspi/raw/Makefile new file mode 100644 index 00000000..e106c40f --- /dev/null +++ b/examples/raspi/raw/Makefile @@ -0,0 +1,39 @@ +# Makefile +# Sample for raw example on Raspberry Pi +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ + +CC = g++ +CFLAGS = -std=c++11 -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" +LIBS = -lbcm2835 +LMICBASE = ../../../src +INCLUDE = -I$(LMICBASE) + +all: raw + +raspi.o: $(LMICBASE)/raspi/raspi.cpp + $(CC) $(CFLAGS) -c $(LMICBASE)/raspi/raspi.cpp $(INCLUDE) + +radio.o: $(LMICBASE)/lmic/radio.c + $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/radio.c $(INCLUDE) + +oslmic.o: $(LMICBASE)/lmic/oslmic.c + $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/oslmic.c $(INCLUDE) + +lmic.o: $(LMICBASE)/lmic/lmic.c + $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/lmic.c $(INCLUDE) + +hal.o: $(LMICBASE)/hal/hal.cpp + $(CC) $(CFLAGS) -c $(LMICBASE)/hal/hal.cpp $(INCLUDE) + +aes.o: $(LMICBASE)/aes/lmic.c + $(CC) $(CFLAGS) -c $(LMICBASE)/aes/lmic.c $(INCLUDE) -o aes.o + +raw.o: raw.cpp + $(CC) $(CFLAGS) -c $(INCLUDE) $< + +raw: raw.o raspi.o radio.o oslmic.o lmic.o hal.o aes.o + $(CC) $^ $(LIBS) -o raw + +clean: + rm -rf *.o raw diff --git a/examples/raspi/raw/raw.cpp b/examples/raspi/raw/raw.cpp new file mode 100644 index 00000000..913c97bb --- /dev/null +++ b/examples/raspi/raw/raw.cpp @@ -0,0 +1,158 @@ +/******************************************************************************* + * 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 + +#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() { + printf("Starting\n"); + + 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); + + printf("Started\n"); + + // setup initial job + os_setCallback(&txjob, tx_func); +} + +int main(void) { + + setup(); + + while(1) { + // execute scheduled jobs and events + os_runloop_once(); + } +} diff --git a/examples/raspi/spi_scan/Makefile b/examples/raspi/spi_scan/Makefile new file mode 100644 index 00000000..ed175b91 --- /dev/null +++ b/examples/raspi/spi_scan/Makefile @@ -0,0 +1,21 @@ +# Makefile +# Sample for spi scan Hope RF module on Raspberry Pi +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ + +CC = g++ +CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" +LIBS = -lbcm2835 +RADIOHEADBASE = ../../.. +INCLUDE = -I$(RADIOHEADBASE) + +all: spi_scan + +spi_scan.o: spi_scan.c + $(CC) $(CFLAGS) -c $(INCLUDE) $< + +spi_scan: spi_scan.o + $(CC) $^ $(LIBS) -o spi_scan + +clean: + rm -rf *.o spi_scan diff --git a/examples/raspi/spi_scan/spi_scan.c b/examples/raspi/spi_scan/spi_scan.c new file mode 100644 index 00000000..0bdb4e1e --- /dev/null +++ b/examples/raspi/spi_scan/spi_scan.c @@ -0,0 +1,106 @@ +// spi_scan.cpp +// +// Example program showing how to detect multiple module RH_RF69/RH_RF95 on Raspberry Pi +// Requires bcm2835 library to be already installed +// http://www.airspayce.com/mikem/bcm2835/ +// Use the Makefile in this directory: +// cd example/raspi/spi_scan +// make +// sudo ./spi_scan +// +// Will check for RFM92/95/96/98 or RFM69/RFM69HCW/RFM69W modules on SPI BUS +// scan with CS = GPIO6, CE0, CEA and GPIO26 +// So it should detect the following boards +// LoRasPi board => https://github.com/hallard/LoRasPI +// RasPI Lora Gateway Board iC880A and LinkLab Lora => https://github.com/ch2i/iC880A-Raspberry-PI +// Raspberri PI Lora Gateway => https://github.com/hallard/RPI-Lora-Gateway +// Dragino Raspberry PI hat => https://github.com/dragino/Lora +// +// Contributed by Charles-Henri Hallard (hallard.me) + +#include +#include + +uint8_t readRegister(uint8_t cs_pin, uint8_t addr) +{ + char spibuf[2]; + spibuf[0] = addr & 0x7F; + spibuf[1] = 0x00; + + bcm2835_gpio_write(cs_pin,0); + bcm2835_spi_transfernb( spibuf, spibuf, sizeof(spibuf) ); + bcm2835_gpio_write(cs_pin,1); + return spibuf[1]; +} + +void getModuleName(uint8_t version) +{ + printf(" => "); + if (version==00 || version==0xFF ) + printf("Nothing!\n"); + else if (version == 0x12) + printf("SX1276 RF95/96"); + else if (version == 0x22) + printf("SX1272 RF92"); + else if (version == 0x24) + printf("SX1231 RFM69"); + else + printf("Unknown"); + + if (version!=00 && version!=0xFF ) + printf(" (V=0x%02X)\n", version); +} + +void readModuleVersion(uint8_t cs_pin) +{ + uint8_t version; + + // RFM9x version is reg 0x42 + printf("Checking register(0x42) with CS=GPIO%02d", cs_pin); + getModuleName( readRegister( cs_pin, 0x42) ); + + // RFM69 version is reg 0x10 + printf("Checking register(0x10) with CS=GPIO%02d", cs_pin); + getModuleName ( readRegister( cs_pin, 0x10) ) ; +} + +int main(int argc, char **argv) +{ + if (!bcm2835_init()) { + printf("bcm2835_init failed. Are you running as root??\n"); + + } else if (!bcm2835_spi_begin()) { + printf("bcm2835_spi_begin failed\n"); + + } else { + // List of all CS line where module can be connected + // GPIO6, GPIO8/CE0, GPIO7/CE1, GPIO26 + uint8_t CS_pins[] = {6, 7, 8, 26}; + uint8_t i; + + // Init SPI + bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // The default + bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // The default + bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default + + // We control CS line manually don't assert CEx line! + bcm2835_spi_chipSelect(BCM2835_SPI_CS_NONE); + + // Drive all CS line as output and set them High to avoid any conflict + for ( i=0; i +#include +#include + +class SFE_BMP180 +{ + public: + SFE_BMP180(); // base type + + char begin(); + // call pressure.begin() to initialize BMP180 before use + // returns 1 if success, 0 if failure (bad component or I2C bus shorted?) + + char startTemperature(void); + // command BMP180 to start a temperature measurement + // returns (number of ms to wait) for success, 0 for fail + + char getTemperature(double &T); + // return temperature measurement from previous startTemperature command + // places returned value in T variable (deg C) + // returns 1 for success, 0 for fail + + char startPressure(char oversampling); + // command BMP180 to start a pressure measurement + // oversampling: 0 - 3 for oversampling value + // returns (number of ms to wait) for success, 0 for fail + + char getPressure(double &P, double &T); + // return absolute pressure measurement from previous startPressure command + // note: requires previous temperature measurement in variable T + // places returned value in P variable (mbar) + // returns 1 for success, 0 for fail + + double sealevel(double P, double A); + // convert absolute pressure to sea-level pressure (as used in weather data) + // P: absolute pressure (mbar) + // A: current altitude (meters) + // returns sealevel pressure in mbar + + double altitude(double P, double P0); + // convert absolute pressure to altitude (given baseline pressure; sea-level, runway, etc.) + // P: absolute pressure (mbar) + // P0: fixed baseline pressure (mbar) + // returns signed altitude in meters + + char getError(void); + // If any library command fails, you can retrieve an extended + // error code using this command. Errors are from the wire library: + // 0 = Success + // 1 = Data too long to fit in transmit buffer + // 2 = Received NACK on transmit of address + // 3 = Received NACK on transmit of data + // 4 = Other error + + private: + + char readInt(char address, int16_t &value); + // read an signed int (16 bits) from a BMP180 register + // address: BMP180 register address + // value: external signed int for returned value (16 bits) + // returns 1 for success, 0 for fail, with result in value + + char readUInt(char address, uint16_t &value); + // read an unsigned int (16 bits) from a BMP180 register + // address: BMP180 register address + // value: external unsigned int for returned value (16 bits) + // returns 1 for success, 0 for fail, with result in value + + char readBytes(unsigned char *values, char length); + // read a number of bytes from a BMP180 register + // values: array of char with register address in first location [0] + // length: number of bytes to read back + // returns 1 for success, 0 for fail, with read bytes in values[] array + + char writeBytes(unsigned char *values, char length); + // write a number of bytes to a BMP180 register (and consecutive subsequent registers) + // values: array of char with register address in first location [0] + // length: number of bytes to write + // returns 1 for success, 0 for fail + + int16_t AC1,AC2,AC3,VB1,VB2,MB,MC,MD; + uint16_t AC4,AC5,AC6; + double c5,c6,mc,md,x0,x1,x2,y0,y1,y2,p0,p1,p2; + char _error; +}; + +#define BMP180_ADDR 0x77 // 7-bit address + +#define BMP180_REG_CONTROL 0xF4 +#define BMP180_REG_RESULT 0xF6 + +#define BMP180_COMMAND_TEMPERATURE 0x2E +#define BMP180_COMMAND_PRESSURE0 0x34 +#define BMP180_COMMAND_PRESSURE1 0x74 +#define BMP180_COMMAND_PRESSURE2 0xB4 +#define BMP180_COMMAND_PRESSURE3 0xF4 + +#endif diff --git a/examples/raspi/ttn-otaa-sensors/si7021.c b/examples/raspi/ttn-otaa-sensors/si7021.c new file mode 100644 index 00000000..cda39c16 --- /dev/null +++ b/examples/raspi/ttn-otaa-sensors/si7021.c @@ -0,0 +1,221 @@ +/* + si7021.c + SI7021 Temperature and Humidity sensor for Raspberry PI + Charles-Henri Hallard from http://ch2i.eu + + + version 1.0 2013/09/20 initial version + Verison 1.1.2 - Updated for Arduino 1.6.4 5/2015 + Version 1.1.3 - Updated for Raspberry PI by Charles-Henri Hallard (hallard.me) + + Our example code uses the "beerware" license. You can do anything + you like with this code. No really, anything. If you find it useful, + buy me a (root) beer someday. + + August 2016 - Charles-Henri Hallard : Addapted to Raspberry PI + + Requires bcm2835 library to be already installed + http://www.airspayce.com/mikem/bcm2835/ + +*/ + +#include "si7021.h" + +/* ====================================================================== +Function: si7021_checkCRC +Purpose : check the CRC of received data +Input : value read from sensor +Output : CRC read from sensor +Comments: 0 if okay +====================================================================== */ +uint8_t si7021_checkCRC(uint16_t data, uint8_t check) +{ + uint32_t remainder, divisor; + + //Pad with 8 bits because we have to add in the check value + remainder = (uint32_t)data << 8; + + // From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html + // POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks + // 0x988000 is the 0x0131 polynomial shifted to farthest left of three bytes + divisor = (uint32_t) 0x988000; + + // Add the check value + remainder |= check; + + // Operate on only 16 positions of max 24. + // The remaining 8 are our remainder and should be zero when we're done. + for (uint8_t i = 0 ; i < 16 ; i++) { + //Check if there is a one in the left position + if( remainder & (uint32_t)1<<(23 - i) ) + remainder ^= divisor; + + //Rotate the divisor max 16 times so that we have 8 bits left of a remainder + divisor >>= 1; + } + return ((uint8_t) remainder); +} + +/* ====================================================================== +Function: si7021_StartConv +Purpose : return temperature or humidity measured +Input : data type SI7021_READ_HUM or SI7021_READ_TEMP +Output : BCM2835_I2C_REASON_OK if okay +Comments: internal values of temp and rh are set +====================================================================== */ +uint8_t si7021_StartConv(si7021_e datatype, int16_t * value) +{ + double data; + uint16_t raw ; + uint8_t checksum; + uint8_t error; + uint8_t buf[3]; + + buf[0] = datatype == SI7021_READ_HUM ? SI7021_MEASURE_HUM : SI7021_MEASURE_TEMP; + error = bcm2835_i2c_write((const char *) buf, 1); + if (error != BCM2835_I2C_REASON_OK ) + return error; + + // Wait for data to become available + // always use time out in loop to avoid + // potential lockup (here 90ms (6*15ms)) + usleep(100000); + + error = bcm2835_i2c_read( (char *) buf, sizeof(buf)); + if (error != BCM2835_I2C_REASON_OK ) { + return error; + } + + // read raw value + raw = ( buf[0] << 8) | buf[1] ; + checksum = buf[2]; + + // Check CRC of data received + if(si7021_checkCRC(raw, checksum) != 0) { + printf("CRC Error %02X\n", checksum); + return -1; + } + + if (datatype == SI7021_READ_HUM) { + // Convert value to Humidity percent (*100) + // for 43.21%rh value will be 4321 + data = -600 + (( raw * 12500 ) / 65536 ) ; + + // Datasheet says doing this check + if (data>10000) data = 10000; + if (data<0) data = 0; + + // save value + *value = (int16_t) data; + + } else { + // Convert value to Temperature (*100) + // for 23.45C value will be 2345 + data = (( raw * 17572) / 65536) - 4685; + + // save value + *value = (int16_t) data; + } + + return error; +} + + +/* ====================================================================== +Function: si7021_readRegister +Purpose : read the user register from the sensor +Input : user register value filled by function +Output : BCM2835_I2C_REASON_OK if okay +Comments: - +====================================================================== */ +uint8_t si7021_readRegister(uint8_t * value) +{ + uint8_t error ; + uint8_t buf[1]; + + buf[0] = SI7021_READ_REG; + error = bcm2835_i2c_write((const char *) buf, 1); + if (error != BCM2835_I2C_REASON_OK ) + return error; + + error = bcm2835_i2c_read( (char*) value, 1); + printf("Error=%d Read Buf[0] = %02X\n", error, *value); + + return error; +} + +/* ====================================================================== +Function: si7021_readValues +Purpose : read temperature and humidity from SI7021 sensor +Input : - +Output : 0 if okay +Comments: - +====================================================================== */ +uint8_t si7021_readValues(int16_t * temp, int16_t * hum) +{ + uint8_t error = 0; + + // start humidity conversion + error |= si7021_StartConv(SI7021_READ_HUM, temp); + + // start temperature conversion + error |= si7021_StartConv(SI7021_READ_TEMP, hum); + + return error; +} + +/* ====================================================================== +Function: si7021_setResolution +Purpose : Sets the sensor resolution to one of four levels +Input : see #define is .h file, default is SI7021_RESOLUTION_14T_12RH +Output : temperature or humidity +Comments: BCM2835_I2C_REASON_OK if okay +====================================================================== */ +uint8_t si7021_setResolution(uint8_t res) +{ + uint8_t buf[2]; + uint8_t reg; + uint8_t error; + + // Get the current register value + error = si7021_readRegister(®); + if ( error == BCM2835_I2C_REASON_OK ) { + // remove resolution bits + reg &= SI7021_RESOLUTION_MASK ; + + // Write the new resolution bits but clear unused before + buf[0] = SI7021_WRITE_REG; + buf[1] = reg | ( res &= ~SI7021_RESOLUTION_MASK); + error = bcm2835_i2c_write( (char *) buf, 2); + } + return error; +} + + +/* ====================================================================== +Function: si7021_getID +Purpose : get the device ID +Input : - +Output : device ID +Comments: Return 0 if an error occured reading device ID +====================================================================== */ +uint8_t si7021_getID( void ) +{ + uint8_t id=0; + uint8_t error; + uint8_t buf[2]; + + buf[0] = SI7021_READ_2ND_ID_1; + buf[1] = SI7021_READ_2ND_ID_2; + error = bcm2835_i2c_write( (char *) buf, 2); + if ( error == BCM2835_I2C_REASON_OK ) { + error = bcm2835_i2c_read( (char*) buf, 1); + if ( error == BCM2835_I2C_REASON_OK ) { + id = buf[0]; + } + } + return id; + } + + + diff --git a/examples/raspi/ttn-otaa-sensors/si7021.h b/examples/raspi/ttn-otaa-sensors/si7021.h new file mode 100644 index 00000000..1e261bb4 --- /dev/null +++ b/examples/raspi/ttn-otaa-sensors/si7021.h @@ -0,0 +1,75 @@ +/* + si7021.c + SI7021 Temperature and Humidity sensor for Raspberry PI + Charles-Henri Hallard from http://ch2i.eu + + version 1.0 2013/09/20 initial version + Verison 1.1.2 - Updated for Arduino 1.6.4 5/2015 + Version 1.1.3 - Updated for Raspberry PI by Charles-Henri Hallard (hallard.me) + + Our example code uses the "beerware" license. You can do anything + you like with this code. No really, anything. If you find it useful, + buy me a (root) beer someday. + + August 2016 - Charles-Henri Hallard : Addapted to Raspberry PI + + Requires bcm2835 library to be already installed + http://www.airspayce.com/mikem/bcm2835/ + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// device ID identifier +#define ID_SI7021 0x15 +#define ID_HTU21D 0x32 + +// ====================================== +// SI7021 sensor +// ====================================== +#define SI7021_I2C_ADDRESS 0x40 // I2C address for the sensor +#define SI7021_MEASURE_TEMP0 0xE0 // Can be read only after a RH conversion done +#define SI7021_MEASURE_TEMP 0xE3 // Default hold +#define SI7021_MEASURE_HUM 0xE5 // Default hold +#define SI7021_MEASURE_NOHOLD 0x80 // NO HOLD Bit flag +#define SI7021_WRITE_REG 0xE6 +#define SI7021_READ_REG 0xE7 +#define SI7021_SOFT_RESET 0xFE +#define SI7021_READ_1ST_ID_1 0xFA +#define SI7021_READ_1ST_ID_2 0x0F +#define SI7021_READ_2ND_ID_1 0xFC +#define SI7021_READ_2ND_ID_2 0xC9 +#define SI7021_READ_FW_REV_1 0x84 +#define SI7021_READ_FW_REV_2 0xB8 + +// SI7021 Sensor resolution +// default at power up is SI7021_RESOLUTION_14T_12RH +#define SI7021_RESOLUTION_14T_12RH 0x00 // 12 bits RH / 14 bits Temp +#define SI7021_RESOLUTION_13T_10RH 0x80 // 10 bits RH / 13 bits Temp +#define SI7021_RESOLUTION_12T_08RH 0x01 // 8 bits RH / 12 bits Temp +#define SI7021_RESOLUTION_11T_11RH 0x81 // 11 bits RH / 11 bits Temp + +#define SI7021_RESOLUTION_MASK 0B01111110 + +// The type of measure we want to trigger on sensor +typedef enum { + SI7021_READ_TEMP, + SI7021_READ_HUM +} +si7021_e; + +// SI7021 temperature / humidity sensor related +uint8_t si7021_StartConv(si7021_e datatype, int16_t * value); +uint8_t si7021_readValues(int32_t * value); +uint8_t si7021_setResolution(uint8_t res); +uint8_t si7021_getID(void); + +double getHumidity(void); +double getTemperature(void); diff --git a/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp b/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp new file mode 100644 index 00000000..5c6b98a8 --- /dev/null +++ b/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp @@ -0,0 +1,417 @@ +/******************************************************************************* + * Copyright (c) 2015 Thomas Telkamp and 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 sends a valid LoRaWAN packet with payload containing + * value from SI7021 or HTU21D sensor Pressure from BMP180 sensor + * using frequency and encryption settings matching those of + * the The Things Network. + * + * This uses OTAA (Over-the-air activation), where where a DevEUI and + * application key is configured, which are used in an over-the-air + * activation procedure where a DevAddr and session keys are + * assigned/generated for use with all further communication. + * + * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in + * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably + * violated by this sketch when left running for longer)! + + * To use this sketch, first register your application and device with + * the things network, to set or generate an AppEUI, DevEUI and AppKey. + * Multiple devices can use the same AppEUI, but each device has its own + * DevEUI and AppKey. + * + * Do not forget to define the radio type correctly in LMIC src/config.h. + * + * This sample has been written by Charles-Henri Hallard (hallard.me) + * It's based on original ttn-otaa sample code + * + * Requires bcm2835 library to be already installed + * http://www.airspayce.com/mikem/bcm2835/ + * use the Makefile in this directory: + * cd examples/raspi/ttn-otaa-sensors + * make + * sudo ./ttn-otaa-sensors + * + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "si7021.h" +#include "bmp180.h" + +// 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]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +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]={ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +// Here on Raspi we use part of MAC Address do define devEUI so +// This one above is not used, but you can still old method +// reverting the comments on the 2 following line +//void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} +void os_getDevEui (u1_t* buf) { getDevEuiFromMac(buf); } + +// 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. +// The key shown here is the semtech default key. +static const u1_t PROGMEM APPKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; +void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} + +// 4 int16_t values +static uint8_t mydata[4*sizeof(int16_t)] ; +static osjob_t sendjob; + +// Schedule TX every this many seconds (might become longer due to duty) +// cycle limitations). +const unsigned TX_INTERVAL = 120; + +//Flag for Ctrl-C +volatile sig_atomic_t force_exit = 0; + +// BMP180 library object +SFE_BMP180 bmp180; +#define ALTITUDE 98 // Chasseuil-du-Poitou FR +//#define ALTITUDE 118 // Montamise FR +//#define ALTITUDE 0 // To get sea-leval altitude +static char dev[16]=""; + + +// LoRasPi board +// see https://github.com/hallard/LoRasPI +#define RF_LED_PIN RPI_V2_GPIO_P1_16 // Led on GPIO23 so P1 connector pin #16 +#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 +#define RF_IRQ_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +#define RF_RST_PIN RPI_V2_GPIO_P1_15 // RST on GPIO22 so P1 connector pin #15 + +// Pin mapping +const lmic_pinmap lmic_pins = { + .nss = RF_CS_PIN, + .rxtx = LMIC_UNUSED_PIN, + .rst = RF_RST_PIN, + .dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN}, +}; + +/* ====================================================================== +Function: getBMP180Values +Purpose : Return temperature and pressure from BPM180 sensor +Input : Altitude +Output : 0 if error otherwise + pressure * 10 filled with absolute pressure or sea-leval + temperature * 100 filled with temperature +Comments: if altitude = 0 then return sea level pressure + value are returned as int16_t to preserve paylaod size +====================================================================== */ +uint8_t getBMP180Values(double altitude, int16_t * pressure, int16_t * temperature) +{ + char status; + double T,P,p0; + + // You must first get a temperature measurement to perform a pressure reading. + + // Start a temperature measurement: + // If request is successful, the number of ms to wait is returned. + // If request is unsuccessful, 0 is returned. + status = bmp180.startTemperature(); + if (status != 0) { + // Wait for the measurement to complete: + usleep( status * 1000); + + // Retrieve the completed temperature measurement: + // Note that the measurement is stored in the variable T. + // Use '&T' to provide the address of T to the function. + // Function returns 1 if successful, 0 if failure. + status = bmp180.getTemperature(T); + if (status != 0) { + // Start a pressure measurement: + // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait). + // If request is successful, the number of ms to wait is returned. + // If request is unsuccessful, 0 is returned. + + // Print out the measurement: + //printf("BMP180 Temperature: %.2f deg C\n", T); + *temperature = (int16_t) (T*100); + + status = bmp180.startPressure(3); + if (status != 0) { + // Wait for the measurement to complete: + usleep(status*1000); + + // Retrieve the completed pressure measurement: + // Note that the measurement is stored in the variable P. + // Use '&P' to provide the address of P. + // Note also that the function requires the previous temperature measurement (T). + // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.) + // Function returns 1 if successful, 0 if failure. + status = bmp180.getPressure(P,T); + + if (status != 0) { + // Print out the measurement: + //printf("absolute pressure: %.1f mb\n", P ); + + // The pressure sensor returns abolute pressure, which varies with altitude. + // To remove the effects of altitude, use the sealevel function and your current altitude. + // This number is commonly used in weather reports. + // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m. + // Result: p0 sea-level compensated pressure in mb + p0 = bmp180.sealevel(P, altitude); + //printf("relative (sea-level) pressure: %.1f mb\n", p0); + + // On the other hand, if you want to determine your altitude from the pressure reading, + // use the altitude function along with a baseline pressure (sea-level or other). + // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb. + // Result: altitude in m. + //printf("computed altitude: %.1f meters\n", bmp180.altitude(P,p0)); + if ( altitude==0) { + *pressure = (int16_t) (P*10) ; + } else { + *pressure = (int16_t) (p0*10); + } + return 1; + } else { + printf("error retrieving pressure measurement\n"); + } + } else { + printf("error starting pressure measurement\n"); + } + } else { + printf("error retrieving temperature measurement\n"); + } + } else { + printf("error starting temperature measurement\n"); + } + + return 0; +} + + +/* ====================================================================== +Function: do_send +Purpose : Measures sensors values and Send a LoraWAN packet +Input : osjob_t * +Output : - +Comments: - +====================================================================== */ +void do_send(osjob_t* j) { + int16_t bmp_pres, bmp_temp, si_temp, si_hum; + char strTime[16]; + getSystemTime(strTime , sizeof(strTime)); + printf("%s: ", strTime); + + // Check if there is not a current TX/RX job running + if (LMIC.opmode & OP_TXRXPEND) { + printf("OP_TXRXPEND, not sending\n"); + } else { + // Clear our payload buffer + memset(mydata,0,sizeof(mydata)); + + printf("Packet queued => "); + // select BMP180 I2C device + bcm2835_i2c_setSlaveAddress (BMP180_ADDR); + if ( getBMP180Values(ALTITUDE, &bmp_pres, &bmp_temp) != 0 ) { + printf("BMP180:%.2fC %.1fmb", bmp_temp/100.0f, bmp_pres/10.0f); + mydata[0] = bmp_temp >> 8; // MSB + mydata[1] = bmp_temp & 0xFF; // LSB + mydata[2] = bmp_pres >> 8; // MSB + mydata[3] = bmp_pres & 0xFF; // LSB + } + + // select SI7021 I2C device + bcm2835_i2c_setSlaveAddress (SI7021_I2C_ADDRESS); + printf(" %s:", dev); + if (si7021_StartConv(SI7021_READ_TEMP, &si_temp)==BCM2835_I2C_REASON_OK ) { + printf("%.2fC ", si_temp /100.0f); + mydata[4] = si_temp >> 8; // MSB + mydata[5] = si_temp & 0xFF; // LSB + } + if ( si7021_StartConv(SI7021_READ_HUM, &si_hum)==BCM2835_I2C_REASON_OK ) { + printf("%.1f%%rh", si_hum / 100.0f); + mydata[6] = si_hum >> 8; // MSB + mydata[7] = si_hum & 0xFF; // LSB + } + + printf("\n"); + + // Prepare upstream data transmission at the next possible time. + LMIC_setTxData2(1, mydata, sizeof(mydata), 0); + } + // Next TX is scheduled after TX_COMPLETE event. +} + +/* ====================================================================== +Function: onEvent +Purpose : callback fired by LMIC stack for event management +Input : ev_t +Output : - +Comments: - +====================================================================== */ +void onEvent (ev_t ev) { + + char strTime[16]; + getSystemTime(strTime , sizeof(strTime)); + printf("%s: ", strTime); + + switch(ev) { + + case EV_JOINED: + printf("EV_JOINED\n"); + + // Disable link check validation (automatically enabled + // during join, but not supported by TTN at this time). + LMIC_setLinkCheckMode(0); + break; + + case EV_TXCOMPLETE: + printf("EV_TXCOMPLETE (includes waiting for RX windows)\n"); + if (LMIC.txrxFlags & TXRX_ACK) + printf("%s Received ack\n", strTime); + if (LMIC.dataLen) { + printf("%s Received %d bytes of payload\n", strTime, LMIC.dataLen); + } + // Light Off LED + digitalWrite(RF_LED_PIN, LOW); + // Schedule next transmission + os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); + break; + + case EV_SCAN_TIMEOUT: printf("EV_SCAN_TIMEOUT\n"); break; + case EV_BEACON_FOUND: printf("EV_BEACON_FOUND\n"); break; + case EV_BEACON_MISSED: printf("EV_BEACON_MISSED\n"); break; + case EV_BEACON_TRACKED: printf("EV_BEACON_TRACKED\n");break; + case EV_JOINING: printf("EV_JOINING\n"); break; + case EV_RFU1: printf("EV_RFU1\n"); break; + case EV_JOIN_FAILED: printf("EV_JOIN_FAILED\n"); break; + case EV_REJOIN_FAILED: printf("EV_REJOIN_FAILED\n"); break; + case EV_LOST_TSYNC: printf("EV_LOST_TSYNC\n"); break; + case EV_RESET: printf("EV_RESET\n"); break; + case EV_RXCOMPLETE: printf("EV_RXCOMPLETE\n"); break; + case EV_LINK_DEAD: printf("EV_LINK_DEAD\n"); break; + case EV_LINK_ALIVE: printf("EV_LINK_ALIVE\n"); break; + default: + printf("Unknown event\n"); + break; + } +} + + +/* ====================================================================== +Function: sig_handler +Purpose : Intercept CTRL-C keyboard to close application +Input : signal received +Output : - +Comments: - +====================================================================== */ +void sig_handler(int sig) +{ + printf("\nBreak received, exiting!\n"); + force_exit=true; +} + +/* ====================================================================== +Function: main +Purpose : Main routine +Input : - +Output : - +Comments: - +====================================================================== */ +int main () +{ + // caught CTRL-C to do clean-up + signal(SIGINT, sig_handler); + + printf("%s Starting\n", __BASEFILE__); + + // Display Hardware RFM95 configuration + printConfig(RF_LED_PIN); + printKeys(); + + // Init GPIO bcm + if (!bcm2835_init()) { + fprintf( stderr, "bcm2835_init() Failed\n\n" ); + return 1; + } + + // Light on LED + pinMode(RF_LED_PIN, OUTPUT); + digitalWrite(RF_LED_PIN, HIGH); + + if (!bcm2835_i2c_begin()) { + fprintf( stderr, "bcm2835_i2c_begin() failed. Are you running as root??\n"); + return 1; + } + + // Set I2C speed to 100KHz + bcm2835_i2c_set_baudrate(100000); + + // Init BMP180 device and check it's here + printf("Checking BMP180 device..."); + if (bmp180.begin()) { + printf("found\n"); + } else { + printf("fail, check wiring\n\n"); + } + + // select SI7021 I2C device + printf("Checking SI7021 or HTU21D device..."); + bcm2835_i2c_setSlaveAddress (SI7021_I2C_ADDRESS); + uint8_t id = si7021_getID(); + // Highest resolution and check device is here + if ( id == ID_SI7021 ) { + strcpy(dev, "SI7021"); + printf("%s found\n", dev ); + + } else if ( id == ID_HTU21D ) { + strcpy(dev, "HTU21D"); + printf("%s found\n", dev); + } else { + strcpy(dev, "Error"); + printf("No SI7021 or HTU21D detected, check wiring\n\n"); + } + + // LMIC init + os_init(); + + // Reset the MAC state. Session and pending data transfers will be discarded. + LMIC_reset(); + + // Start job (sending automatically starts OTAA too) + // Then on transmit will reset it's own send + do_send(&sendjob); + + // Main loop until CTRL-C + while (!force_exit) { + + os_runloop_once(); + + // We're on a multitasking OS let some time for others + // Without this one CPU is 99% and with this one just 3% + // On a Raspberry PI 3 + usleep(1000); + } + + // We're here because we need to exit, do it clean + + // Light off on board LED + digitalWrite(RF_LED_PIN, LOW); + + // Release I2C and BCM2835 + bcm2835_i2c_end(); + bcm2835_close(); + return 0; +} diff --git a/examples/raspi/ttn-otaa/Makefile b/examples/raspi/ttn-otaa/Makefile new file mode 100644 index 00000000..3c101325 --- /dev/null +++ b/examples/raspi/ttn-otaa/Makefile @@ -0,0 +1,39 @@ +# Makefile +# Sample for ttn-otaa example on Raspberry Pi +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ + +CC = g++ +CFLAGS = -std=c++11 -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" +LIBS = -lbcm2835 +LMICBASE = ../../../src +INCLUDE = -I$(LMICBASE) + +all: ttn-otaa + +raspi.o: $(LMICBASE)/raspi/raspi.cpp + $(CC) $(CFLAGS) -c $(LMICBASE)/raspi/raspi.cpp $(INCLUDE) + +radio.o: $(LMICBASE)/lmic/radio.c + $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/radio.c $(INCLUDE) + +oslmic.o: $(LMICBASE)/lmic/oslmic.c + $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/oslmic.c $(INCLUDE) + +lmic.o: $(LMICBASE)/lmic/lmic.c + $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/lmic.c $(INCLUDE) + +hal.o: $(LMICBASE)/hal/hal.cpp + $(CC) $(CFLAGS) -c $(LMICBASE)/hal/hal.cpp $(INCLUDE) + +aes.o: $(LMICBASE)/aes/lmic.c + $(CC) $(CFLAGS) -c $(LMICBASE)/aes/lmic.c $(INCLUDE) -o aes.o + +ttn-otaa.o: ttn-otaa.cpp + $(CC) $(CFLAGS) -c $(INCLUDE) $< + +ttn-otaa: ttn-otaa.o raspi.o radio.o oslmic.o lmic.o hal.o aes.o + $(CC) $^ $(LIBS) -o ttn-otaa + +clean: + rm -rf *.o ttn-otaa diff --git a/examples/raspi/ttn-otaa/ttn-otaa.cpp b/examples/raspi/ttn-otaa/ttn-otaa.cpp new file mode 100644 index 00000000..5b18a9a0 --- /dev/null +++ b/examples/raspi/ttn-otaa/ttn-otaa.cpp @@ -0,0 +1,261 @@ +/******************************************************************************* + * Copyright (c) 2015 Thomas Telkamp and 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 sends a valid LoRaWAN packet with payload "Hello, + * world!", using frequency and encryption settings matching those of + * the The Things Network. + * + * This uses OTAA (Over-the-air activation), where where a DevEUI and + * application key is configured, which are used in an over-the-air + * activation procedure where a DevAddr and session keys are + * assigned/generated for use with all further communication. + * + * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in + * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably + * violated by this sketch when left running for longer)! + + * To use this sketch, first register your application and device with + * the things network, to set or generate an AppEUI, DevEUI and AppKey. + * Multiple devices can use the same AppEUI, but each device has its own + * DevEUI and AppKey. + * + * Do not forget to define the radio type correctly in config.h. + * + *******************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +// 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]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +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]={ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +// Here on Raspi we use part of MAC Address do define devEUI so +// This one above is not used, but you can still old method +// reverting the comments on the 2 following line +//void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} +void os_getDevEui (u1_t* buf) { getDevEuiFromMac(buf); } + +// 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. +// The key shown here is the semtech default key. +static const u1_t PROGMEM APPKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; +void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} + +static uint8_t mydata[] = "Raspi LMIC!"; +static osjob_t sendjob; + +// Schedule TX every this many seconds (might become longer due to duty) +// cycle limitations). +const unsigned TX_INTERVAL = 120; + +//Flag for Ctrl-C +volatile sig_atomic_t force_exit = 0; + +// LoRasPi board +// see https://github.com/hallard/LoRasPI +//#define RF_LED_PIN RPI_V2_GPIO_P1_16 // Led on GPIO23 so P1 connector pin #16 +//#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 +//#define RF_IRQ_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +//#define RF_RST_PIN RPI_V2_GPIO_P1_15 // RST on GPIO22 so P1 connector pin #15 + +// Raspberri PI Lora Gateway for multiple modules +// see https://github.com/hallard/RPI-Lora-Gateway +// Module 1 on board RFM95 868 MHz (example) +#define RF_LED_PIN RPI_V2_GPIO_P1_07 // Led on GPIO4 so P1 connector pin #7 +#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 +#define RF_IRQ_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +#define RF_RST_PIN RPI_V2_GPIO_P1_29 // Reset on GPIO5 so P1 connector pin #29 + + +// Dragino Raspberry PI hat (no onboard led) +// see https://github.com/dragino/Lora +//#define RF_CS_PIN RPI_V2_GPIO_P1_22 // Slave Select on GPIO25 so P1 connector pin #22 +//#define RF_IRQ_PIN RPI_V2_GPIO_P1_07 // IRQ on GPIO4 so P1 connector pin #7 +//#define RF_RST_PIN RPI_V2_GPIO_P1_11 // Reset on GPIO17 so P1 connector pin #11 + +// Pin mapping +const lmic_pinmap lmic_pins = { + .nss = RF_CS_PIN, + .rxtx = LMIC_UNUSED_PIN, + .rst = RF_RST_PIN, + .dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN}, +}; + +#ifndef RF_LED_PIN +#define RF_LED_PIN NOT_A_PIN +#endif + +void do_send(osjob_t* j) { + char strTime[16]; + getSystemTime(strTime , sizeof(strTime)); + printf("%s: ", strTime); + + // Check if there is not a current TX/RX job running + if (LMIC.opmode & OP_TXRXPEND) { + printf("OP_TXRXPEND, not sending\n"); + } else { + digitalWrite(RF_LED_PIN, HIGH); + // Prepare upstream data transmission at the next possible time. + LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0); + printf("Packet queued\n"); + } + // Next TX is scheduled after TX_COMPLETE event. +} + +void onEvent (ev_t ev) { + char strTime[16]; + getSystemTime(strTime , sizeof(strTime)); + printf("%s: ", strTime); + + switch(ev) { + case EV_SCAN_TIMEOUT: + printf("EV_SCAN_TIMEOUT\n"); + break; + case EV_BEACON_FOUND: + printf("EV_BEACON_FOUND\n"); + break; + case EV_BEACON_MISSED: + printf("EV_BEACON_MISSED\n"); + break; + case EV_BEACON_TRACKED: + printf("EV_BEACON_TRACKED\n"); + break; + case EV_JOINING: + printf("EV_JOINING\n"); + break; + case EV_JOINED: + printf("EV_JOINED\n"); + digitalWrite(RF_LED_PIN, LOW); + // Disable link check validation (automatically enabled + // during join, but not supported by TTN at this time). + LMIC_setLinkCheckMode(0); + break; + case EV_RFU1: + printf("EV_RFU1\n"); + break; + case EV_JOIN_FAILED: + printf("EV_JOIN_FAILED\n"); + break; + case EV_REJOIN_FAILED: + printf("EV_REJOIN_FAILED\n"); + break; + case EV_TXCOMPLETE: + printf("EV_TXCOMPLETE (includes waiting for RX windows)\n"); + if (LMIC.txrxFlags & TXRX_ACK) + printf("%s Received ack\n", strTime); + if (LMIC.dataLen) { + printf("%s Received %d bytes of payload\n", strTime, LMIC.dataLen); + } + digitalWrite(RF_LED_PIN, LOW); + // Schedule next transmission + os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); + break; + case EV_LOST_TSYNC: + printf("EV_LOST_TSYNC\n"); + break; + case EV_RESET: + printf("EV_RESET\n"); + break; + case EV_RXCOMPLETE: + // data received in ping slot + printf("EV_RXCOMPLETE\n"); + break; + case EV_LINK_DEAD: + printf("EV_LINK_DEAD\n"); + break; + case EV_LINK_ALIVE: + printf("EV_LINK_ALIVE\n"); + break; + default: + printf("Unknown event\n"); + break; + } +} + +/* ====================================================================== +Function: sig_handler +Purpose : Intercept CTRL-C keyboard to close application +Input : signal received +Output : - +Comments: - +====================================================================== */ +void sig_handler(int sig) +{ + printf("\nBreak received, exiting!\n"); + force_exit=true; +} + +/* ====================================================================== +Function: main +Purpose : not sure ;) +Input : command line parameters +Output : - +Comments: - +====================================================================== */ +int main(void) +{ + // caught CTRL-C to do clean-up + signal(SIGINT, sig_handler); + + printf("%s Starting\n", __BASEFILE__); + + // Init GPIO bcm + if (!bcm2835_init()) { + fprintf( stderr, "bcm2835_init() Failed\n\n" ); + return 1; + } + + // Show board config + printConfig(RF_LED_PIN); + printKeys(); + + // Light off on board LED + pinMode(RF_LED_PIN, OUTPUT); + digitalWrite(RF_LED_PIN, HIGH); + + // LMIC init + os_init(); + // Reset the MAC state. Session and pending data transfers will be discarded. + LMIC_reset(); + + // Start job (sending automatically starts OTAA too) + do_send(&sendjob); + + while(!force_exit) { + os_runloop_once(); + + // We're on a multitasking OS let some time for others + // Without this one CPU is 99% and with this one just 3% + // On a Raspberry PI 3 + usleep(1000); + } + + // We're here because we need to exit, do it clean + + // Light off on board LED + digitalWrite(RF_LED_PIN, LOW); + + // module CS line High + digitalWrite(lmic_pins.nss, HIGH); + printf( "\n%s, done my job!\n", __BASEFILE__ ); + bcm2835_close(); + return 0; +} From 24e19a615b84af29f9fcb46da5ddff50c98b573e Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Thu, 23 May 2019 14:25:54 +0200 Subject: [PATCH 2/5] raspberry pi hal --- src/raspi/raspi.cpp | 347 ++++++++++++++++++++++++++++++++++++++++++++ src/raspi/raspi.h | 158 ++++++++++++++++++++ 2 files changed, 505 insertions(+) create mode 100644 src/raspi/raspi.cpp create mode 100644 src/raspi/raspi.h diff --git a/src/raspi/raspi.cpp b/src/raspi/raspi.cpp new file mode 100644 index 00000000..f5807fef --- /dev/null +++ b/src/raspi/raspi.cpp @@ -0,0 +1,347 @@ +// raspi.cpp +// +// Routines for implementing Arduino-LIMC on Raspberry Pi +// using BCM2835 library for GPIO +// This code has been grabbed from excellent RadioHead Library + +#ifdef RASPBERRY_PI +#include +#include +#include +#include "raspi.h" + +//Initialize the values for sanity +static uint64_t epochMilli ; +static uint64_t epochMicro ; + +void SPIClass::begin() { + initialiseEpoch(); + + if (!bcm2835_spi_begin()) { + printf( "bcm2835_spi_begin() failed. Are you running as root??\n"); + } else { + // LMIC Library code control CS line + bcm2835_spi_chipSelect(BCM2835_SPI_CS_NONE); + } +} + +void SPIClass::end() { + //End the SPI + bcm2835_spi_end(); +} + +void SPIClass::beginTransaction(SPISettings settings) { + //Set SPI clock divider + bcm2835_spi_setClockDivider(settings.divider); + //Set the SPI bit Order + bcm2835_spi_setBitOrder(settings.bitOrder); + //Set SPI data mode + bcm2835_spi_setDataMode(settings.dataMode); + + uint8_t cs = lmic_pins.nss; + // This one was really tricky and spent some time to find + // it. When SPI transaction is done bcm2835 can setup CE0/CE1 + // pins as ALT0 function which may cause chip unselected or + // selected depending on chip. And if there are more than 1, + // then it can also interfere with other chip communication so + // what we do here is to ensure ou CE0 and CE1 are output HIGH so + // no other interference is happening if other chip are connected + bcm2835_gpio_fsel ( 7, BCM2835_GPIO_FSEL_OUTP ); + bcm2835_gpio_fsel ( 8, BCM2835_GPIO_FSEL_OUTP ); + bcm2835_gpio_write( 7, HIGH ); + bcm2835_gpio_write( 8, HIGH ); + + // CS line as output + if ( cs!=7 && cs!=8) { + bcm2835_gpio_fsel( cs, BCM2835_GPIO_FSEL_OUTP ); + bcm2835_gpio_write( cs, HIGH); + } +} + +void SPIClass::endTransaction() { +} + +byte SPIClass::transfer(byte _data) { + byte data; + data= bcm2835_spi_transfer((uint8_t)_data); + return data; +} + +void pinMode(unsigned char pin, unsigned char mode) { + if (pin == LMIC_UNUSED_PIN) { + return; + } + if (mode == OUTPUT) { + bcm2835_gpio_fsel(pin,BCM2835_GPIO_FSEL_OUTP); + } else { + bcm2835_gpio_fsel(pin,BCM2835_GPIO_FSEL_INPT); + } +} + +void digitalWrite(unsigned char pin, unsigned char value) { + if (pin == LMIC_UNUSED_PIN) { + return; + } + bcm2835_gpio_write(pin, value); +} + +unsigned char digitalRead(unsigned char pin) { + if (pin == LMIC_UNUSED_PIN) { + return 0; + } + return bcm2835_gpio_lev(pin); +} + +//Initialize a timestamp for millis/micros calculation +// Grabbed from WiringPi +void initialiseEpoch() { + struct timeval tv ; + gettimeofday (&tv, NULL) ; + epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ; + epochMicro = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)(tv.tv_usec) ; + pinMode(lmic_pins.nss, OUTPUT); + digitalWrite(lmic_pins.nss, HIGH); +} + +unsigned int millis() { + struct timeval tv ; + uint64_t now ; + gettimeofday (&tv, NULL) ; + now = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ; + return (uint32_t)(now - epochMilli) ; +} + +unsigned int micros() { + struct timeval tv ; + uint64_t now ; + gettimeofday (&tv, NULL) ; + now = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)tv.tv_usec ; + return (uint32_t)(now - epochMicro) ; +} + +char * getSystemTime(char * time_buff, int len) { + time_t t; + struct tm* tm_info; + + t = time(NULL); + tm_info = localtime(&t); + if (tm_info) { + if (strftime(time_buff, len, "%H:%M:%S", tm_info)) { + } else { + strncpy(time_buff, "strftime() ERR", len); + } + } else { + strncpy(time_buff, "localtime() ERR", len); + } + return time_buff; +} + +void printConfig(const uint8_t led) { + printf( "RFM95 device configuration\n" ); + if (lmic_pins.nss ==LMIC_UNUSED_PIN ) { + printf( "!! CS pin is not defined !!\n" ); + } else { + printf( "CS=GPIO%d", lmic_pins.nss ); + } + + printf( " RST=" ); + if (lmic_pins.rst==LMIC_UNUSED_PIN ) { + printf( "Unused" ); + } else { + printf( "GPIO%d", lmic_pins.rst ); + } + + printf( " LED=" ); + if ( led==LMIC_UNUSED_PIN ) { + printf( "Unused" ); + } else { + printf( "GPIO%d", led ); + } + + // DIO + for (uint8_t i=0; i<3 ; i++) { + printf( " DIO%d=", i ); + if (lmic_pins.dio[i]==LMIC_UNUSED_PIN ) { + printf( "Unused" ); + } else { + printf( "GPIO%d", lmic_pins.dio[i] ); + } + } + printf( "\n" ); +} + +// Display a Key +// ============= +void printKey(const char * name, const uint8_t * key, uint8_t len, bool lsb) +{ + uint8_t start=lsb?len:0; + uint8_t end = lsb?0:len; + const uint8_t * p ; + + printf("%s : ", name); + for (uint8_t i=0; iifa_next) { + // Ethernet + if ( (ifa->ifa_addr) && (ifa->ifa_addr->sa_family==AF_PACKET) ) { + // Not loopback interface + if (! (ifa->ifa_flags & IFF_LOOPBACK)) { + char fname[128]; + int fd; + int up=0; + struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr; + + // Get interface status + // Interface can be up with no cable connected and to be sure + // It's up, active and connected we need to get operstate + // + // if up + cable if up + NO cable if down + cable + // ============= ========== ================== + // carrier:1 carrier:0 carrier:Invalid + // dormant:0 dormant:0 dormant:Invalid + // operstate:up operstate:down operstate :own + sprintf(fname, "/sys/class/net/%s/operstate", ifa->ifa_name); + if ( (fd = open( fname, O_RDONLY)) > 0 ){ + char buf[2]; + if ( read(fd, buf, 2) > 0 ) { + // only first active interface "up" + if ( buf[0]=='u' && buf[1]=='p' ) { + uint8_t * p = pdeveui; + // deveui is LSB to we reverse it so TTN display + // will remain the same as MAC address + // MAC is 6 bytes, devEUI 8, set first 2 ones + // with an arbitrary value + *p++ = 0x00; + *p++ = 0x04; + // Then next 6 bytes are mac address still reversed + for ( i=0; i<6 ; i++) { + *p++ = s->sll_addr[5-i]; + } + + gotit = true; + close(fd); + break; + } + } + close(fd); + } + } + } + } + // Free our Linked list + freeifaddrs(ifaddr); + } + + // just in case of error put deveui to 0102030405060708 + if (!gotit) { + for (i=1; i<=8; i++) { + *pdeveui++=i; + } + } + return gotit; +} + +void SerialSimulator::begin(int baud) { + // No implementation neccesary - Serial emulation on Linux = standard console + // Initialize a timestamp for millis calculation - we do this here as well in case SPI + // isn't used for some reason + initialiseEpoch(); +} + +size_t SerialSimulator::println(void) { + fprintf(stdout, "\n"); +} + +size_t SerialSimulator::println(const char* s) { + fprintf( stdout, "%s\n",s); +} + +size_t SerialSimulator::print(const char* s) { + fprintf( stdout, "%s",s); +} + +size_t SerialSimulator::println(u2_t n) { + fprintf(stdout, "%d\n", n); +} + +size_t SerialSimulator::print(ostime_t n) { + fprintf(stdout, "%d\n", n); +} + +size_t SerialSimulator::print(unsigned int n, int base) { + if (base == DEC) + fprintf(stdout, "%d", n); + else if (base == HEX) + fprintf(stdout, "%02x", n); + else if (base == OCT) + fprintf(stdout, "%o", n); + // TODO: BIN +} + +size_t SerialSimulator::print(char ch) { + fprintf(stdout, "%c", ch); +} + +size_t SerialSimulator::println(char ch) { + fprintf(stdout, "%c\n", ch); +} + +size_t SerialSimulator::print(unsigned char ch, int base) { + return print((unsigned int)ch, base); +} + +size_t SerialSimulator::println(unsigned char ch, int base) { + print((unsigned int)ch, base); + fprintf( stdout, "\n"); +} + +size_t SerialSimulator::write(char ch) { + fprintf( stdout, "%c", ch); +} + +size_t SerialSimulator::write(unsigned char* s, size_t len) { + for (int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "hal/hal.h" + +#ifndef NULL + #define NULL 0 +#endif + +#ifndef OUTPUT + #define OUTPUT BCM2835_GPIO_FSEL_OUTP +#endif + +#ifndef INPUT + #define INPUT BCM2835_GPIO_FSEL_INPT +#endif + +#ifndef NOT_A_PIN + #define NOT_A_PIN 0xFF +#endif + +#ifndef LED_BUILTIN + #define LED_BUILTIN NOT_A_PIN +#endif + +// We don't have IRQ on Raspberry PI +#define interrupts() {} +#define noInterrupts() {} + +// Delay macros +#define delay(x) bcm2835_delay(x) +#define delayMicroseconds(m) bcm2835_delayMicroseconds(m) + +// No memcpy_P/PROGMEM on Raspberry PI +#ifndef memcpy_P +#define memcpy_P memcpy +#endif + +#ifndef PROGMEM +#define PROGMEM +#endif + +// F() Macro +#define F(s) + +#define random(x) (rand() % x) + +typedef unsigned char byte; + +class SPISettings +{ + public: + SPISettings(uint16_t divider, uint8_t bitOrder, uint8_t dataMode) { + init(divider, bitOrder, dataMode); + } + SPISettings() { + init(BCM2835_SPI_CLOCK_DIVIDER_256, BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_SPI_MODE0); + } + private: + void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode) { + this->divider = divider ; + this->bitOrder = bitOrder; + this->dataMode = dataMode; + } + + uint16_t divider ; + uint8_t bitOrder ; + uint8_t dataMode ; + friend class SPIClass; +}; + +class SPIClass { + public: + static byte transfer(byte _data); + // SPI Configuration methods + static void begin(); // Default + static void end(); + static void beginTransaction(SPISettings settings); + static void endTransaction(); + static void setBitOrder(uint8_t); + static void setDataMode(uint8_t); + static void setClockDivider(uint16_t); +}; + +extern SPIClass SPI; + +class SerialSimulator { + public: + #define DEC 10 + #define HEX 16 + #define OCT 8 + #define BIN 2 + + // TODO: move these from being inlined + static void begin(int baud); + static size_t println(void); + static size_t println(const char* s); + static size_t print(const char* s); + static size_t println(u2_t n); + static size_t print(ostime_t n); + static size_t print(unsigned int n, int base = DEC); + static size_t print(char ch); + static size_t println(char ch); + static size_t print(unsigned char ch, int base = DEC); + static size_t println(unsigned char ch, int base = DEC); + static size_t write(char ch); + static size_t write(unsigned char * s, size_t len); + static void flush(void); + +}; +extern SerialSimulator Serial; + +#ifdef __cplusplus +extern "C"{ +#endif + +void printConfig(const uint8_t led) ; +void printKey(const char * name, const uint8_t * key, uint8_t len, bool lsb); +void printKeys() ; +bool getDevEuiFromMac(uint8_t *); +char * getSystemTime(char * time_buff, int len); +void pinMode(unsigned char, unsigned char); +void digitalWrite(unsigned char, unsigned char); +unsigned char digitalRead(unsigned char) ; +void initialiseEpoch(); +unsigned int millis(); +unsigned int micros(); + +#ifdef __cplusplus +} +#endif + +#endif // RASPI_h +#endif // RASPBERRY_PI + From 19939a6c52fbc9e1c21b995645a12f6c6edebcfa Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 23 May 2019 15:06:28 +0000 Subject: [PATCH 3/5] rpi updates --- examples/raspi/Makefile | 54 ++++ examples/raspi/Makefile.env | 13 + examples/raspi/ttn-abp/Makefile | 17 ++ examples/raspi/ttn-abp/ttn-abp.cpp | 374 +++++++++++++++++++++++++++ examples/raspi/ttn-otaa/Makefile | 34 +-- examples/raspi/ttn-otaa/ttn-otaa.cpp | 34 ++- project_config/lmic_project_config.h | 4 +- src/hal/hal.cpp | 26 ++ src/lmic/config.h | 8 +- src/lmic/lmic.c | 4 +- src/raspi/raspi.cpp | 8 + src/raspi/raspi.h | 6 +- 12 files changed, 540 insertions(+), 42 deletions(-) create mode 100644 examples/raspi/Makefile create mode 100644 examples/raspi/Makefile.env create mode 100644 examples/raspi/ttn-abp/Makefile create mode 100644 examples/raspi/ttn-abp/ttn-abp.cpp diff --git a/examples/raspi/Makefile b/examples/raspi/Makefile new file mode 100644 index 00000000..c75e9da5 --- /dev/null +++ b/examples/raspi/Makefile @@ -0,0 +1,54 @@ +# Makefile +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ + +include Makefile.env + +all: arduino-lmic.a + +arduino-lmic.a: raspi.o radio.o oslmic.o lmic.o hal.o aes.o \ + lmic_as923.o lmic_au921.o lmic_eu868.o lmic_in866.o lmic_us915.o \ + lmic_us_like.o lmic_eu_like.o + $(AR) rcs $@ $^ + +raspi.o: $(LMICBASE)/raspi/raspi.cpp + $(CXX) $(CFLAGS) -c $^ $(INCLUDE) + +radio.o: $(LMICBASE)/lmic/radio.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +oslmic.o: $(LMICBASE)/lmic/oslmic.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic.o: $(LMICBASE)/lmic/lmic.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +hal.o: $(LMICBASE)/hal/hal.cpp + $(CXX) $(CFLAGS) -c $^ $(INCLUDE) + +aes.o: $(LMICBASE)/aes/lmic.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) -o aes.o + +lmic_as923.o: $(LMICBASE)/lmic/lmic_as923.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic_au921.o: $(LMICBASE)/lmic/lmic_au921.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic_eu868.o: $(LMICBASE)/lmic/lmic_eu868.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic_in866.o: $(LMICBASE)/lmic/lmic_in866.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic_us915.o: $(LMICBASE)/lmic/lmic_us915.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic_us_like.o: $(LMICBASE)/lmic/lmic_us_like.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +lmic_eu_like.o: $(LMICBASE)/lmic/lmic_eu_like.c + $(CC) $(CFLAGS) -c $^ $(INCLUDE) + +clean: + rm -rf *.o *.a diff --git a/examples/raspi/Makefile.env b/examples/raspi/Makefile.env new file mode 100644 index 00000000..41780430 --- /dev/null +++ b/examples/raspi/Makefile.env @@ -0,0 +1,13 @@ +# Makefile +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ + +CC = gcc -std=c99 +CXX = g++ -std=c++11 +CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" +LIBS = -lbcm2835 +LMICBASE = ../../src +INCLUDE = -I$(LMICBASE) -I$(LMICBASE)/raspi/mock + +.SUFFIXES: # no implicit rules + diff --git a/examples/raspi/ttn-abp/Makefile b/examples/raspi/ttn-abp/Makefile new file mode 100644 index 00000000..94c8e4f9 --- /dev/null +++ b/examples/raspi/ttn-abp/Makefile @@ -0,0 +1,17 @@ +# Sample for ttn-abp example on Raspberry Pi +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ + +include ../Makefile.env +LMICBASE = ../../../src + +all: ttn-abp + +%.o: %.cpp + $(CXX) $(CFLAGS) -c $(INCLUDE) $< + +%: %.o ../arduino-lmic.a + $(CXX) $^ $(LIBS) -o $@ + +clean: + rm -rf *.o ttn-abp diff --git a/examples/raspi/ttn-abp/ttn-abp.cpp b/examples/raspi/ttn-abp/ttn-abp.cpp new file mode 100644 index 00000000..dc229bfc --- /dev/null +++ b/examples/raspi/ttn-abp/ttn-abp.cpp @@ -0,0 +1,374 @@ +/******************************************************************************* + * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman + * Copyright (c) 2018 Terry Moore, MCCI + * + * 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 sends a valid LoRaWAN packet with payload "Hello, + * world!", using frequency and encryption settings matching those of + * the The Things Network. + * + * This uses ABP (Activation-by-personalisation), where a DevAddr and + * Session keys are preconfigured (unlike OTAA, where a DevEUI and + * application key is configured, while the DevAddr and session keys are + * assigned/generated in the over-the-air-activation procedure). + * + * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in + * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably + * violated by this sketch when left running for longer)! + * + * To use this sketch, first register your application and device with + * the things network, to set or generate a DevAddr, NwkSKey and + * AppSKey. Each device should have their own unique values for these + * fields. + * + * Do not forget to define the radio type correctly in + * arduino-lmic/project_config/lmic_project_config.h or from your BOARDS.txt. + * + *******************************************************************************/ + + // References: + // [feather] adafruit-feather-m0-radio-with-lora-module.pdf + +#include +#include +#include +#include + +#include +#include + +#include +#include + +// +// For normal use, we require that you edit the sketch to replace FILLMEIN +// with values assigned by the TTN console. However, for regression tests, +// we want to be able to compile these scripts. The regression tests define +// COMPILE_REGRESSION_TEST, and in that case we define FILLMEIN to a non- +// working but innocuous value. +// +#ifdef COMPILE_REGRESSION_TEST +# define FILLMEIN 0 +#else +# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!" +# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN) +#endif + +// LoRaWAN NwkSKey, network session key +static const PROGMEM u1_t NWKSKEY[16] = { 0xC3, 0x24, 0x64, 0x98, 0xDE, 0x56, 0x5D, 0x8C, 0x55, 0x88, 0x7C, 0x05, 0x86, 0xF9, 0x82, 0x26 }; + +// LoRaWAN AppSKey, application session key +static const u1_t PROGMEM APPSKEY[16] = { 0x15, 0xF6, 0xF4, 0xD4, 0x2A, 0x95, 0xB0, 0x97, 0x53, 0x27, 0xB7, 0xC1, 0x45, 0x6E, 0xC5, 0x45 }; + +// LoRaWAN end-device address (DevAddr) +// See http://thethingsnetwork.org/wiki/AddressSpace +// The library converts the address to network byte order as needed. +static const u4_t DEVADDR = 0x1234 ; // <-- Change this address for every node! + +// 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-lmic/project_config/lmic_project_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 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 = 60; + +// LoRasPi board +// see https://github.com/hallard/LoRasPI +//#define RF_LED_PIN RPI_V2_GPIO_P1_16 // Led on GPIO23 so P1 connector pin #16 +//#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 +//#define RF_DIO0_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +//#define RF_RST_PIN RPI_V2_GPIO_P1_15 // RST on GPIO22 so P1 connector pin #15 + +// Raspberri PI Lora Gateway for multiple modules +// see https://github.com/hallard/RPI-Lora-Gateway +// Module 1 on board RFM95 868 MHz (example) +//#define RF_LED_PIN RPI_V2_GPIO_P1_07 // Led on GPIO4 so P1 connector pin #7 +//#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 +//#define RF_DIO0_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +//#define RF_RST_PIN RPI_V2_GPIO_P1_29 // Reset on GPIO5 so P1 connector pin #29 + +// Dragino Raspberry PI hat (no onboard led) +// see https://github.com/dragino/Lora +//#define RF_CS_PIN RPI_V2_GPIO_P1_22 // Slave Select on GPIO25 so P1 connector pin #22 +//#define RF_DIO0_PIN RPI_V2_GPIO_P1_07 // IRQ on GPIO4 so P1 connector pin #7 +//#define RF_RST_PIN RPI_V2_GPIO_P1_11 // Reset on GPIO17 so P1 connector pin #11 + +// Chistera-Pi (no onboard led) +// see https://www.framboise314.fr/chistera-pi-lora-a-portee-de-main-grace-a-snootlab/ +#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0/GPIO8 so P1 connector pin #24 +#define RF_DIO0_PIN RPI_V2_GPIO_P1_07 // IRQ on GPIO4 so P1 connector pin #7 +#define RF_DIO1_PIN RPI_V2_GPIO_P1_16 // IRQ on GPIO23 so P1 connector pin #7 +#define RF_RST_PIN RPI_V2_GPIO_P1_11 // Reset on GPIO17 so P1 connector pin #11 + +#ifndef RF_DIO0_PIN +#define RF_DIO0_PIN LMIC_UNUSED_PIN +#endif +#ifndef RF_DIO1_PIN +#define RF_DIO1_PIN LMIC_UNUSED_PIN +#endif +#ifndef RF_DIO2_PIN +#define RF_DIO2_PIN LMIC_UNUSED_PIN +#endif + +// Pin mapping +const lmic_pinmap lmic_pins = { + .nss = RF_CS_PIN, + .rxtx = LMIC_UNUSED_PIN, + .rst = RF_RST_PIN, + .dio = {RF_DIO0_PIN,RF_DIO1_PIN,RF_DIO2_PIN}, +}; + +void do_send(osjob_t* j); + +void onEvent (ev_t ev) { + Serial.print(os_getTime()); + Serial.print(": "); + switch(ev) { + case EV_SCAN_TIMEOUT: + Serial.println(F("EV_SCAN_TIMEOUT")); + break; + case EV_BEACON_FOUND: + Serial.println(F("EV_BEACON_FOUND")); + break; + case EV_BEACON_MISSED: + Serial.println(F("EV_BEACON_MISSED")); + break; + case EV_BEACON_TRACKED: + Serial.println(F("EV_BEACON_TRACKED")); + break; + case EV_JOINING: + Serial.println(F("EV_JOINING")); + break; + case EV_JOINED: + Serial.println(F("EV_JOINED")); + break; + /* + || This event is defined but not used in the code. No + || point in wasting codespace on it. + || + || case EV_RFU1: + || Serial.println(F("EV_RFU1")); + || break; + */ + case EV_JOIN_FAILED: + Serial.println(F("EV_JOIN_FAILED")); + break; + case EV_REJOIN_FAILED: + Serial.println(F("EV_REJOIN_FAILED")); + break; + case EV_TXCOMPLETE: + Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); + if (LMIC.txrxFlags & TXRX_ACK) + Serial.println(F("Received ack")); + if (LMIC.dataLen) { + Serial.println(F("Received ")); + Serial.println(LMIC.dataLen); + Serial.println(F(" bytes of payload")); + } + // Schedule next transmission + os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); + break; + case EV_LOST_TSYNC: + Serial.println(F("EV_LOST_TSYNC")); + break; + case EV_RESET: + Serial.println(F("EV_RESET")); + break; + case EV_RXCOMPLETE: + // data received in ping slot + Serial.println(F("EV_RXCOMPLETE")); + break; + case EV_LINK_DEAD: + Serial.println(F("EV_LINK_DEAD")); + break; + case EV_LINK_ALIVE: + Serial.println(F("EV_LINK_ALIVE")); + break; + /* + || This event is defined but not used in the code. No + || point in wasting codespace on it. + || + || case EV_SCAN_FOUND: + || Serial.println(F("EV_SCAN_FOUND")); + || break; + */ + case EV_TXSTART: + Serial.println(F("EV_TXSTART")); + break; + default: + Serial.print(F("Unknown event: ")); + Serial.println((unsigned) 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. + LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0); + Serial.println(F("Packet queued")); + } + // Next TX is scheduled after TX_COMPLETE event. +} + +void setup() { +// pinMode(13, OUTPUT); + while (!Serial); // wait for Serial to be initialized + Serial.begin(115200); + delay(100); // per sample code on RF_95 test + Serial.println(F("Starting")); + + #ifdef VCC_ENABLE + // For Pinoccio Scout boards + pinMode(VCC_ENABLE, OUTPUT); + digitalWrite(VCC_ENABLE, HIGH); + delay(1000); + #endif + + // LMIC init + os_init(); + // Reset the MAC state. Session and pending data transfers will be discarded. + LMIC_reset(); + + // Set static session parameters. Instead of dynamically establishing a session + // by joining the network, precomputed session parameters are be provided. + #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 (0x13, DEVADDR, nwkskey, appskey); + #else + // If not running an AVR with PROGMEM, just use the arrays directly + LMIC_setSession (0x13, DEVADDR, NWKSKEY, APPSKEY); + #endif + + #if defined(CFG_eu868) + // Set up the channels used by the Things Network, which corresponds + // to the defaults of most gateways. Without this, only three base + // channels from the LoRaWAN specification are used, which certainly + // works, so it is good for debugging, but can overload those + // frequencies, so be sure to configure the full frequency range of + // your network here (unless your network autoconfigures them). + // Setting up channels should happen after LMIC_setSession, as that + // configures the minimal channel set. + LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band + LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band + LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band + // TTN defines an additional channel at 869.525Mhz using SF9 for class B + // devices' ping slots. LMIC does not have an easy way to define set this + // frequency and support for class B is spotty and untested, so this + // frequency is not configured here. + #elif defined(CFG_us915) + // NA-US channels 0-71 are configured automatically + // but only one group of 8 should (a subband) should be active + // TTN recommends the second sub band, 1 in a zero based count. + // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json + LMIC_selectSubBand(1); + #endif + + // Disable link check validation + LMIC_setLinkCheckMode(0); + + // TTN uses SF9 for its RX2 window. + LMIC.dn2Dr = DR_SF9; + + // Set data rate and transmit power for uplink + LMIC_setDrTxpow(DR_SF7,14); + + // Start job + do_send(&sendjob); +} + +void loop() { + unsigned long now; + now = millis(); + if ((now & 512) != 0) { + digitalWrite(13, HIGH); + } + else { + digitalWrite(13, LOW); + } + + os_runloop_once(); + +} + +/// arduino emulation on rpi + +volatile sig_atomic_t force_exit = 0; +SerialSimulator Serial; + +void sig_handler(int sig) +{ + printf("\nBreak received, exiting!\n"); + force_exit=true; +} + +int main(void) +{ + // caught CTRL-C to do clean-up + signal(SIGINT, sig_handler); + + printf("%s Starting\n", __BASEFILE__); + + // Init GPIO bcm + if (!bcm2835_init()) { + fprintf( stderr, "bcm2835_init() Failed\n\n" ); + return 1; + } + + // Show board config + //printConfig(RF_LED_PIN); + printKeys(); + + // Light off on board LED + //pinMode(RF_LED_PIN, OUTPUT); + //digitalWrite(RF_LED_PIN, HIGH); + + setup(); + while(!force_exit) { + loop(); + + // We're on a multitasking OS let some time for others + // Without this one CPU is 99% and with this one just 3% + // On a Raspberry PI 3 + usleep(1000); + } + + // We're here because we need to exit, do it clean + + // Light off on board LED + //digitalWrite(RF_LED_PIN, LOW); + + // module CS line High + digitalWrite(lmic_pins.nss, HIGH); + printf( "\n%s, done my job!\n", __BASEFILE__ ); + bcm2835_close(); + return 0; +} diff --git a/examples/raspi/ttn-otaa/Makefile b/examples/raspi/ttn-otaa/Makefile index 3c101325..a44cd0e7 100644 --- a/examples/raspi/ttn-otaa/Makefile +++ b/examples/raspi/ttn-otaa/Makefile @@ -1,39 +1,17 @@ -# Makefile # Sample for ttn-otaa example on Raspberry Pi # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ -CC = g++ -CFLAGS = -std=c++11 -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" -LIBS = -lbcm2835 +include ../Makefile.env LMICBASE = ../../../src -INCLUDE = -I$(LMICBASE) all: ttn-otaa -raspi.o: $(LMICBASE)/raspi/raspi.cpp - $(CC) $(CFLAGS) -c $(LMICBASE)/raspi/raspi.cpp $(INCLUDE) +%.o: %.cpp + $(CXX) $(CFLAGS) -c $(INCLUDE) $< -radio.o: $(LMICBASE)/lmic/radio.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/radio.c $(INCLUDE) - -oslmic.o: $(LMICBASE)/lmic/oslmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/oslmic.c $(INCLUDE) - -lmic.o: $(LMICBASE)/lmic/lmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/lmic.c $(INCLUDE) - -hal.o: $(LMICBASE)/hal/hal.cpp - $(CC) $(CFLAGS) -c $(LMICBASE)/hal/hal.cpp $(INCLUDE) - -aes.o: $(LMICBASE)/aes/lmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/aes/lmic.c $(INCLUDE) -o aes.o - -ttn-otaa.o: ttn-otaa.cpp - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -ttn-otaa: ttn-otaa.o raspi.o radio.o oslmic.o lmic.o hal.o aes.o - $(CC) $^ $(LIBS) -o ttn-otaa +%: %.o ../arduino-lmic.a + $(CXX) $^ $(LIBS) -o $@ clean: - rm -rf *.o ttn-otaa + rm -rf *.o ttn-otaa diff --git a/examples/raspi/ttn-otaa/ttn-otaa.cpp b/examples/raspi/ttn-otaa/ttn-otaa.cpp index 5b18a9a0..5d7490a2 100644 --- a/examples/raspi/ttn-otaa/ttn-otaa.cpp +++ b/examples/raspi/ttn-otaa/ttn-otaa.cpp @@ -37,6 +37,8 @@ #include #include +#include + // This EUI must be in little-endian format, so least-significant-byte // first. When copying an EUI from ttnctl output, this means to reverse @@ -73,30 +75,46 @@ volatile sig_atomic_t force_exit = 0; // see https://github.com/hallard/LoRasPI //#define RF_LED_PIN RPI_V2_GPIO_P1_16 // Led on GPIO23 so P1 connector pin #16 //#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 -//#define RF_IRQ_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +//#define RF_DIO0_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 //#define RF_RST_PIN RPI_V2_GPIO_P1_15 // RST on GPIO22 so P1 connector pin #15 // Raspberri PI Lora Gateway for multiple modules // see https://github.com/hallard/RPI-Lora-Gateway // Module 1 on board RFM95 868 MHz (example) -#define RF_LED_PIN RPI_V2_GPIO_P1_07 // Led on GPIO4 so P1 connector pin #7 -#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 -#define RF_IRQ_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 -#define RF_RST_PIN RPI_V2_GPIO_P1_29 // Reset on GPIO5 so P1 connector pin #29 - +//#define RF_LED_PIN RPI_V2_GPIO_P1_07 // Led on GPIO4 so P1 connector pin #7 +//#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0 so P1 connector pin #24 +//#define RF_DIO0_PIN RPI_V2_GPIO_P1_22 // IRQ on GPIO25 so P1 connector pin #22 +//#define RF_RST_PIN RPI_V2_GPIO_P1_29 // Reset on GPIO5 so P1 connector pin #29 // Dragino Raspberry PI hat (no onboard led) // see https://github.com/dragino/Lora //#define RF_CS_PIN RPI_V2_GPIO_P1_22 // Slave Select on GPIO25 so P1 connector pin #22 -//#define RF_IRQ_PIN RPI_V2_GPIO_P1_07 // IRQ on GPIO4 so P1 connector pin #7 +//#define RF_DIO0_PIN RPI_V2_GPIO_P1_07 // IRQ on GPIO4 so P1 connector pin #7 //#define RF_RST_PIN RPI_V2_GPIO_P1_11 // Reset on GPIO17 so P1 connector pin #11 +// Chistera-Pi (no onboard led) +// see https://www.framboise314.fr/chistera-pi-lora-a-portee-de-main-grace-a-snootlab/ +#define RF_CS_PIN RPI_V2_GPIO_P1_24 // Slave Select on CE0/GPIO8 so P1 connector pin #24 +#define RF_DIO0_PIN RPI_V2_GPIO_P1_07 // IRQ on GPIO4 so P1 connector pin #7 +#define RF_DIO1_PIN RPI_V2_GPIO_P1_16 // IRQ on GPIO23 so P1 connector pin #7 +#define RF_RST_PIN RPI_V2_GPIO_P1_11 // Reset on GPIO17 so P1 connector pin #11 + +#ifndef RF_DIO0_PIN +#define RF_DIO0_PIN LMIC_UNUSED_PIN +#endif +#ifndef RF_DIO1_PIN +#define RF_DIO1_PIN LMIC_UNUSED_PIN +#endif +#ifndef RF_DIO2_PIN +#define RF_DIO2_PIN LMIC_UNUSED_PIN +#endif + // Pin mapping const lmic_pinmap lmic_pins = { .nss = RF_CS_PIN, .rxtx = LMIC_UNUSED_PIN, .rst = RF_RST_PIN, - .dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN}, + .dio = {RF_DIO0_PIN,RF_DIO1_PIN,RF_DIO2_PIN}, }; #ifndef RF_LED_PIN diff --git a/project_config/lmic_project_config.h b/project_config/lmic_project_config.h index 7c19d39e..329372c4 100644 --- a/project_config/lmic_project_config.h +++ b/project_config/lmic_project_config.h @@ -1,6 +1,6 @@ // project-specific definitions -//#define CFG_eu868 1 -#define CFG_us915 1 +#define CFG_eu868 1 +//#define CFG_us915 1 //#define CFG_au921 1 //#define CFG_as923 1 // #define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP /* for as923-JP */ diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index 098cf517..fc8c9785 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -10,8 +10,12 @@ * This the HAL to run LMIC on top of the Arduino environment. *******************************************************************************/ +#ifdef RASPBERRY_PI +#include "raspi/raspi.h" +#else #include #include +#endif // include all the lmic header files, including ../lmic/hal.h #include "../lmic.h" // include the C++ hal.h @@ -53,6 +57,13 @@ static void hal_io_init () { if (plmic_pins->rst != LMIC_UNUSED_PIN) { // initialize RST to floating pinMode(plmic_pins->rst, INPUT); + +#ifdef RASPBERRY_PI + // Enable pull down an rising edge detection on this one + bcm2835_gpio_set_pud(plmic_pins->rst, BCM2835_GPIO_PUD_DOWN); + bcm2835_gpio_ren(plmic_pins->rst); +#endif + } hal_interrupt_init(); @@ -94,6 +105,15 @@ static bool dio_states[NUM_DIO] = {0}; static void hal_io_check() { uint8_t i; for (i = 0; i < NUM_DIO; ++i) { +#ifdef RASPBERRY_PI + // Rising edge fired ? + if (bcm2835_gpio_eds(lmic_pins.dio[i])) { + // Now clear the eds flag by setting it to 1 + bcm2835_gpio_set_eds(lmic_pins.dio[i]); + // Handle pseudo interrupt + radio_irq_handler(i); + } +#else if (plmic_pins->dio[i] == LMIC_UNUSED_PIN) continue; @@ -102,6 +122,7 @@ static void hal_io_check() { if (dio_states[i]) radio_irq_handler(i); } +#endif } } @@ -164,7 +185,12 @@ static void hal_spi_trx(u1_t cmd, u1_t* buf, size_t len, bit_t is_read) { if ((spi_freq = plmic_pins->spi_freq) == 0) spi_freq = LMIC_SPI_FREQ; +#ifdef RASPBERRY_PI + // Clock divider / 32 = 8MHz + SPISettings settings(BCM2835_SPI_CLOCK_DIVIDER_32 , BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_SPI_MODE0); +#else SPISettings settings(spi_freq, MSBFIRST, SPI_MODE0); +#endif SPI.beginTransaction(settings); digitalWrite(nss, 0); diff --git a/src/lmic/config.h b/src/lmic/config.h index 32e30a92..ed720390 100644 --- a/src/lmic/config.h +++ b/src/lmic/config.h @@ -84,7 +84,7 @@ // configured (e.g. on AVR it is not by default), otherwise using it can // cause crashing. #ifndef LMIC_DEBUG_LEVEL -#define LMIC_DEBUG_LEVEL 0 +#define LMIC_DEBUG_LEVEL 1 #endif // Enable this to allow using printf() to print to the given serial port @@ -149,6 +149,12 @@ # error "You may define at most one of USE_ORIGINAL_AES and USE_IDEETRON_AES" #endif +// Force Original AES on RPI +#if defined(RASPBERRY_PI) && defined(USE_IDEETRON_AES) +#undef USE_IDEETRON_AES +#define USE_ORIGINAL_AES +#endif + // LMIC_DISABLE_DR_LEGACY // turn off legacy DR_* symbols that vary by bandplan. // Older code uses these for configuration. EU868_DR_*, US915_DR_* diff --git a/src/lmic/lmic.c b/src/lmic/lmic.c index 2a907f2e..4acedd2e 100644 --- a/src/lmic/lmic.c +++ b/src/lmic/lmic.c @@ -1203,7 +1203,7 @@ static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) { // (again note that hsym is half a sumbol time, so no /2 needed) LMIC.rxtime = LMIC.txend + delay + PAMBL_SYMS * hsym - LMIC.rxsyms * hsym; - LMIC_X_DEBUG_PRINTF("%"LMIC_PRId_ostime_t": sched Rx12 %"LMIC_PRId_ostime_t"\n", os_getTime(), LMIC.rxtime - RX_RAMPUP); + LMIC_X_DEBUG_PRINTF("%" LMIC_PRId_ostime_t ": sched Rx12 %" LMIC_PRId_ostime_t "\n", os_getTime(), LMIC.rxtime - RX_RAMPUP); os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); } @@ -2229,7 +2229,7 @@ static void engineUpdate (void) { e_.eui = MAIN::CDEV->getEui(), e_.info = osticks2ms(txbeg-now), e_.info2 = LMIC.seqnoUp-1)); - LMIC_X_DEBUG_PRINTF("%"LMIC_PRId_ostime_t": next engine update in %"LMIC_PRId_ostime_t"\n", now, txbeg-TX_RAMPUP); + LMIC_X_DEBUG_PRINTF("%" LMIC_PRId_ostime_t ": next engine update in %" LMIC_PRId_ostime_t "\n", now, txbeg-TX_RAMPUP); os_setTimedCallback(&LMIC.osjob, txbeg-TX_RAMPUP, FUNC_ADDR(runEngineUpdate)); } diff --git a/src/raspi/raspi.cpp b/src/raspi/raspi.cpp index f5807fef..5ec0e781 100644 --- a/src/raspi/raspi.cpp +++ b/src/raspi/raspi.cpp @@ -321,6 +321,14 @@ size_t SerialSimulator::println(char ch) { fprintf(stdout, "%c\n", ch); } +size_t SerialSimulator::print(unsigned int i) { + fprintf(stdout, "%d", i); +} + +size_t SerialSimulator::println(unsigned int i) { + fprintf(stdout, "%d\n", i); +} + size_t SerialSimulator::print(unsigned char ch, int base) { return print((unsigned int)ch, base); } diff --git a/src/raspi/raspi.h b/src/raspi/raspi.h index 4625e5f1..3a72132a 100644 --- a/src/raspi/raspi.h +++ b/src/raspi/raspi.h @@ -64,7 +64,7 @@ #endif // F() Macro -#define F(s) +#define F(s) s #define random(x) (rand() % x) @@ -114,6 +114,8 @@ class SerialSimulator { #define OCT 8 #define BIN 2 + operator bool() { return true; } + // TODO: move these from being inlined static void begin(int baud); static size_t println(void); @@ -124,6 +126,8 @@ class SerialSimulator { static size_t print(unsigned int n, int base = DEC); static size_t print(char ch); static size_t println(char ch); + static size_t print(unsigned int i); + static size_t println(unsigned int i); static size_t print(unsigned char ch, int base = DEC); static size_t println(unsigned char ch, int base = DEC); static size_t write(char ch); From 9d646da9769cd7bc0ce78abb3ccb08f57fc02983 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 28 May 2019 14:16:15 +0000 Subject: [PATCH 4/5] fix examples --- examples/raspi/Makefile | 13 ++++-- examples/raspi/Makefile.env | 19 ++++++-- examples/raspi/get_deveui/Makefile | 26 +++-------- examples/raspi/get_deveui/get_deveui.c | 1 + examples/raspi/raw/Makefile | 40 ++-------------- examples/raspi/raw/raw.cpp | 2 + examples/raspi/spi_scan/Makefile | 22 ++------- examples/raspi/ttn-abp/Makefile | 16 ++----- examples/raspi/ttn-otaa-sensors/Makefile | 46 ++----------------- .../ttn-otaa-sensors/ttn-otaa-sensors.cpp | 6 ++- examples/raspi/ttn-otaa/Makefile | 18 ++------ 11 files changed, 63 insertions(+), 146 deletions(-) diff --git a/examples/raspi/Makefile b/examples/raspi/Makefile index c75e9da5..8e302374 100644 --- a/examples/raspi/Makefile +++ b/examples/raspi/Makefile @@ -1,10 +1,11 @@ # Makefile # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ +BCM2835 = 1.59 include Makefile.env -all: arduino-lmic.a +all: /usr/local/lib/libbcm2835.a arduino-lmic.a arduino-lmic.a: raspi.o radio.o oslmic.o lmic.o hal.o aes.o \ lmic_as923.o lmic_au921.o lmic_eu868.o lmic_in866.o lmic_us915.o \ @@ -50,5 +51,11 @@ lmic_us_like.o: $(LMICBASE)/lmic/lmic_us_like.c lmic_eu_like.o: $(LMICBASE)/lmic/lmic_eu_like.c $(CC) $(CFLAGS) -c $^ $(INCLUDE) -clean: - rm -rf *.o *.a +/usr/local/lib/libbcm2835.a: + [ -f bcm2835-$(BCM2835).tar.gz ] || wget http://www.airspayce.com/mikem/bcm2835/bcm2835-$(BCM2835).tar.gz + if [ ! -f $@ ]; then \ + set -e; \ + tar xvfz bcm2835-$(BCM2835).tar.gz; \ + cd bcm2835-$(BCM2835); \ + ./configure && make && sudo make install; \ + fi diff --git a/examples/raspi/Makefile.env b/examples/raspi/Makefile.env index 41780430..690e1f50 100644 --- a/examples/raspi/Makefile.env +++ b/examples/raspi/Makefile.env @@ -4,10 +4,21 @@ CC = gcc -std=c99 CXX = g++ -std=c++11 -CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" +CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" -D_GNU_SOURCE LIBS = -lbcm2835 -LMICBASE = ../../src -INCLUDE = -I$(LMICBASE) -I$(LMICBASE)/raspi/mock +LMICBASE = $(LIBDIR)../../src +INCLUDE = -I$(LMICBASE) -.SUFFIXES: # no implicit rules +%.o: %.c + $(CC) $(CFLAGS) -c $(INCLUDE) $< + +%.o: %.cpp + $(CXX) $(CFLAGS) -c $(INCLUDE) $< + +%: %.o $(LIBDIR)arduino-lmic.a + $(CXX) $^ $(LIBS) -o $@ +clean: + rm -rf *.o *.a $(BIN) + +.SUFFIXES: # no implicit rules diff --git a/examples/raspi/get_deveui/Makefile b/examples/raspi/get_deveui/Makefile index 8a622e87..b14fcc75 100644 --- a/examples/raspi/get_deveui/Makefile +++ b/examples/raspi/get_deveui/Makefile @@ -1,21 +1,9 @@ -# Makefile -# Sample for gettting device EUI from MAC address -# -# +# Sample for ttn-abp example on Raspberry Pi +# Caution: requires bcm2835 library to be already installed +# http://www.airspayce.com/mikem/bcm2835/ -CC = g++ -CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" -LIBS = -lbcm2835 -RADIOHEADBASE = ../../.. -INCLUDE = -I$(RADIOHEADBASE) +BIN=get_deveui -all: get_deveui - -get_deveui.o: get_deveui.c - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -get_deveui: get_deveui.o - $(CC) $^ $(LIBS) -o get_deveui - -clean: - rm -rf *.o get_deveui +LIBDIR=../ +all: $(BIN) +include ../Makefile.env diff --git a/examples/raspi/get_deveui/get_deveui.c b/examples/raspi/get_deveui/get_deveui.c index 469eb931..c35fa0da 100644 --- a/examples/raspi/get_deveui/get_deveui.c +++ b/examples/raspi/get_deveui/get_deveui.c @@ -17,6 +17,7 @@ #include #include #include +#include int main (int argc, const char * argv[]) { diff --git a/examples/raspi/raw/Makefile b/examples/raspi/raw/Makefile index e106c40f..c0993d3c 100644 --- a/examples/raspi/raw/Makefile +++ b/examples/raspi/raw/Makefile @@ -1,39 +1,9 @@ -# Makefile -# Sample for raw example on Raspberry Pi +# Sample for ttn-abp example on Raspberry Pi # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ -CC = g++ -CFLAGS = -std=c++11 -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" -LIBS = -lbcm2835 -LMICBASE = ../../../src -INCLUDE = -I$(LMICBASE) +BIN=raw -all: raw - -raspi.o: $(LMICBASE)/raspi/raspi.cpp - $(CC) $(CFLAGS) -c $(LMICBASE)/raspi/raspi.cpp $(INCLUDE) - -radio.o: $(LMICBASE)/lmic/radio.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/radio.c $(INCLUDE) - -oslmic.o: $(LMICBASE)/lmic/oslmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/oslmic.c $(INCLUDE) - -lmic.o: $(LMICBASE)/lmic/lmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/lmic.c $(INCLUDE) - -hal.o: $(LMICBASE)/hal/hal.cpp - $(CC) $(CFLAGS) -c $(LMICBASE)/hal/hal.cpp $(INCLUDE) - -aes.o: $(LMICBASE)/aes/lmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/aes/lmic.c $(INCLUDE) -o aes.o - -raw.o: raw.cpp - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -raw: raw.o raspi.o radio.o oslmic.o lmic.o hal.o aes.o - $(CC) $^ $(LIBS) -o raw - -clean: - rm -rf *.o raw +LIBDIR=../ +all: $(BIN) +include ../Makefile.env diff --git a/examples/raspi/raw/raw.cpp b/examples/raspi/raw/raw.cpp index 913c97bb..ea9e13d7 100644 --- a/examples/raspi/raw/raw.cpp +++ b/examples/raspi/raw/raw.cpp @@ -15,6 +15,8 @@ #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. diff --git a/examples/raspi/spi_scan/Makefile b/examples/raspi/spi_scan/Makefile index ed175b91..46d92b82 100644 --- a/examples/raspi/spi_scan/Makefile +++ b/examples/raspi/spi_scan/Makefile @@ -1,21 +1,9 @@ -# Makefile -# Sample for spi scan Hope RF module on Raspberry Pi +# Sample for ttn-abp example on Raspberry Pi # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ -CC = g++ -CFLAGS = -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" -LIBS = -lbcm2835 -RADIOHEADBASE = ../../.. -INCLUDE = -I$(RADIOHEADBASE) +BIN=spi_scan -all: spi_scan - -spi_scan.o: spi_scan.c - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -spi_scan: spi_scan.o - $(CC) $^ $(LIBS) -o spi_scan - -clean: - rm -rf *.o spi_scan +LIBDIR=../ +all: $(BIN) +include ../Makefile.env diff --git a/examples/raspi/ttn-abp/Makefile b/examples/raspi/ttn-abp/Makefile index 94c8e4f9..4350eca0 100644 --- a/examples/raspi/ttn-abp/Makefile +++ b/examples/raspi/ttn-abp/Makefile @@ -2,16 +2,8 @@ # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ -include ../Makefile.env -LMICBASE = ../../../src - -all: ttn-abp - -%.o: %.cpp - $(CXX) $(CFLAGS) -c $(INCLUDE) $< +BIN=ttn-abp -%: %.o ../arduino-lmic.a - $(CXX) $^ $(LIBS) -o $@ - -clean: - rm -rf *.o ttn-abp +LIBDIR=../ +all: $(BIN) +include ../Makefile.env diff --git a/examples/raspi/ttn-otaa-sensors/Makefile b/examples/raspi/ttn-otaa-sensors/Makefile index 811efb16..56a62281 100644 --- a/examples/raspi/ttn-otaa-sensors/Makefile +++ b/examples/raspi/ttn-otaa-sensors/Makefile @@ -1,45 +1,9 @@ -# Makefile -# Sample for ttn-otaa + si7021/htu21d example on Raspberry Pi +# Sample for ttn-abp example on Raspberry Pi # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ -CC = g++ -CFLAGS = -std=c++11 -Wall -DRASPBERRY_PI -DBCM2835_NO_DELAY_COMPATIBILITY -D__BASEFILE__=\"$*\" -LIBS = -lbcm2835 -LMICBASE = ../../../src -INCLUDE = -I$(LMICBASE) +BIN=ttn-otaa-sensors -all: ttn-otaa-sensors - -raspi.o: $(LMICBASE)/raspi/raspi.cpp - $(CC) $(CFLAGS) -c $(LMICBASE)/raspi/raspi.cpp $(INCLUDE) - -radio.o: $(LMICBASE)/lmic/radio.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/radio.c $(INCLUDE) - -oslmic.o: $(LMICBASE)/lmic/oslmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/oslmic.c $(INCLUDE) - -lmic.o: $(LMICBASE)/lmic/lmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/lmic/lmic.c $(INCLUDE) - -hal.o: $(LMICBASE)/hal/hal.cpp - $(CC) $(CFLAGS) -c $(LMICBASE)/hal/hal.cpp $(INCLUDE) - -aes.o: $(LMICBASE)/aes/lmic.c - $(CC) $(CFLAGS) -c $(LMICBASE)/aes/lmic.c $(INCLUDE) -o aes.o - -si7021.o: si7021.c - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -bmp180.o: bmp180.cpp - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -ttn-otaa-sensors.o: ttn-otaa-sensors.cpp - $(CC) $(CFLAGS) -c $(INCLUDE) $< - -ttn-otaa-sensors: ttn-otaa-sensors.o raspi.o si7021.o bmp180.o radio.o oslmic.o lmic.o hal.o aes.o - $(CC) $^ $(LIBS) -o ttn-otaa-sensors - -clean: - rm -rf *.o ttn-otaa-sensors +LIBDIR=../ +all: $(BIN) +include ../Makefile.env diff --git a/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp b/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp index 5c6b98a8..566a978c 100644 --- a/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp +++ b/examples/raspi/ttn-otaa-sensors/ttn-otaa-sensors.cpp @@ -50,8 +50,10 @@ #include #include -#include "si7021.h" -#include "bmp180.h" +#include + +#include "si7021.c" +#include "bmp180.cpp" // This EUI must be in little-endian format, so least-significant-byte // first. When copying an EUI from ttnctl output, this means to reverse diff --git a/examples/raspi/ttn-otaa/Makefile b/examples/raspi/ttn-otaa/Makefile index a44cd0e7..c5bf9331 100644 --- a/examples/raspi/ttn-otaa/Makefile +++ b/examples/raspi/ttn-otaa/Makefile @@ -1,17 +1,9 @@ -# Sample for ttn-otaa example on Raspberry Pi +# Sample for ttn-abp example on Raspberry Pi # Caution: requires bcm2835 library to be already installed # http://www.airspayce.com/mikem/bcm2835/ -include ../Makefile.env -LMICBASE = ../../../src - -all: ttn-otaa - -%.o: %.cpp - $(CXX) $(CFLAGS) -c $(INCLUDE) $< +BIN=ttn-otaa -%: %.o ../arduino-lmic.a - $(CXX) $^ $(LIBS) -o $@ - -clean: - rm -rf *.o ttn-otaa +LIBDIR=../ +all: $(BIN) +include ../Makefile.env From 4c0029f03898c682a68f48c298af05595f4a43bc Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 28 May 2019 14:57:05 +0000 Subject: [PATCH 5/5] restore upstream defaults --- examples/raspi/Makefile | 4 ++-- examples/raspi/Makefile.env | 2 +- project_config/lmic_project_config.h | 4 ++-- src/lmic/config.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/raspi/Makefile b/examples/raspi/Makefile index 8e302374..9ffaabd3 100644 --- a/examples/raspi/Makefile +++ b/examples/raspi/Makefile @@ -3,10 +3,10 @@ # http://www.airspayce.com/mikem/bcm2835/ BCM2835 = 1.59 -include Makefile.env - all: /usr/local/lib/libbcm2835.a arduino-lmic.a +include Makefile.env + arduino-lmic.a: raspi.o radio.o oslmic.o lmic.o hal.o aes.o \ lmic_as923.o lmic_au921.o lmic_eu868.o lmic_in866.o lmic_us915.o \ lmic_us_like.o lmic_eu_like.o diff --git a/examples/raspi/Makefile.env b/examples/raspi/Makefile.env index 690e1f50..aa640858 100644 --- a/examples/raspi/Makefile.env +++ b/examples/raspi/Makefile.env @@ -14,7 +14,7 @@ INCLUDE = -I$(LMICBASE) %.o: %.cpp $(CXX) $(CFLAGS) -c $(INCLUDE) $< - + %: %.o $(LIBDIR)arduino-lmic.a $(CXX) $^ $(LIBS) -o $@ diff --git a/project_config/lmic_project_config.h b/project_config/lmic_project_config.h index 329372c4..7c19d39e 100644 --- a/project_config/lmic_project_config.h +++ b/project_config/lmic_project_config.h @@ -1,6 +1,6 @@ // project-specific definitions -#define CFG_eu868 1 -//#define CFG_us915 1 +//#define CFG_eu868 1 +#define CFG_us915 1 //#define CFG_au921 1 //#define CFG_as923 1 // #define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP /* for as923-JP */ diff --git a/src/lmic/config.h b/src/lmic/config.h index ed720390..6b49afe6 100644 --- a/src/lmic/config.h +++ b/src/lmic/config.h @@ -84,7 +84,7 @@ // configured (e.g. on AVR it is not by default), otherwise using it can // cause crashing. #ifndef LMIC_DEBUG_LEVEL -#define LMIC_DEBUG_LEVEL 1 +#define LMIC_DEBUG_LEVEL 0 #endif // Enable this to allow using printf() to print to the given serial port