diff --git a/.cproject b/.cproject
index 62eba26..ade7cf0 100644
--- a/.cproject
+++ b/.cproject
@@ -133,7 +133,7 @@
-
+
@@ -277,7 +277,7 @@
-
+
diff --git a/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp b/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp
new file mode 100644
index 0000000..854854c
--- /dev/null
+++ b/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp
@@ -0,0 +1,559 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Tomoaki Yamaguchi - initial API and implementation
+ **************************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+#define LORA_PHY_MAXPAYLOAD 256
+#define LORALINK_MAX_API_LEN ( LORA_PHY_MAXPAYLOAD + 5 ) // PayloadType[1] + Rssi[2] + Snr[2]
+
+#define LORALINK_ACK 0x10
+#define LORALINK_NO_FREE_CH 0x20
+#define LORALINK_TX_TIMEOUT 0x40
+
+#define LORALINK_TIMEOUT_ACK 10000 // 10 secs
+
+/*===========================================
+ Class SensorNetAddreess
+ ============================================*/
+SensorNetAddress::SensorNetAddress()
+{
+ _devAddr = 0;
+}
+
+SensorNetAddress::~SensorNetAddress()
+{
+
+}
+
+void SensorNetAddress::setAddress( uint8_t devAddr)
+{
+ _devAddr = devAddr;
+}
+
+
+int SensorNetAddress::setAddress(string* address)
+{
+ _devAddr = atoi(address->c_str());
+
+ if ( _devAddr == 0 )
+ {
+ return -1;
+ }
+ return 0;
+}
+
+void SensorNetAddress::setBroadcastAddress(void)
+{
+ _devAddr = BROADCAST_DEVADDR;
+}
+
+bool SensorNetAddress::isMatch(SensorNetAddress* addr)
+{
+ return _devAddr == addr->_devAddr;
+}
+
+SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
+{
+ _devAddr = addr._devAddr;
+ return *this;
+}
+
+char* SensorNetAddress::sprint(char* buf)
+{
+ sprintf( buf, "%d", _devAddr);
+ return buf;
+}
+
+/*===========================================
+ Class SensorNetwork
+ ============================================*/
+SensorNetwork::SensorNetwork()
+{
+
+}
+
+SensorNetwork::~SensorNetwork()
+{
+
+}
+
+int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
+{
+ return LoRaLink::unicast(payload, payloadLength, sendToAddr);
+}
+
+int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
+{
+ return LoRaLink::broadcast(payload, payloadLength);
+}
+
+int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
+{
+ return LoRaLink::recv(buf, bufLen, &_clientAddr);
+}
+
+int SensorNetwork::initialize(void)
+{
+ char param[MQTTSNGW_PARAM_MAX];
+ uint32_t baudrate = 115200;
+
+ if (theProcess->getParam("BaudrateLoRaLink", param) == 0)
+ {
+ baudrate = (uint32_t)atoi(param);
+ }
+ _description += "LoRaLink, Baudrate ";
+ sprintf(param ,"%d", baudrate);
+ _description += param;
+
+ theProcess->getParam("DeviceRxLoRaLink", param);
+ _description += ", SerialRx ";
+ _description += param;
+ if ( LoRaLink::open(LORALINK_MODEM_RX, param, baudrate) < 0 )
+ {
+ return -1;
+ }
+
+ theProcess->getParam("DeviceTxLoRaLink", param);
+ _description += ", SerialTx ";
+ _description += param;
+ return LoRaLink::open(LORALINK_MODEM_TX, param, baudrate);
+}
+
+const char* SensorNetwork::getDescription(void)
+{
+ return _description.c_str();
+}
+
+SensorNetAddress* SensorNetwork::getSenderAddress(void)
+{
+ return &_clientAddr;
+}
+
+/*===========================================
+ Class LoRaLink
+ ============================================*/
+LoRaLink::LoRaLink(){
+ _serialPortRx = new SerialPort();
+ _serialPortTx = new SerialPort();
+ _respCd = 0;
+}
+
+LoRaLink::~LoRaLink(){
+ if ( _serialPortRx )
+ {
+ delete _serialPortRx;
+ }
+ if ( _serialPortTx )
+ {
+ delete _serialPortTx;
+ }
+}
+
+int LoRaLink::open(LoRaLinkModemType_t type, char* device, int baudrate)
+{
+ int rate = B9600;
+
+ switch (baudrate)
+ {
+ case 9600:
+ rate = B9600;
+ break;
+ case 19200:
+ rate = B19200;
+ break;
+ case 38400:
+ rate = B38400;
+ break;
+ case 57600:
+ rate = B57600;
+ break;
+ case 115200:
+ rate = B115200;
+ break;
+ default:
+ return -1;
+ }
+
+ int rc = 0;
+ if ( type == LORALINK_MODEM_RX )
+ {
+ if ( (rc = _serialPortRx->open(device, rate, false, 1, O_RDWR | O_NOCTTY)) < 0 )
+ return rc;
+ }
+ else
+ {
+ rc = _serialPortTx->open(device, rate, false, 1, O_RDWR | O_NOCTTY);
+ }
+ return rc;
+}
+
+int LoRaLink::broadcast(const uint8_t* payload, uint16_t payloadLen){
+ SensorNetAddress addr;
+ addr.setBroadcastAddress();
+ return send(MQTT_SN, payload, (uint8_t) payloadLen, &addr);
+}
+
+int LoRaLink:: unicast(const uint8_t* payload, uint16_t payloadLen, SensorNetAddress* addr){
+ return send(MQTT_SN, payload, (uint8_t) payloadLen, addr);
+}
+
+int LoRaLink::recv(uint8_t* buf, uint16_t bufLen, SensorNetAddress* clientAddr)
+{
+ while ( true )
+ {
+ if ( ( readApiFrame( &_loRaLinkApi, &_loRaLinkPara) == true ) && (_loRaLinkPara.Available == true) && ( _loRaLinkPara.Error == false ) )
+ {
+ clientAddr->_devAddr = _loRaLinkApi.SourceAddr;
+
+ bufLen = _loRaLinkApi.PayloadLen;
+
+ memcpy( buf, _loRaLinkApi.Payload, bufLen );
+
+ switch ( (int) _loRaLinkApi.PayloadType )
+ {
+ case API_RSP_ACK:
+ _respCd = LORALINK_ACK;
+ break;
+
+ case API_RSP_NFC:
+ _respCd = LORALINK_NO_FREE_CH;
+ break;
+
+ case API_RSP_TOT:
+ _respCd = LORALINK_TX_TIMEOUT;
+ break;
+
+
+ case MQTT_SN:
+ memcpy( buf, _loRaLinkApi.Payload, bufLen );
+ return bufLen;
+
+ default:
+ return 0;
+ }
+ _sem.post();
+ return bufLen;
+
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
+
+
+
+bool LoRaLink::readApiFrame(LoRaLinkFrame_t* api, LoRaLinkReadParameters_t* para)
+{
+ uint8_t byte = 0;
+ uint16_t val = 0;
+
+ while ( recv(&byte) == 0 )
+ {
+ if ( byte == START_BYTE )
+ {
+ para->apipos= 1;
+ para->Error = true;
+ para->Available = false;
+ continue;
+ }
+
+ if ( para->apipos > 0 && byte == ESCAPE )
+ {
+ if( recv(&byte ) == 0 )
+ {
+ byte ^= PAD; // decode
+ }
+ else
+ {
+ para->Escape = true;
+ continue;
+ }
+ }
+
+ if( para->Escape == true )
+ {
+ byte ^= PAD;
+ para->Escape = false;
+ }
+
+ switch ( para->apipos )
+ {
+ case 0:
+ break;
+
+ case 1:
+ val = (uint16_t)byte;
+ api->PayloadLen = val << 8;
+ break;
+
+ case 2:
+ api->PayloadLen += byte;
+ break;
+
+ case 3:
+ api->SourceAddr = byte;
+ para->checksum = byte;
+ break;
+
+ case 4:
+ val = (uint16_t)byte;
+ api->Rssi = val << 8;
+ para->checksum += byte;
+ break;
+
+ case 5:
+ api->Rssi += byte;
+ para->checksum += byte;
+ break;
+
+ case 6:
+ val = (uint16_t)byte;
+ api->Snr = val << 8;
+ para->checksum += byte;
+ break;
+
+ case 7:
+ api->Snr += byte;
+ para->checksum += byte;
+ break;
+
+ case 8:
+ api->PayloadType = byte;
+ para->checksum += byte;
+ break;
+
+ default:
+ if ( para->apipos >= api->PayloadLen + 2 ) // FRM_DEL + CRC = 2
+ {
+ para->Error = ( (0xff - para->checksum) != byte );
+ para->Available = true;
+ api->PayloadLen -= 7; // 7 = SrcAddr[1] + Rssi[2] + Snr[2] + PlType[1] + Crc[1]
+ para->apipos = 0;
+ para->checksum = 0;
+ return true;
+ }
+ else
+ {
+ para->checksum += byte;
+ api->Payload[para->apipos - 9] = byte;
+ }
+ break;
+ }
+
+ para->apipos++;
+ }
+ return false;
+}
+
+int LoRaLink::send(LoRaLinkPayloadType_t type, const uint8_t* payload, uint16_t pLen, SensorNetAddress* addr)
+{
+ D_NWSTACK("\r\n===> Send: ");
+ uint8_t buf[2] = { 0 };
+ uint8_t chks = 0;
+ uint16_t len = pLen + 3; // 3 = DestAddr[1] + PayloadType[1] + Crc[1]
+ _respCd = 0;
+
+ _serialPortTx->send(START_BYTE);
+
+ buf[0] = (len >> 8) & 0xff;
+ buf[1] = len & 0xff;
+ send(buf[0]);
+ send(buf[1]);
+
+ send( addr->_devAddr );
+ chks = addr->_devAddr;
+
+
+
+ send(type);
+ chks += type;
+
+ D_NWSTACK("\r\n Payload: ");
+
+ for ( uint8_t i = 0; i < pLen; i++ ){
+ send(payload[i]); // Payload
+ chks += payload[i];
+ }
+
+ chks = 0xff - chks;
+ D_NWSTACK(" checksum ");
+ send(chks);
+ D_NWSTACK("\r\n");
+
+ /* wait ACK */
+ _sem.timedwait(LORALINK_TIMEOUT_ACK);
+
+ if ( _respCd == LORALINK_NO_FREE_CH )
+ {
+ D_NWSTACK(" Channel isn't free\r\n");
+ return -1;
+ }
+ else if ( _respCd != LORALINK_ACK )
+ {
+ D_NWSTACK(" Not Acknowleged\r\n");
+ return -1;
+ }
+ return (int)pLen;
+}
+
+void LoRaLink::send(uint8_t c)
+{
+ if( (c == START_BYTE || c == ESCAPE || c == XON || c == XOFF)){
+ _serialPortTx->send(ESCAPE);
+ _serialPortTx->send(c ^ PAD);
+ }else{
+ _serialPortTx->send(c);
+ }
+}
+
+int LoRaLink::recv(uint8_t* buf)
+{
+ struct timeval timeout;
+ int maxfd;
+ int fd;
+ fd_set rfds;
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0; // 500ms
+ FD_ZERO(&rfds);
+ FD_SET(_serialPortRx->_fd, &rfds);
+ FD_SET(_serialPortTx->_fd, &rfds);
+ if ( _serialPortRx->_fd > _serialPortTx->_fd )
+ {
+ maxfd = _serialPortRx->_fd;
+ }
+ else
+ {
+ maxfd = _serialPortTx->_fd;
+ }
+
+ if ( select(maxfd + 1, &rfds, 0, 0, &timeout) > 0 )
+ {
+ if ( FD_ISSET(_serialPortRx->_fd, &rfds) )
+ {
+ fd = _serialPortRx->_fd;
+ }
+ else
+ {
+ fd = _serialPortTx->_fd;
+ }
+
+ if ( read(fd, buf, 1) == 1 )
+ {
+ /*
+ if ( *buf == ESCAPE )
+ {
+ D_NWSTACK( " %02x",buf[0] );
+ if ( read(fd, buf, 1) == 1 )
+ {
+ *buf = PAD ^ *buf;
+ }
+ else
+ {
+ return -1;
+ }
+
+ }
+ */
+ D_NWSTACK( " %02x",buf[0] );
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/*=========================================
+ Class SerialPort
+ =========================================*/
+SerialPort::SerialPort()
+{
+ _tio.c_iflag = IGNBRK | IGNPAR;
+ _tio.c_cflag = CS8 | CLOCAL | CREAD;
+ _tio.c_cc[VINTR] = 0;
+ _tio.c_cc[VTIME] = 10; // 1 sec.
+ _tio.c_cc[VMIN] = 1;
+ _fd = 0;
+}
+
+SerialPort::~SerialPort()
+{
+ if (_fd)
+ {
+ ::close(_fd);
+ }
+}
+
+int SerialPort::open(char* devName, unsigned int baudrate, bool parity,
+ unsigned int stopbit, unsigned int flg)
+{
+ _fd = ::open(devName, flg);
+ if (_fd < 0)
+ {
+ return _fd;
+ }
+
+ if (parity)
+ {
+ _tio.c_cflag = _tio.c_cflag | PARENB;
+ }
+ if (stopbit == 2)
+ {
+ _tio.c_cflag = _tio.c_cflag | CSTOPB;
+ }
+
+ if (cfsetspeed(&_tio, baudrate) < 0)
+ {
+ return errno;
+ }
+ return tcsetattr(_fd, TCSANOW, &_tio);
+}
+
+bool SerialPort::send(unsigned char b)
+{
+ if (write(_fd, &b, 1) <= 0)
+ {
+ return false;
+ }
+ else
+ {
+ D_NWSTACK( " %02x", b);
+ return true;
+ }
+}
+
+
+
+void SerialPort::flush(void)
+{
+ tcsetattr(_fd, TCSAFLUSH, &_tio);
+}
+
diff --git a/MQTTSNGateway/src/linux/loralink/SensorNetwork.h b/MQTTSNGateway/src/linux/loralink/SensorNetwork.h
new file mode 100644
index 0000000..0565ff1
--- /dev/null
+++ b/MQTTSNGateway/src/linux/loralink/SensorNetwork.h
@@ -0,0 +1,187 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Tomoaki Yamaguchi - initial API and implementation
+ **************************************************************************************/
+#ifndef SENSORNETWORKX_H_
+#define SENSORNETWORKX_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWProcess.h"
+#include
+#include
+
+using namespace std;
+
+namespace MQTTSNGW
+{
+//#define DEBUG_NWSTACK
+
+#ifdef DEBUG_NWSTACK
+ #define D_NWSTACK(...) printf(__VA_ARGS__); fflush(stdout)
+#else
+ #define D_NWSTACK(...)
+#endif
+
+
+#define XMIT_STATUS_TIME_OVER 5000
+
+#define START_BYTE 0x7e
+#define ESCAPE 0x7d
+#define XON 0x11
+#define XOFF 0x13
+#define PAD 0x20
+
+#define BROADCAST_DEVADDR 0xFF
+
+#define LORA_PHY_MAXPAYLOAD 256
+
+/*!
+ * LoRaLink Modem Type
+ */
+typedef enum
+{
+ LORALINK_MODEM_TX,
+ LORALINK_MODEM_RX,
+}LoRaLinkModemType_t;
+
+/*!
+ * LoRaLink Serialized API
+ */
+typedef struct
+{
+ uint16_t PanId;
+ uint8_t DestinationAddr;
+ uint8_t SourceAddr;
+ uint16_t Rssi;
+ uint16_t Snr;
+ uint8_t PayloadType;
+ uint8_t Payload[LORA_PHY_MAXPAYLOAD];
+ uint16_t PayloadLen;
+}LoRaLinkFrame_t;
+
+typedef struct
+{
+ bool Available;
+ bool Error;
+ bool Escape;
+ uint16_t apipos;
+ uint8_t checksum;
+} LoRaLinkReadParameters_t;
+
+typedef enum
+{
+ MQTT_SN = 0x40,
+ API_RSP_ACK = 0x80,
+ API_RSP_NFC,
+ API_RSP_TOT,
+ API_REQ_UTC,
+ API_RSP_UTC,
+ API_CHG_TASK_PARAM,
+ API_REQ_RESET,
+
+}LoRaLinkPayloadType_t;
+
+/*===========================================
+ Class SerialPort
+ ============================================*/
+class SerialPort
+{
+ friend class LoRaLink;
+public:
+ SerialPort();
+ ~SerialPort();
+ int open(char* devName, unsigned int baudrate, bool parity, unsigned int stopbit, unsigned int flg);
+ bool send(unsigned char b);
+ void flush();
+
+private:
+ int _fd; // file descriptor
+ struct termios _tio;
+};
+
+/*===========================================
+ Class SensorNetAddreess
+ ============================================*/
+class SensorNetAddress
+{
+ friend class LoRaLink;
+public:
+ SensorNetAddress();
+ ~SensorNetAddress();
+ void setAddress( uint8_t devAddr);
+ int setAddress(string* data);
+ void setBroadcastAddress(void);
+ bool isMatch(SensorNetAddress* addr);
+ SensorNetAddress& operator =(SensorNetAddress& addr);
+ char* sprint(char*);
+private:
+ uint8_t _devAddr;
+// uint8_t _destAddr;
+};
+
+/*========================================
+ Class LoRaLink
+ =======================================*/
+class LoRaLink
+{
+public:
+ LoRaLink();
+ ~LoRaLink();
+
+ int open(LoRaLinkModemType_t type, char* device, int boudrate );
+ void close(void);
+ int unicast(const uint8_t* buf, uint16_t length, SensorNetAddress* sendToAddr);
+ int broadcast(const uint8_t* buf, uint16_t length);
+ int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
+ void setApiMode(uint8_t mode);
+
+private:
+ bool readApiFrame(LoRaLinkFrame_t* api, LoRaLinkReadParameters_t* para);
+ int recv(uint8_t* buf);
+ int send(LoRaLinkPayloadType_t type, const uint8_t* payload, uint16_t pLen, SensorNetAddress* addr);
+ void send(uint8_t b);
+
+ Semaphore _sem;
+ Mutex _meutex;
+ uint8_t _respCd;
+ SerialPort* _serialPortRx;
+ SerialPort* _serialPortTx;
+ LoRaLinkFrame_t _loRaLinkApi;
+ LoRaLinkReadParameters_t _loRaLinkPara;
+};
+
+/*===========================================
+ Class SensorNetwork
+ ============================================*/
+class SensorNetwork: public LoRaLink
+{
+public:
+ SensorNetwork();
+ ~SensorNetwork();
+
+ int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto);
+ int broadcast(const uint8_t* payload, uint16_t payloadLength);
+ int read(uint8_t* buf, uint16_t bufLen);
+ int initialize(void);
+ const char* getDescription(void);
+ SensorNetAddress* getSenderAddress(void);
+
+private:
+ SensorNetAddress _clientAddr; // Sender's address. not gateway's one.
+ string _description;
+};
+
+}
+
+#endif /* SENSORNETWORKX_H_ */