mirror of
https://github.com/eclipse/paho.mqtt-sn.embedded-c.git
synced 2025-12-14 07:56:52 +01:00
First Commit of MQTT-SN Gateway
Add new SensorNetwork XBee Add a sensor network type in a start message. Update MQTTSNClient to avoid build warning. Update WiringPi's functions to my original ones. BugFix check msgId before adding waitdTopicId table. BugFix Process termination procedures Update print curent time in millseconds. update move currentDateTime() to linux directory. Bugfix: blink blue lightiIndicator. Bugfix: Register returns wrong id. change a status of the client to Disconnected. change client status procedure Update README BugFix: change Network Disconnect procedures. Signed-off-by: tomoaki <tomoaki@tomy-tech.com>
This commit is contained in:
563
MQTTSNGateway/src/linux/Network.cpp
Normal file
563
MQTTSNGateway/src/linux/Network.cpp
Normal file
@@ -0,0 +1,563 @@
|
||||
/**************************************************************************************
|
||||
* 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 and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <error.h>
|
||||
|
||||
#include "Network.h"
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
#define SOCKET_MAXCONNECTIONS 5
|
||||
char* currentDateTime();
|
||||
|
||||
/*========================================
|
||||
Class TCPStack
|
||||
=======================================*/
|
||||
TCPStack::TCPStack()
|
||||
{
|
||||
_addrinfo = 0;
|
||||
_sockfd = 0;
|
||||
}
|
||||
|
||||
TCPStack::~TCPStack()
|
||||
{
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
}
|
||||
}
|
||||
|
||||
bool TCPStack::isValid()
|
||||
{
|
||||
return (_sockfd > 0);
|
||||
}
|
||||
|
||||
void TCPStack::close()
|
||||
{
|
||||
if (_sockfd > 0)
|
||||
{
|
||||
::close(_sockfd);
|
||||
_sockfd = 0;
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
_addrinfo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool TCPStack::bind(const char* service)
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
}
|
||||
int err = getaddrinfo(0, service, &hints, &_addrinfo);
|
||||
if (err)
|
||||
{
|
||||
WRITELOG("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),
|
||||
gai_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
_sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol);
|
||||
if (_sockfd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int on = 1;
|
||||
if (setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on)) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::bind(_sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPStack::listen()
|
||||
{
|
||||
if (!isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int listen_return = ::listen(_sockfd, SOCKET_MAXCONNECTIONS);
|
||||
if (listen_return == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPStack::accept(TCPStack& new_socket)
|
||||
{
|
||||
sockaddr_storage sa;
|
||||
socklen_t len = sizeof(sa);
|
||||
new_socket._sockfd = ::accept(_sockfd, (struct sockaddr*) &sa, &len);
|
||||
if (new_socket._sockfd <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int TCPStack::send(const uint8_t* buf, int length)
|
||||
{
|
||||
return ::send(_sockfd, buf, length, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
int TCPStack::recv(uint8_t* buf, int len)
|
||||
{
|
||||
return ::recv(_sockfd, buf, len, 0);
|
||||
}
|
||||
|
||||
bool TCPStack::connect(const char* host, const char* service)
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
}
|
||||
|
||||
int err = getaddrinfo(host, service, &hints, &_addrinfo);
|
||||
if (err)
|
||||
{
|
||||
WRITELOG("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),
|
||||
gai_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
int sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol);
|
||||
|
||||
if (sockfd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int on = 1;
|
||||
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on)) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::connect(sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen) < 0)
|
||||
{
|
||||
//perror("TCPStack connect");
|
||||
::close(sockfd);
|
||||
return false;
|
||||
}
|
||||
|
||||
_sockfd = sockfd;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPStack::setNonBlocking(const bool b)
|
||||
{
|
||||
int opts;
|
||||
|
||||
opts = fcntl(_sockfd, F_GETFL);
|
||||
|
||||
if (opts < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (b)
|
||||
{
|
||||
opts = (opts | O_NONBLOCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
opts = (opts & ~O_NONBLOCK);
|
||||
}
|
||||
fcntl(_sockfd, F_SETFL, opts);
|
||||
}
|
||||
|
||||
int TCPStack::getSock()
|
||||
{
|
||||
return _sockfd;
|
||||
}
|
||||
|
||||
/*========================================
|
||||
Class Network
|
||||
=======================================*/
|
||||
int Network::_numOfInstance = 0;
|
||||
SSL_CTX* Network::_ctx = 0;
|
||||
SSL_SESSION* Network::_session = 0;
|
||||
|
||||
Network::Network(bool secure) :
|
||||
TCPStack()
|
||||
{
|
||||
char error[256];
|
||||
if (secure)
|
||||
{
|
||||
_numOfInstance++;
|
||||
if (_ctx == 0)
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
_ctx = SSL_CTX_new(TLSv1_2_client_method());
|
||||
if (_ctx == 0)
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
|
||||
WRITELOG("SSL_CTX_new() %s\n", error);
|
||||
throw Exception( ERR_get_error(), "Network can't create SSL context.");
|
||||
}
|
||||
if (!SSL_CTX_load_verify_locations(_ctx, 0, MQTTSNGW_TLS_CA_DIR))
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
|
||||
WRITELOG("SSL_CTX_load_verify_locations() %s\n", error);
|
||||
throw Exception( ERR_get_error(), "Network can't load CA_LIST.");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ssl = 0;
|
||||
_disconReq = false;
|
||||
_secureFlg = secure;
|
||||
_busy = false;
|
||||
}
|
||||
|
||||
Network::~Network()
|
||||
{
|
||||
if (_secureFlg)
|
||||
{
|
||||
_numOfInstance--;
|
||||
}
|
||||
if (_ssl)
|
||||
{
|
||||
SSL_free(_ssl);
|
||||
}
|
||||
if (_session && _numOfInstance == 0)
|
||||
{
|
||||
SSL_SESSION_free(_session);
|
||||
_session = 0;
|
||||
}
|
||||
if (_ctx && _numOfInstance == 0)
|
||||
{
|
||||
SSL_CTX_free(_ctx);
|
||||
_ctx = 0;
|
||||
ERR_free_strings();
|
||||
}
|
||||
}
|
||||
|
||||
bool Network::connect(const char* host, const char* service)
|
||||
{
|
||||
char errmsg[256];
|
||||
int rc = 0;
|
||||
char peer_CN[256];
|
||||
SSL_SESSION* sess = 0;
|
||||
X509* peer;
|
||||
|
||||
if (isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!TCPStack::connect(host, service))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!_secureFlg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SSL* ssl = SSL_new(_ctx);
|
||||
if (ssl == 0)
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("SSL_new() %s\n", errmsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = SSL_set_fd(ssl, TCPStack::getSock());
|
||||
if (rc == 0)
|
||||
{
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_session)
|
||||
{
|
||||
rc = SSL_set_session(ssl, sess);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = SSL_connect(ssl);
|
||||
}
|
||||
if (rc != 1)
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("SSL_connect() %s\n", errmsg);
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SSL_get_verify_result(ssl) != X509_V_OK)
|
||||
{
|
||||
WRITELOG("SSL_get_verify_result() error: Certificate doesn't verify.\n");
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
|
||||
peer = SSL_get_peer_certificate(ssl);
|
||||
X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 256);
|
||||
if (strcasecmp(peer_CN, host))
|
||||
{
|
||||
WRITELOG("SSL_get_peer_certificate() error: Broker dosen't much host name.\n");
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
if (_session == 0)
|
||||
{
|
||||
_session = sess;
|
||||
}
|
||||
_ssl = ssl;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Network::send(const uint8_t* buf, uint16_t length)
|
||||
{
|
||||
char errmsg[256];
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
bool writeBlockedOnRead = false;
|
||||
int bpos = 0;
|
||||
|
||||
if (_secureFlg)
|
||||
{
|
||||
_mutex.lock();
|
||||
_busy = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(getSock(), &rset);
|
||||
FD_SET(getSock(), &wset);
|
||||
|
||||
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
|
||||
if (activity > 0)
|
||||
{
|
||||
if (FD_ISSET(getSock(), &wset) || (writeBlockedOnRead && FD_ISSET(getSock(), &rset)))
|
||||
{
|
||||
|
||||
writeBlockedOnRead = false;
|
||||
int r = SSL_write(_ssl, buf + bpos, length);
|
||||
|
||||
switch (SSL_get_error(_ssl, r))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
length -= r;
|
||||
bpos += r;
|
||||
if (length == 0)
|
||||
{
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return bpos;
|
||||
}
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
writeBlockedOnRead = true;
|
||||
break;
|
||||
default:
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("TLSStack::send() default %s\n", errmsg);
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return TCPStack::send(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
int Network::recv(uint8_t* buf, uint16_t len)
|
||||
{
|
||||
char errmsg[256];
|
||||
bool writeBlockedOnRead = false;
|
||||
bool readBlockedOnWrite = false;
|
||||
bool readBlocked = false;
|
||||
int rlen = 0;
|
||||
int bpos = 0;
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
|
||||
if (_secureFlg)
|
||||
{
|
||||
if (_busy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_mutex.lock();
|
||||
_busy = true;
|
||||
|
||||
loop: do
|
||||
{
|
||||
readBlockedOnWrite = false;
|
||||
readBlocked = false;
|
||||
|
||||
rlen = SSL_read(_ssl, buf + bpos, len - bpos);
|
||||
|
||||
switch (SSL_get_error(_ssl, rlen))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return rlen + bpos;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
SSL_shutdown(_ssl);
|
||||
_ssl = 0;
|
||||
TCPStack::close();
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
readBlocked = true;
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
readBlockedOnWrite = true;
|
||||
break;
|
||||
default:
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("TLSStack::recv() default %s\n", errmsg);
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
} while (SSL_pending(_ssl) && !readBlocked);
|
||||
|
||||
bpos += rlen;
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(getSock(), &rset);
|
||||
FD_SET(getSock(), &wset);
|
||||
|
||||
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
|
||||
if (activity > 0)
|
||||
{
|
||||
if ((FD_ISSET(getSock(),&rset) && !writeBlockedOnRead)
|
||||
|| (readBlockedOnWrite && FD_ISSET(getSock(), &wset)))
|
||||
{
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("TLSStack::recv() select %s\n", errmsg);
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TCPStack::recv(buf, len);
|
||||
}
|
||||
|
||||
bool Network::isValid()
|
||||
{
|
||||
if (!_secureFlg)
|
||||
{
|
||||
return TCPStack::isValid();
|
||||
}
|
||||
if (_ssl)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Network::disconnect()
|
||||
{
|
||||
if (_ssl)
|
||||
{
|
||||
SSL_shutdown(_ssl);
|
||||
_ssl = 0;
|
||||
TCPStack::close();
|
||||
}
|
||||
else
|
||||
{
|
||||
TCPStack::close();
|
||||
}
|
||||
}
|
||||
|
||||
int Network::getSock()
|
||||
{
|
||||
return TCPStack::getSock();
|
||||
}
|
||||
|
||||
SSL* Network::getSSL()
|
||||
{
|
||||
if (_secureFlg)
|
||||
{
|
||||
return _ssl;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Network::isSecure()
|
||||
{
|
||||
return _secureFlg;
|
||||
}
|
||||
|
||||
95
MQTTSNGateway/src/linux/Network.h
Normal file
95
MQTTSNGateway/src/linux/Network.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**************************************************************************************
|
||||
* 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 and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef NETWORK_H_
|
||||
#define NETWORK_H_
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "Threading.h"
|
||||
#include "MQTTSNGWDefines.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*========================================
|
||||
Class TCPStack
|
||||
=======================================*/
|
||||
class TCPStack
|
||||
{
|
||||
public:
|
||||
TCPStack();
|
||||
virtual ~TCPStack();
|
||||
|
||||
// Server initialization
|
||||
bool bind(const char* service);
|
||||
bool listen();
|
||||
bool accept(TCPStack&);
|
||||
|
||||
// Client initialization
|
||||
bool connect(const char* host, const char* service);
|
||||
|
||||
int send(const uint8_t* buf, int length);
|
||||
int recv(uint8_t* buf, int len);
|
||||
void close();
|
||||
|
||||
void setNonBlocking(const bool);
|
||||
|
||||
bool isValid();
|
||||
int getSock();
|
||||
|
||||
private:
|
||||
int _sockfd;
|
||||
addrinfo* _addrinfo;
|
||||
};
|
||||
|
||||
/*========================================
|
||||
Class Network
|
||||
=======================================*/
|
||||
class Network: public TCPStack
|
||||
{
|
||||
public:
|
||||
Network(bool secure);
|
||||
virtual ~Network();
|
||||
|
||||
bool connect(const char* host, const char* service);
|
||||
void disconnect();
|
||||
int send(const uint8_t* buf, uint16_t length);
|
||||
int recv(uint8_t* buf, uint16_t len);
|
||||
|
||||
bool isValid();
|
||||
bool isSecure();
|
||||
int getSock();
|
||||
SSL* getSSL();
|
||||
|
||||
private:
|
||||
static SSL_CTX* _ctx;
|
||||
static int _numOfInstance;
|
||||
static SSL_SESSION* _session;
|
||||
|
||||
SSL* _ssl;
|
||||
bool _secureFlg;
|
||||
bool _disconReq;
|
||||
Mutex _mutex;
|
||||
bool _busy;
|
||||
};
|
||||
|
||||
#endif /* NETWORK_H_ */
|
||||
502
MQTTSNGateway/src/linux/Threading.cpp
Normal file
502
MQTTSNGateway/src/linux/Threading.cpp
Normal file
@@ -0,0 +1,502 @@
|
||||
/**************************************************************************************
|
||||
* 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 and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "Threading.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <semaphore.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*=====================================
|
||||
Class Mutex
|
||||
=====================================*/
|
||||
|
||||
Mutex::Mutex(void)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutex_init(&_mutex, &attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
_shmid = 0;
|
||||
_pmutex = 0;
|
||||
}
|
||||
|
||||
Mutex::Mutex(const char* fileName)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
key_t key = ftok(fileName, 1);
|
||||
|
||||
if ((_shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | 0666)) < 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't create a shared memory.");
|
||||
}
|
||||
_pmutex = (pthread_mutex_t*) shmat(_shmid, NULL, 0);
|
||||
if (_pmutex < 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't attach shared memory.");
|
||||
}
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
|
||||
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't set the process-shared flag");
|
||||
}
|
||||
if (pthread_mutex_init(_pmutex, &attr) != 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't initialize.");
|
||||
}
|
||||
}
|
||||
|
||||
Mutex::~Mutex(void)
|
||||
{
|
||||
if (_pmutex)
|
||||
{
|
||||
pthread_mutex_lock(_pmutex);
|
||||
pthread_mutex_unlock(_pmutex);
|
||||
pthread_mutex_destroy(_pmutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&_mutex);
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
}
|
||||
if (_shmid)
|
||||
{
|
||||
shmctl(_shmid, IPC_RMID, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::lock(void)
|
||||
{
|
||||
if (_pmutex)
|
||||
{
|
||||
pthread_mutex_lock(_pmutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pthread_mutex_lock(&_mutex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
} catch (char* errmsg)
|
||||
{
|
||||
throw Exception( -1, "The same thread can't aquire a mutex twice.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::unlock(void)
|
||||
{
|
||||
|
||||
if (_pmutex)
|
||||
{
|
||||
pthread_mutex_unlock(_pmutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pthread_mutex_unlock(&_mutex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
} catch (char* errmsg)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't unlock.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Semaphore
|
||||
=====================================*/
|
||||
|
||||
Semaphore::Semaphore()
|
||||
{
|
||||
sem_init(&_sem, 0, 0);
|
||||
_name = 0;
|
||||
_psem = 0;
|
||||
}
|
||||
|
||||
Semaphore::Semaphore(unsigned int val)
|
||||
{
|
||||
sem_init(&_sem, 0, val);
|
||||
_name = 0;
|
||||
_psem = 0;
|
||||
}
|
||||
|
||||
Semaphore::Semaphore(const char* name, unsigned int val)
|
||||
{
|
||||
_psem = sem_open(name, O_CREAT, 0666, val);
|
||||
if (_psem == SEM_FAILED)
|
||||
{
|
||||
throw Exception( -1, "Semaphore can't be created.");
|
||||
}
|
||||
_name = (char*) calloc(strlen(name + 1), 1);
|
||||
if (_name == NULL)
|
||||
{
|
||||
throw Exception( -1, "Semaphore can't allocate memories.");
|
||||
}
|
||||
_name = strdup(name);
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
if (_name)
|
||||
{
|
||||
sem_close(_psem);
|
||||
sem_unlink(_name);
|
||||
free((void*) _name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_destroy(&_sem);
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::post(void)
|
||||
{
|
||||
int val = 0;
|
||||
if (_psem)
|
||||
{
|
||||
sem_getvalue(_psem, &val);
|
||||
if (val <= 0)
|
||||
{
|
||||
sem_post(_psem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_getvalue(&_sem, &val);
|
||||
if (val <= 0)
|
||||
{
|
||||
sem_post(&_sem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::wait(void)
|
||||
{
|
||||
if (_psem)
|
||||
{
|
||||
sem_wait(_psem);
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_wait(&_sem);
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::timedwait(uint16_t millsec)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += millsec / 1000;
|
||||
ts.tv_nsec = (millsec % 1000) * 1000000;
|
||||
if (_psem)
|
||||
{
|
||||
sem_timedwait(_psem, &ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_timedwait(&_sem, &ts);
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Class RingBuffer
|
||||
=========================================*/
|
||||
RingBuffer::RingBuffer()
|
||||
{
|
||||
key_t key = ftok(MQTTSNGW_RINGBUFFER_KEY, 1);
|
||||
|
||||
if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE,
|
||||
IPC_CREAT | IPC_EXCL | 0666)) >= 0)
|
||||
{
|
||||
if ((_shmaddr = (uint16_t*) shmat(_shmid, NULL, 0)) > 0)
|
||||
{
|
||||
_length = (uint16_t*) _shmaddr;
|
||||
_start = (uint16_t*) _length + sizeof(uint16_t*);
|
||||
_end = (uint16_t*) _start + sizeof(uint16_t*);
|
||||
_buffer = (char*) _end + sizeof(uint16_t*);
|
||||
_createFlg = true;
|
||||
|
||||
*_length = PROCESS_LOG_BUFFER_SIZE - sizeof(uint16_t*) * 3 - 16;
|
||||
*_start = *_end = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't attach shared memory.");
|
||||
}
|
||||
}
|
||||
else if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE, IPC_CREAT | 0666)) >= 0)
|
||||
{
|
||||
if ((_shmaddr = (uint16_t*) shmat(_shmid, NULL, 0)) > 0)
|
||||
{
|
||||
_length = (uint16_t*) _shmaddr;
|
||||
_start = (uint16_t*) _length + sizeof(uint16_t*);
|
||||
_end = (uint16_t*) _start + sizeof(uint16_t*);
|
||||
_buffer = (char*) _end + sizeof(uint16_t*);
|
||||
_createFlg = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't create a shared memory.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't create a shared memory.");
|
||||
}
|
||||
|
||||
_pmx = new Mutex(MQTTSNGW_RB_MUTEX_KEY);
|
||||
}
|
||||
|
||||
RingBuffer::~RingBuffer()
|
||||
{
|
||||
if (_createFlg)
|
||||
{
|
||||
if (_shmid > 0)
|
||||
{
|
||||
shmctl(_shmid, IPC_RMID, NULL);
|
||||
}
|
||||
if (_pmx > 0)
|
||||
{
|
||||
delete _pmx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_shmid > 0)
|
||||
{
|
||||
shmdt(_shmaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RingBuffer::put(char* data)
|
||||
{
|
||||
_pmx->lock();
|
||||
|
||||
uint16_t dlen = strlen(data);
|
||||
uint16_t blen = *_length - *_end;
|
||||
|
||||
if (*_end > *_start)
|
||||
{
|
||||
if (dlen < blen)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
if (*_end - *_start == 1)
|
||||
{ // Buffer is empty.
|
||||
*_start = *_end;
|
||||
}
|
||||
*_end += dlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(_buffer + *_end, data, blen);
|
||||
strncpy(_buffer, data + blen, dlen - blen);
|
||||
if (*_end - *_start == 1)
|
||||
{ // Buffer is empty.
|
||||
*_start = *_end;
|
||||
*_end = dlen - blen;
|
||||
}
|
||||
else
|
||||
{
|
||||
*_end = dlen - blen;
|
||||
*_start = *_end + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*_end == *_start)
|
||||
{
|
||||
if (dlen < blen)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
*_end += dlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* errmsg = "RingBuffer Error: data is too long";
|
||||
strcpy(_buffer + *_end, errmsg);
|
||||
*_end += strlen(errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // *_end < *_start
|
||||
if (dlen < *_start - *_end)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
*_end += dlen;
|
||||
*_start = *_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dlen < blen)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
*_end += dlen;
|
||||
*_start = *_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(_buffer + *_end, data, blen);
|
||||
strncpy(_buffer, data + blen, dlen - blen);
|
||||
*_start = *_end;
|
||||
*_end = dlen - blen;
|
||||
}
|
||||
}
|
||||
}
|
||||
_pmx->unlock();
|
||||
}
|
||||
|
||||
int RingBuffer::get(char* buf, int length)
|
||||
{
|
||||
int len = 0;
|
||||
_pmx->lock();
|
||||
|
||||
if (*_end > *_start)
|
||||
{
|
||||
if (length > *_end - *_start)
|
||||
{
|
||||
len = *_end - *_start;
|
||||
if (len == 1)
|
||||
{
|
||||
len = 0;
|
||||
}
|
||||
strncpy(buf, _buffer + *_start, len);
|
||||
*_start = *_end - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = length;
|
||||
strncpy(buf, _buffer + *_start, len);
|
||||
*_start = *_start + len;
|
||||
}
|
||||
}
|
||||
else if (*_end < *_start)
|
||||
{
|
||||
int blen = *_length - *_start;
|
||||
if (length > blen)
|
||||
{
|
||||
strncpy(buf, _buffer + *_start, blen);
|
||||
*_start = 0;
|
||||
if (length - (blen + *_end) > 0)
|
||||
{
|
||||
strncpy(buf + blen, _buffer, *_end);
|
||||
len = blen + *_end;
|
||||
if (*_end > 0)
|
||||
{
|
||||
*_start = *_end - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(buf + blen, _buffer, length - blen);
|
||||
len = length;
|
||||
*_start = length - blen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(buf, _buffer + *_start, length);
|
||||
*_start += length;
|
||||
len = length;
|
||||
}
|
||||
}
|
||||
_pmx->unlock();
|
||||
return len;
|
||||
}
|
||||
|
||||
void RingBuffer::reset()
|
||||
{
|
||||
_pmx->lock();
|
||||
if ( _start && _end )
|
||||
{
|
||||
*_start = *_end = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't reset. need to clear shared memory.");
|
||||
}
|
||||
_pmx->unlock();
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Thread
|
||||
=====================================*/
|
||||
Thread::Thread()
|
||||
{
|
||||
_stopProcessEvent = theMultiTaskProcess->getStopProcessEvent();
|
||||
_threadID = 0;
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
pthread_cancel(_threadID);
|
||||
pthread_join(_threadID, 0);
|
||||
}
|
||||
|
||||
void* Thread::_run(void* runnable)
|
||||
{
|
||||
static_cast<Runnable*>(runnable)->EXECRUN();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::initialize(int argc, char** argv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
pthread_t Thread::getID()
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
bool Thread::equals(pthread_t *t1, pthread_t *t2)
|
||||
{
|
||||
return (pthread_equal(*t1, *t2) ? false : true);
|
||||
}
|
||||
|
||||
int Thread::start(void)
|
||||
{
|
||||
Runnable *runnable = this;
|
||||
return pthread_create(&_threadID, 0, _run, runnable);
|
||||
}
|
||||
|
||||
void Thread::stopProcess(void)
|
||||
{
|
||||
_stopProcessEvent->post();
|
||||
}
|
||||
|
||||
void Thread::testThreadCancel(void)
|
||||
{
|
||||
pthread_testcancel();
|
||||
}
|
||||
@@ -1,36 +1,145 @@
|
||||
/**************************************************************************************
|
||||
* 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 and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef THREADING_H_
|
||||
#define THREADING_H_
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "Thread.h"
|
||||
}
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include "MQTTSNGWDefines.h"
|
||||
|
||||
|
||||
class Thread
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
/*
|
||||
Thread(void (*fn)(void const *argument), void *argument)
|
||||
{
|
||||
Thread_start(fn, arg);
|
||||
}*/
|
||||
|
||||
public:
|
||||
|
||||
Thread(void (*fn)(void const *argument))
|
||||
{
|
||||
const void* arg = NULL;
|
||||
|
||||
//Thread_start((void (*)(void *))fn, arg);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define MQTTSNGW_RINGBUFFER_KEY "/usr/local/etc/mqttsnGateway/config/ringbuffer.key"
|
||||
#define MQTTSNGW_RB_MUTEX_KEY "/usr/local/etc/mqttsnGateway/config/rbmutex.key"
|
||||
#define MQTTSNGW_RB_SEMAPHOR_NAME "/rbsemaphor"
|
||||
|
||||
/*=====================================
|
||||
Class Mutex
|
||||
====================================*/
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex();
|
||||
Mutex(const char* name);
|
||||
~Mutex();
|
||||
void lock(void);
|
||||
void unlock(void);
|
||||
|
||||
private:
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_mutex_t* _pmutex;
|
||||
int _shmid;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class Semaphore
|
||||
====================================*/
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore();
|
||||
Semaphore(unsigned int val);
|
||||
Semaphore(const char* name, unsigned int val);
|
||||
~Semaphore();
|
||||
void post(void);
|
||||
void wait(void);
|
||||
void timedwait(uint16_t millsec);
|
||||
|
||||
private:
|
||||
sem_t* _psem;
|
||||
sem_t _sem;
|
||||
char* _name;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class RingBuffer
|
||||
=====================================*/
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer();
|
||||
~RingBuffer();
|
||||
void put(char* buffer);
|
||||
int get(char* buffer, int bufferLength);
|
||||
void reset();
|
||||
private:
|
||||
void* _shmaddr;
|
||||
uint16_t* _length;
|
||||
uint16_t* _start;
|
||||
uint16_t* _end;
|
||||
char* _buffer;
|
||||
int _shmid;
|
||||
Mutex* _pmx;
|
||||
bool _createFlg;
|
||||
};
|
||||
|
||||
|
||||
/*=====================================
|
||||
Class Runnable
|
||||
====================================*/
|
||||
class Runnable
|
||||
{
|
||||
public:
|
||||
Runnable(){}
|
||||
virtual ~Runnable(){}
|
||||
virtual void EXECRUN(){}
|
||||
};
|
||||
|
||||
|
||||
#define MAGIC_WORD_FOR_THREAD \
|
||||
public: void EXECRUN() \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
run(); \
|
||||
} \
|
||||
catch(Exception& ex) \
|
||||
{ \
|
||||
ex.writeMessage();\
|
||||
stopProcess(); \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
throw; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Thread
|
||||
====================================*/
|
||||
class Thread : virtual public Runnable{
|
||||
public:
|
||||
Thread();
|
||||
~Thread();
|
||||
int start(void);
|
||||
static pthread_t getID();
|
||||
static bool equals(pthread_t*, pthread_t*);
|
||||
virtual void initialize(int argc, char** argv);
|
||||
void stopProcess(void);
|
||||
void testThreadCancel(void);
|
||||
private:
|
||||
pthread_t _threadID;
|
||||
Semaphore* _stopProcessEvent;
|
||||
|
||||
static void* _run(void*);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* THREADING_H_ */
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
g++ main.cpp -I MQTTPacket/src -I MQTTSNPacket/src -I linux MQTTPacket/src/*.c MQTTSNPacket/src/*.c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2015 IBM Corp.
|
||||
/**************************************************************************************
|
||||
* 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
|
||||
@@ -11,214 +11,214 @@
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "linux.h"
|
||||
|
||||
class IPStack
|
||||
using namespace std;
|
||||
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*=====================================
|
||||
Print Current Date & Time
|
||||
=====================================*/
|
||||
char theCurrentTime[32];
|
||||
|
||||
char* currentDateTime()
|
||||
{
|
||||
public:
|
||||
IPStack()
|
||||
{
|
||||
struct timeval now;
|
||||
struct tm tstruct;
|
||||
gettimeofday(&now, 0);
|
||||
tstruct = *localtime(&now.tv_sec);
|
||||
strftime(theCurrentTime, sizeof(theCurrentTime), "%Y%m%d %H%M%S", &tstruct);
|
||||
sprintf(theCurrentTime + 15, " %03d", (int)now.tv_usec / 1000 );
|
||||
return theCurrentTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int Socket_error(const char* aString)
|
||||
{
|
||||
int rc = 0;
|
||||
//if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
|
||||
//{
|
||||
if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
|
||||
{
|
||||
if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
|
||||
printf("Socket error %s in %s for socket %d\n", strerror(errno), aString, mysock);
|
||||
rc = errno;
|
||||
}
|
||||
//}
|
||||
return errno;
|
||||
}
|
||||
|
||||
int connect(const char* hostname, int port)
|
||||
{
|
||||
int type = SOCK_STREAM;
|
||||
struct sockaddr_in address;
|
||||
int rc = -1;
|
||||
sa_family_t family = AF_INET;
|
||||
struct addrinfo *result = NULL;
|
||||
struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
|
||||
|
||||
if ((rc = getaddrinfo(hostname, NULL, &hints, &result)) == 0)
|
||||
{
|
||||
struct addrinfo* res = result;
|
||||
|
||||
/* prefer ip4 addresses */
|
||||
while (res)
|
||||
{
|
||||
if (res->ai_family == AF_INET)
|
||||
{
|
||||
result = res;
|
||||
break;
|
||||
}
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
if (result->ai_family == AF_INET)
|
||||
{
|
||||
address.sin_port = htons(port);
|
||||
address.sin_family = family = AF_INET;
|
||||
address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
|
||||
}
|
||||
else
|
||||
rc = -1;
|
||||
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
mysock = socket(family, type, 0);
|
||||
if (mysock != -1)
|
||||
{
|
||||
int opt = 1;
|
||||
|
||||
//if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
|
||||
// printf("Could not set SO_NOSIGPIPE for socket %d", mysock);
|
||||
|
||||
rc = ::connect(mysock, (struct sockaddr*)&address, sizeof(address));
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int read(unsigned char* buffer, int len, int timeout_ms)
|
||||
{
|
||||
struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
|
||||
if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
|
||||
{
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_usec = 100;
|
||||
}
|
||||
|
||||
setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
|
||||
|
||||
int bytes = 0;
|
||||
while (bytes < len)
|
||||
{
|
||||
int rc = ::recv(mysock, &buffer[bytes], (size_t)(len - bytes), 0);
|
||||
if (rc == -1)
|
||||
{
|
||||
if (Socket_error("read") != 0)
|
||||
{
|
||||
bytes = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
bytes += rc;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int write(unsigned char* buffer, int len, int timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0; /* 30 Secs Timeout */
|
||||
tv.tv_usec = timeout * 1000; // Not init'ing this can cause strange errors
|
||||
|
||||
setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
|
||||
int rc = ::write(mysock, buffer, len);
|
||||
//printf("write rc %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disconnect()
|
||||
{
|
||||
return ::close(mysock);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int mysock;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Countdown
|
||||
/*============================================
|
||||
Timer
|
||||
============================================*/
|
||||
Timer::Timer(void)
|
||||
{
|
||||
public:
|
||||
Countdown()
|
||||
{
|
||||
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
Countdown(int ms)
|
||||
{
|
||||
countdown_ms(ms);
|
||||
}
|
||||
|
||||
Timer::~Timer(void)
|
||||
{
|
||||
|
||||
bool expired()
|
||||
{
|
||||
struct timeval now, res;
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&end_time, &now, &res);
|
||||
//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
|
||||
//if (res.tv_sec > 0 || res.tv_usec > 0)
|
||||
// printf("expired %d %d\n", res.tv_sec, res.tv_usec);
|
||||
return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void countdown_ms(int ms)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval interval = {ms / 1000, (ms % 1000) * 1000};
|
||||
//printf("interval %d %d\n", interval.tv_sec, interval.tv_usec);
|
||||
timeradd(&now, &interval, &end_time);
|
||||
}
|
||||
void Timer::start(uint32_t msecs)
|
||||
{
|
||||
gettimeofday(&_startTime, 0);
|
||||
_millis = msecs;
|
||||
}
|
||||
|
||||
|
||||
void countdown(int seconds)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval interval = {seconds, 0};
|
||||
timeradd(&now, &interval, &end_time);
|
||||
}
|
||||
bool Timer::isTimeup(void)
|
||||
{
|
||||
return isTimeup(_millis);
|
||||
}
|
||||
|
||||
|
||||
int left_ms()
|
||||
{
|
||||
struct timeval now, res;
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&end_time, &now, &res);
|
||||
//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
|
||||
return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Timer::isTimeup(uint32_t msecs)
|
||||
{
|
||||
struct timeval curTime;
|
||||
long secs, usecs;
|
||||
if (_startTime.tv_sec == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
gettimeofday(&curTime, 0);
|
||||
secs = (curTime.tv_sec - _startTime.tv_sec) * 1000;
|
||||
usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0;
|
||||
return ((secs + usecs) > (long) msecs);
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::stop()
|
||||
{
|
||||
_startTime.tv_sec = 0;
|
||||
_millis = 0;
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class LightIndicator
|
||||
=====================================*/
|
||||
|
||||
LightIndicator::LightIndicator()
|
||||
{
|
||||
_greenStatus = false;
|
||||
for ( int i = 0; i <= MAX_GPIO; i++)
|
||||
{
|
||||
_gpio[i] = 0;
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
LightIndicator::~LightIndicator()
|
||||
{
|
||||
for ( int i = 0; i <= MAX_GPIO; i++)
|
||||
{
|
||||
if ( _gpio[i] )
|
||||
{
|
||||
close( _gpio[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::greenLight(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
if (!_greenStatus)
|
||||
{
|
||||
_greenStatus = true;
|
||||
//Turn Green on & turn Red off
|
||||
lit(LIGHT_INDICATOR_GREEN, "1");
|
||||
lit(LIGHT_INDICATOR_RED, "0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_greenStatus)
|
||||
{
|
||||
_greenStatus = false;
|
||||
//Turn Green off & turn Red on
|
||||
lit(LIGHT_INDICATOR_GREEN, "0");
|
||||
lit(LIGHT_INDICATOR_RED, "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
void LightIndicator::blueLight(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
lit(LIGHT_INDICATOR_BLUE, "1");
|
||||
if ( !_greenStatus )
|
||||
{
|
||||
greenLight(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lit(LIGHT_INDICATOR_BLUE, "0");
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::redLight(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
lit(LIGHT_INDICATOR_RED, "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
lit(LIGHT_INDICATOR_RED, "0");
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::allLightOff(void)
|
||||
{
|
||||
lit(LIGHT_INDICATOR_RED, "0");
|
||||
lit(LIGHT_INDICATOR_BLUE, "0");
|
||||
lit(LIGHT_INDICATOR_GREEN, "0");
|
||||
_greenStatus = false;
|
||||
}
|
||||
|
||||
void LightIndicator::init()
|
||||
{
|
||||
pinMode(LIGHT_INDICATOR_GREEN);
|
||||
pinMode(LIGHT_INDICATOR_RED);
|
||||
pinMode(LIGHT_INDICATOR_BLUE);
|
||||
}
|
||||
|
||||
void LightIndicator::lit(int gpioNo, const char* onoff)
|
||||
{
|
||||
if( _gpio[gpioNo] )
|
||||
{
|
||||
write(_gpio[gpioNo], onoff, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::pinMode(int gpioNo)
|
||||
{
|
||||
int fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if ( fd < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
char no[4];
|
||||
sprintf(no,"%d", gpioNo);
|
||||
write(fd, no, strlen(no));
|
||||
close(fd);
|
||||
|
||||
char fileName[64];
|
||||
sprintf( fileName, "/sys/class/gpio/gpio%d/direction", gpioNo);
|
||||
|
||||
fd = open(fileName, O_WRONLY);
|
||||
if ( fd < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
write(fd,"out", 3);
|
||||
close(fd);
|
||||
|
||||
sprintf( fileName, "/sys/class/gpio/gpio%d/value", gpioNo);
|
||||
fd = open(fileName, O_WRONLY);
|
||||
if ( fd > 0 )
|
||||
{
|
||||
_gpio[gpioNo] = fd;
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval end_time;
|
||||
};
|
||||
|
||||
|
||||
70
MQTTSNGateway/src/linux/linux.h
Normal file
70
MQTTSNGateway/src/linux/linux.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/**************************************************************************************
|
||||
* 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 MQTTSNGATEWAY_SRC_LINUX_LINUX_H_
|
||||
#define MQTTSNGATEWAY_SRC_LINUX_LINUX_H_
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
/*==========================================================
|
||||
* Light Indicators
|
||||
===========================================================*/
|
||||
#define MAX_GPIO 27 // GPIO02 - GPIO27
|
||||
#define LIGHT_INDICATOR_GREEN 23 // RPi connector 16
|
||||
#define LIGHT_INDICATOR_RED 24 // RPi connector 18
|
||||
#define LIGHT_INDICATOR_BLUE 25 // RPi connector 22
|
||||
|
||||
/*============================================
|
||||
Timer
|
||||
============================================*/
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(void);
|
||||
~Timer(void);
|
||||
void start(uint32_t msecs = 0);
|
||||
bool isTimeup(void);
|
||||
bool isTimeup(uint32_t msecs);
|
||||
void stop();
|
||||
|
||||
private:
|
||||
struct timeval _startTime;
|
||||
uint32_t _millis;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class LightIndicator
|
||||
=====================================*/
|
||||
class LightIndicator
|
||||
{
|
||||
public:
|
||||
LightIndicator();
|
||||
~LightIndicator();
|
||||
void greenLight(bool on);
|
||||
void blueLight(bool on);
|
||||
void redLight(bool on);
|
||||
void allLightOff(void);
|
||||
|
||||
private:
|
||||
void init();
|
||||
void lit(int gpioNo, const char* onoff);
|
||||
void pinMode(int gpioNo);
|
||||
bool _greenStatus;
|
||||
int _gpio[MAX_GPIO + 1];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGATEWAY_SRC_LINUX_LINUX_H_ */
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
#include "Threading.h"
|
||||
|
||||
//#include "MQTTSNUDP.h"
|
||||
//#include "MQTTEthernet.h"
|
||||
#include "linux.cpp"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
MQTTSN::Parms parms();
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// set up MQTT-SN network listening
|
||||
UDPStack net;
|
||||
net.listen(1884);
|
||||
|
||||
MQTTSN::Gateway<UDPStack, IPStack, Countdown, Thread, Mutex> gateway =
|
||||
MQTTSN::Gateway<UDPStack, IPStack, Countdown, Thread, Mutex>(net);
|
||||
|
||||
gateway.run(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
336
MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
Normal file
336
MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
/**************************************************************************************
|
||||
* 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 and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include "SensorNetwork.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
SensorNetAddress::SensorNetAddress()
|
||||
{
|
||||
_portNo = 0;
|
||||
_IpAddr = 0;
|
||||
}
|
||||
|
||||
SensorNetAddress::~SensorNetAddress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SensorNetAddress::setAddress(uint32_t IpAddr, uint16_t port)
|
||||
{
|
||||
_IpAddr = IpAddr;
|
||||
_portNo = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert Text data to SensorNetAddress
|
||||
* @param buf is pointer of PortNo@IP_Address format text
|
||||
* @return success = 0, Invalid format = -1
|
||||
*/
|
||||
int SensorNetAddress::setAddress(string* data)
|
||||
{
|
||||
size_t pos = data->find_first_of("@");
|
||||
|
||||
if ( pos == string::npos )
|
||||
{
|
||||
_portNo = 0;
|
||||
_IpAddr = INADDR_NONE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
string port = data->substr(0, pos);
|
||||
string ip = data->substr(pos + 1);
|
||||
int portNo = 0;
|
||||
|
||||
if ((portNo = atoi(port.c_str())) == 0 || (_IpAddr = inet_addr(ip.c_str())) == INADDR_NONE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
_portNo = htons(portNo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SensorNetAddress::isMatch(SensorNetAddress* addr)
|
||||
{
|
||||
return ((this->_portNo == addr->_portNo) && (this->_IpAddr == addr->_IpAddr));
|
||||
}
|
||||
|
||||
SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
|
||||
{
|
||||
this->_portNo = addr._portNo;
|
||||
this->_IpAddr = addr._IpAddr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
SensorNetwork::SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SensorNetwork::~SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
|
||||
{
|
||||
return UDPPort::unicast(payload, payloadLength, sendToAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
|
||||
{
|
||||
return UDPPort::broadcast(payload, payloadLength);
|
||||
}
|
||||
|
||||
int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
|
||||
{
|
||||
return UDPPort::recv(buf, bufLen, &_clientAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::initialize(void)
|
||||
{
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
uint16_t multicastPortNo = 0;
|
||||
uint16_t unicastPortNo = 0;
|
||||
|
||||
if (theProcess->getParam("MulticastPortNo", param) == 0)
|
||||
{
|
||||
multicastPortNo = atoi(param);
|
||||
}
|
||||
if (theProcess->getParam("GatewayPortNo", param) == 0)
|
||||
{
|
||||
unicastPortNo = atoi(param);
|
||||
}
|
||||
|
||||
theProcess->getParam("MulticastIP", param);
|
||||
return UDPPort::open(param, multicastPortNo, unicastPortNo);
|
||||
}
|
||||
|
||||
const char* SensorNetwork::getType(void)
|
||||
{
|
||||
return "UDP";
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Class udpStack
|
||||
=========================================*/
|
||||
|
||||
UDPPort::UDPPort()
|
||||
{
|
||||
_disconReq = false;
|
||||
_sockfdUnicast = -1;
|
||||
_sockfdMulticast = -1;
|
||||
}
|
||||
|
||||
UDPPort::~UDPPort()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void UDPPort::close(void)
|
||||
{
|
||||
if (_sockfdUnicast > 0)
|
||||
{
|
||||
::close(_sockfdUnicast);
|
||||
_sockfdUnicast = -1;
|
||||
}
|
||||
if (_sockfdMulticast > 0)
|
||||
{
|
||||
::close(_sockfdMulticast);
|
||||
_sockfdMulticast = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int UDPPort::open(char* ipAddress, uint16_t multiPortNo, uint16_t uniPortNo)
|
||||
{
|
||||
char loopch = 0;
|
||||
const int reuse = 1;
|
||||
|
||||
if (uniPortNo == 0 || multiPortNo == 0)
|
||||
{
|
||||
D_NWSTACK("error portNo undefined in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t ip = inet_addr(ipAddress);
|
||||
_grpAddr.setAddress(ip, htons(multiPortNo));
|
||||
_clientAddr.setAddress(ip, htons(uniPortNo));
|
||||
|
||||
/*------ Create unicast socket --------*/
|
||||
_sockfdUnicast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (_sockfdUnicast < 0)
|
||||
{
|
||||
D_NWSTACK("error can't create unicast socket in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
sockaddr_in addru;
|
||||
addru.sin_family = AF_INET;
|
||||
addru.sin_port = htons(uniPortNo);
|
||||
addru.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (::bind(_sockfdUnicast, (sockaddr*) &addru, sizeof(addru)) < 0)
|
||||
{
|
||||
D_NWSTACK("error can't bind unicast socket in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0)
|
||||
{
|
||||
D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------ Create Multicast socket --------*/
|
||||
_sockfdMulticast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (_sockfdMulticast < 0)
|
||||
{
|
||||
D_NWSTACK("error can't create multicast socket in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(_sockfdMulticast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
sockaddr_in addrm;
|
||||
addrm.sin_family = AF_INET;
|
||||
addrm.sin_port = _grpAddr.getPortNo();
|
||||
addrm.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (::bind(_sockfdMulticast, (sockaddr*) &addrm, sizeof(addrm)) < 0)
|
||||
{
|
||||
D_NWSTACK("error can't bind multicast socket in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0)
|
||||
{
|
||||
D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip_mreq mreq;
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
mreq.imr_multiaddr.s_addr = _grpAddr.getIpAddress();
|
||||
|
||||
if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
{
|
||||
D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
{
|
||||
D_NWSTACK("error Unicast IP_ADD_MEMBERSHIP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPPort::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr)
|
||||
{
|
||||
sockaddr_in dest;
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = addr->getPortNo();
|
||||
dest.sin_addr.s_addr = addr->getIpAddress();
|
||||
;
|
||||
|
||||
int status = ::sendto(_sockfdUnicast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest));
|
||||
if (status < 0)
|
||||
{
|
||||
D_NWSTACK("errno == %d in UDPPort::sendto\n", errno);
|
||||
}
|
||||
D_NWSTACK("sendto %s:%u length = %d\n", inet_ntoa(dest.sin_addr), htons(addr->getPortNo()), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int UDPPort::broadcast(const uint8_t* buf, uint32_t length)
|
||||
{
|
||||
return unicast(buf, length, &_grpAddr);
|
||||
}
|
||||
|
||||
int UDPPort::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr)
|
||||
{
|
||||
fd_set recvfds;
|
||||
int maxSock = 0;
|
||||
|
||||
FD_ZERO(&recvfds);
|
||||
FD_SET(_sockfdUnicast, &recvfds);
|
||||
FD_SET(_sockfdMulticast, &recvfds);
|
||||
|
||||
if (_sockfdMulticast > _sockfdUnicast)
|
||||
{
|
||||
maxSock = _sockfdMulticast;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxSock = _sockfdUnicast;
|
||||
}
|
||||
|
||||
select(maxSock + 1, &recvfds, 0, 0, 0);
|
||||
|
||||
if (FD_ISSET(_sockfdUnicast, &recvfds))
|
||||
{
|
||||
return recvfrom(_sockfdUnicast, buf, len, 0, addr);
|
||||
}
|
||||
else if (FD_ISSET(_sockfdMulticast, &recvfds))
|
||||
{
|
||||
return recvfrom(_sockfdMulticast, buf, len, 0, &_grpAddr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPPort::recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr)
|
||||
{
|
||||
sockaddr_in sender;
|
||||
socklen_t addrlen = sizeof(sender);
|
||||
memset(&sender, 0, addrlen);
|
||||
|
||||
int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen);
|
||||
|
||||
if (status < 0 && errno != EAGAIN)
|
||||
{
|
||||
D_NWSTACK("errno == %d in UDPPort::recvfrom\n", errno);
|
||||
return -1;
|
||||
}
|
||||
addr->setAddress(sender.sin_addr.s_addr, sender.sin_port);
|
||||
D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr), htons(addr->getPortNo()), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
114
MQTTSNGateway/src/linux/udp/SensorNetwork.h
Normal file
114
MQTTSNGateway/src/linux/udp/SensorNetwork.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************************
|
||||
* 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 and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef SENSORNETWORK_H_
|
||||
#define SENSORNETWORK_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
#ifdef DEBUG_NWSTACK
|
||||
#define D_NWSTACK(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define D_NWSTACK(...)
|
||||
#endif
|
||||
|
||||
#define SENSORNETWORK_TYPE "UDP"
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
class SensorNetAddress
|
||||
{
|
||||
public:
|
||||
SensorNetAddress();
|
||||
~SensorNetAddress();
|
||||
void setAddress(uint32_t IpAddr, uint16_t port);
|
||||
int setAddress(string* data);
|
||||
uint32_t getIpAddress(void)
|
||||
{
|
||||
return _IpAddr;
|
||||
}
|
||||
uint16_t getPortNo(void)
|
||||
{
|
||||
return _portNo;
|
||||
}
|
||||
bool isMatch(SensorNetAddress* addr);
|
||||
SensorNetAddress& operator =(SensorNetAddress& addr);
|
||||
|
||||
private:
|
||||
uint16_t _portNo;
|
||||
uint32_t _IpAddr;
|
||||
};
|
||||
|
||||
/*========================================
|
||||
Class UpdPort
|
||||
=======================================*/
|
||||
class UDPPort
|
||||
{
|
||||
public:
|
||||
UDPPort();
|
||||
virtual ~UDPPort();
|
||||
|
||||
int open(char* ipAddress, uint16_t multiPortNo, uint16_t uniPortNo);
|
||||
void close(void);
|
||||
int unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* sendToAddr);
|
||||
int broadcast(const uint8_t* buf, uint32_t length);
|
||||
int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
|
||||
|
||||
private:
|
||||
void setNonBlocking(const bool);
|
||||
int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr);
|
||||
|
||||
int _sockfdUnicast;
|
||||
int _sockfdMulticast;
|
||||
|
||||
SensorNetAddress _grpAddr;
|
||||
SensorNetAddress _clientAddr;
|
||||
bool _disconReq;
|
||||
|
||||
};
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
class SensorNetwork: public UDPPort
|
||||
{
|
||||
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* getType(void);
|
||||
SensorNetAddress* getSenderAddress(void)
|
||||
{
|
||||
return &_clientAddr;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
SensorNetAddress _clientAddr; // Sender's address. not gateway's one.
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* SENSORNETWORK_H_ */
|
||||
434
MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
Normal file
434
MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/**************************************************************************************
|
||||
* 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 "SensorNetwork.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "Threading.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
SensorNetAddress::SensorNetAddress()
|
||||
{
|
||||
memset(_address64, 0, sizeof(_address64));
|
||||
memset(_address16, 0, sizeof(_address16));
|
||||
}
|
||||
|
||||
SensorNetAddress::~SensorNetAddress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SensorNetAddress::setAddress(uint8_t* address64, uint8_t* address16)
|
||||
{
|
||||
memcpy(_address64, address64, 8);
|
||||
memcpy(_address16, address16, 2);
|
||||
}
|
||||
|
||||
|
||||
int SensorNetAddress::setAddress(string* address64)
|
||||
{
|
||||
memcpy(_address64, address64->c_str(), 8);
|
||||
memset(_address16, 0, sizeof(_address16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SensorNetAddress::setBroadcastAddress(void)
|
||||
{
|
||||
memset(_address64, 0, 6);
|
||||
_address64[6] = 0xff;
|
||||
_address64[7] = 0xff;
|
||||
_address16[0] = 0xff;
|
||||
_address16[1] = 0xfe;
|
||||
}
|
||||
|
||||
bool SensorNetAddress::isMatch(SensorNetAddress* addr)
|
||||
{
|
||||
|
||||
return (memcmp(this->_address64, addr->_address64, 8 ) == 0 && memcmp(this->_address16, addr->_address16, 2) == 0);
|
||||
}
|
||||
|
||||
SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
|
||||
{
|
||||
memcpy(_address64, addr._address64, 8);
|
||||
memcpy(_address16, addr._address16, 2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
SensorNetwork::SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SensorNetwork::~SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
|
||||
{
|
||||
return XBee::unicast(payload, payloadLength, sendToAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
|
||||
{
|
||||
return XBee::broadcast(payload, payloadLength);
|
||||
}
|
||||
|
||||
int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
|
||||
{
|
||||
return XBee::recv(buf, bufLen, &_clientAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::initialize(void)
|
||||
{
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
uint16_t baudrate = 9600;
|
||||
|
||||
if (theProcess->getParam("Baudrate", param) == 0)
|
||||
{
|
||||
baudrate = (uint16_t)atoi(param);
|
||||
}
|
||||
|
||||
theProcess->getParam("SerialDevice", param);
|
||||
|
||||
return XBee::open(param, baudrate);
|
||||
}
|
||||
|
||||
const char* SensorNetwork::getType(void)
|
||||
{
|
||||
return "XBee";
|
||||
}
|
||||
|
||||
/*===========================================
|
||||
Class XBee
|
||||
============================================*/
|
||||
XBee::XBee(){
|
||||
_serialPort = new SerialPort();
|
||||
_respCd = 0;
|
||||
_dataLen = 0;
|
||||
_frameId = 0;
|
||||
}
|
||||
|
||||
XBee::~XBee(){
|
||||
if ( _serialPort )
|
||||
{
|
||||
delete _serialPort;
|
||||
}
|
||||
}
|
||||
|
||||
int XBee::open(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;
|
||||
}
|
||||
|
||||
return _serialPort->open(device, rate, false, 1, O_RDWR | O_NOCTTY);
|
||||
}
|
||||
|
||||
int XBee::broadcast(const uint8_t* payload, uint16_t payloadLen){
|
||||
SensorNetAddress addr;
|
||||
addr.setBroadcastAddress();
|
||||
send(payload, (uint8_t) payloadLen, &addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int XBee:: unicast(const uint8_t* payload, uint16_t payloadLen, SensorNetAddress* addr){
|
||||
send(payload, (uint8_t) payloadLen, addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int XBee::recv(uint8_t* buf, uint16_t bufLen, SensorNetAddress* clientAddr)
|
||||
{
|
||||
uint8_t data[128];
|
||||
int len;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
|
||||
if ( (len = readApiFrame(data)) > 0 )
|
||||
{
|
||||
|
||||
if ( data[0] == API_RESPONSE )
|
||||
{
|
||||
memcpy(clientAddr->_address64, data + 1, 8);
|
||||
memcpy(clientAddr->_address16, data + 9, 2);
|
||||
len -= 12;
|
||||
memcpy( buf, data + 12, len);
|
||||
return len;
|
||||
}
|
||||
else if ( data[0] == API_XMITSTATUS )
|
||||
{
|
||||
_respCd = data[5];
|
||||
_respId = data[1];
|
||||
_sem.post();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int XBee::readApiFrame(uint8_t* recvData){
|
||||
uint8_t buf;
|
||||
uint8_t pos = 0;
|
||||
uint8_t checksum = 0;
|
||||
uint8_t len = 0;
|
||||
|
||||
while ( _serialPort->recv(&buf) )
|
||||
{
|
||||
if ( buf == START_BYTE)
|
||||
{
|
||||
pos = 1;
|
||||
D_NWSTACK("\r\n===> Recv: ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pos == 0 )
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if ( recv(&buf) < 0 ) // MSB length
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if ( recv(&buf) < 0 ) // LSB length
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = buf;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
while ( len-- )
|
||||
{
|
||||
if ( recv(&buf) < 0 )
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
recvData[pos++] = buf;
|
||||
checksum += buf;
|
||||
}
|
||||
|
||||
recv(&buf); // checksum
|
||||
if ( (0xff - checksum ) == buf ){
|
||||
D_NWSTACK(" checksum ok\r\n");
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_NWSTACK(" checksum error %02x\r\n", 0xff - checksum);
|
||||
goto errexit;
|
||||
}
|
||||
errexit:
|
||||
_serialPort->flush();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int XBee::send(const uint8_t* payload, uint8_t pLen, SensorNetAddress* addr){
|
||||
D_NWSTACK("\r\n===> Send: ");
|
||||
uint8_t checksum = 0;
|
||||
_respCd = -1;
|
||||
|
||||
_serialPort->send(START_BYTE);
|
||||
send(0x00); // Message Length
|
||||
send(14 + pLen); // Message Length
|
||||
|
||||
_serialPort->send(API_XMITREQUEST); // Transmit Request API
|
||||
checksum += API_XMITREQUEST;
|
||||
|
||||
if (_frameId++ == 0x00 ) // Frame ID
|
||||
{
|
||||
_frameId = 1;
|
||||
}
|
||||
send(_frameId);
|
||||
checksum += _frameId;
|
||||
|
||||
for ( int i = 0; i < 8; i++) // Address64
|
||||
{
|
||||
send(addr->_address64[i]);
|
||||
checksum += addr->_address64[i];
|
||||
}
|
||||
for ( int i = 0; i < 2; i++) // Address16
|
||||
{
|
||||
send(addr->_address16[i]);
|
||||
checksum += addr->_address16[i];
|
||||
}
|
||||
|
||||
send(0x00); // Broadcast Radius
|
||||
checksum += 0x00;
|
||||
|
||||
send(0x00); // Option: Use the extended transmission timeout 0x40
|
||||
checksum += 0x00;
|
||||
|
||||
D_NWSTACK("\r\n Payload: ");
|
||||
|
||||
for ( uint8_t i = 0; i < pLen; i++ ){
|
||||
send(payload[i]); // Payload
|
||||
checksum += payload[i];
|
||||
}
|
||||
|
||||
checksum = 0xff - checksum;
|
||||
D_NWSTACK(" checksum ");
|
||||
send(checksum);
|
||||
D_NWSTACK("\r\n");
|
||||
|
||||
/* wait Txim Status 0x8B */
|
||||
_sem.timedwait(5000); // 5sec
|
||||
|
||||
if ( _respCd || _frameId != _respId )
|
||||
{
|
||||
D_NWSTACK(" frameId = %02x Not Acknowleged\r\n", _frameId);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XBee::send(uint8_t c)
|
||||
{
|
||||
if(c == START_BYTE || c == ESCAPE || c == XON || c == XOFF){
|
||||
_serialPort->send(ESCAPE);
|
||||
_serialPort->send(c ^ 0x20);
|
||||
}else{
|
||||
_serialPort->send(c);
|
||||
}
|
||||
}
|
||||
|
||||
int XBee::recv(uint8_t* buf)
|
||||
{
|
||||
if (_serialPort->recv(buf) )
|
||||
{
|
||||
if ( *buf == ESCAPE)
|
||||
{
|
||||
_serialPort->recv(buf);
|
||||
*buf = 0x20 ^ *buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Class SerialPort
|
||||
=========================================*/
|
||||
SerialPort::SerialPort()
|
||||
{
|
||||
_tio.c_iflag = IGNBRK | IGNPAR;
|
||||
_tio.c_cflag = CS8 | CLOCAL | CRTSCTS;
|
||||
_tio.c_cc[VINTR] = 0;
|
||||
_tio.c_cc[VTIME] = 0;
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialPort::recv(unsigned char* buf)
|
||||
{
|
||||
if (read(_fd, buf, 1) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_NWSTACK( " %02x",buf[0] );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPort::flush(void)
|
||||
{
|
||||
tcsetattr(_fd, TCSAFLUSH, &_tio);
|
||||
}
|
||||
|
||||
141
MQTTSNGateway/src/linux/xbee/SensorNetwork.h
Normal file
141
MQTTSNGateway/src/linux/xbee/SensorNetwork.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/**************************************************************************************
|
||||
* 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 <string>
|
||||
#include <termios.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
//#define DEBUG_NWSTACK
|
||||
|
||||
#ifdef DEBUG_NWSTACK
|
||||
#define D_NWSTACK(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define D_NWSTACK(...)
|
||||
#endif
|
||||
|
||||
#define API_XMITREQUEST 0x10
|
||||
#define API_RESPONSE 0x90
|
||||
#define API_MODEMSTATUS 0x8A
|
||||
#define API_XMITSTATUS 0x8B
|
||||
|
||||
#define START_BYTE 0x7e
|
||||
#define ESCAPE 0x7d
|
||||
#define XON 0x11
|
||||
#define XOFF 0x13
|
||||
|
||||
/*===========================================
|
||||
Class SerialPort
|
||||
============================================*/
|
||||
class SerialPort{
|
||||
public:
|
||||
SerialPort();
|
||||
~SerialPort();
|
||||
int open(char* devName, unsigned int baudrate, bool parity, unsigned int stopbit, unsigned int flg);
|
||||
bool send(unsigned char b);
|
||||
bool recv(unsigned char* b);
|
||||
void flush();
|
||||
|
||||
private:
|
||||
int _fd; // file descriptor
|
||||
struct termios _tio;
|
||||
};
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
class SensorNetAddress
|
||||
{
|
||||
friend class XBee;
|
||||
public:
|
||||
SensorNetAddress();
|
||||
~SensorNetAddress();
|
||||
void setAddress(uint8_t* address64, uint8_t* address16);
|
||||
int setAddress(string* data);
|
||||
void setBroadcastAddress(void);
|
||||
bool isMatch(SensorNetAddress* addr);
|
||||
SensorNetAddress& operator =(SensorNetAddress& addr);
|
||||
|
||||
private:
|
||||
uint8_t _address16[2];
|
||||
uint8_t _address64[8];
|
||||
};
|
||||
|
||||
/*========================================
|
||||
Class XBee
|
||||
=======================================*/
|
||||
class XBee
|
||||
{
|
||||
public:
|
||||
XBee();
|
||||
~XBee();
|
||||
|
||||
int open(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);
|
||||
|
||||
private:
|
||||
int readApiFrame(uint8_t* recvData);
|
||||
int recv(uint8_t* buf);
|
||||
int send(const uint8_t* payload, uint8_t pLen, SensorNetAddress* addr);
|
||||
void send(uint8_t b);
|
||||
|
||||
Semaphore _sem;
|
||||
Mutex _meutex;
|
||||
SerialPort* _serialPort;
|
||||
uint8_t _frameId;
|
||||
|
||||
uint8_t _respCd;
|
||||
uint8_t _respId;
|
||||
uint8_t _dataLen;
|
||||
};
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
class SensorNetwork: public XBee
|
||||
{
|
||||
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* getType(void);
|
||||
|
||||
SensorNetAddress* getSenderAddress(void)
|
||||
{
|
||||
return &_clientAddr;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
SensorNetAddress _clientAddr; // Sender's address. not gateway's one.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SENSORNETWORKX_H_ */
|
||||
Reference in New Issue
Block a user