From 1ceb9bc42eb08e54a5123b20740fcf2f3553a190 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 30 Jun 2016 17:41:56 +0200 Subject: [PATCH 01/17] Added define for LinkLabs RPI GW to control onboard LEDs --- poly_pkt_fwd/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/poly_pkt_fwd/Makefile b/poly_pkt_fwd/Makefile index 66ec746b..36ec962b 100644 --- a/poly_pkt_fwd/Makefile +++ b/poly_pkt_fwd/Makefile @@ -54,6 +54,11 @@ else endif endif +ifeq ($(PLATFORM),linklabs_blowfish_rpi) + LIBS += -lwiringPi + VFLAG += -D LINKLABS_BLOWFISH_RPI +endif + ### General build targets all: $(APP_NAME) From 9c5fcaffe94a168c8778c7e958e2e60793e21b58 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 30 Jun 2016 17:51:03 +0200 Subject: [PATCH 02/17] Added LinkLabs LEDs managment --- poly_pkt_fwd/src/poly_pkt_fwd.c | 56 +++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/poly_pkt_fwd/src/poly_pkt_fwd.c b/poly_pkt_fwd/src/poly_pkt_fwd.c index 298de462..19b8c674 100644 --- a/poly_pkt_fwd/src/poly_pkt_fwd.c +++ b/poly_pkt_fwd/src/poly_pkt_fwd.c @@ -16,6 +16,8 @@ License: Revised BSD License, see LICENSE.TXT file include in the project Maintainer: Ruud Vlaming + +- 2016-30-06 : Charles-Henri Hallard, added LED management on LinkLabs RPI GW */ @@ -118,6 +120,15 @@ Maintainer: Ruud Vlaming #define STATUS_SIZE 328 #define TX_BUFF_SIZE ((540 * NB_PKT_MAX) + 30 + STATUS_SIZE) +// For LinkLabs Raspberry Pi Gateway +#ifdef LINKLABS_BLOWFISH_RPI +#include +#define GPS_PPS 7 /* GPIO4 wPI:7 */ +#define LL_LED_1 2 /* GPIO27 wPI:2 */ +#define LL_LED_2 6 /* GPIO25 wPI:6 */ +#define LL_LED_BLINK_DURATION 250 /* Blink 250Ms */ +#endif + /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ @@ -1361,6 +1372,15 @@ int main(int argc, char *argv[]) MSG("WARNING: [main] All streams have been disabled, gateway may be completely silent.\n"); } +#ifdef LINKLABS_BLOWFISH_RPI + wiringPiSetup() ; + pinMode(GPS_PPS, INPUT) ; + pinMode(LL_LED_1, OUTPUT) ; + pinMode(LL_LED_2, OUTPUT) ; + digitalWrite(LL_LED_1, HIGH); + digitalWrite(LL_LED_2, HIGH); +#endif + /* main loop task : statistics collection */ while (!exit_sig && !quit_sig) { /* wait for next reporting interval */ @@ -1521,7 +1541,13 @@ int main(int argc, char *argv[]) } } } - + +#ifdef LINKLABS_BLOWFISH_RPI + // Be sure to ligh of the LED + digitalWrite(LL_LED_1, LOW) ; + digitalWrite(LL_LED_2, LOW) ; +#endif + MSG("INFO: Exiting packet forwarder program\n"); exit(EXIT_SUCCESS); } @@ -1586,7 +1612,24 @@ void thread_up(void) { *(uint32_t *)(buff_up + 8) = net_mac_l; while (!exit_sig && !quit_sig) { - + +#ifdef LINKLABS_BLOWFISH_RPI + + static unsigned long led2_timer = 0; + + // Manage blinking led timer expiration + if (led2_timer && (millis()-led2_timer>LL_LED_BLINK_DURATION)) { + digitalWrite(LL_LED_2, HIGH) ; + led2_timer = 0; + } + + // Report on LED GPS PPS Signal (blink when satellites OK) + // Signal is reversed, like this when running (even with no GPS) + // the led will be on, and if PPS signal from GPS is okay the led + // will blink off for a short time + digitalWrite(LL_LED_1, !digitalRead(GPS_PPS)) ; +#endif + /* fetch packets */ pthread_mutex_lock(&mx_concent); if (radiostream_enabled == true) nb_pkt = lgw_receive(NB_PKT_MAX, rxpkt); else nb_pkt = 0; @@ -1603,6 +1646,15 @@ void thread_up(void) { /* check if there are status report to send */ send_report = report_ready; /* copy the variable so it doesn't change mid-function */ /* no mutex, we're only reading */ + +#ifdef LINKLABS_BLOWFISH_RPI + if ( nb_pkt > 0) { + // Blink LED2 + digitalWrite(LL_LED_2, LOW) ; + led2_timer = millis(); + } +#endif + /* wait a short time if no packets, nor status report */ if ((nb_pkt == 0) && (send_report == false)) { From b9d45bda40740cb206a62e46c910b56bb8b123e6 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Sep 2016 16:53:23 +0200 Subject: [PATCH 03/17] Example configuration for ic880A board --- poly_pkt_fwd/local_conf-ic880a.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 poly_pkt_fwd/local_conf-ic880a.json diff --git a/poly_pkt_fwd/local_conf-ic880a.json b/poly_pkt_fwd/local_conf-ic880a.json new file mode 100644 index 00000000..3b7ffc79 --- /dev/null +++ b/poly_pkt_fwd/local_conf-ic880a.json @@ -0,0 +1,25 @@ +{ +/* Put there parameters that are different for each gateway (eg. pointing one gateway to a test server while the others stay in production) */ +/* Settings defined in global_conf will be overwritten by those in local_conf */ + "gateway_conf": { + /* you must pick a unique 64b number for each gateway (represented by an hex string) */ + "gateway_ID": "AA555A000004BABA", + /* Email of gateway operator, max 40 chars*/ + "contact_email": "operator@gateway.tst", + /* Public description of this device, max 64 chars */ + "description": "Update me", + + /* For ic880A plate */ + /* https://github.com/ch2i/iC880A-Raspberry-PI */ + "led_heartbeat": 4, /* GPIO4 Blue */ + "led_down": 18, /* GPIO18 White */ + "led_error": 23, /* GPIO23 Red */ + "led_packet": 24, /* GPIO24 Green */ + + /* Enter VALID GPS coordinates below before enabling fake GPS */ + "fake_gps": false, + "ref_latitude": 10, + "ref_longitude": 20, + "ref_altitude": -1 + } +} From 3010bfe8beda1e93df4c55b46ff9582dcabf46c4 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Sep 2016 16:53:36 +0200 Subject: [PATCH 04/17] Example configuration for linklabs board --- poly_pkt_fwd/local_conf-linklabs.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 poly_pkt_fwd/local_conf-linklabs.json diff --git a/poly_pkt_fwd/local_conf-linklabs.json b/poly_pkt_fwd/local_conf-linklabs.json new file mode 100644 index 00000000..36e36aa0 --- /dev/null +++ b/poly_pkt_fwd/local_conf-linklabs.json @@ -0,0 +1,23 @@ +{ +/* Put there parameters that are different for each gateway (eg. pointing one gateway to a test server while the others stay in production) */ +/* Settings defined in global_conf will be overwritten by those in local_conf */ + "gateway_conf": { + /* you must pick a unique 64b number for each gateway (represented by an hex string) */ + "gateway_ID": "AA555A000004BABA", + /* Email of gateway operator, max 40 chars*/ + "contact_email": "operator@gateway.tst", + /* Public description of this device, max 64 chars */ + "description": "Update me", + + /* For Linklabs boards */ + "pin_pps": 4, /* GPIO4 PPS from GPS */ + "led_pps": 25, /* GPIO25 PPS RED */ + "led_packet": 27, /* GPIO27 RED */ + + /* Enter VALID GPS coordinates below before enabling fake GPS */ + "fake_gps": false, + "ref_latitude": 10, + "ref_longitude": 20, + "ref_altitude": -1 + } +} From 01185e121323bf6f7442b0547a2342a41a05481c Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 13 Sep 2016 11:19:34 +0200 Subject: [PATCH 05/17] Added doc on specific features --- poly_pkt_fwd/readme.md | 85 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/poly_pkt_fwd/readme.md b/poly_pkt_fwd/readme.md index e1e5a67a..74b9f392 100644 --- a/poly_pkt_fwd/readme.md +++ b/poly_pkt_fwd/readme.md @@ -30,6 +30,91 @@ up/down stream, all can be (de)activated by modifying the json. To learn more about the network protocol between the gateway and the server, please read the PROTOCOL.TXT document. +Specific Raspberry PI boards version features +============================================= + +To be able to drive Raspbery PI concentrator on boards LED, this program +use bcm2835 library, you need to install them before anything. +see http://www.airspayce.com/mikem/bcm2835/ + +This version has been written to works with Linklabs board and also with +ic880a concentrator + Raspberry Pi Plate. +https://github.com/ch2i/iC880A-Raspberry-PI + +Option for LED are in the configuration file so it should works with +any board just adjusting GPIO settings. Settings are the following, +a name and the GPIO pin number. Names are : + +- `led_heartbeat` LED used for hearbeat, will always blink when running +- `led_down` LED used for downstream, will blink on each downstream from server +- `led_error` LED used for hearbeat, will blink when a error occured +- `led_packet` LED will blink on each packet received +- `led_pps` LED used for GPS PPS indicator (mainly linklabs board) +- `pin_pps` Pin where PPS signal is connected to (if any, mainly linklabs board) + +GPS PPS pin on linklabs boards are not connected to LED but on a GPIO, so `led_pps` +and `pin_pps` are used for a "software link", incoming PPS signal going to GPIO input +is redirected to GPIO led output, thus for example, with linklabs, configuration can be + + +```json + "pin_pps": 4, /* GPIO4 PPS from GPS */ + "led_pps": 25, /* GPIO25 PPS RED */ + "led_packet": 27, /* GPIO27 RED */ +``` + +And fot ic880a RPI plate (4 leds), configuration can be +```json + "led_heartbeat": 4, /* GPIO4 Blue */ + "led_down": 18, /* GPIO18 White */ + "led_error": 23, /* GPIO23 Red */ + "led_packet": 24, /* GPIO24 Green */ +``` + +An extented Log ouput on each packet received has also been added to this version, this +can be usefull for monitoring packet recevided by concentrator, regardless if they are or +not send the gateway. It's logged as info with the following informations + +INFO: [#DeviceAddr] containing the device Addr (as seen on TTN dashboard) so you can +filter with a grep for example +`tail -f /var/log/lora_pkt_fwd.log | grep "\[\#"` + +then it's followed by : + +- `jRQ` for join request +- `jAC` for join accept +- `uUP` for unconfirmed up +- `uDN` for unconfirmed down +- `cUP` for confirmed up +- `cDN` for confirmed down +- `RFU` for RFU + +Other following data are classic information of frame received. Here below an example of log + +``` +root@pi01(ro):~# tail -f /var/log/lora_pkt_fwd.log +INFO: [up] PUSH_ACK for server log.gatewaystats.org received in 26 ms +INFO: [down] for server log.gatewaystats.org PULL_ACK received in 25 ms +INFO: [#25FAAE33] RFU CRC:Bad Freq:867.30MHz ch:4 RFch:0 LORA[SF7 125Khz 2/3] RSSI:-107dB SNR:-11.5dB Size:232b +INFO: [down] for server router.eu.thethings.network PULL_ACK received in 40 ms +INFO: [down] for server log.gatewaystats.org PULL_ACK received in 26 ms +INFO: [#1DCDB85F] cUP CRC:OK Freq:867.10MHz ch:3 RFch:0 LORA[SF12 125Khz 4/5] RSSI:-65dB SNR:+9.0dB Size:16b Data:'gF+4zR0ArAEBqkBtIvDn+A==' +INFO: [up] PUSH_ACK for server router.eu.thethings.network received in 40 ms +INFO: [up] PUSH_ACK for server log.gatewaystats.org received in 26 ms +INFO: [down] for server router.eu.thethings.network serv_addr[ic]PULL_RESP received :) +INFO: [down] a packet will be sent on timestamp value 2481851356 +INFO: [#87802833] jAC CRC:Bad Freq:867.50MHz ch:5 RFch:0 LORA[SF7 125Khz 4/7] RSSI:-107dB SNR:-11.0dB Size:20b +INFO: [down] for server router.eu.thethings.network PULL_ACK received in 43 ms +INFO: [#DD5343A9] jAC CRC:Bad Freq:868.10MHz ch:0 RFch:1 LORA[SF7 125Khz 4/5] RSSI:-105dB SNR:-7.0dB Size:23b +INFO: [#37F76D0D] jRQ CRC:Bad Freq:867.10MHz ch:3 RFch:0 LORA[SF7 125Khz 4/5] RSSI:-102dB SNR:-7.0dB Size:23b +INFO: [#1D57298D] uUP CRC:OK Freq:867.30MHz ch:4 RFch:0 LORA[SF7 125Khz 4/5] RSSI:-95dB SNR:-3.0dB Size:23b Data:'QI0pVx2ADgABMTFQD+MBsz7x6VL877c=' +INFO: [#1D57298D] uUP CRC:OK Freq:867.50MHz ch:5 RFch:0 LORA[SF7 125Khz 4/5] RSSI:-49dB SNR:+7.5dB Size:23b Data:'QI0pVx2ADgABMTFQD+MBsz7x6VL877c=' +INFO: [up] PUSH_ACK for server router.eu.thethings.network received in 42 ms +INFO: [up] PUSH_ACK for server log.gatewaystats.org received in 27 ms + +``` + + 2. System schematic and definitions ------------------------------------ From 252992a859d302abe434a40d97e45d3e464ed988 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 13 Sep 2016 11:20:07 +0200 Subject: [PATCH 06/17] Added bcm2835 library --- poly_pkt_fwd/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poly_pkt_fwd/Makefile b/poly_pkt_fwd/Makefile index 36ec962b..be2fadd0 100644 --- a/poly_pkt_fwd/Makefile +++ b/poly_pkt_fwd/Makefile @@ -54,10 +54,10 @@ else endif endif -ifeq ($(PLATFORM),linklabs_blowfish_rpi) - LIBS += -lwiringPi - VFLAG += -D LINKLABS_BLOWFISH_RPI -endif +# To drive onboards LED and other stuff you need +# to install and link with bcm2835 library, see +# http://www.airspayce.com/mikem/bcm2835/ +LIBS += -lbcm2835 ### General build targets From 61cc54758e94b4cf4f549b8c876b93e8008025f3 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 13 Sep 2016 11:20:22 +0200 Subject: [PATCH 07/17] Led Management + Extented Logs --- poly_pkt_fwd/src/poly_pkt_fwd.c | 379 ++++++++++++++++++++++++++------ 1 file changed, 314 insertions(+), 65 deletions(-) diff --git a/poly_pkt_fwd/src/poly_pkt_fwd.c b/poly_pkt_fwd/src/poly_pkt_fwd.c index 19b8c674..322c8056 100644 --- a/poly_pkt_fwd/src/poly_pkt_fwd.c +++ b/poly_pkt_fwd/src/poly_pkt_fwd.c @@ -17,7 +17,8 @@ License: Revised BSD License, see LICENSE.TXT file include in the project Maintainer: Ruud Vlaming -- 2016-30-06 : Charles-Henri Hallard, added LED management on LinkLabs RPI GW + + */ @@ -51,6 +52,8 @@ Maintainer: Ruud Vlaming #include /* gai_strerror */ #include + +#include #include #include @@ -70,6 +73,9 @@ Maintainer: Ruud Vlaming #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define STRINGIFY(x) #x #define STR(x) STRINGIFY(x) +#ifndef MSG +#define MSG(args...) printf(args) /* message that is destined to the user */ +#endif #define TRACE() fprintf(stderr, "@ %s %d\n", __FUNCTION__, __LINE__); /* -------------------------------------------------------------------------- */ @@ -92,7 +98,7 @@ Maintainer: Ruud Vlaming #define DEFAULT_KEEPALIVE 5 /* default time interval for downstream keep-alive packet */ -#define DEFAULT_STAT 30 /* default time interval for statistics */ +#define DEFAULT_STAT 30/* default time interval for statistics */ #define PUSH_TIMEOUT_MS 100 #define PULL_TIMEOUT_MS 200 #define GPS_REF_MAX_AGE 30 /* maximum admitted delay in seconds of GPS loss before considering latest GPS sync unusable */ @@ -120,18 +126,21 @@ Maintainer: Ruud Vlaming #define STATUS_SIZE 328 #define TX_BUFF_SIZE ((540 * NB_PKT_MAX) + 30 + STATUS_SIZE) -// For LinkLabs Raspberry Pi Gateway -#ifdef LINKLABS_BLOWFISH_RPI -#include -#define GPS_PPS 7 /* GPIO4 wPI:7 */ -#define LL_LED_1 2 /* GPIO27 wPI:2 */ -#define LL_LED_2 6 /* GPIO25 wPI:6 */ -#define LL_LED_BLINK_DURATION 250 /* Blink 250Ms */ +#ifndef NOT_A_PIN +#define NOT_A_PIN 0xFF #endif /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ +static char *short_options = "c:l:h"; +static struct option long_options[] = { + {"config-dir", 1, 0, 'c'}, + {"logfile", 1, 0, 'l'}, + {"help", 0, 0, 'h'}, + {0, 0, 0, 0}, +}; + /* signal handling variables */ volatile bool exit_sig = false; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ volatile bool quit_sig = false; /* 1 -> application terminates without shutting down the hardware */ @@ -153,6 +162,14 @@ static int keepalive_time = DEFAULT_KEEPALIVE; /* send a PULL_DATA request every /* statistics collection configuration variables */ static unsigned stat_interval = DEFAULT_STAT; /* time interval (in sec) at which statistics are collected and displayed */ +/* LED */ +static unsigned led_heartbeat = NOT_A_PIN;/* heartbeat LED */ +static unsigned led_down = NOT_A_PIN; /* downlink for server */ +static unsigned led_error = NOT_A_PIN; /* error LED */ +static unsigned led_packet = NOT_A_PIN; /* packet led */ +static unsigned led_pps = NOT_A_PIN; /* PPS GPS Led (linklabs board) */ +static unsigned pin_pps = NOT_A_PIN; /* PPS GPS pin (LinkLabs board) */ + /* gateway <-> MAC protocol variables */ static uint32_t net_mac_h; /* Most Significant Nibble, network order */ static uint32_t net_mac_l; /* Least Significant Nibble, network order */ @@ -738,7 +755,49 @@ static int parse_gateway_configuration(const char * conf_file) { stat_interval = (unsigned)json_value_get_number(val); MSG("INFO: statistics display interval is configured to %i seconds\n", stat_interval); } + + /* get hearttbeat GPIO LED (optional) */ + val = json_object_get_value(conf_obj, "led_heartbeat"); + if (val != NULL) { + led_heartbeat = (unsigned)json_value_get_number(val); + MSG("INFO: LED heartbeat is configured to GPIO%i\n", led_heartbeat); + } + + /* get downlink GPIO LED (optional) */ + val = json_object_get_value(conf_obj, "led_down"); + if (val != NULL) { + led_down = (unsigned)json_value_get_number(val); + MSG("INFO: LED downlink is configured to GPIO%i\n", led_down); + } + + /* get error GPIO LED (optional) */ + val = json_object_get_value(conf_obj, "led_error"); + if (val != NULL) { + led_error = (unsigned)json_value_get_number(val); + MSG("INFO: LED error is configured to GPIO%i\n", led_error); + } + + /* get packet GPIO LED (optional) */ + val = json_object_get_value(conf_obj, "led_packet"); + if (val != NULL) { + led_packet = (unsigned)json_value_get_number(val); + MSG("INFO: LED packet is configured to GPIO%i\n", led_packet); + } + + /* get PPS PIN Input LED (optional) */ + val = json_object_get_value(conf_obj, "pin_pps"); + if (val != NULL) { + pin_pps = (unsigned)json_value_get_number(val); + MSG("INFO: GPS PPS pin is configured to GPIO%i\n", pin_pps); + } + /* get PPS GPIO LED (optional) */ + val = json_object_get_value(conf_obj, "led_pps"); + if (val != NULL) { + led_pps = (unsigned)json_value_get_number(val); + MSG("INFO: LED pps is configured to GPIO%i\n", led_pps); + } + /* get time-out value (in ms) for upstream datagrams (optional) */ val = json_object_get_value(conf_obj, "push_timeout_ms"); if (val != NULL) { @@ -1019,22 +1078,146 @@ double difftimespec(struct timespec end, struct timespec beginning) { return x; } + + +void log_packet( struct lgw_pkt_rx_s* p) { + + uint8_t mtype = (*p->payload) ; + + /* writing devAddr */ + printf( "INFO: [#"); + for (int j=4; j>0; j--) { + printf("%02X", p->payload[j]); + } + printf( "] "); + + // RFU & Major + //printf("%X:%X ", (mtype>>2)&0x07, (mtype)&0x03 ) ; + + // Message type (3 bits) + switch ( (mtype>>5)&0x07 ) { + case 0x00: printf("jRQ"); break; /* join request */ + case 0x01: printf("jAC"); break; /* join accept */ + case 0x02: printf("uUP"); break; /* unconfirmed up */ + case 0x03: printf("uDN"); break; /* unconfirmed down */ + case 0x04: printf("cUP"); break; /* Confirmed up */ + case 0x05: printf("cDN"); break; /* Confirmed down */ + case 0x06: printf("RFU"); break; + case 0x07: printf("Prp"); break; + } + + + /* writing RX frequency */ + printf( " CRC:"); + + /* writing CRC status */ + switch(p->status) { + case STAT_CRC_OK: printf("OK "); break; + case STAT_CRC_BAD: printf("Bad "); break; + case STAT_NO_CRC: printf("None "); break; + case STAT_UNDEFINED:printf("Undefined "); break; + default: printf("???? "); + } + + /* writing Frequency, RX modem/IF chan and RF chan */ + printf("Freq:%3.2fMHz ch:%d RFch:%u ", p->freq_hz/1000000.0f, p->if_chain, p->rf_chain); + + /* writing modulation */ + switch(p->modulation) { + case MOD_LORA:printf("LORA["); break; + case MOD_FSK: printf("FSK["); break; + default: printf("???["); + } + + if (p->modulation == MOD_LORA) { + switch (p->datarate) { + case DR_LORA_SF7: printf("SF7 "); break; + case DR_LORA_SF8: printf("SF8 "); break; + case DR_LORA_SF9: printf("SF9 "); break; + case DR_LORA_SF10:printf("SF10 "); break; + case DR_LORA_SF11:printf("SF11 "); break; + case DR_LORA_SF12:printf("SF12 "); break; + default: printf("??? "); + } + } else if (p->modulation == MOD_FSK) { + printf("FSK:%6u ", p->datarate); + } else { + printf("??? "); + } + + /* writing bandwidth */ + switch(p->bandwidth) { + case BW_500KHZ: printf("500Khz "); break; + case BW_250KHZ: printf("250Khz "); break; + case BW_125KHZ: printf("125Khz "); break; + case BW_62K5HZ: printf("62K5hz "); break; + case BW_31K2HZ: printf("31K2hz "); break; + case BW_15K6HZ: printf("15K6hz "); break; + case BW_7K8HZ: printf("7K8hz "); break; + case BW_UNDEFINED:printf("0 "); break; + default: printf("-1 "); + } + + /* writing coderate */ + switch (p->coderate) { + case CR_LORA_4_5: printf("4/5"); break; + case CR_LORA_4_6: printf("2/3"); break; + case CR_LORA_4_7: printf("4/7"); break; + case CR_LORA_4_8: printf("1/2"); break; + case CR_UNDEFINED:printf("Undefined"); break; + default: printf("???"); + } + + /* writing packet RSSI + average SNR */ + printf("] RSSI:%+.0fdB SNR:%+.1fdB ", p->rssi, p->snr); + + /* writing packet size */ + printf("Size:%db ", p->size); + + /* writing status */ + if (p->status==STAT_CRC_OK || p->status==STAT_NO_CRC ) { + char buff[341]; /* 255 bytes = 340 chars in b64 + null char */ + int j = bin_to_b64(p->payload, p->size, buff, sizeof(buff)); + if (j>0) { + printf("Data:'%s'", buff); + } else { + printf("Error Encoding data"); + } + + /* + printf(" => "); + // writing hex-encoded payload (bundled in 32-bit words) + for (int j = 0; j < p->size; ++j) { + if ((j > 0) && (j%4 == 0)) printf("-"); + printf("%02X", p->payload[j]); + } + */ + } + + /* end of line */ + printf("\n"); + + /* whole paylaod + if (p->status==STAT_CRC_OK || p->status==STAT_NO_CRC ) { + printf("HEX Payload: "); + // writing hex-encoded payload (bundled in 32-bit words) + for (int j = 0; j < p->size; ++j) { + printf(" %02X", p->payload[j]); + } + } + printf("\n"); + */ + +} + + void usage(char *proc_name) { fprintf(stderr, "Usage: %s [-c config_dir] [-l logfile]\n", proc_name); exit(1); } -static char *short_options = "c:l:h"; -static struct option long_options[] = { - {"config-dir", 1, 0, 'c'}, - {"logfile", 1, 0, 'l'}, - {"help", 0, 0, 'h'}, - {0, 0, 0, 0}, -}; - /* -------------------------------------------------------------------------- */ /* --- MAIN FUNCTION -------------------------------------------------------- */ - int main(int argc, char *argv[]) { struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ @@ -1045,7 +1228,7 @@ int main(int argc, char *argv[]) char *global_cfg_name= "global_conf.json"; /* contain global (typ. network-wide) configuration */ char *local_cfg_name = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */ char *debug_cfg_name = "debug_conf.json"; /* if present, all other configuration files are ignored */ - + int opt_ind = 0; char cfg_dir[PATH_MAX] = {0}; @@ -1136,7 +1319,7 @@ int main(int argc, char *argv[]) exit(1); } } - + /* display version informations */ MSG("*** Poly Packet Forwarder for Lora Gateway ***\nVersion: " VERSION_STRING "\n"); MSG("*** Lora concentrator HAL library version info ***\n%s\n***\n", lgw_version_info()); @@ -1175,6 +1358,39 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (led_down!=NOT_A_PIN || led_heartbeat!=NOT_A_PIN || + led_pps!=NOT_A_PIN || pin_pps!=NOT_A_PIN || + led_error!=NOT_A_PIN || led_packet!=NOT_A_PIN ) { + if (!bcm2835_init()) { + MSG("ERROR: [main] failed to initialize with bcm2835_init()\n"); + exit(EXIT_FAILURE); + } + + if (led_down!=NOT_A_PIN) { + bcm2835_gpio_fsel(led_down, BCM2835_GPIO_FSEL_OUTP); + bcm2835_gpio_write(led_down, LOW); + } + if (led_heartbeat!=NOT_A_PIN) { + bcm2835_gpio_fsel(led_heartbeat, BCM2835_GPIO_FSEL_OUTP); + bcm2835_gpio_write(led_heartbeat, LOW); + } + if (led_error!=NOT_A_PIN) { + bcm2835_gpio_fsel(led_error, BCM2835_GPIO_FSEL_OUTP); + bcm2835_gpio_write(led_error, LOW); + } + if (led_packet!=NOT_A_PIN) { + bcm2835_gpio_fsel(led_packet, BCM2835_GPIO_FSEL_OUTP); + bcm2835_gpio_write(led_packet, LOW); + } + if (led_pps!=NOT_A_PIN) { + bcm2835_gpio_fsel(led_pps, BCM2835_GPIO_FSEL_OUTP); + bcm2835_gpio_write(led_pps, LOW); + } + if (pin_pps!=NOT_A_PIN) { + bcm2835_gpio_fsel(pin_pps, BCM2835_GPIO_FSEL_INPT); + } + } + /* Start GPS a.s.a.p., to allow it to lock */ if (gps_enabled == true) { if (gps_fake_enable == false) { @@ -1372,15 +1588,6 @@ int main(int argc, char *argv[]) MSG("WARNING: [main] All streams have been disabled, gateway may be completely silent.\n"); } -#ifdef LINKLABS_BLOWFISH_RPI - wiringPiSetup() ; - pinMode(GPS_PPS, INPUT) ; - pinMode(LL_LED_1, OUTPUT) ; - pinMode(LL_LED_2, OUTPUT) ; - digitalWrite(LL_LED_1, HIGH); - digitalWrite(LL_LED_2, HIGH); -#endif - /* main loop task : statistics collection */ while (!exit_sig && !quit_sig) { /* wait for next reporting interval */ @@ -1510,6 +1717,12 @@ int main(int argc, char *argv[]) report_ready = true; pthread_mutex_unlock(&mx_stat_rep); } + + uint32_t trig_cnt_us; + if (lgw_get_trigcnt(&trig_cnt_us) == LGW_HAL_SUCCESS && trig_cnt_us == 0x7E000000) { + MSG("ERROR: [main] unintended SX1301 reset detected, terminating packet forwarder.\n"); + exit(EXIT_FAILURE); + } } /* wait for upstream thread to finish (1 fetch cycle max) */ @@ -1539,15 +1752,17 @@ int main(int argc, char *argv[]) } else { MSG("WARNING: failed to stop concentrator successfully\n"); } - } - } - -#ifdef LINKLABS_BLOWFISH_RPI - // Be sure to ligh of the LED - digitalWrite(LL_LED_1, LOW) ; - digitalWrite(LL_LED_2, LOW) ; -#endif + } + // Light off the LED + if (led_down!=NOT_A_PIN) { bcm2835_gpio_write(led_down , LOW);} + if (led_heartbeat!=NOT_A_PIN){ bcm2835_gpio_write(led_heartbeat, LOW);} + if (led_error!=NOT_A_PIN) { bcm2835_gpio_write(led_error , LOW);} + if (led_packet!=NOT_A_PIN) { bcm2835_gpio_write(led_packet , LOW);} + if (led_pps!=NOT_A_PIN) { bcm2835_gpio_write(led_pps , LOW);} + + } + MSG("INFO: Exiting packet forwarder program\n"); exit(EXIT_SUCCESS); } @@ -1583,6 +1798,10 @@ void thread_up(void) { uint8_t token_h; /* random token for acknowledgement matching */ uint8_t token_l; /* random token for acknowledgement matching */ + int led_heartbeat_cnt=0; + int led_error_cnt=0; + int led_packet_cnt=0; + /* ping measurement variables */ struct timespec send_time; struct timespec recv_time; @@ -1612,31 +1831,22 @@ void thread_up(void) { *(uint32_t *)(buff_up + 8) = net_mac_l; while (!exit_sig && !quit_sig) { + + /* fetch packets */ + pthread_mutex_lock(&mx_concent); + if (radiostream_enabled == true) nb_pkt = lgw_receive(NB_PKT_MAX, rxpkt); else nb_pkt = 0; + if (ghoststream_enabled == true) nb_pkt = ghost_get(NB_PKT_MAX-nb_pkt, &rxpkt[nb_pkt]) + nb_pkt; -#ifdef LINKLABS_BLOWFISH_RPI - - static unsigned long led2_timer = 0; - - // Manage blinking led timer expiration - if (led2_timer && (millis()-led2_timer>LL_LED_BLINK_DURATION)) { - digitalWrite(LL_LED_2, HIGH) ; - led2_timer = 0; - } // Report on LED GPS PPS Signal (blink when satellites OK) // Signal is reversed, like this when running (even with no GPS) // the led will be on, and if PPS signal from GPS is okay the led // will blink off for a short time - digitalWrite(LL_LED_1, !digitalRead(GPS_PPS)) ; -#endif - - /* fetch packets */ - pthread_mutex_lock(&mx_concent); - if (radiostream_enabled == true) nb_pkt = lgw_receive(NB_PKT_MAX, rxpkt); else nb_pkt = 0; - if (ghoststream_enabled == true) nb_pkt = ghost_get(NB_PKT_MAX-nb_pkt, &rxpkt[nb_pkt]) + nb_pkt; - + if (led_pps!=NOT_A_PIN && pin_pps!=NOT_A_PIN) { + bcm2835_gpio_write(led_pps, bcm2835_gpio_lev(pin_pps)); + } - //TODO this test should in fact be before the ghost packets are collected. + //TODO this test should in fact be before the ghost packets are collected. pthread_mutex_unlock(&mx_concent); if (nb_pkt == LGW_HAL_ERROR) { MSG("ERROR: [up] failed packet fetch, exiting\n"); @@ -1646,19 +1856,34 @@ void thread_up(void) { /* check if there are status report to send */ send_report = report_ready; /* copy the variable so it doesn't change mid-function */ /* no mutex, we're only reading */ - -#ifdef LINKLABS_BLOWFISH_RPI - if ( nb_pkt > 0) { - // Blink LED2 - digitalWrite(LL_LED_2, LOW) ; - led2_timer = millis(); - } -#endif - /* wait a short time if no packets, nor status report */ if ((nb_pkt == 0) && (send_report == false)) { wait_ms(FETCH_SLEEP_MS); + if (led_heartbeat != NOT_A_PIN) { + led_heartbeat_cnt++; + if (led_heartbeat_cnt == 40) { + bcm2835_gpio_write(led_heartbeat, HIGH); + } + else if (led_heartbeat_cnt >= 80) { + bcm2835_gpio_write(led_heartbeat, LOW); + led_heartbeat_cnt=0; + } + } + + // Led time out expired + if (led_error != NOT_A_PIN) { + if (--led_error_cnt==0) { + bcm2835_gpio_write(led_error, LOW); + } + } + if (led_packet != NOT_A_PIN) { + if (--led_packet_cnt==0) { + bcm2835_gpio_write(led_packet, LOW); + } + } + + continue; } @@ -1694,11 +1919,17 @@ void thread_up(void) { for (i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; + // Display information + log_packet(p); + /* basic packet filtering */ pthread_mutex_lock(&mx_meas_up); meas_nb_rx_rcv += 1; switch(p->status) { case STAT_CRC_OK: + // Green led + led_packet_cnt=FETCH_SLEEP_MS*10; + bcm2835_gpio_write(led_packet, HIGH); meas_nb_rx_ok += 1; if (!fwd_valid_pkt) { pthread_mutex_unlock(&mx_meas_up); @@ -1706,6 +1937,9 @@ void thread_up(void) { } break; case STAT_CRC_BAD: + // Red led + led_error_cnt=FETCH_SLEEP_MS*10; + bcm2835_gpio_write(led_error, HIGH); meas_nb_rx_bad += 1; if (!fwd_error_pkt) { pthread_mutex_unlock(&mx_meas_up); @@ -1713,6 +1947,11 @@ void thread_up(void) { } break; case STAT_NO_CRC: + // Green and Red led + led_packet_cnt=FETCH_SLEEP_MS*10; + led_error_cnt=FETCH_SLEEP_MS*10; + bcm2835_gpio_write(led_packet, HIGH); + bcm2835_gpio_write(led_error, HIGH); meas_nb_rx_nocrc += 1; if (!fwd_nocrc_pkt) { pthread_mutex_unlock(&mx_meas_up); @@ -1720,6 +1959,9 @@ void thread_up(void) { } break; default: + // Red led + led_error_cnt=FETCH_SLEEP_MS*10; + bcm2835_gpio_write(led_error, HIGH); MSG("WARNING: [up] received packet with unknown status %u (size %u, modulation %u, BW %u, DR %u, RSSI %.1f)\n", p->status, p->size, p->modulation, p->bandwidth, p->datarate, p->rssi); pthread_mutex_unlock(&mx_meas_up); continue; /* skip that packet */ @@ -2149,6 +2391,10 @@ void thread_down(void* pic) { break; } + if (led_down!=NOT_A_PIN) { + bcm2835_gpio_write(led_down, HIGH); + } + /* generate random token for request */ token_h = (uint8_t)rand(); /* random token */ token_l = (uint8_t)rand(); /* random token */ @@ -2268,9 +2514,12 @@ void thread_down(void* pic) { } else { /* out-of-sync token */ MSG("INFO: [down] for server %s, received out-of-sync ACK\n",serv_addr[ic]); } + if (led_down!=NOT_A_PIN) { + bcm2835_gpio_write(led_down, LOW); + } + continue; } - //TODO: This might generate to much logging data. The reporting should be reevaluated and an option -q should be added. /* the datagram is a PULL_RESP */ From 05702dfedbd52b65eeda45975dffcb26a31f229a Mon Sep 17 00:00:00 2001 From: hallard Date: Thu, 7 Dec 2017 17:46:25 +0100 Subject: [PATCH 08/17] Added Math library on link --- basic_pkt_fwd/Makefile | 8 ++++---- beacon_pkt_fwd/Makefile | 8 ++++---- gps_pkt_fwd/Makefile | 8 ++++---- poly_pkt_fwd/Makefile | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/basic_pkt_fwd/Makefile b/basic_pkt_fwd/Makefile index fa20a531..3964c899 100644 --- a/basic_pkt_fwd/Makefile +++ b/basic_pkt_fwd/Makefile @@ -35,17 +35,17 @@ LGW_INC += $(LGW_PATH)/inc/loragw_hal.h ### Linking options ifeq ($(CFG_SPI),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(CFG_SPI),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(CFG_SPI),mac) $(error [error] Option mac not supported for SPI here) else # keep compatibility with SX1301 HAL version 1.2.x and bellow ifeq ($(LGW_PHY),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(LGW_PHY),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(LGW_PHY),mac) $(error [error] Option mac not supported for SPI here) else diff --git a/beacon_pkt_fwd/Makefile b/beacon_pkt_fwd/Makefile index b98925b1..c070ce62 100644 --- a/beacon_pkt_fwd/Makefile +++ b/beacon_pkt_fwd/Makefile @@ -36,17 +36,17 @@ LGW_INC += $(LGW_PATH)/inc/loragw_gps.h ### Linking options ifeq ($(CFG_SPI),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(CFG_SPI),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(CFG_SPI),mac) $(error [error] Option mac not supported for SPI here) else # keep compatibility with SX1301 HAL version 1.2.x and bellow ifeq ($(LGW_PHY),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(LGW_PHY),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(LGW_PHY),mac) $(error [error] Option mac not supported for SPI here) else diff --git a/gps_pkt_fwd/Makefile b/gps_pkt_fwd/Makefile index ea8873fe..cf7176a6 100644 --- a/gps_pkt_fwd/Makefile +++ b/gps_pkt_fwd/Makefile @@ -36,17 +36,17 @@ LGW_INC += $(LGW_PATH)/inc/loragw_gps.h ### Linking options ifeq ($(CFG_SPI),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(CFG_SPI),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(CFG_SPI),mac) $(error [error] Option mac not supported for SPI here) else # keep compatibility with SX1301 HAL version 1.2.x and bellow ifeq ($(LGW_PHY),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(LGW_PHY),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(LGW_PHY),mac) $(error [error] Option mac not supported for SPI here) else diff --git a/poly_pkt_fwd/Makefile b/poly_pkt_fwd/Makefile index be2fadd0..79f1a599 100644 --- a/poly_pkt_fwd/Makefile +++ b/poly_pkt_fwd/Makefile @@ -36,19 +36,19 @@ LGW_INC += $(LGW_PATH)/inc/loragw_gps.h ### Linking options ifeq ($(CFG_SPI),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(CFG_SPI),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(CFG_SPI),mac) - LIBS := -lloragw -lpthread -lmpsse + LIBS := -lloragw -lpthread -lmpsse -lm else # keep compatibility with SX1301 HAL version 1.2.x and bellow ifeq ($(LGW_PHY),native) - LIBS := -lloragw -lrt -lpthread + LIBS := -lloragw -lrt -lpthread -lm else ifeq ($(LGW_PHY),ftdi) - LIBS := -lloragw -lrt -lpthread -lmpsse + LIBS := -lloragw -lrt -lpthread -lmpsse -lm else ifeq ($(LGW_PHY),mac) - LIBS := -lloragw -lpthread -lmpsse + LIBS := -lloragw -lpthread -lmpsse -lm else $(error [error] Can't find configuration for SPI phy) endif From d5617a5e8af0549547b9a6abf905f8b6745c872c Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:04:24 +0100 Subject: [PATCH 09/17] use gpiolib library instead of BCM2835 --- poly_pkt_fwd/Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/poly_pkt_fwd/Makefile b/poly_pkt_fwd/Makefile index 79f1a599..0b60d191 100644 --- a/poly_pkt_fwd/Makefile +++ b/poly_pkt_fwd/Makefile @@ -19,6 +19,7 @@ RELEASE_VERSION := $(shell cat ../VERSION) CC := $(CROSS_COMPILE)gcc AR := $(CROSS_COMPILE)ar +#CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. VFLAG := -D VERSION_STRING="\"$(RELEASE_VERSION)\"" @@ -54,10 +55,6 @@ else endif endif -# To drive onboards LED and other stuff you need -# to install and link with bcm2835 library, see -# http://www.airspayce.com/mikem/bcm2835/ -LIBS += -lbcm2835 ### General build targets @@ -78,15 +75,18 @@ obj/parson.o: src/parson.c inc/parson.h obj/monitor.o: src/monitor.c inc/monitor.h $(CC) -c $(CFLAGS) $< -o $@ +obj/gpiolib.o: src/gpiolib.c inc/gpiolib.h + $(CC) -c $(CFLAGS) $< -o $@ + obj/ghost.o: src/ghost.c inc/ghost.h $(LGW_INC) $(CC) -I$(LGW_PATH)/inc -c $(CFLAGS) $< -o $@ ### Main program compilation and assembly -obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h inc/ghost.h inc/monitor.h +obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h inc/ghost.h inc/monitor.h inc/gpiolib.h $(CC) -c $(CFLAGS) $(VFLAG) -I$(LGW_PATH)/inc $< -o $@ -$(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a obj/parson.o obj/base64.o obj/ghost.o obj/monitor.o - $(CC) -L$(LGW_PATH) $< obj/parson.o obj/base64.o obj/ghost.o obj/monitor.o -o $@ $(LIBS) +$(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a obj/parson.o obj/base64.o obj/ghost.o obj/monitor.o obj/gpiolib.o + $(CC) -L$(LGW_PATH) $< obj/parson.o obj/base64.o obj/ghost.o obj/monitor.o obj/gpiolib.o -o $@ $(LIBS) ### EOF From 1f144cbdabfaa32232e36af9c2a363624331fa56 Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:06:54 +0100 Subject: [PATCH 10/17] moved from BCM2835 to gpiolib, added reset pin --- poly_pkt_fwd/src/poly_pkt_fwd.c | 120 ++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/poly_pkt_fwd/src/poly_pkt_fwd.c b/poly_pkt_fwd/src/poly_pkt_fwd.c index 322c8056..1bcab756 100644 --- a/poly_pkt_fwd/src/poly_pkt_fwd.c +++ b/poly_pkt_fwd/src/poly_pkt_fwd.c @@ -53,7 +53,7 @@ Maintainer: Ruud Vlaming #include -#include +#include #include #include @@ -163,12 +163,13 @@ static int keepalive_time = DEFAULT_KEEPALIVE; /* send a PULL_DATA request every static unsigned stat_interval = DEFAULT_STAT; /* time interval (in sec) at which statistics are collected and displayed */ /* LED */ -static unsigned led_heartbeat = NOT_A_PIN;/* heartbeat LED */ -static unsigned led_down = NOT_A_PIN; /* downlink for server */ -static unsigned led_error = NOT_A_PIN; /* error LED */ -static unsigned led_packet = NOT_A_PIN; /* packet led */ -static unsigned led_pps = NOT_A_PIN; /* PPS GPS Led (linklabs board) */ -static unsigned pin_pps = NOT_A_PIN; /* PPS GPS pin (LinkLabs board) */ +static int led_heartbeat = NOT_A_PIN;/* heartbeat LED */ +static int led_down = NOT_A_PIN; /* downlink for server */ +static int led_error = NOT_A_PIN; /* error LED */ +static int led_packet = NOT_A_PIN; /* packet led */ +static int led_pps = NOT_A_PIN; /* PPS GPS Led (linklabs board) */ +static int pin_pps = NOT_A_PIN; /* PPS GPS pin (LinkLabs board) */ +static int pin_reset = NOT_A_PIN; /* Concentrator Reset pin */ /* gateway <-> MAC protocol variables */ static uint32_t net_mac_h; /* Most Significant Nibble, network order */ @@ -798,6 +799,13 @@ static int parse_gateway_configuration(const char * conf_file) { MSG("INFO: LED pps is configured to GPIO%i\n", led_pps); } + /* get Reset PIN */ + val = json_object_get_value(conf_obj, "pin_reset"); + if (val != NULL) { + pin_reset = (unsigned)json_value_get_number(val); + MSG("INFO: SX1301 RESET is configured to GPIO%i\n", pin_reset); + } + /* get time-out value (in ms) for upstream datagrams (optional) */ val = json_object_get_value(conf_obj, "push_timeout_ms"); if (val != NULL) { @@ -1211,6 +1219,22 @@ void log_packet( struct lgw_pkt_rx_s* p) { } +// Value : 1=Low Output (2=High Output) +void gpio_config(int * gpio, int value) { + if ( *gpio != NOT_A_PIN ) { + // Went fine + if ( gpio_export(*gpio) > -1 ) { + // Set value and direction + gpio_direction(*gpio,value); + } else { + MSG("INFO: can't export GPIO%d pin\n", *gpio); + // Can't export set to not a pin + *gpio = NOT_A_PIN; + } + } +} + + void usage(char *proc_name) { fprintf(stderr, "Usage: %s [-c config_dir] [-l logfile]\n", proc_name); exit(1); @@ -1358,37 +1382,23 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if (led_down!=NOT_A_PIN || led_heartbeat!=NOT_A_PIN || - led_pps!=NOT_A_PIN || pin_pps!=NOT_A_PIN || - led_error!=NOT_A_PIN || led_packet!=NOT_A_PIN ) { - if (!bcm2835_init()) { - MSG("ERROR: [main] failed to initialize with bcm2835_init()\n"); - exit(EXIT_FAILURE); - } + gpio_config(&led_down, 1); // 1=Low Output (2=High Output) + gpio_config(&led_heartbeat, 1); // 1=Low Output (2=High Output) + gpio_config(&led_error, 1); // 1=Low Output (2=High Output) + gpio_config(&led_packet, 1); // 1=Low Output (2=High Output) + gpio_config(&led_pps, 1); // 1=Low Output (2=High Output) + gpio_config(&pin_pps, 0); // 0=Input + gpio_config(&pin_reset, 0); // 1=Low Output (2=High Output) - if (led_down!=NOT_A_PIN) { - bcm2835_gpio_fsel(led_down, BCM2835_GPIO_FSEL_OUTP); - bcm2835_gpio_write(led_down, LOW); - } - if (led_heartbeat!=NOT_A_PIN) { - bcm2835_gpio_fsel(led_heartbeat, BCM2835_GPIO_FSEL_OUTP); - bcm2835_gpio_write(led_heartbeat, LOW); - } - if (led_error!=NOT_A_PIN) { - bcm2835_gpio_fsel(led_error, BCM2835_GPIO_FSEL_OUTP); - bcm2835_gpio_write(led_error, LOW); - } - if (led_packet!=NOT_A_PIN) { - bcm2835_gpio_fsel(led_packet, BCM2835_GPIO_FSEL_OUTP); - bcm2835_gpio_write(led_packet, LOW); - } - if (led_pps!=NOT_A_PIN) { - bcm2835_gpio_fsel(led_pps, BCM2835_GPIO_FSEL_OUTP); - bcm2835_gpio_write(led_pps, LOW); - } - if (pin_pps!=NOT_A_PIN) { - bcm2835_gpio_fsel(pin_pps, BCM2835_GPIO_FSEL_INPT); - } + // reset the concentrator + if (pin_reset != NOT_A_PIN) { + MSG("INFO: Reseting concentrator with GPIO%d\n", pin_reset); + // Assert reset + gpio_write(pin_reset,1); + // Wait 100ms + usleep(100000); + // Free reset + gpio_write(pin_reset,0); } /* Start GPS a.s.a.p., to allow it to lock */ @@ -1755,11 +1765,13 @@ int main(int argc, char *argv[]) } // Light off the LED - if (led_down!=NOT_A_PIN) { bcm2835_gpio_write(led_down , LOW);} - if (led_heartbeat!=NOT_A_PIN){ bcm2835_gpio_write(led_heartbeat, LOW);} - if (led_error!=NOT_A_PIN) { bcm2835_gpio_write(led_error , LOW);} - if (led_packet!=NOT_A_PIN) { bcm2835_gpio_write(led_packet , LOW);} - if (led_pps!=NOT_A_PIN) { bcm2835_gpio_write(led_pps , LOW);} + if (led_down!=NOT_A_PIN) { gpio_write(led_down , 0); gpio_unexport(led_down); } + if (led_heartbeat!=NOT_A_PIN){ gpio_write(led_heartbeat, 0); gpio_unexport(led_heartbeat); } + if (led_error!=NOT_A_PIN) { gpio_write(led_error , 0); gpio_unexport(led_error ); } + if (led_packet!=NOT_A_PIN) { gpio_write(led_packet , 0); gpio_unexport(led_packet ); } + if (led_pps!=NOT_A_PIN) { gpio_write(led_pps , 0); gpio_unexport(led_pps ); } + if (pin_pps!=NOT_A_PIN) { gpio_unexport(pin_pps); } + if (pin_reset!=NOT_A_PIN) { gpio_unexport(pin_reset); } } @@ -1843,7 +1855,7 @@ void thread_up(void) { // the led will be on, and if PPS signal from GPS is okay the led // will blink off for a short time if (led_pps!=NOT_A_PIN && pin_pps!=NOT_A_PIN) { - bcm2835_gpio_write(led_pps, bcm2835_gpio_lev(pin_pps)); + gpio_write( led_pps, gpio_read(pin_pps) ); } //TODO this test should in fact be before the ghost packets are collected. @@ -1863,10 +1875,10 @@ void thread_up(void) { if (led_heartbeat != NOT_A_PIN) { led_heartbeat_cnt++; if (led_heartbeat_cnt == 40) { - bcm2835_gpio_write(led_heartbeat, HIGH); + gpio_write(led_heartbeat, 1); } else if (led_heartbeat_cnt >= 80) { - bcm2835_gpio_write(led_heartbeat, LOW); + gpio_write(led_heartbeat, 0); led_heartbeat_cnt=0; } } @@ -1874,12 +1886,12 @@ void thread_up(void) { // Led time out expired if (led_error != NOT_A_PIN) { if (--led_error_cnt==0) { - bcm2835_gpio_write(led_error, LOW); + gpio_write(led_error, 0); } } if (led_packet != NOT_A_PIN) { if (--led_packet_cnt==0) { - bcm2835_gpio_write(led_packet, LOW); + gpio_write(led_packet, 0); } } @@ -1929,7 +1941,7 @@ void thread_up(void) { case STAT_CRC_OK: // Green led led_packet_cnt=FETCH_SLEEP_MS*10; - bcm2835_gpio_write(led_packet, HIGH); + gpio_write(led_packet, 1); meas_nb_rx_ok += 1; if (!fwd_valid_pkt) { pthread_mutex_unlock(&mx_meas_up); @@ -1939,7 +1951,7 @@ void thread_up(void) { case STAT_CRC_BAD: // Red led led_error_cnt=FETCH_SLEEP_MS*10; - bcm2835_gpio_write(led_error, HIGH); + gpio_write(led_error, 1); meas_nb_rx_bad += 1; if (!fwd_error_pkt) { pthread_mutex_unlock(&mx_meas_up); @@ -1950,8 +1962,8 @@ void thread_up(void) { // Green and Red led led_packet_cnt=FETCH_SLEEP_MS*10; led_error_cnt=FETCH_SLEEP_MS*10; - bcm2835_gpio_write(led_packet, HIGH); - bcm2835_gpio_write(led_error, HIGH); + gpio_write(led_packet, 1); + gpio_write(led_error, 1); meas_nb_rx_nocrc += 1; if (!fwd_nocrc_pkt) { pthread_mutex_unlock(&mx_meas_up); @@ -1961,7 +1973,7 @@ void thread_up(void) { default: // Red led led_error_cnt=FETCH_SLEEP_MS*10; - bcm2835_gpio_write(led_error, HIGH); + gpio_write(led_error, 1); MSG("WARNING: [up] received packet with unknown status %u (size %u, modulation %u, BW %u, DR %u, RSSI %.1f)\n", p->status, p->size, p->modulation, p->bandwidth, p->datarate, p->rssi); pthread_mutex_unlock(&mx_meas_up); continue; /* skip that packet */ @@ -2392,7 +2404,7 @@ void thread_down(void* pic) { } if (led_down!=NOT_A_PIN) { - bcm2835_gpio_write(led_down, HIGH); + gpio_write(led_down, 1); } /* generate random token for request */ @@ -2515,7 +2527,7 @@ void thread_down(void* pic) { MSG("INFO: [down] for server %s, received out-of-sync ACK\n",serv_addr[ic]); } if (led_down!=NOT_A_PIN) { - bcm2835_gpio_write(led_down, LOW); + gpio_write(led_down, 0); } continue; From ed157b4048828d880345e37fe8120d48d5968386 Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:15:16 +0100 Subject: [PATCH 11/17] added pin_reset and gpiolib doc --- poly_pkt_fwd/readme.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/poly_pkt_fwd/readme.md b/poly_pkt_fwd/readme.md index 74b9f392..7c6e0a51 100644 --- a/poly_pkt_fwd/readme.md +++ b/poly_pkt_fwd/readme.md @@ -34,8 +34,10 @@ Specific Raspberry PI boards version features ============================================= To be able to drive Raspbery PI concentrator on boards LED, this program -use bcm2835 library, you need to install them before anything. -see http://www.airspayce.com/mikem/bcm2835/ +use ~~bcm2835 library, you need to install them before anything. +see http://www.airspayce.com/mikem/bcm2835/~~ gpiolib which control GPIO using +linux filesystem, making this packet forwarder more compatible with different +target. This version has been written to works with Linklabs board and also with ic880a concentrator + Raspberry Pi Plate. @@ -51,6 +53,7 @@ a name and the GPIO pin number. Names are : - `led_packet` LED will blink on each packet received - `led_pps` LED used for GPS PPS indicator (mainly linklabs board) - `pin_pps` Pin where PPS signal is connected to (if any, mainly linklabs board) +- `pin_reset` GPIO pin connected to SX1301 concentrator reset GPS PPS pin on linklabs boards are not connected to LED but on a GPIO, so `led_pps` and `pin_pps` are used for a "software link", incoming PPS signal going to GPIO input @@ -63,14 +66,22 @@ is redirected to GPIO led output, thus for example, with linklabs, configuration "led_packet": 27, /* GPIO27 RED */ ``` -And fot ic880a RPI plate (4 leds), configuration can be +for ic880a RPI plate (4 leds), configuration can be ```json "led_heartbeat": 4, /* GPIO4 Blue */ "led_down": 18, /* GPIO18 White */ "led_error": 23, /* GPIO23 Red */ "led_packet": 24, /* GPIO24 Green */ + "reset_pin": 17, /* GPIO17 concentrator reset */ + +``` + +And for RAK831 RPI Zero plate configuration can be (no led pins) +```json + "reset_pin": 25, /* GPIO25 concentrator reset */ ``` + An extented Log ouput on each packet received has also been added to this version, this can be usefull for monitoring packet recevided by concentrator, regardless if they are or not send the gateway. It's logged as info with the following informations From 27c5b58b39ab187d538352a352fe8653ea11841f Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:15:57 +0100 Subject: [PATCH 12/17] bump to 2.2.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7ec1d6db..ccbccc3d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 +2.2.0 From a98a49a4fbaa952bb3133cb05e00aa05fc66d0c1 Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:17:39 +0100 Subject: [PATCH 13/17] creation --- poly_pkt_fwd/inc/gpiolib.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 poly_pkt_fwd/inc/gpiolib.h diff --git a/poly_pkt_fwd/inc/gpiolib.h b/poly_pkt_fwd/inc/gpiolib.h new file mode 100644 index 00000000..ed68dcee --- /dev/null +++ b/poly_pkt_fwd/inc/gpiolib.h @@ -0,0 +1,21 @@ +#ifndef _GPIOLIB_H_ + +/* returns -1 or the file descriptor of the gpio value file */ +int gpio_export(int gpio); +/* Set direction to 2 = high output, 1 low output, 0 input */ +int gpio_direction(int gpio, int dir); +/* Release the GPIO to be claimed by other processes or a kernel driver */ +void gpio_unexport(int gpio); +/* Single GPIO read */ +int gpio_read(int gpio); +/* Set GPIO to val (1 = high) */ +int gpio_write(int gpio, int val); +/* Set which edge(s) causes the value select to return */ +int gpio_setedge(int gpio, int rising, int falling); +/* Blocks on select until GPIO toggles on edge */ +int gpio_select(int gpio); + +/* Return the GPIO file descriptor */ +int gpio_getfd(int gpio); + +#endif //_GPIOLIB_H_ \ No newline at end of file From 4cacb9b865ecc3d81bb4cd51dcc7c2d1bee4b7a2 Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:17:51 +0100 Subject: [PATCH 14/17] creation --- poly_pkt_fwd/src/gpiolib.c | 210 +++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 poly_pkt_fwd/src/gpiolib.c diff --git a/poly_pkt_fwd/src/gpiolib.c b/poly_pkt_fwd/src/gpiolib.c new file mode 100644 index 00000000..d149c1b0 --- /dev/null +++ b/poly_pkt_fwd/src/gpiolib.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gpiolib.h" + +int gpio_direction(int gpio, int dir) +{ + int ret = 0; + char buf[50]; + sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio); + int gpiofd = open(buf, O_WRONLY); + if(gpiofd < 0) { + perror("Couldn't open IRQ file"); + ret = -1; + } + + if(dir == 2 && gpiofd){ + if (3 != write(gpiofd, "high", 3)) { + perror("Couldn't set GPIO direction to out"); + ret = -2; + } + } + + if(dir == 1 && gpiofd){ + if (3 != write(gpiofd, "out", 3)) { + perror("Couldn't set GPIO direction to out"); + ret = -3; + } + } + else if(gpiofd) { + if(2 != write(gpiofd, "in", 2)) { + perror("Couldn't set GPIO directio to in"); + ret = -4; + } + } + + close(gpiofd); + return ret; +} + +int gpio_setedge(int gpio, int rising, int falling) +{ + int ret = 0; + char buf[50]; + sprintf(buf, "/sys/class/gpio/gpio%d/edge", gpio); + int gpiofd = open(buf, O_WRONLY); + if(gpiofd < 0) { + perror("Couldn't open IRQ file"); + ret = -1; + } + + if(gpiofd && rising && falling) { + if(4 != write(gpiofd, "both", 4)) { + perror("Failed to set IRQ to both falling & rising"); + ret = -2; + } + } else { + if(rising && gpiofd) { + if(6 != write(gpiofd, "rising", 6)) { + perror("Failed to set IRQ to rising"); + ret = -2; + } + } else if(falling && gpiofd) { + if(7 != write(gpiofd, "falling", 7)) { + perror("Failed to set IRQ to falling"); + ret = -3; + } + } + } + + close(gpiofd); + + return ret; +} + +int gpio_export(int gpio) +{ + int efd; + char buf[50]; + int ret; + + /* Quick test if it has already been exported */ + sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); + efd = open(buf, O_WRONLY); + if(efd != -1) { + close(efd); + return 0; + } + + efd = open("/sys/class/gpio/export", O_WRONLY); + + if(efd != -1) { + sprintf(buf, "%d", gpio); + ret = write(efd, buf, strlen(buf)); + if(ret < 0) { + perror("Export failed"); + return -2; + } + close(efd); + } else { + // If we can't open the export file, we probably + // dont have any gpio permissions + return -1; + } + return 0; +} + +void gpio_unexport(int gpio) +{ + int gpiofd; + char buf[50]; + gpiofd = open("/sys/class/gpio/unexport", O_WRONLY); + sprintf(buf, "%d", gpio); + write(gpiofd, buf, strlen(buf)); + close(gpiofd); +} + +int gpio_getfd(int gpio) +{ + char buf[50]; + int gpiofd; + sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); + gpiofd = open(buf, O_RDWR); + if(gpiofd < 0) { + fprintf(stderr, "Failed to open gpio %d value\n", gpio); + perror("gpio failed"); + } + + return gpiofd; +} + +int gpio_read(int gpio) +{ + char in[3] = {0, 0, 0}; + char buf[50]; + int nread, gpiofd; + sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); + gpiofd = open(buf, O_RDWR); + if(gpiofd < 0) { + fprintf(stderr, "Failed to open gpio %d value\n", gpio); + perror("gpio failed"); + } + + do { + nread = read(gpiofd, in, 1); + } while (nread == 0); + if(nread == -1){ + perror("GPIO Read failed"); + return -1; + } + + close(gpiofd); + return atoi(in); +} + +int gpio_write(int gpio, int val) +{ + char buf[50]; + int ret, gpiofd; + sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); + gpiofd = open(buf, O_RDWR); + if(gpiofd > 0) { + snprintf(buf, 2, "%d", val); + ret = write(gpiofd, buf, 2); + if(ret < 0) { + perror("failed to set gpio"); + return 1; + } + + close(gpiofd); + if(ret == 2) return 0; + } + return 1; +} + + +int gpio_select(int gpio) +{ + char gpio_irq[64]; + int buf, irqfd; + fd_set fds; + FD_ZERO(&fds); + + snprintf(gpio_irq, sizeof(gpio_irq), "/sys/class/gpio/gpio%d/value", gpio); + irqfd = open(gpio_irq, O_RDONLY, S_IRUSR); + if(irqfd < 1) { + perror("Couldn't open the value file"); + return -1; + } + + // Read first since there is always an initial status + read(irqfd, &buf, sizeof(buf)); + + while(1) { + FD_SET(irqfd, &fds); + select(irqfd + 1, NULL, NULL, &fds, NULL); + if(FD_ISSET(irqfd, &fds)) + { + FD_CLR(irqfd, &fds); //Remove the filedes from set + // Clear the junk data in the IRQ file + read(irqfd, &buf, sizeof(buf)); + return 1; + } + } +} From b2f482a5bf4c9b45b9541540b981e460828109ef Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:38:40 +0100 Subject: [PATCH 15/17] bump to v2.2.0 --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 88638ac6..da509e79 100644 --- a/readme.md +++ b/readme.md @@ -102,6 +102,10 @@ Please refer to the script header for more details. 5. Changelog ------------- +### v2.2.0 - 2018-01-02 ### + +* Added features to poly_pkt_fwd, see dedicated [read.me](https://github.com/ch2i/packet_forwarder/master/poly_pkt_fwd/readme.md) + ### v2.1.0 - 2015-06-29 ### * Added helper script for concentrator reset through GPIO, needed on IoT Starter Kit (reset_pkt_fwd.sh). From 5ef046089842a7a4413b4fba9a31618166958834 Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:39:59 +0100 Subject: [PATCH 16/17] link error --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index da509e79..e2c8308d 100644 --- a/readme.md +++ b/readme.md @@ -104,7 +104,7 @@ Please refer to the script header for more details. ### v2.2.0 - 2018-01-02 ### -* Added features to poly_pkt_fwd, see dedicated [read.me](https://github.com/ch2i/packet_forwarder/master/poly_pkt_fwd/readme.md) +* Added features to poly_pkt_fwd, see dedicated [read.me](https://github.com/ch2i/packet_forwarder/blob/master/poly_pkt_fwd/readme.md) ### v2.1.0 - 2015-06-29 ### From 8192e8d67f8fa0d16b14a2dd0645d4eb584429f4 Mon Sep 17 00:00:00 2001 From: hallard Date: Tue, 2 Jan 2018 21:41:39 +0100 Subject: [PATCH 17/17] pin_reset error --- poly_pkt_fwd/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poly_pkt_fwd/readme.md b/poly_pkt_fwd/readme.md index 7c6e0a51..443a772f 100644 --- a/poly_pkt_fwd/readme.md +++ b/poly_pkt_fwd/readme.md @@ -72,13 +72,13 @@ for ic880a RPI plate (4 leds), configuration can be "led_down": 18, /* GPIO18 White */ "led_error": 23, /* GPIO23 Red */ "led_packet": 24, /* GPIO24 Green */ - "reset_pin": 17, /* GPIO17 concentrator reset */ + "pin_reset": 17, /* GPIO17 concentrator reset */ ``` And for RAK831 RPI Zero plate configuration can be (no led pins) ```json - "reset_pin": 25, /* GPIO25 concentrator reset */ + "pin_reset": 25, /* GPIO25 concentrator reset */ ```