Add Bluetooth classic as a sensor network #69, #195, #90

I think the architecture of the ble sensor network, which does not use
threads per socket, can be applied to DTLS.

Known bug:
Occasionally a timeout error occurs when connecting to RFCOMM.
BLE is not supported yet. I need help to do it.


Signed-off-by: tomoaki <tomoaki@tomy-tech.com>
This commit is contained in:
tomoaki
2021-06-02 20:15:52 +09:00
parent 982e6d4884
commit 55128f0f0e
54 changed files with 1764 additions and 934 deletions

View File

@@ -20,6 +20,7 @@ CPPSRCS := \
$(SUBDIR)/LGwProxy.cpp \
$(SUBDIR)/LMqttsnClient.cpp \
$(SUBDIR)/LNetworkUdp.cpp \
$(SUBDIR)/LNetworkBle.cpp \
$(SUBDIR)/LPublishManager.cpp \
$(SUBDIR)/LRegisterManager.cpp \
$(SUBDIR)/LSubscribeManager.cpp \
@@ -41,7 +42,7 @@ DEFS :=
LIBS +=
LDFLAGS :=
CXXFLAGS := -Wall -O3 -std=c++11
LDADD :=
LDADD := -lbluetooth
OUTDIR := Build
PROG := $(OUTDIR)/$(PROGTEST)

View File

@@ -1,7 +1,7 @@
###Gateway Test Program.
# Gateway Test Program.
**sample/mainTest.cpp** is a Test sample coading.
Each test is described as one function. test1(), test2()...
````
```
/*------------------------------------------------------
* Test functions
*
@@ -25,37 +25,51 @@ Each test is described as one function. test1(), test2()...
void test1(void)
{
char payload[300];
sprintf(payload, "ESP8266-08b133 ");
uint8_t qos = 0;
PUBLISH(topic1,(uint8_t*)payload, strlen(payload), qos);
char payload[300];
sprintf(payload, "ESP8266-08b133 ");
uint8_t qos = 0;
PUBLISH(topic1,(uint8_t*)payload, strlen(payload), qos);
}
void test2(void)
{
uint8_t qos = 1;
SUBSCRIBE(topic2, on_publish02, qos);
uint8_t qos = 1;
SUBSCRIBE(topic2, on_publish02, qos);
}
````
```
**TEST_LIST** is a test senario. Test functions are executed one by one.
````
```
/*------------------------------------------------------
* A List of Test Tasks
*------------------------------------------------------*/
TEST_LIST = {// e.g. TEST( Label, Test),
TEST("Publish topic1", test1),
TEST("Subscribe topic2", test2),
TEST("Publish topic2", test3),
TEST("Unsubscribe topic2", test4),
TEST("Publish topic2", test3),
TEST("Disconnect", test5),
END_OF_TEST_LIST
};
````
TEST("Publish topic1", test1),
TEST("Subscribe topic2", test2),
TEST("Publish topic2", test3),
TEST("Unsubscribe topic2", test4),
TEST("Publish topic2", test3),
TEST("Disconnect", test5),
END_OF_TEST_LIST
};
```
## step1. Define a sensor network
### **step1. Build **
````
**UDP** or **Bluetooth** is available as a sensor network.
Uncomment a line \#define UDP or BLE in LMqttsnClientApp.h file.
```
/*======================================
* Program mode Flag
======================================*/
//#define CLIENT_MODE
#define UDP
//#define BLE
```
## step2. Build
```
$ git clone https://github.com/eclipse/paho.mqtt-sn.embedded-c
$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway/GatewayTester
$ make
@@ -65,9 +79,9 @@ $ make clean
MQTT-SNGatewayTester program is copied into ../../../ directory.
### **step2. Execute Gateway Tester.**
## **step3. Execute Gateway Tester.**
````
```
$ cd ../../..
$ ./MQTT-SNGatewayTester
@@ -116,4 +130,4 @@ recved 192.168.11.17 :10000 08 13 20 00 01 00 01 00
Execute Publish topic1 Test ? ( Y/N ) :
````
```

View File

@@ -58,6 +58,14 @@ UDPCONF = {
20010, // Local PortNo
};
/*------------------------------------------------------
* BLE Configuration (theNetcon)
*------------------------------------------------------*/
BLECONF = { "GatewayTestClient", // ClientId
{ 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address
1, // Rfcomm channel
};
/*------------------------------------------------------
* Client Configuration (theMqcon)
*------------------------------------------------------*/

View File

@@ -58,6 +58,14 @@ UDPCONF = {
20001, // Local PortNo
};
/*------------------------------------------------------
* BLE Configuration (theNetcon)
*------------------------------------------------------*/
BLECONF = { "GatewayTestClient", // ClientId
{ 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address
1, // Rfcomm channel
};
/*------------------------------------------------------
* Client Configuration (theMqcon)
*------------------------------------------------------*/

View File

@@ -58,6 +58,14 @@ UDPCONF = {
20011, // Local PortNo
};
/*------------------------------------------------------
* BLE Configuration (theNetcon)
*------------------------------------------------------*/
BLECONF = { "GatewayTestClient", // ClientId
{ 0x44, 0x1C, 0xA8, 0x16, 0x94, 0x94 }, // GW Address
1, // Rfcomm channel
};
/*------------------------------------------------------
* Client Configuration (theMqcon)
*------------------------------------------------------*/

View File

@@ -51,25 +51,31 @@ extern LScreen* theScreen;
/*------------------------------------------------------
* UDP Configuration (theNetcon)
*------------------------------------------------------*/
UDPCONF =
{ "GatewayTestClient", // ClientId
UDPCONF = { "GatewayTestClient", // ClientId
{ 225, 1, 1, 1 }, // Multicast group IP
1883, // Multicast group Port
20020, // Local PortNo
};
1883, // Multicast group Port
20020, // Local PortNo
};
/*------------------------------------------------------
* BLE Configuration (theNetcon)
*------------------------------------------------------*/
BLECONF = { "GatewayTestClient", // ClientId
{ 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address
1, // Rfcomm channel
};
/*------------------------------------------------------
* Client Configuration (theMqcon)
*------------------------------------------------------*/
MQTTSNCONF =
{ 60, //KeepAlive [seconds]
true, //Clean session
300, //Sleep duration [seconds]
"", //WillTopic
"", //WillMessage
0, //WillQos
false //WillRetain
};
MQTTSNCONF = { 60, //KeepAlive [seconds]
true, //Clean session
300, //Sleep duration [seconds]
"", //WillTopic
"", //WillMessage
0, //WillQos
false //WillRetain
};
/*------------------------------------------------------
* Define Topics

View File

@@ -66,7 +66,7 @@ LGwProxy::~LGwProxy()
_topicTbl.clearTopic();
}
void LGwProxy::initialize(LUdpConfig netconf, LMqttsnConfig mqconf)
void LGwProxy::initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf)
{
_network.initialize(netconf);
_clientId = netconf.clientId;
@@ -87,6 +87,12 @@ void LGwProxy::connect()
{
pos = _msg;
if (!_network.isBroadcastable() && _status == GW_LOST)
{
_status = GW_CONNECTING;
continue;
}
if (_status == GW_LOST)
{

View File

@@ -23,6 +23,7 @@
#include "LMqttsnClientApp.h"
#include "LNetworkUdp.h"
#include "LNetworkBle.h"
#include "LRegisterManager.h"
#include "LTimer.h"
#include "LTopicTable.h"
@@ -54,7 +55,7 @@ public:
LGwProxy();
~LGwProxy();
void initialize(LUdpConfig netconf, LMqttsnConfig mqconf);
void initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf);
void connect(void);
void disconnect(uint16_t sec = 0);
int getMessage(void);

View File

@@ -29,7 +29,7 @@ extern TaskList theTaskList[];
extern TestList theTestList[];
extern OnPublishList theOnPublishList[];
extern MQTTSNCONF;
extern UDPCONF;
extern SENSORNET_CONFIG_t theNetcon;
extern void setup(void);
/*=====================================
@@ -50,7 +50,14 @@ int main(int argc, char** argv)
#ifndef CLIENT_MODE
char c = 0;
printf("\n%s", PAHO_COPYRIGHT4);
printf("\n%s\n", PAHO_COPYRIGHT0);
printf("\n%s", PAHO_COPYRIGHT0);
#if defined(UDP)
printf(" UDP\n");
#elif defined(BLE)
printf(" BLE\n");
#else
printf("\n");
#endif
printf("%s\n", PAHO_COPYRIGHT1);
printf("%s\n", PAHO_COPYRIGHT2);
printf(" *\n%s\n", PAHO_COPYRIGHT3);
@@ -108,7 +115,7 @@ LMqttsnClient::~LMqttsnClient()
}
void LMqttsnClient::initialize(LUdpConfig netconf, LMqttsnConfig mqconf)
void LMqttsnClient::initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf)
{
_gwProxy.initialize(netconf, mqconf);
setSleepDuration(mqconf.sleepDuration);

View File

@@ -58,7 +58,7 @@ public:
void unsubscribe(const char* topicName);
void unsubscribe(const uint16_t topicId);
void disconnect(uint16_t sleepInSecs);
void initialize(LUdpConfig netconf, LMqttsnConfig mqconf);
void initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf);
void run(void);
void addTask(bool test);
void setSleepDuration(uint32_t duration);

View File

@@ -21,11 +21,12 @@
* Program mode Flag
======================================*/
//#define CLIENT_MODE
#define UDP
//#define BLE
/*======================================
* Debug Flag
======================================*/
//#define DEBUG_NW
#define DEBUG_NW
//#define DEBUG_MQTTSN
/****************************************
@@ -55,7 +56,8 @@ typedef signed int int32_t;
Application config structures
*****************************************/
struct LMqttsnConfig{
struct LMqttsnConfig
{
uint16_t keepAlive;
bool cleanSession;
uint32_t sleepDuration;
@@ -65,13 +67,21 @@ struct LMqttsnConfig{
bool willRetain;
};
struct LUdpConfig{
struct LUdpConfig
{
const char* clientId;
uint8_t ipAddress[4];
uint16_t gPortNo;
uint16_t uPortNo;
};
struct LBleConfig
{
const char* clientId;
uint8_t gwAddress[6];
uint8_t channel;
};
typedef enum
{
@@ -85,7 +95,19 @@ typedef enum
MACROs for Application
=======================================*/
#define MQTTSN_CONFIG MqttsnConfig theMqttsnConfig
#define MQTTSNCONF LMqttsnConfig theMqcon
#ifdef UDP
#define NETWORK_CONFIG UdpConfig theNetworkConfig
#define UDPCONF LUdpConfig theNetcon
#define BLECONF LBleConfig theConf
#define SENSORNET_CONFIG_t LUdpConfig
#else
#define NETWORK_CONFIG BleConfig theNetworkConfig
#define BLECONF LBleConfig theNetcon
#define UDPCONF LUdpConfig theConf
#define SENSORNET_CONFIG_t LBleConfig
#endif
#define CONNECT(...) theClient->getGwProxy()->connect(__VA_ARGS__)
#define PUBLISH(...) theClient->publish(__VA_ARGS__)
@@ -104,8 +126,7 @@ typedef enum
#define SUBSCRIBE_LIST OnPublishList theOnPublishList[]
#define SUB(...) {__VA_ARGS__}
#define END_OF_SUBSCRIBE_LIST {MQTTSN_TOPIC_TYPE_NORMAL,0,0,0, 0}
#define UDPCONF LUdpConfig theNetcon
#define MQTTSNCONF LMqttsnConfig theMqcon
#define SetForwarderMode(...) theClient->getGwProxy()->setForwarderMode(__VA_ARGS__)
#define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__)

View File

@@ -0,0 +1,295 @@
/**************************************************************************************
* Copyright (c) 2021, 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 "LMqttsnClientApp.h"
#ifdef BLE
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include "LNetworkBle.h"
#include "LTimer.h"
#include "LScreen.h"
using namespace std;
using namespace linuxAsyncClient;
extern uint16_t getUint16(const uint8_t* pos);
extern uint32_t getUint32(const uint8_t* pos);
extern LScreen* theScreen;
extern bool theClientMode;
extern LBleConfig theNetcon;
/*=========================================
Class LNetwork
=========================================*/
LNetwork::LNetwork()
{
_sleepflg = false;
_returnCode = 0;
}
LNetwork::~LNetwork()
{
}
int LNetwork::broadcast(const uint8_t* xmitData, uint16_t dataLen)
{
return LBlePort::unicast(xmitData, dataLen);
}
int LNetwork::unicast(const uint8_t* xmitData, uint16_t dataLen)
{
return LBlePort::unicast(xmitData, dataLen);
}
uint8_t* LNetwork::getMessage(int* len)
{
*len = 0;
if (checkRecvBuf())
{
uint16_t recvLen = LBlePort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false);
if (recvLen < 0)
{
*len = recvLen;
return 0;
}
else
{
if (_rxDataBuf[0] == 0x01)
{
*len = getUint16(_rxDataBuf + 1);
}
else
{
*len = _rxDataBuf[0];
}
//if(recvLen != *len){
// *len = 0;
// return 0;
//}else{
return _rxDataBuf;
//}
}
}
return 0;
}
void LNetwork::setGwAddress(void)
{
}
void LNetwork::setFixedGwAddress(void)
{
_channel = LBlePort::_channel;
memcpy(_gwAddress, theNetcon.gwAddress, 6);
}
bool LNetwork::initialize(LBleConfig config)
{
return LBlePort::open(config);
}
void LNetwork::setSleep()
{
_sleepflg = true;
}
bool LNetwork::isBroadcastable()
{
return false;
}
/*=========================================
Class BleStack
=========================================*/
LBlePort::LBlePort()
{
_disconReq = false;
_sockBle = 0;
_channel = 0;
}
LBlePort::~LBlePort()
{
close();
}
void LBlePort::close()
{
if (_sockBle > 0)
{
::close(_sockBle);
_sockBle = 0;
}
}
bool LBlePort::open(LBleConfig config)
{
const int reuse = 1;
uint8_t* gw = config.gwAddress + 5;
for (int i = 0; i < 6; i++)
{
*(_gwAddress + i) = *gw--;
}
_channel = config.channel;
if (_channel == 0 || _gwAddress == 0 || _devAddress == 0)
{
D_NWLOG("\033[0m\033[0;31merror BLE Address in BlePort::open\033[0m\033[0;37m\n");
DISPLAY("\033[0m\033[0;31m\nerror BLE Address in BlePort::open\033[0m\033[0;37m\n");
return false;
}
_sockBle = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
if (_sockBle < 0)
{
D_NWLOG("\033[0m\033[0;31merror Can't create socket in BlePort::open\033[0m\033[0;37m\n");
DISPLAY("\033[0m\033[0;31m\nerror Can't create socket in BlePort::open\033[0m\033[0;37m\n");
return false;
}
setsockopt(_sockBle, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
struct sockaddr_rc addru = { 0 };
addru.rc_family = AF_BLUETOOTH;
addru.rc_channel = _channel;
memcpy(&addru.rc_bdaddr, _gwAddress, 6);
char bufgw[30];
ba2str(&addru.rc_bdaddr, bufgw);
DISPLAY("GW MAC = %s RFCOMM CH = %d\n", bufgw, addru.rc_channel);
// connect to server
errno = 0;
int status = connect(_sockBle, (struct sockaddr *) &addru, sizeof(addru));
if (status < 0)
{
D_NWLOG("\033[0m\033[0;31merror = %d Can't connect to GW in BlePort::open\033[0m\033[0;37m\n", errno);
DISPLAY("\033[0m\033[0;31mCan't connect to GW Ble socket in BlePort::open\033[0m\033[0;37m\n");
close();
return false;
}
return true;
}
int LBlePort::unicast(const uint8_t* buf, uint32_t length)
{
int status = ::write(_sockBle, buf, length);
if (status < 0)
{
D_NWLOG("errno == %d in LBlePort::unicast\n", errno);
DISPLAY("errno == %d in LBlePort::unicast\n", errno);
}
else
{
D_NWLOG("sendto %-2d", _channel);
for (uint16_t i = 0; i < length; i++)
{
D_NWLOG(" %02x", *(buf + i));
}
D_NWLOG("\n");
if (!theClientMode)
{
char sbuf[SCREEN_BUFF_SIZE];
int pos = 0;
sprintf(sbuf, "\033[0;34msendto %-2dch", _channel);
pos = strlen(sbuf);
for (uint16_t i = 0; i < length; i++)
{
sprintf(sbuf + pos, " %02x", *(buf + i));
if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) // -20 for Escape sequence
{
break;
}
pos += 3;
}
sprintf(sbuf + strlen(sbuf), "\033[0;37m\n");
theScreen->display(sbuf);
}
}
return status;
}
bool LBlePort::checkRecvBuf()
{
uint8_t buf[2];
if (::recv(_sockBle, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0)
{
return true;
}
return false;
}
int LBlePort::recv(uint8_t* buf, uint16_t length, bool flg)
{
int flags = flg ? MSG_DONTWAIT : 0;
int status = ::recv(_sockBle, buf, length, flags);
if (status < 0 && errno != EAGAIN)
{
D_NWLOG("\033[0m\033[0;31merrno == %d in BlePort::recv \033[0m\033[0;37m\n", errno);
DISPLAY("\033[0m\033[0;31merrno == %d in BlePort::recv \033[0m\033[0;37m\n", errno);
}
else if (status > 0)
{
D_NWLOG("\nrecved ");
for (uint16_t i = 0; i < status; i++)
{
D_NWLOG(" %02x", *(buf + i));
}
D_NWLOG("\n");
if (!theClientMode)
{
char sbuf[SCREEN_BUFF_SIZE];
int pos = 0;
sprintf(sbuf, "\033[0;34mrecved ");
pos = strlen(sbuf);
for (uint16_t i = 0; i < status; i++)
{
sprintf(sbuf + pos, " %02x", *(buf + i));
if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20)
{
break;
}
pos += 3;
}
sprintf(sbuf + strlen(sbuf), "\033[0;37m\n");
theScreen->display(sbuf);
}
return status;
}
else
{
return 0;
}
return status;
}
#endif

View File

@@ -0,0 +1,106 @@
/**************************************************************************************
* Copyright (c) 2021, 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 NETWORKBLE_H_
#define NETWORKBLE_H_
#include "LMqttsnClientApp.h"
#ifdef BLE
#include <sys/time.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string>
#include <bluetooth/bluetooth.h>
#define SOCKET_MAXHOSTNAME 200
#define SOCKET_MAXCONNECTIONS 5
#define SOCKET_MAXRECV 500
#define SOCKET_MAXBUFFER_LENGTH 500 // buffer size
#define STAT_UNICAST 1
#define STAT_MULTICAST 2
using namespace std;
namespace linuxAsyncClient
{
/*========================================
Class LBlePort
=======================================*/
class LBlePort
{
friend class LNetwork;
public:
LBlePort();
virtual ~LBlePort();
bool open(LBleConfig config);
int unicast(const uint8_t* buf, uint32_t length);
int recv(uint8_t* buf, uint16_t len, bool nonblock);
bool checkRecvBuf();
bool isUnicast();
private:
void close();
int _sockBle;
uint8_t _devAddress[6];
uint8_t _gwAddress[6];
uint8_t _channel;
bool _disconReq;
};
#define NO_ERROR 0
#define PACKET_EXCEEDS_LENGTH 1
/*===========================================
Class Network
============================================*/
class LNetwork: public LBlePort
{
public:
LNetwork();
~LNetwork();
int broadcast(const uint8_t* payload, uint16_t payloadLen);
int unicast(const uint8_t* payload, uint16_t payloadLen);
void setGwAddress(void);
void resetGwAddress(void);
void setFixedGwAddress(void);
bool initialize(LBleConfig config);
uint8_t* getMessage(int* len);
bool isBroadcastable();
private:
void setSleep();
int readApiFrame(void);
int _returnCode;
bool _sleepflg;
uint8_t _rxDataBuf[MQTTSN_MAX_PACKET_SIZE + 1]; // defined in MqttsnClientApp.h
};
} /* end of namespace */
#endif /* BLE */
#endif /* NETWORKBLE_H_ */

View File

@@ -13,6 +13,8 @@
* Contributors:
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
**************************************************************************************/
#include "LMqttsnClientApp.h"
#ifdef UDP
#include <stdio.h>
#include <sys/time.h>
@@ -29,7 +31,6 @@
#include "LTimer.h"
#include "LScreen.h"
#include "LMqttsnClientApp.h"
using namespace std;
using namespace linuxAsyncClient;
@@ -111,6 +112,10 @@ void LNetwork::setSleep(){
_sleepflg = true;
}
bool LNetwork::isBroadcastable()
{
return true;
}
/*=========================================
Class udpStack
=========================================*/
@@ -385,5 +390,5 @@ int LUdpPort::recvfrom (uint8_t* buf, uint16_t length, int flags, uint32_t* ipAd
return status;
}
#endif

View File

@@ -17,6 +17,9 @@
#ifndef NETWORKUDP_H_
#define NETWORKUDP_H_
#include "LMqttsnClientApp.h"
#ifdef UDP
#include <sys/time.h>
#include <iostream>
#include <sys/types.h>
@@ -27,7 +30,6 @@
#include <string>
#include <arpa/inet.h>
#include "LMqttsnClientApp.h"
#define SOCKET_MAXHOSTNAME 200
#define SOCKET_MAXCONNECTIONS 5
@@ -89,6 +91,7 @@ public:
void setFixedGwAddress(void);
bool initialize(LUdpConfig config);
uint8_t* getMessage(int* len);
bool isBroadcastable();
private:
void setSleep();
int readApiFrame(void);
@@ -103,6 +106,6 @@ private:
};
} /* end of namespace */
#endif /* UDP */
#endif /* NETWORKUDP_H_ */