Merge pull request #420 from cyberman54/development

Development
This commit is contained in:
Verkehrsrot 2019-09-01 00:20:29 +02:00 committed by GitHub
commit 20732f13dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 160 additions and 56 deletions

View File

@ -158,7 +158,7 @@ You can add up to 3 user defined sensors. Insert sensor's payload scheme in [*se
Output of user sensor data can be switched by user remote control command 0x14 sent to Port 2. Output of user sensor data can be switched by user remote control command 0x14 sent to Port 2.
Output of sensor and peripheral data is internally switched by a bitmask register. Default mask (0xFF) can be tailored by editing *cfg.payloadmask* initialization value in [*configmanager.cpp*](src/configmanager.cpp) following this scheme: Output of sensor and peripheral data is internally switched by a bitmask register. Default mask can be tailored by editing *cfg.payloadmask* initialization value in [*configmanager.cpp*](src/configmanager.cpp) following this scheme:
| Bit | Sensordata | | Bit | Sensordata |
| --- | ------------- | | --- | ------------- |

View File

@ -4,7 +4,7 @@
#include "globals.h" #include "globals.h"
#include "rcommand.h" #include "rcommand.h"
#include "timekeeper.h" #include "timekeeper.h"
#if(TIME_SYNC_LORASERVER) #if (TIME_SYNC_LORASERVER)
#include "timesync.h" #include "timesync.h"
#endif #endif
@ -23,6 +23,13 @@
extern QueueHandle_t LoraSendQueue; extern QueueHandle_t LoraSendQueue;
extern TaskHandle_t lmicTask, lorasendTask; extern TaskHandle_t lmicTask, lorasendTask;
// table of LORAWAN MAC commands
typedef struct {
const uint8_t opcode;
const char cmdname[20];
const uint8_t params;
} mac_t;
esp_err_t lora_stack_init(); esp_err_t lora_stack_init();
void lmictask(void *pvParameters); void lmictask(void *pvParameters);
void onEvent(ev_t ev); void onEvent(ev_t ev);
@ -37,6 +44,11 @@ void switch_lora(uint8_t sf, uint8_t tx);
void lora_send(void *pvParameters); void lora_send(void *pvParameters);
void lora_enqueuedata(MessageBuffer_t *message); void lora_enqueuedata(MessageBuffer_t *message);
void lora_queuereset(void); void lora_queuereset(void);
void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
size_t nMsg);
void myTxCallback(void *pUserData, int fSuccess);
void mac_decode(const uint8_t cmd[], const uint8_t cmdlength);
#if (TIME_SYNC_LORAWAN) #if (TIME_SYNC_LORAWAN)
void user_request_network_time_callback(void *pVoidUserUTCTime, void user_request_network_time_callback(void *pVoidUserUTCTime,
int flagSuccess); int flagSuccess);

View File

@ -19,11 +19,11 @@
typedef struct { typedef struct {
const uint8_t opcode; const uint8_t opcode;
void (*func)(uint8_t []); void (*func)(uint8_t []);
uint8_t params; const uint8_t params;
const bool store; const bool store;
} cmd_t; } cmd_t;
void rcommand(uint8_t cmd[], uint8_t cmdlength); void rcommand(const uint8_t cmd[], const uint8_t cmdlength);
void do_reset(); void do_reset();
#endif #endif

View File

@ -12,7 +12,7 @@
void timesync_init(void); void timesync_init(void);
void send_timesync_req(void); void send_timesync_req(void);
int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len); int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t buf_len);
void process_timesync_req(void *taskparameter); void process_timesync_req(void *taskparameter);
void store_time_sync_req(uint32_t t_millisec); void store_time_sync_req(uint32_t t_millisec);

View File

@ -42,7 +42,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
[common] [common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c" ; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
release_version = 1.7.974 release_version = 1.7.979
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 3 debug_level = 3

View File

@ -144,7 +144,7 @@ int checkIaqSensorStatus(void) {
// store current BME sensor data in struct // store current BME sensor data in struct
void bme_storedata(bmeStatus_t *bme_store) { void bme_storedata(bmeStatus_t *bme_store) {
if ((cfg.payloadmask && MEMS_DATA) & if ((cfg.payloadmask & MEMS_DATA) &&
(I2C_MUTEX_LOCK())) { // block i2c bus access (I2C_MUTEX_LOCK())) { // block i2c bus access
#ifdef HAS_BME680 #ifdef HAS_BME680

View File

@ -138,7 +138,7 @@ void gps_loop(void *pvParameters) {
while (1) { while (1) {
if (cfg.payloadmask && GPS_DATA) { if (cfg.payloadmask & GPS_DATA) {
#ifdef GPS_SERIAL #ifdef GPS_SERIAL
// feed GPS decoder with serial NMEA data from GPS device // feed GPS decoder with serial NMEA data from GPS device
while (GPS_Serial.available()) { while (GPS_Serial.available()) {

View File

@ -19,10 +19,15 @@
// LMIC LORAWAN STACK SETTINGS // LMIC LORAWAN STACK SETTINGS
// --> adapt to your device only if necessary // --> adapt to your device only if necessary
// use interrupts only if LORA_IRQ and LORA_DIO are connected to interrupt
// capable GPIO pins on your board, if not disable interrupts
//#define LMIC_USE_INTERRUPTS 1 //#define LMIC_USE_INTERRUPTS 1
//time sync via LoRaWAN network, is not yet supported by TTN (LoRaWAN spec v1.0.3) // needed for paxcounter code
//#define LMIC_ENABLE_DeviceTimeReq 1 #define LMIC_ENABLE_user_events 1
// time sync via LoRaWAN network, note: not supported by TTNv2
// #define LMIC_ENABLE_DeviceTimeReq 1
// 16 μs per tick // 16 μs per tick
// LMIC requires ticks to be 15.5μs - 100 μs long // LMIC requires ticks to be 15.5μs - 100 μs long
@ -33,7 +38,7 @@
// This tells LMIC to make the receive windows bigger, in case your clock is // This tells LMIC to make the receive windows bigger, in case your clock is
// faster or slower. This causes the transceiver to be earlier switched on, // faster or slower. This causes the transceiver to be earlier switched on,
// so consuming more power. You may sharpen (reduce) this value if you are // so consuming more power. You may sharpen (reduce) this value if you are
// limited on battery. // limited on battery.
// ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES // ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES
#define CLOCK_ERROR_PROCENTAGE 7 #define CLOCK_ERROR_PROCENTAGE 7

View File

@ -244,38 +244,6 @@ void onEvent(ev_t ev) {
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK") strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK")
: PSTR("TX COMPLETE")); : PSTR("TX COMPLETE"));
sprintf(display_line6, " "); // clear previous lmic status sprintf(display_line6, " "); // clear previous lmic status
if (LMIC.dataLen) { // did we receive payload data -> display info
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",
LMIC.dataLen, LMIC.rssi, LMIC.snr / 4);
sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi, LMIC.snr / 4);
if (LMIC.txrxFlags & TXRX_PORT) { // FPort -> use to switch
switch (LMIC.frame[LMIC.dataBeg - 1]) {
case RCMDPORT: // opcode -> call rcommand interpreter
rcommand(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
break;
default:
#if (TIME_SYNC_LORASERVER)
// timesync answer -> call timesync processor
if ((LMIC.frame[LMIC.dataBeg - 1] >= TIMEANSWERPORT_MIN) &&
(LMIC.frame[LMIC.dataBeg - 1] <= TIMEANSWERPORT_MAX)) {
recv_timesync_ans(LMIC.frame[LMIC.dataBeg - 1],
LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
break;
}
#endif
// unknown port -> display info
ESP_LOGI(TAG, "Received data on unsupported port #%d",
LMIC.frame[LMIC.dataBeg - 1]);
break;
}
}
}
break; break;
case EV_LOST_TSYNC: case EV_LOST_TSYNC:
@ -402,14 +370,15 @@ void lora_send(void *pvParameters) {
// attempt to transmit payload // attempt to transmit payload
else { else {
switch (LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, switch (LMIC_sendWithCallback(
SendBuffer.MessageSize, SendBuffer.MessagePort, SendBuffer.Message, SendBuffer.MessageSize,
(cfg.countermode & 0x02))) { (cfg.countermode & 0x02), myTxCallback, NULL)) {
case 0: case 0:
ESP_LOGI(TAG, "%d byte(s) delivered to LMIC", SendBuffer.MessageSize); ESP_LOGI(TAG, "%d byte(s) sent to LORA", SendBuffer.MessageSize);
break; break;
case -1: // LMIC already has a tx message pending case -1: // LMIC already has a tx message pending
ESP_LOGD(TAG, "LMIC busy, message re-enqueued"); // ESP_LOGD(TAG, "LMIC busy, message re-enqueued");
vTaskDelay(pdMS_TO_TICKS(1000 + random(500))); // wait a while vTaskDelay(pdMS_TO_TICKS(1000 + random(500))); // wait a while
lora_enqueuedata(&SendBuffer); // re-enqueue the undeliverd message lora_enqueuedata(&SendBuffer); // re-enqueue the undeliverd message
break; break;
@ -554,6 +523,9 @@ void lmictask(void *pvParameters) {
// rate for 125 kHz channels, and it minimizes air time and battery power. // rate for 125 kHz channels, and it minimizes air time and battery power.
// Set the transmission power to 14 dBi (25 mW). // Set the transmission power to 14 dBi (25 mW).
LMIC_setDrTxpow(DR_SF7, 14); LMIC_setDrTxpow(DR_SF7, 14);
// register a callback for downlink messages. We aren't trying to write
// reentrant code, so pUserData is NULL.
LMIC_registerRxMessageCb(myRxCallback, NULL);
#if defined(CFG_US915) || defined(CFG_au921) #if defined(CFG_US915) || defined(CFG_au921)
// in the US, with TTN, it saves join time if we start on subband 1 // in the US, with TTN, it saves join time if we start on subband 1
@ -569,4 +541,118 @@ void lmictask(void *pvParameters) {
} }
} // lmictask } // lmictask
#endif // HAS_LORA // receive message handler
void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
size_t nMsg) {
// tell the compiler that pUserData is required by the API, but we don't
// happen to use it.
LMIC_API_PARAMETER(pUserData);
// display type of received data
if (nMsg)
ESP_LOGI(TAG, "Received %u bytes of payload on port %u", nMsg, port);
else if (port)
ESP_LOGI(TAG, "Received empty message on port %u", port);
// list MAC messages, if any
uint8_t nMac = pMsg - &LMIC.frame[0];
if (port != MACPORT)
--nMac;
if (nMac) {
ESP_LOGI(TAG, "Received %u MAC messages:", nMac);
// NOT WORKING YET
// whe need to strip some protocol overhead from LMIC.frame to unwrap the
// MAC command
mac_decode(LMIC.frame, nMac);
}
switch (port) {
// ignore mac messages
case MACPORT:
break;
// rcommand received -> call interpreter
case RCMDPORT:
rcommand(pMsg, nMsg);
break;
default:
#if (TIME_SYNC_LORASERVER)
// valid timesync answer -> call timesync processor
if ((port >= TIMEANSWERPORT_MIN) && (port <= TIMEANSWERPORT_MAX))
recv_timesync_ans(port, pMsg, nMsg);
break;
#endif
// unknown port -> display info
ESP_LOGI(TAG, "Received data on unsupported port %u", port);
break;
} // switch
}
// transmit complete message handler
void myTxCallback(void *pUserData, int fSuccess) {
/* currently no code here */
// tell the compiler that pUserData is required by the API, but we don't
// happen to use it.
LMIC_API_PARAMETER(pUserData);
}
// LORAWAN MAC interpreter
// table of LORAWAN MAC messages sent by the network to the device
// format: opcode, cmdname (max 19 chars), #bytes params
// source: LoRaWAN 1.1 Specification (October 11, 2017)
static mac_t table[] = {
{0x01, "ResetConf", 1}, {0x02, "LinkCheckAns", 2},
{0x03, "LinkADRReq", 4}, {0x04, "DutyCycleReq", 1},
{0x05, "RXParamSetupReq", 4}, {0x06, "DevStatusReq", 0},
{0x07, "NewChannelReq", 5}, {0x08, "RxTimingSetupReq", 1},
{0x09, "TxParamSetupReq", 1}, {0x0A, "DlChannelReq", 4},
{0x0B, "RekeyConf", 1}, {0x0C, "ADRParamSetupReq", 1},
{0x0D, "DeviceTimeAns", 5}, {0x0E, "ForceRejoinReq", 2},
{0x0F, "RejoinParamSetupReq", 1}};
static const uint8_t cmdtablesize =
sizeof(table) / sizeof(table[0]); // number of commands in command table
// decode mac message
void mac_decode(const uint8_t cmd[], const uint8_t cmdlength) {
if (!cmdlength)
return;
uint8_t foundcmd[cmdlength], cursor = 0;
while (cursor < cmdlength) {
int i = cmdtablesize;
while (i--) {
if (cmd[cursor] == table[i].opcode) { // lookup command in opcode table
cursor++; // strip 1 byte opcode
if ((cursor + table[i].params) <= cmdlength) {
memmove(foundcmd, cmd + cursor,
table[i].params); // strip opcode from cmd array
cursor += table[i].params;
ESP_LOGI(TAG, "Network command %s", table[i].cmdname);
} else
ESP_LOGI(TAG, "MAC message 0x%02X with missing parameter(s)",
table[i].opcode);
break; // command found -> exit table lookup loop
} // end of command validation
} // end of command table lookup loop
if (i < 0) { // command not found -> skip it
ESP_LOGI(TAG, "Unknown MAC message 0x%02X", cmd[cursor]);
cursor++;
}
} // command parsing loop
} // mac_decode()
#endif // HAS_LORA

View File

@ -85,6 +85,7 @@
// Ports on which the device sends and listenes on LoRaWAN and SPI // Ports on which the device sends and listenes on LoRaWAN and SPI
#define COUNTERPORT 1 // counts #define COUNTERPORT 1 // counts
#define MACPORT 0 // network commands
#define RCMDPORT 2 // remote commands #define RCMDPORT 2 // remote commands
#define STATUSPORT 2 // remote command results #define STATUSPORT 2 // remote command results
#define CONFIGPORT 3 // config query results #define CONFIGPORT 3 // config query results

View File

@ -127,7 +127,7 @@ void set_gps(uint8_t val[]) {
if (val[0]) { if (val[0]) {
cfg.payloadmask |= (uint8_t)GPS_DATA; // set bit in mask cfg.payloadmask |= (uint8_t)GPS_DATA; // set bit in mask
} else { } else {
cfg.payloadmask &= ~(uint8_t)GPS_DATA; // clear bit in mask cfg.payloadmask &= (uint8_t)~GPS_DATA; // clear bit in mask
} }
} }
@ -136,7 +136,7 @@ void set_bme(uint8_t val[]) {
if (val[0]) { if (val[0]) {
cfg.payloadmask |= (uint8_t)MEMS_DATA; // set bit in mask cfg.payloadmask |= (uint8_t)MEMS_DATA; // set bit in mask
} else { } else {
cfg.payloadmask &= ~(uint8_t)MEMS_DATA; // clear bit in mask cfg.payloadmask &= (uint8_t)~MEMS_DATA; // clear bit in mask
} }
} }
@ -146,7 +146,7 @@ void set_batt(uint8_t val[]) {
if (val[0]) { if (val[0]) {
cfg.payloadmask |= (uint8_t)BATT_DATA; // set bit in mask cfg.payloadmask |= (uint8_t)BATT_DATA; // set bit in mask
} else { } else {
cfg.payloadmask &= ~(uint8_t)BATT_DATA; // clear bit in mask cfg.payloadmask &= (uint8_t)~BATT_DATA; // clear bit in mask
} }
} }
@ -332,7 +332,7 @@ void set_flush(uint8_t val[]) {
// format: opcode, function, #bytes params, // format: opcode, function, #bytes params,
// flag (true = do make settings persistent / false = don't) // flag (true = do make settings persistent / false = don't)
// //
cmd_t table[] = { static cmd_t table[] = {
{0x01, set_rssi, 1, true}, {0x02, set_countmode, 1, true}, {0x01, set_rssi, 1, true}, {0x02, set_countmode, 1, true},
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true}, {0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
{0x05, set_lorasf, 1, true}, {0x06, set_lorapower, 1, true}, {0x05, set_lorasf, 1, true}, {0x06, set_lorapower, 1, true},
@ -349,11 +349,11 @@ cmd_t table[] = {
{0x85, get_bme, 0, false}, {0x86, get_time, 0, false}, {0x85, get_bme, 0, false}, {0x86, get_time, 0, false},
{0x87, set_time, 0, false}, {0x99, set_flush, 0, false}}; {0x87, set_time, 0, false}, {0x99, set_flush, 0, false}};
const uint8_t cmdtablesize = static const uint8_t cmdtablesize =
sizeof(table) / sizeof(table[0]); // number of commands in command table sizeof(table) / sizeof(table[0]); // number of commands in command table
// check and execute remote command // check and execute remote command
void rcommand(uint8_t cmd[], uint8_t cmdlength) { void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
if (cmdlength == 0) if (cmdlength == 0)
return; return;

View File

@ -154,7 +154,7 @@ void store_time_sync_req(uint32_t timestamp) {
} }
// process timeserver timestamp answer, called from lorawan.cpp // process timeserver timestamp answer, called from lorawan.cpp
int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) { int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t buf_len) {
// if no timesync handshake is pending then exit // if no timesync handshake is pending then exit
if (!timeSyncPending) if (!timeSyncPending)