Merge pull request #8962 from s-hadinger/zigbee_ezsp_july_22

EZSP flow control
This commit is contained in:
Theo Arends 2020-07-22 19:48:29 +02:00 committed by GitHub
commit 26646d6941
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 32 deletions

View File

@ -1097,7 +1097,7 @@ void ZigbeeStateMachine_Run(void) {
ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 /* len */);
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
ZigbeeEZSPSendCmd((uint8_t*) cur_ptr1, cur_d8 /* len */, true); // send cancel byte
ZigbeeEZSPSendCmd((uint8_t*) cur_ptr1, cur_d8 /* len */); // send cancel byte
#endif // USE_ZIGBEE_EZSP
break;
case ZGB_INSTR_WAIT_UNTIL:

View File

@ -1005,7 +1005,7 @@ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload,
buf.addBuffer(payload, payload_len);
}
ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true);
ZigbeeEZSPSendCmd(buf.buf(), buf.len());
}
/*********************************************************************************************\

View File

@ -36,11 +36,15 @@ const uint32_t ZIGBEE_LED_SEND = 0; // LED<2> blinks when receiving
class EZSP_Serial_t {
public:
uint8_t to_ack = 0; // 0..7, frame number of next id to send
uint8_t to_send = 0; // 0..7, frame number of next packet to send, nothing to send if equal to to_end
uint8_t to_end = 0; // 0..7, frame number of next packet to send
uint8_t to_ack = 0; // 0..7, frame number of last packet acknowledged + 1
uint8_t from_ack = 0; // 0..7, frame to ack
uint8_t ezsp_seq = 0; // 0..255, EZSP sequence number
SBuffer *to_packets[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
};
EZSP_Serial_t EZSP_Serial;
#endif // USE_ZIGBEE_EZSP
@ -493,7 +497,7 @@ void ZigbeeEZSPSendRaw(const uint8_t *msg, size_t len, bool send_cancel) {
// Send an EZSP command and data
// Ex: Version with min v8 = 000008
void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len, bool send_cancel) {
void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len) {
char hex_char[len*2 + 2];
ToHex_P(msg, len, hex_char, sizeof(hex_char));
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %s"), hex_char);
@ -506,20 +510,45 @@ void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len, bool send_cancel) {
cmd.addBuffer(msg, len);
// send
ZigbeeEZSPSendDATA(cmd.getBuffer(), cmd.len(), send_cancel);
ZigbeeEZSPSendDATA(cmd.getBuffer(), cmd.len());
}
// Send an EZSP DATA frame, automatically calculating the correct frame numbers
void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len, bool send_cancel) {
uint8_t control_byte = ((EZSP_Serial.to_ack & 0x07) << 4) + (EZSP_Serial.from_ack & 0x07);
// increment to_ack
EZSP_Serial.to_ack = (EZSP_Serial.to_ack + 1) & 0x07;
// build complete frame
SBuffer buf(len+1);
buf.add8(control_byte);
buf.addBuffer(msg, len);
void ZigbeeEZSPSendDATA_frm(bool send_cancel, uint8_t to_frm, uint8_t from_ack) {
SBuffer *buf = EZSP_Serial.to_packets[to_frm];
if (!buf) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Buffer for packet %d is not allocated"), EZSP_Serial.to_send);
return;
}
uint8_t control_byte = ((to_frm & 0x07) << 4) + (from_ack & 0x07);
buf->set8(0, control_byte); // change control_byte
// send
ZigbeeEZSPSendRaw(buf.getBuffer(), buf.len(), send_cancel);
ZigbeeEZSPSendRaw(buf->getBuffer(), buf->len(), send_cancel);
}
// Send an EZSP DATA frame, automatically calculating the correct frame numbers
void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len) {
// prepare buffer by adding 1 byte prefix
SBuffer *buf = new SBuffer(len+1); // prepare for control_byte prefix
buf->add8(0x00); // placeholder for control_byte
buf->addBuffer(msg, len);
//
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: adding packet to_send, to_ack:%d, to_send:%d, to_end:%d"),
EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end);
uint8_t to_frm = EZSP_Serial.to_end;
if (EZSP_Serial.to_packets[to_frm]) {
delete EZSP_Serial.to_packets[to_frm];
EZSP_Serial.to_packets[to_frm] = nullptr;
}
EZSP_Serial.to_packets[to_frm] = buf;
EZSP_Serial.to_end = (to_frm + 1) & 0x07; // move cursor
// ZigbeeEZSPSendDATA_frm(send_cancel, to_frm, EZSP_Serial.from_ack);
// increment to_frame
//EZSP_Serial.to_ack = (EZSP_Serial.to_ack + 1) & 0x07;
//EZSP_Serial.to_frm = (EZSP_Serial.to_frm + 1) & 0x07;
}
// Receive a high-level EZSP command/response, starting with 16-bits frame ID
@ -557,23 +586,41 @@ int32_t ZigbeeProcessInputEZSP(class SBuffer &buf) {
ZigbeeProcessInput(buf);
}
// Check if we advanced in the ACKed frames, and free from memory packets acknowledged
void EZSP_HandleAck(uint8_t new_ack) {
if (EZSP_Serial.to_ack != new_ack) { // new ack receveid
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: new ack/data received, was %d now %d"), EZSP_Serial.to_ack, new_ack);
uint32_t i = EZSP_Serial.to_ack;
do {
if (EZSP_Serial.to_packets[i]) {
delete EZSP_Serial.to_packets[i];
EZSP_Serial.to_packets[i] = nullptr;
}
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: freeing packet %d from memory"), i);
i = (i + 1) & 0x07;
} while (i != new_ack);
EZSP_Serial.to_ack = new_ack;
}
}
// Receive raw ASH frame (CRC was removed, data unstuffed) but still contains frame numbers
int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
uint8_t control_byte = buf.get8(0);
uint8_t ack_num = control_byte & 0x07; // keep 3 LSB
if (control_byte & 0x80) {
if (control_byte & 0x80) { // non DATA frame
// non DATA frame
uint8_t frame_type = control_byte & 0xE0; // keep 3 MSB
if (frame_type == 0x80) {
// ACK
EZSP_Serial.from_ack = ack_num; // update ack num
EZSP_HandleAck(ack_num);
} else if (frame_type == 0xA0) {
// NAK
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: Received NAK %d, resending not implemented"), ack_num);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Received NAK %d, to_ack:%d, to_send:%d, to_end:%d"),
ack_num, EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end);
EZSP_Serial.to_send = ack_num;
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: NAK, resending packet %d"), ack_num);
} else if (control_byte == 0xC1) {
// RSTACK
@ -581,6 +628,8 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
EZ_RSTACK(buf.get8(2));
EZSP_Serial.from_ack = 0;
EZSP_Serial.to_ack = 0;
EZSP_Serial.to_end = 0;
EZSP_Serial.to_send = 0;
// pass it to state machine with a special 0xFFFE frame code (EZSP_RSTACK_ID)
buf.set8(0, Z_B0(EZSP_rstAck));
@ -598,14 +647,12 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
// Unknown
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Received unknown control byte 0x%02X"), control_byte);
}
} else {
} else { // DATA Frame
// adjust to latest acked packet
uint8_t new_ack = control_byte & 0x07;
EZSP_HandleAck(new_ack);
// DATA Frame
// check the frame number, and send ACK or NAK
if ((control_byte & 0x07) != EZSP_Serial.to_ack) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: wrong ack, received %d, expected %d"), control_byte & 0x07, EZSP_Serial.to_ack);
//EZSP_Serial.to_ack = control_byte & 0x07;
}
// MCU acknowledged the correct frame
// we acknowledge the frame too
EZSP_Serial.from_ack = ((control_byte >> 4) + 1) & 0x07;
@ -651,9 +698,9 @@ void CmndZbEZSPSendOrReceive(bool send)
}
if (send) {
// Command was `ZbEZSPSend`
if (2 == XdrvMailbox.index) { ZigbeeEZSPSendDATA(buf.getBuffer(), buf.len(), true); }
if (2 == XdrvMailbox.index) { ZigbeeEZSPSendDATA(buf.getBuffer(), buf.len()); }
else if (3 == XdrvMailbox.index) { ZigbeeEZSPSendRaw(buf.getBuffer(), buf.len(), true); }
else { ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true); }
else { ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); }
} else {
// Command was `ZbEZSPReceive`
@ -785,7 +832,25 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI
}
}
ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true);
ZigbeeEZSPSendCmd(buf.buf(), buf.len());
#endif // USE_ZIGBEE_EZSP
}
//
// Send any buffered data to the NCP
//
// Used only with EZSP, as there is no replay of procotol control with ZNP
void ZigbeeOutputLoop(void) {
#ifdef USE_ZIGBEE_EZSP
// while (EZSP_Serial.to_send != EZSP_Serial.to_end) {
if (EZSP_Serial.to_send != EZSP_Serial.to_end) { // we send only one packet per tick to lower the chance of NAK
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Something to_send, to_ack:%d, to_send:%d, to_end:%d"),
EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end);
// we have a frame waiting to be sent
ZigbeeEZSPSendDATA_frm(true, EZSP_Serial.to_send, EZSP_Serial.from_ack);
// increment sent counter
EZSP_Serial.to_send = (EZSP_Serial.to_send + 1) & 0x07;
}
#endif // USE_ZIGBEE_EZSP
}

View File

@ -1023,13 +1023,13 @@ void CmndZbPermitJoin(void) {
SBuffer buf(3);
buf.add16(EZSP_permitJoining);
buf.add8(duration);
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true);
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len());
// send ZDO_Mgmt_Permit_Joining_req to all routers
buf.setLen(0);
buf.add8(duration);
buf.add8(0x01); // TC_Significance - This field shall always have a value of 1, indicating a request to change the Trust Center policy. If a frame is received with a value of 0, it shall be treated as having a value of 1.
// EZ_SendZDO(0xFFFC, ZDO_Mgmt_Permit_Joining_req, buf.buf(), buf.len()); TODO fix NAK/ACK first
EZ_SendZDO(0xFFFC, ZDO_Mgmt_Permit_Joining_req, buf.buf(), buf.len());
#endif // USE_ZIGBEE_EZSP
ResponseCmndDone();
@ -1059,7 +1059,7 @@ void CmndZbEZSPListen(void) {
buf.add16(group); // group
buf.add8(0x01); // endpoint
buf.add8(0x00); // network index
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true);
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len());
ResponseCmndDone();
}
@ -1240,7 +1240,10 @@ bool Xdrv23(uint8_t function)
}
break;
case FUNC_LOOP:
if (ZigbeeSerial) { ZigbeeInputLoop(); }
if (ZigbeeSerial) {
ZigbeeInputLoop();
ZigbeeOutputLoop(); // send any outstanding data
}
if (zigbee.state_machine) {
ZigbeeStateMachine_Run();
}