Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

port for Raspberry PI #322

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions examples/raspi/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Makefile
# Caution: requires bcm2835 library to be already installed
# http://www.airspayce.com/mikem/bcm2835/
BCM2835 = 1.59

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
$(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)

/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
24 changes: 24 additions & 0 deletions examples/raspi/Makefile.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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__=\"$*\" -D_GNU_SOURCE
LIBS = -lbcm2835
LMICBASE = $(LIBDIR)../../src
INCLUDE = -I$(LMICBASE)

%.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
3 changes: 3 additions & 0 deletions examples/raspi/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

raspberry pi examples
origin: https://github.com/hallard/arduino-lmic/tree/rpi/examples/raspi
9 changes: 9 additions & 0 deletions examples/raspi/get_deveui/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Sample for ttn-abp example on Raspberry Pi
# Caution: requires bcm2835 library to be already installed
# http://www.airspayce.com/mikem/bcm2835/

BIN=get_deveui

LIBDIR=../
all: $(BIN)
include ../Makefile.env
119 changes: 119 additions & 0 deletions examples/raspi/get_deveui/get_deveui.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// 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 <stdio.h>
#include <ifaddrs.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>

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;
}

9 changes: 9 additions & 0 deletions examples/raspi/raw/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Sample for ttn-abp example on Raspberry Pi
# Caution: requires bcm2835 library to be already installed
# http://www.airspayce.com/mikem/bcm2835/

BIN=raw

LIBDIR=../
all: $(BIN)
include ../Makefile.env
160 changes: 160 additions & 0 deletions examples/raspi/raw/raw.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*******************************************************************************
* 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 <lmic.h>
#include <hal/hal.h>

#include <raspi/raspi.h>

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