V1.1.0 Update
This commit is contained in:
parent
9dd60e1ca5
commit
8c7e5b75f1
17
README.md
17
README.md
|
@ -1,15 +1,17 @@
|
|||
# DLLN3X_zigbee_mesh_module_library
|
||||
This library allows you to use DLLN3X ZigBee mesh module very easily.
|
||||
|
||||
This library is now complete, the remaining work is mainly maintenance and bug fixes, welcome feedback by opening issues.
|
||||
|
||||
# Available Features
|
||||
|
||||
1. Basic message sending and receiving.
|
||||
2. Module address reading.
|
||||
3. On-chip red led flashing control.
|
||||
4. Configuration reading, modification (baud rate, address, etc.).(TODO)
|
||||
5. Error Report.(TODO)
|
||||
6. Link quality test.(TODO)
|
||||
7. On-chip pin control.(TODO)
|
||||
4. Configuration reading, modification (baud rate, address, etc.).
|
||||
5. Error Report.
|
||||
6. Link quality test.
|
||||
7. On-chip pin control.
|
||||
|
||||
# Example run results
|
||||
|
||||
|
@ -17,6 +19,13 @@ This library allows you to use DLLN3X ZigBee mesh module very easily.
|
|||
|
||||
# Change Log
|
||||
|
||||
**V1.1.0 2023.3.18**
|
||||
|
||||
+ Completely rewritten.
|
||||
+ Join the ZigbeeFrame container.
|
||||
+ Greatly improve stability.
|
||||
+ Supports configuration reading and modification, link quality testing, on-board pin control, error reporting, etc.
|
||||
|
||||
**V1.0.4 2023.1.26**
|
||||
|
||||
- Bug fixes and stability improvements.
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
#include "DLLN3X.h"
|
||||
|
||||
using namespace zigbee_protocol;
|
||||
|
||||
DLLN3X dlln33; //Instantiating DLLN3X module
|
||||
zigbee_frame zframe;
|
||||
void zigbee_call_back(uint8_t orig_port,
|
||||
uint8_t dest_port, uint16_t addr,
|
||||
uint8_t data[], int length) {
|
||||
switch (dest_port) {
|
||||
void zigbee_call_back(ZigbeeFrame &zframe) {
|
||||
switch (zframe.getDesPort()) {
|
||||
case 0x82:
|
||||
{
|
||||
/* Do everything you want to do */
|
||||
char temp[200];
|
||||
sprintf(temp, "Hello from port 0x%X: %s",orig_port,data);
|
||||
sprintf(temp, "Hello from port 0x%X: %.*s",zframe.getSrcPort(),zframe.getDataLength(),zframe.getData().data());
|
||||
Serial.println(temp);
|
||||
break;
|
||||
}
|
||||
|
@ -30,21 +29,32 @@ void setup() {
|
|||
Serial.println("Waiting for DLLN3X to connect........");
|
||||
delay(1000);
|
||||
}
|
||||
char temp[20];
|
||||
char temp[50];
|
||||
sprintf(temp, "DLLN3X addr: 0x%04X.",dlln33.read_addr());
|
||||
Serial.println(temp);
|
||||
sprintf(temp, "DLLN3X network id: 0x%04X.",dlln33.read_network_id());
|
||||
Serial.println(temp);
|
||||
sprintf(temp, "DLLN3X channel: 0x%02X.",dlln33.read_channel());
|
||||
Serial.println(temp);
|
||||
sprintf(temp, "DLLN3X baud rate: %d.",dlln33.read_baudrate());
|
||||
Serial.println(temp);
|
||||
dlln33.set_addr(0xFFFF); //test error report
|
||||
//dlln33.get_link_quality(YOUR_ANOTHER_CHIP_ADDR); //test link quility
|
||||
dlln33.pin_control(DLLN3X::PIN::PIN4, DLLN3X::PIN_CONTROL::HIGH); //test pin, PIN4 is TTx, PIN5 is TRx
|
||||
}
|
||||
|
||||
uint64_t interval = 5000, pre_milli = 0;
|
||||
void loop() {
|
||||
dlln33.loop();
|
||||
if (millis() - pre_milli >= interval) {
|
||||
zframe.src_port = 0x81;
|
||||
zframe.des_port = 0x82;
|
||||
*((uint16_t *)&zframe.remote_addrL) = dlln33.read_addr(); // send pkg to self.
|
||||
strncpy((char*)zframe.data,"Hello to port 0x82!",19);
|
||||
zframe.length = 19;
|
||||
dlln33.send(&zframe);
|
||||
ZigbeeFrame zf;
|
||||
zf.setSrcPort(0x81);
|
||||
zf.setDesPort(0x82);
|
||||
zf.setRemoteAddr(dlln33.read_addr());
|
||||
zf.setData("Hello to port 0x82!");
|
||||
dlln33.send(zf);
|
||||
zf = zf + "I'm port 0x81!";
|
||||
dlln33.send(zf);
|
||||
pre_milli = millis();
|
||||
}
|
||||
}
|
BIN
imgs/example.png
BIN
imgs/example.png
Binary file not shown.
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 98 KiB |
41
keywords.txt
41
keywords.txt
|
@ -7,24 +7,53 @@
|
|||
#######################################
|
||||
|
||||
DLLN3X KEYWORD1
|
||||
zigbee_frame KEYWORD1
|
||||
ZigbeeFrame KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
_clear KEYWORD2
|
||||
_pack KEYWORD2
|
||||
_depack KEYWORD2
|
||||
_callback KEYWORD2
|
||||
setDesPort KEYWORD2
|
||||
setSrcPort KEYWORD2
|
||||
setRemoteAddr KEYWORD2
|
||||
getDesPort KEYWORD2
|
||||
getSrcPort KEYWORD2
|
||||
getRemoteAddr KEYWORD2
|
||||
getLength KEYWORD2
|
||||
getDataLength KEYWORD2
|
||||
getData KEYWORD2
|
||||
setData KEYWORD2
|
||||
addData KEYWORD2
|
||||
clear KEYWORD2
|
||||
data KEYWORD2
|
||||
data_size KEYWORD2
|
||||
size KEYWORD2
|
||||
append KEYWORD2
|
||||
pack KEYWORD2
|
||||
depack KEYWORD2
|
||||
make_package KEYWORD2
|
||||
get_package KEYWORD2
|
||||
load_package KEYWORD2
|
||||
print KEYWORD2
|
||||
init KEYWORD2
|
||||
recv KEYWORD2
|
||||
send KEYWORD2
|
||||
send_cmd KEYWORD2
|
||||
rled_blink KEYWORD2
|
||||
loop KEYWORD2
|
||||
setcallback KEYWORD2
|
||||
rw_config KEYWORD2
|
||||
read_network_id KEYWORD2
|
||||
set_network_id KEYWORD2
|
||||
read_channel KEYWORD2
|
||||
set_channel KEYWORD2
|
||||
read_addr KEYWORD2
|
||||
|
||||
set_addr KEYWORD2
|
||||
read_baudrate KEYWORD2
|
||||
set_baudrate KEYWORD2
|
||||
soft_reboot KEYWORD2
|
||||
get_link_quality KEYWORD2
|
||||
pin_control KEYWORD2
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
name= DLLN3X ZigBee Mesh Module Library
|
||||
version= 1.0.4
|
||||
version= 1.1.0
|
||||
author= Dylan Liu <mentalflow@ourdocs.cn>
|
||||
maintainer= Dylan Liu <mentalflow@ourdocs.cn>
|
||||
sentence= This library allows you to use DLLN3X ZigBee mesh module very easily.
|
||||
paragraph= This library currently allows basic send and receive operations using the DLLN3X module, with more features to come.
|
||||
paragraph= This library currently allows basic send and receive operations, config read/modify, link quility test, pin control and more.
|
||||
category= Communication
|
||||
architectures= *
|
||||
includes= DLLN3X.h
|
||||
includes= DLLN3X.h zigbeeframe.h
|
||||
license= MIT
|
||||
url= https://github.com/mentalfl0w/DLLN3X_zigbee_mesh_module_library
|
||||
|
|
398
src/DLLN3X.cpp
398
src/DLLN3X.cpp
|
@ -1,218 +1,290 @@
|
|||
#include "DLLN3X.h"
|
||||
|
||||
DLLN3X::DLLN3X(){}
|
||||
DLLN3X::~DLLN3X() {}
|
||||
using namespace zigbee_protocol;
|
||||
|
||||
void DLLN3X::init(HardwareSerial *DSerial)
|
||||
DLLN3X::DLLN3X() { }
|
||||
DLLN3X::~DLLN3X() { }
|
||||
|
||||
void DLLN3X::init(HardwareSerial* DSerial)
|
||||
{
|
||||
_DSerial = DSerial;
|
||||
DSerial->begin(115200);
|
||||
DSerial->setTimeout(10000);
|
||||
rled_blink();
|
||||
read_addr();
|
||||
read_baudrate();
|
||||
read_channel();
|
||||
read_network_id();
|
||||
}
|
||||
|
||||
void DLLN3X::init(SoftwareSerial *DSerial)
|
||||
#if __has_include(<SoftwareSerial.h>)
|
||||
void DLLN3X::init(SoftwareSerial* DSerial)
|
||||
{
|
||||
_DSerial = DSerial;
|
||||
DSerial->begin(115200);
|
||||
DSerial->setTimeout(10000);
|
||||
rled_blink();
|
||||
read_addr();
|
||||
read_baudrate();
|
||||
read_channel();
|
||||
read_network_id();
|
||||
}
|
||||
#endif
|
||||
|
||||
void DLLN3X::_clear()
|
||||
ZigbeeFrame DLLN3X::recv(bool non_blocked)
|
||||
{
|
||||
while (_DSerial->available())
|
||||
_DSerial->read();
|
||||
}
|
||||
|
||||
int DLLN3X::_pack(uint8_t buf[], uint8_t data[], int length)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (data[i] == 0xFE)
|
||||
{
|
||||
buf[count++] = data[i];
|
||||
buf[count++] = 0xFC;
|
||||
uint8_t buf[65] = "", length = 0;
|
||||
ZigbeeFrame zf;
|
||||
if (non_blocked) {
|
||||
if (_DSerial->available() < 6)
|
||||
return zf;
|
||||
}
|
||||
else if (data[i] == 0xFF)
|
||||
{
|
||||
buf[count++] = 0xFE;
|
||||
buf[count++] = 0xFD;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[count++] = data[i];
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int DLLN3X::_depack(uint8_t buf[], uint8_t data[], int length)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (buf[i] != 0xFE)
|
||||
{
|
||||
data[count++] = buf[i];
|
||||
}
|
||||
else if (buf[i + 1] == 0xFD)
|
||||
{
|
||||
data[count++] = 0xFF;
|
||||
i++;
|
||||
}
|
||||
else if (buf[i + 1] == 0xFC)
|
||||
{
|
||||
data[count++] = 0xFE;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void DLLN3X::recv(zigbee_frame *frame)
|
||||
{
|
||||
_recv_lock = true;
|
||||
_DSerial->readBytesUntil(0xFF, (char *)frame, 64);
|
||||
_DSerial->read();
|
||||
length = _DSerial->readBytesUntil(0xFF, buf, 65);
|
||||
buf[length] = _DSerial->read();
|
||||
_recv_lock = false;
|
||||
zf.load_package(buf, length + 1);
|
||||
return zf;
|
||||
}
|
||||
|
||||
bool DLLN3X::recv(uint8_t *orig_port,
|
||||
uint8_t *dest_port, uint16_t *addr,
|
||||
uint8_t data[], int *length)
|
||||
bool DLLN3X::send(ZigbeeFrame zf)
|
||||
{
|
||||
_recv_lock = true;
|
||||
uint8_t buf[200] = "";
|
||||
uint8_t head = 0, tail = 0;
|
||||
if(_DSerial->available()<6)
|
||||
if (zf.getSrcPort() < 0x80)
|
||||
return false;
|
||||
head = _DSerial->read();
|
||||
if (head == 0xFE)
|
||||
{
|
||||
*length = _DSerial->read();
|
||||
*length -= 4;
|
||||
*orig_port = _DSerial->read();
|
||||
*dest_port = _DSerial->read();
|
||||
*addr = _DSerial->read();
|
||||
*addr += _DSerial->read() << 8;
|
||||
int count = 0;
|
||||
for (int i = 0; i < *length; i++)
|
||||
{
|
||||
while(_DSerial->available()<1);
|
||||
buf[count++] = _DSerial->read();
|
||||
if (buf[count-1]==0xFE)
|
||||
{
|
||||
while(_DSerial->available()<1);
|
||||
buf[count++]=_DSerial->read();
|
||||
}
|
||||
}
|
||||
*length = count;
|
||||
while(_DSerial->available()<1);
|
||||
_DSerial->read(); // read pkg tail
|
||||
*length = _depack(buf, data, *length);
|
||||
_recv_lock = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_recv_lock = false;
|
||||
return false;
|
||||
}
|
||||
return _DSerial->write(zf.data(), zf.size());
|
||||
}
|
||||
|
||||
bool DLLN3X::send(uint8_t orig_port,
|
||||
uint8_t dest_port, uint16_t addr,
|
||||
uint8_t data[], int length)
|
||||
bool DLLN3X::send_cmd(uint8_t des_port, uint8_t arg, uint8_t* data, uint8_t data_length)
|
||||
{
|
||||
if (orig_port<0x80)
|
||||
ZigbeeFrame zf(0x80, des_port, 0x0000);
|
||||
if (data_length - 4 > 63 - 1)
|
||||
return false;
|
||||
uint8_t send_buf[208] = {0xFE}, buf[200] = "";
|
||||
uint8_t head = 0, buf_length = 0;
|
||||
buf_length = _pack(buf, data, length);
|
||||
send_buf[1] = length+4;
|
||||
send_buf[2] = orig_port;
|
||||
send_buf[3] = dest_port;
|
||||
send_buf[4] = addr & 0xFF;
|
||||
send_buf[5] = (addr & 0xFF00) >> 8;
|
||||
memcpy(send_buf + 6, buf, buf_length);
|
||||
send_buf[6 + buf_length] = 0xFF;
|
||||
return _DSerial->write(send_buf, buf_length + 7);
|
||||
zf.append(arg);
|
||||
zf.addData(data, data_length);
|
||||
return send(zf);
|
||||
}
|
||||
|
||||
bool DLLN3X::send(zigbee_frame *frame)
|
||||
{
|
||||
return send(frame->src_port, frame->des_port, (frame->remote_addrH << 8) | (frame->remote_addrL & 0xFF),
|
||||
frame->data, frame->length);
|
||||
}
|
||||
|
||||
void DLLN3X::rled_blink(uint8_t orig_port, uint16_t addr, uint8_t time)
|
||||
void DLLN3X::rled_blink(uint8_t time)
|
||||
{
|
||||
uint8_t gap = 5;
|
||||
for (int i = 0; i < time; i += gap)
|
||||
{
|
||||
if (i%2!=0)
|
||||
send(orig_port, 0x20, addr, &gap, 1);
|
||||
for (int i = 0; i < time; i += gap) {
|
||||
if (i % 2 != 0)
|
||||
send_cmd(0x20, gap);
|
||||
else
|
||||
delay(gap*200);
|
||||
delay(gap * 250);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t DLLN3X::read_addr()
|
||||
{
|
||||
if (self_addr!=0)
|
||||
return self_addr;
|
||||
uint8_t orig_port = 0xFF, dest_port = 0xFF;
|
||||
uint8_t arg = 0x01;
|
||||
uint16_t addr = 0xFFFF;
|
||||
uint8_t data[60] = "";
|
||||
int length = 0;
|
||||
send(0x80, 0x21, 0x0000, &arg, 1);
|
||||
while(_DSerial->available()<10);
|
||||
_recv_lock = true;
|
||||
recv(&orig_port, &dest_port, &addr, data, &length);
|
||||
_recv_lock = false;
|
||||
if (orig_port!=0x21||dest_port!=0x80||addr !=0x0000||length!=3||data[0]!=0x21)
|
||||
if (_self_addr != 0)
|
||||
return _self_addr;
|
||||
_self_addr = rw_config(CONFIG::ADDR);
|
||||
return _self_addr;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::set_addr(uint16_t addr)
|
||||
{
|
||||
uint8_t resp = rw_config(CONFIG::ADDR, addr, CONFIG_RW_MASK::WRITE);
|
||||
if (resp == CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
return 0;
|
||||
_self_addr = addr;
|
||||
soft_reboot();
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
uint32_t DLLN3X::read_baudrate()
|
||||
{
|
||||
if (_self_baud_rate != 0)
|
||||
return _self_baud_rate;
|
||||
uint8_t arg = rw_config(CONFIG::BAUDRATE);
|
||||
_self_baud_rate = _baud_rate_list[arg];
|
||||
return _self_baud_rate;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::set_baudrate(uint32_t baud_rate)
|
||||
{
|
||||
uint8_t arg = 0;
|
||||
for (uint8_t i = 0; i < 13; i++)
|
||||
{
|
||||
if (baud_rate == _baud_rate_list[i])
|
||||
{
|
||||
arg = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t resp = rw_config(CONFIG::BAUDRATE, arg, CONFIG_RW_MASK::WRITE);
|
||||
if (resp == CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
_self_baud_rate = baud_rate;
|
||||
soft_reboot();
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::read_network_id()
|
||||
{
|
||||
if (_self_network_id != 0)
|
||||
return _self_network_id;
|
||||
_self_network_id = rw_config(CONFIG::NETWORKID);
|
||||
return _self_network_id;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::set_network_id(uint16_t network_id)
|
||||
{
|
||||
uint8_t resp = rw_config(CONFIG::NETWORKID, network_id, CONFIG_RW_MASK::WRITE);
|
||||
if (resp == CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
_self_network_id = network_id;
|
||||
soft_reboot();
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::read_channel()
|
||||
{
|
||||
if (_self_channel != 0)
|
||||
return _self_channel;
|
||||
_self_channel = rw_config(CONFIG::CHANNEL);
|
||||
return _self_channel;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::set_channel(uint8_t channel)
|
||||
{
|
||||
uint8_t resp = rw_config(CONFIG::CHANNEL, channel, CONFIG_RW_MASK::WRITE);
|
||||
if (resp == CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
_self_channel = channel;
|
||||
soft_reboot();
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
uint16_t DLLN3X::rw_config(CONFIG arg, uint16_t data, CONFIG_RW_MASK mask)
|
||||
{
|
||||
uint8_t cmd_arg = arg|mask;
|
||||
if (mask == CONFIG_RW_MASK::WRITE)
|
||||
{
|
||||
if (arg == CONFIG::ADDR || arg == CONFIG::NETWORKID)
|
||||
{
|
||||
send_cmd(0x21, cmd_arg, (uint8_t *)&data, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->self_addr = data[1] + (data[2] << 8);
|
||||
return this->self_addr;
|
||||
send_cmd(0x21, cmd_arg, (uint8_t *)&data, 1);
|
||||
}
|
||||
else
|
||||
send_cmd(0x21, cmd_arg);
|
||||
ZigbeeFrame zf = recv(false);
|
||||
if (zf.getSrcPort() != 0x21 || zf.getDesPort() != 0x80 || zf.getRemoteAddr() != 0x0000)
|
||||
return 0;
|
||||
switch (arg) {
|
||||
case CONFIG::ADDR: {
|
||||
if (zf.getDataLength() != 3 || zf.getData()[0] != 0x21) {
|
||||
if (zf.getData()[0] != CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
Serial.print("DLLN3X write config error: 0x");
|
||||
Serial.println(zf.getData()[0], HEX);
|
||||
}
|
||||
return zf.getData()[0];
|
||||
} else
|
||||
return (zf.getData()[2] << 8) | zf.getData()[1];
|
||||
}
|
||||
case CONFIG::NETWORKID: {
|
||||
if (zf.getDataLength() != 3 || zf.getData()[0] != 0x22) {
|
||||
if (zf.getData()[0] != CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
Serial.print("DLLN3X write config error: 0x");
|
||||
Serial.println(zf.getData()[0], HEX);
|
||||
}
|
||||
return zf.getData()[0];
|
||||
} else
|
||||
return (zf.getData()[2] << 8) | zf.getData()[1];
|
||||
}
|
||||
case CONFIG::CHANNEL: {
|
||||
if (zf.getDataLength() != 2 || zf.getData()[0] != 0x23) {
|
||||
if (zf.getData()[0] != CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
Serial.print("DLLN3X write config error: 0x");
|
||||
Serial.println(zf.getData()[0], HEX);
|
||||
}
|
||||
return zf.getData()[0];
|
||||
} else
|
||||
return zf.getData()[1];
|
||||
}
|
||||
case CONFIG::BAUDRATE: {
|
||||
if (zf.getDataLength() != 2 || zf.getData()[0] != 0x24) {
|
||||
if (zf.getData()[0] != CONFIG_RESPONSE::DONE)
|
||||
{
|
||||
Serial.print("DLLN3X write config error: 0x");
|
||||
Serial.println(zf.getData()[0], HEX);
|
||||
}
|
||||
return zf.getData()[0];
|
||||
} else
|
||||
return zf.getData()[1];
|
||||
}
|
||||
default:
|
||||
return CONFIG_RESPONSE::CMD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void DLLN3X::soft_reboot()
|
||||
{
|
||||
send_cmd(0x21, CONFIG::SOFT_REBOOT);
|
||||
_self_addr = 0;
|
||||
_self_baud_rate = 0;
|
||||
_self_channel = 0;
|
||||
_self_network_id = 0;
|
||||
}
|
||||
|
||||
uint8_t DLLN3X::get_link_quality(uint16_t des_addr, uint16_t src_addr)
|
||||
{
|
||||
if (des_addr == 0x0000 || des_addr == 0xFFFF)
|
||||
return CONFIG_RESPONSE::CMD_ERROR;
|
||||
ZigbeeFrame zf(0x80, 0x23, src_addr), r_zf;
|
||||
zf.addData((uint8_t *)&des_addr, 2);
|
||||
r_zf = recv(false);
|
||||
uint16_t pkg_des_addr = (r_zf.getData()[1] << 8) | r_zf.getData()[0];
|
||||
if (pkg_des_addr != des_addr)
|
||||
return CONFIG_RESPONSE::PKG_DATA_ERROR;
|
||||
else
|
||||
return r_zf.getData()[2];
|
||||
}
|
||||
|
||||
enum DLLN3X::PIN_CONTROL DLLN3X::pin_control(PIN pin, PIN_CONTROL cmd)
|
||||
{
|
||||
send_cmd(pin, cmd);
|
||||
if (cmd == PIN_CONTROL::READ_PIN)
|
||||
{
|
||||
ZigbeeFrame zf = recv(false);
|
||||
return PIN_CONTROL(zf.getData()[0] ^ 0x10);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void DLLN3X::loop()
|
||||
{
|
||||
uint8_t orig_port = 0xFF, dest_port = 0xFF;
|
||||
uint16_t addr = 0xFFFF;
|
||||
uint8_t data[200] = "";
|
||||
int length = 0;
|
||||
if (_DSerial->available()>7&&!_recv_lock)
|
||||
{
|
||||
recv(&orig_port,&dest_port,&addr,data,&length);
|
||||
if (_DSerial->available() > 7 && !_recv_lock) {
|
||||
ZigbeeFrame zf = recv();
|
||||
Serial.print("Message: ");
|
||||
for (int i = 0; i < length;i++)
|
||||
{
|
||||
for (int i = 0; i < zf.size(); i++) {
|
||||
char temp[3];
|
||||
sprintf(temp, "%02X ", data[i]);
|
||||
sprintf(temp, "%02X ", zf[i]);
|
||||
Serial.print(temp);
|
||||
}
|
||||
char temp[200];
|
||||
sprintf(temp, "at port %02X from %04X:%02X.", dest_port, addr, orig_port);
|
||||
char temp[30];
|
||||
sprintf(temp, "at port %02X from %04X:%02X.", zf.getDesPort(), zf.getRemoteAddr(), zf.getSrcPort());
|
||||
Serial.println(temp);
|
||||
if (_callback!=nullptr)
|
||||
_callback(orig_port, dest_port, addr, data, length);
|
||||
if (zf.getSrcPort() == 0x22)
|
||||
{
|
||||
Serial.print("DLLN3X send msg error: 0x");
|
||||
Serial.print(zf.getData()[0], HEX);
|
||||
Serial.print(", Send data to incorrect port: 0x");
|
||||
Serial.print(zf.getData()[1], HEX);
|
||||
}
|
||||
if (_callback != nullptr)
|
||||
_callback(zf);
|
||||
}
|
||||
}
|
||||
|
||||
void DLLN3X::setcallback(void (*callback)(uint8_t orig_port,
|
||||
uint8_t dest_port, uint16_t addr,
|
||||
uint8_t data[], int length))
|
||||
{
|
||||
_callback = callback;
|
||||
}
|
||||
void DLLN3X::setcallback(void (*callback)(ZigbeeFrame& zf)) { _callback = callback; }
|
||||
|
|
98
src/DLLN3X.h
98
src/DLLN3X.h
|
@ -1,62 +1,60 @@
|
|||
#ifndef _DLLN3X_H_
|
||||
#define _DLLN3X_H_
|
||||
|
||||
#include "zigbeeframe.h"
|
||||
#include <Arduino.h>
|
||||
#if __has_include(<SoftwareSerial.h>)
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
typedef struct zigbee_frame
|
||||
{
|
||||
uint8_t length;
|
||||
uint8_t src_port;
|
||||
uint8_t des_port;
|
||||
uint8_t remote_addrL;
|
||||
uint8_t remote_addrH;
|
||||
uint8_t data[59];
|
||||
}zigbee_frame;
|
||||
|
||||
#define new_zigbee_frame(num) \
|
||||
struct \
|
||||
{ \
|
||||
uint8_t length; \
|
||||
uint8_t src_port; \
|
||||
uint8_t des_port; \
|
||||
uint8_t remote_addrL;\
|
||||
uint8_t remote_addrH;\
|
||||
uint8_t data[num]; \
|
||||
}
|
||||
|
||||
class DLLN3X
|
||||
{
|
||||
#endif
|
||||
namespace zigbee_protocol {
|
||||
class DLLN3X {
|
||||
private:
|
||||
void _clear();
|
||||
bool _online = false, _recv_lock = false;
|
||||
int _pack(uint8_t buf[], uint8_t data[], int length);
|
||||
int _depack(uint8_t buf[], uint8_t data[], int length);
|
||||
Stream *_DSerial;
|
||||
void (*_callback) (uint8_t orig_port,
|
||||
uint8_t dest_port, uint16_t addr,
|
||||
uint8_t data[], int length)=nullptr;
|
||||
uint8_t _self_channel = 0;
|
||||
uint16_t _self_addr = 0x0000, _self_network_id = 0x0000;
|
||||
uint32_t _self_baud_rate = 0;
|
||||
const uint32_t _baud_rate_list[13] = {2400, 4800, 9600, 14400, 19200,
|
||||
28800, 38400, 57600, 115200,
|
||||
230400, 125000, 250000, 500000};
|
||||
Stream* _DSerial;
|
||||
void (*_callback)(ZigbeeFrame& zf) = nullptr;
|
||||
|
||||
public:
|
||||
enum CONFIG_RW_MASK {READ = 0x00, WRITE = 0x10};
|
||||
enum CONFIG { ADDR = 0x01, NETWORKID = 0x02, CHANNEL = 0x03, BAUDRATE = 0x04 , SOFT_REBOOT = 0x10};
|
||||
enum CONFIG_RESPONSE {
|
||||
DONE = 0x00,
|
||||
PORT_REMOTE_ACCESS_DENIED = 0xF0,
|
||||
CMD_ERROR = 0xF8,
|
||||
PKG_LENGTH_ERROR = 0xF9,
|
||||
PKG_DATA_ERROR = 0xFA
|
||||
};
|
||||
enum PIN_CONTROL{ HIGH = 0x11, LOW = 0x10, READ_PIN = 0x12};
|
||||
enum PIN{ PIN4 = 0x44, PIN5 = 0x45};
|
||||
DLLN3X();
|
||||
~DLLN3X();
|
||||
void init(HardwareSerial *DSerial);
|
||||
void init(SoftwareSerial *DSerial);
|
||||
void recv(zigbee_frame *frame);
|
||||
bool recv(uint8_t *orig_port,
|
||||
uint8_t *dest_port, uint16_t *addr,
|
||||
uint8_t data[], int *length);
|
||||
bool send(uint8_t orig_port,
|
||||
uint8_t dest_port, uint16_t addr,
|
||||
uint8_t data[], int length);
|
||||
bool send(zigbee_frame *frame);
|
||||
void rled_blink(uint8_t orig_port = 0x80,
|
||||
uint16_t addr = 0x00, uint8_t time = 50);
|
||||
void loop();
|
||||
void setcallback(void (*callback)(uint8_t orig_port,
|
||||
uint8_t dest_port, uint16_t addr,
|
||||
uint8_t data[], int length));
|
||||
uint16_t read_addr();
|
||||
uint16_t self_addr = 0x0000;
|
||||
};
|
||||
void init(HardwareSerial* DSerial);
|
||||
#if __has_include(<SoftwareSerial.h>)
|
||||
void init(SoftwareSerial* DSerial);
|
||||
#endif
|
||||
ZigbeeFrame recv(bool non_blocked = true);
|
||||
bool send(ZigbeeFrame zf);
|
||||
bool send_cmd(uint8_t des_port, uint8_t arg, uint8_t* data = nullptr, uint8_t data_length = 0);
|
||||
void rled_blink(uint8_t time = 50);
|
||||
void loop();
|
||||
void setcallback(void (*callback)(ZigbeeFrame& zf));
|
||||
uint16_t rw_config(CONFIG arg, uint16_t data = 0, CONFIG_RW_MASK mask = CONFIG_RW_MASK::READ);
|
||||
uint8_t read_network_id();
|
||||
uint8_t set_network_id(uint16_t network_id);
|
||||
uint8_t read_channel();
|
||||
uint8_t set_channel(uint8_t channel);
|
||||
uint16_t read_addr();
|
||||
uint8_t set_addr(uint16_t addr);
|
||||
uint32_t read_baudrate();
|
||||
uint8_t set_baudrate(uint32_t baud_rate);
|
||||
void soft_reboot();
|
||||
uint8_t get_link_quality(uint16_t des_addr, uint16_t src_addr = 0x0000);
|
||||
enum PIN_CONTROL pin_control(PIN pin, PIN_CONTROL cmd);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
#ifndef _ZIGBEEFRAME_H_
|
||||
#define _ZIGBEEFRAME_H_
|
||||
#include <Arduino.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace zigbee_protocol {
|
||||
class ZigbeeFrame {
|
||||
private:
|
||||
const uint8_t head = 0xFE, tail = 0xFF;
|
||||
uint8_t _length = 0, _src_port = 0, _des_port = 0;
|
||||
uint8_t _pack_len = 0;
|
||||
uint16_t _remote_addr = 0;
|
||||
std::vector<uint8_t> _data, _packed_data, _package;
|
||||
|
||||
public:
|
||||
ZigbeeFrame(char* data) { setData((uint8_t*)data, strlen(data)); };
|
||||
ZigbeeFrame(char* data, uint8_t length) { setData((uint8_t*)data, length); };
|
||||
ZigbeeFrame(uint8_t* data, uint8_t length) { setData(data, length); };
|
||||
ZigbeeFrame(uint8_t src_port, uint8_t des_port, uint16_t remote_addr, uint8_t* data, uint8_t data_length)
|
||||
{
|
||||
_length = data_length + 4;
|
||||
_src_port = src_port;
|
||||
_des_port = des_port;
|
||||
_remote_addr = remote_addr;
|
||||
setData(data, data_length);
|
||||
};
|
||||
ZigbeeFrame(uint8_t src_port, uint8_t des_port, uint16_t remote_addr, char* data, uint8_t data_length)
|
||||
{
|
||||
_length = data_length + 4;
|
||||
_src_port = src_port;
|
||||
_des_port = des_port;
|
||||
_remote_addr = remote_addr;
|
||||
setData((uint8_t*)data, data_length);
|
||||
};
|
||||
ZigbeeFrame(uint8_t src_port, uint8_t des_port, uint16_t remote_addr)
|
||||
{
|
||||
_src_port = src_port;
|
||||
_des_port = des_port;
|
||||
_remote_addr = remote_addr;
|
||||
};
|
||||
ZigbeeFrame(const ZigbeeFrame& zf)
|
||||
{
|
||||
_length = zf._length;
|
||||
_src_port = zf._src_port;
|
||||
_des_port = zf._des_port;
|
||||
_pack_len = zf._pack_len;
|
||||
_remote_addr = zf._remote_addr;
|
||||
_data = zf._data;
|
||||
_packed_data = zf._packed_data;
|
||||
_package = zf._package;
|
||||
};
|
||||
ZigbeeFrame(const ZigbeeFrame* zf)
|
||||
{
|
||||
_length = zf->_length;
|
||||
_src_port = zf->_src_port;
|
||||
_des_port = zf->_des_port;
|
||||
_pack_len = zf->_pack_len;
|
||||
_remote_addr = zf->_remote_addr;
|
||||
_data = zf->_data;
|
||||
_packed_data = zf->_packed_data;
|
||||
_package = zf->_package;
|
||||
};
|
||||
ZigbeeFrame() {};
|
||||
~ZigbeeFrame() {};
|
||||
void setDesPort(uint8_t des_port) { _des_port = des_port; };
|
||||
void setSrcPort(uint8_t src_port) { _src_port = src_port; };
|
||||
void setRemoteAddr(uint16_t remote_addr) { _remote_addr = remote_addr; };
|
||||
uint8_t getDesPort() { return _des_port; };
|
||||
uint8_t getSrcPort() { return _src_port; };
|
||||
uint16_t getRemoteAddr() { return _remote_addr; };
|
||||
uint8_t getLength(){ return _data.size() + 4;};
|
||||
uint8_t getDataLength(){ return _data.size();};
|
||||
std::vector<uint8_t>& getData(){ return _data; };
|
||||
void setData(uint8_t* data, uint8_t length)
|
||||
{
|
||||
_data.clear();
|
||||
addData(data, length);
|
||||
};
|
||||
void setData(char* data) { setData((uint8_t*)data, strlen(data)); };
|
||||
void setData(char* data, uint8_t length) { setData((uint8_t*)data, length); };
|
||||
void setData(std::vector<uint8_t> data) { _data = data; };
|
||||
void addData(char* data) { addData(data, strlen(data)); };
|
||||
void addData(uint8_t* data, uint8_t length)
|
||||
{
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
_data.push_back(data[i]);
|
||||
}
|
||||
};
|
||||
void addData(char* data, uint8_t length) { addData((uint8_t*)data, length); };
|
||||
void addData(std::vector<uint8_t> data) { _data.insert(_data.end(), data.begin(), data.end()); };
|
||||
void clear()
|
||||
{
|
||||
_package.clear();
|
||||
_packed_data.clear();
|
||||
_data.clear();
|
||||
};
|
||||
uint8_t* data()
|
||||
{
|
||||
get_package();
|
||||
return _package.data();
|
||||
};
|
||||
uint8_t data_size() { return _data.size(); };
|
||||
uint8_t size()
|
||||
{
|
||||
get_package();
|
||||
return _package.size();
|
||||
};
|
||||
void append(uint8_t byte)
|
||||
{
|
||||
_data.push_back(byte);
|
||||
_length = _data.size() + 4;
|
||||
};
|
||||
void pack() { pack(_data, _packed_data); };
|
||||
void pack(std::vector<uint8_t> data, std::vector<uint8_t>& pack_data)
|
||||
{
|
||||
pack_data.clear();
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
if (data[i] == 0xFE) {
|
||||
pack_data.push_back(data[i]);
|
||||
pack_data.push_back(0xFC);
|
||||
} else if (data[i] == 0xFF) {
|
||||
pack_data.push_back(0xFE);
|
||||
pack_data.push_back(0xFD);
|
||||
} else {
|
||||
pack_data.push_back(data[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
void depack() { depack(_data, _packed_data); };
|
||||
void depack(std::vector<uint8_t>& data, std::vector<uint8_t> pack_data)
|
||||
{
|
||||
data.clear();
|
||||
for (int i = 0; i < pack_data.size(); i++) {
|
||||
if (pack_data[i] != 0xFE) {
|
||||
data.push_back(pack_data[i]);
|
||||
} else if (pack_data[i + 1] == 0xFD) {
|
||||
data.push_back(0xFF);
|
||||
i++;
|
||||
} else if (pack_data[i + 1] == 0xFC) {
|
||||
data.push_back(0xFE);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
void make_package(uint8_t src_port, uint8_t des_port, uint16_t remote_addr, std::vector<uint8_t>& package,
|
||||
std::vector<uint8_t> data, std::vector<uint8_t>& pack_data)
|
||||
{
|
||||
pack(data, pack_data);
|
||||
package.clear();
|
||||
package.push_back(head);
|
||||
package.push_back(data.size() + 4);
|
||||
package.push_back(src_port);
|
||||
package.push_back(des_port);
|
||||
package.push_back(remote_addr & 0xFF);
|
||||
package.push_back((remote_addr >> 8) & 0xFF);
|
||||
package.insert(package.end(), pack_data.begin(), pack_data.end());
|
||||
package.push_back(tail);
|
||||
};
|
||||
std::vector<uint8_t> get_package()
|
||||
{
|
||||
make_package(_src_port, _des_port, _remote_addr, _package, _data, _packed_data);
|
||||
return _package;
|
||||
};
|
||||
void load_package(std::vector <uint8_t> &buf)
|
||||
{
|
||||
load_package(buf.data(),buf.size());
|
||||
};
|
||||
void load_package(uint8_t *buf, uint8_t length)
|
||||
{
|
||||
_packed_data.clear();
|
||||
for (uint8_t i=0;i<length;i++)
|
||||
{
|
||||
_package.push_back(buf[i]);
|
||||
if (i>5 && i<length-1)
|
||||
_packed_data.push_back(buf[i]);
|
||||
}
|
||||
_length = _package[1];
|
||||
_src_port = _package[2];
|
||||
_des_port = _package[3];
|
||||
_remote_addr = _package[4] | (_package[5]<<8);
|
||||
depack(_data, _packed_data);
|
||||
};
|
||||
void print()
|
||||
{
|
||||
get_package();
|
||||
Serial.print("src_port:");
|
||||
Serial.println(_src_port, HEX);
|
||||
Serial.print("des_port:");
|
||||
Serial.println(_des_port, HEX);
|
||||
Serial.print("remote_addr:");
|
||||
Serial.println(_remote_addr, HEX);
|
||||
Serial.print("data:");
|
||||
for (auto byte : _data) {
|
||||
char buf[4];
|
||||
sprintf(buf, "%02X ", byte);
|
||||
Serial.print(buf);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("packed_data:");
|
||||
for (auto byte : _packed_data) {
|
||||
char buf[4];
|
||||
sprintf(buf, "%02X ", byte);
|
||||
Serial.print(buf);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("package:");
|
||||
for (auto byte : _package) {
|
||||
char buf[4];
|
||||
sprintf(buf, "%02X ", byte);
|
||||
Serial.print(buf);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
ZigbeeFrame operator+(const ZigbeeFrame& zf)
|
||||
{
|
||||
ZigbeeFrame temp(this);
|
||||
temp.addData(zf._data);
|
||||
return temp;
|
||||
};
|
||||
void operator+=(const ZigbeeFrame& zf) { addData(zf._data); };
|
||||
void operator=(const ZigbeeFrame& zf)
|
||||
{
|
||||
_length = zf._length;
|
||||
_src_port = zf._src_port;
|
||||
_des_port = zf._des_port;
|
||||
_pack_len = zf._pack_len;
|
||||
_remote_addr = zf._remote_addr;
|
||||
_data = zf._data;
|
||||
_packed_data = zf._packed_data;
|
||||
_package = zf._package;
|
||||
};
|
||||
ZigbeeFrame operator+(char* data)
|
||||
{
|
||||
ZigbeeFrame temp(this);
|
||||
temp.addData(data);
|
||||
return temp;
|
||||
};
|
||||
uint8_t& operator[](uint8_t i)
|
||||
{
|
||||
get_package();
|
||||
return _package[i];
|
||||
};
|
||||
void operator+=(char* data) { addData(data, (uint8_t)strlen(data)); };
|
||||
friend std::ostream& operator<<(std::ostream& os, const ZigbeeFrame& zf)
|
||||
{
|
||||
os << "src_port:" << zf._src_port << '\n'
|
||||
<< "des_port:" << zf._des_port << '\n'
|
||||
<< "remote_addr:" << zf._remote_addr << '\n'
|
||||
<< "packed_data:";
|
||||
for (auto byte : zf._packed_data)
|
||||
os << std::hex << std::uppercase << byte << ' ';
|
||||
os << '\n';
|
||||
return os;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue