mirror of https://github.com/arendst/Tasmota.git
EZSP flow control
This commit is contained in:
parent
6f320780a0
commit
eec6869a0a
|
@ -1097,7 +1097,7 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 /* len */);
|
ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 /* len */);
|
||||||
#endif // USE_ZIGBEE_ZNP
|
#endif // USE_ZIGBEE_ZNP
|
||||||
#ifdef USE_ZIGBEE_EZSP
|
#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
|
#endif // USE_ZIGBEE_EZSP
|
||||||
break;
|
break;
|
||||||
case ZGB_INSTR_WAIT_UNTIL:
|
case ZGB_INSTR_WAIT_UNTIL:
|
||||||
|
|
|
@ -1005,7 +1005,7 @@ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload,
|
||||||
buf.addBuffer(payload, payload_len);
|
buf.addBuffer(payload, payload_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true);
|
ZigbeeEZSPSendCmd(buf.buf(), buf.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
|
|
@ -36,11 +36,15 @@ const uint32_t ZIGBEE_LED_SEND = 0; // LED<2> blinks when receiving
|
||||||
|
|
||||||
class EZSP_Serial_t {
|
class EZSP_Serial_t {
|
||||||
public:
|
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 from_ack = 0; // 0..7, frame to ack
|
||||||
uint8_t ezsp_seq = 0; // 0..255, EZSP sequence number
|
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;
|
EZSP_Serial_t EZSP_Serial;
|
||||||
|
|
||||||
#endif // USE_ZIGBEE_EZSP
|
#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
|
// Send an EZSP command and data
|
||||||
// Ex: Version with min v8 = 000008
|
// 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];
|
char hex_char[len*2 + 2];
|
||||||
ToHex_P(msg, len, hex_char, sizeof(hex_char));
|
ToHex_P(msg, len, hex_char, sizeof(hex_char));
|
||||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %s"), 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);
|
cmd.addBuffer(msg, len);
|
||||||
|
|
||||||
// send
|
// send
|
||||||
ZigbeeEZSPSendDATA(cmd.getBuffer(), cmd.len(), send_cancel);
|
ZigbeeEZSPSendDATA(cmd.getBuffer(), cmd.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send an EZSP DATA frame, automatically calculating the correct frame numbers
|
// Send an EZSP DATA frame, automatically calculating the correct frame numbers
|
||||||
void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len, bool send_cancel) {
|
void ZigbeeEZSPSendDATA_frm(bool send_cancel, uint8_t to_frm, uint8_t from_ack) {
|
||||||
uint8_t control_byte = ((EZSP_Serial.to_ack & 0x07) << 4) + (EZSP_Serial.from_ack & 0x07);
|
SBuffer *buf = EZSP_Serial.to_packets[to_frm];
|
||||||
// increment to_ack
|
if (!buf) {
|
||||||
EZSP_Serial.to_ack = (EZSP_Serial.to_ack + 1) & 0x07;
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Buffer for packet %d is not allocated"), EZSP_Serial.to_send);
|
||||||
// build complete frame
|
return;
|
||||||
SBuffer buf(len+1);
|
}
|
||||||
buf.add8(control_byte);
|
|
||||||
buf.addBuffer(msg, len);
|
uint8_t control_byte = ((to_frm & 0x07) << 4) + (from_ack & 0x07);
|
||||||
|
buf->set8(0, control_byte); // change control_byte
|
||||||
// send
|
// 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
|
// 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);
|
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
|
// Receive raw ASH frame (CRC was removed, data unstuffed) but still contains frame numbers
|
||||||
int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
|
int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
|
||||||
uint8_t control_byte = buf.get8(0);
|
uint8_t control_byte = buf.get8(0);
|
||||||
uint8_t ack_num = control_byte & 0x07; // keep 3 LSB
|
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
|
uint8_t frame_type = control_byte & 0xE0; // keep 3 MSB
|
||||||
if (frame_type == 0x80) {
|
if (frame_type == 0x80) {
|
||||||
|
|
||||||
// ACK
|
// ACK
|
||||||
EZSP_Serial.from_ack = ack_num; // update ack num
|
EZSP_HandleAck(ack_num);
|
||||||
} else if (frame_type == 0xA0) {
|
} else if (frame_type == 0xA0) {
|
||||||
|
|
||||||
// NAK
|
// 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) {
|
} else if (control_byte == 0xC1) {
|
||||||
|
|
||||||
// RSTACK
|
// RSTACK
|
||||||
|
@ -581,6 +628,8 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
|
||||||
EZ_RSTACK(buf.get8(2));
|
EZ_RSTACK(buf.get8(2));
|
||||||
EZSP_Serial.from_ack = 0;
|
EZSP_Serial.from_ack = 0;
|
||||||
EZSP_Serial.to_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)
|
// pass it to state machine with a special 0xFFFE frame code (EZSP_RSTACK_ID)
|
||||||
buf.set8(0, Z_B0(EZSP_rstAck));
|
buf.set8(0, Z_B0(EZSP_rstAck));
|
||||||
|
@ -598,14 +647,12 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) {
|
||||||
// Unknown
|
// Unknown
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Received unknown control byte 0x%02X"), control_byte);
|
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
|
// MCU acknowledged the correct frame
|
||||||
// we acknowledge the frame too
|
// we acknowledge the frame too
|
||||||
EZSP_Serial.from_ack = ((control_byte >> 4) + 1) & 0x07;
|
EZSP_Serial.from_ack = ((control_byte >> 4) + 1) & 0x07;
|
||||||
|
@ -651,9 +698,9 @@ void CmndZbEZSPSendOrReceive(bool send)
|
||||||
}
|
}
|
||||||
if (send) {
|
if (send) {
|
||||||
// Command was `ZbEZSPSend`
|
// 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 if (3 == XdrvMailbox.index) { ZigbeeEZSPSendRaw(buf.getBuffer(), buf.len(), true); }
|
||||||
else { ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true); }
|
else { ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); }
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Command was `ZbEZSPReceive`
|
// 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
|
#endif // USE_ZIGBEE_EZSP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1023,13 +1023,13 @@ void CmndZbPermitJoin(void) {
|
||||||
SBuffer buf(3);
|
SBuffer buf(3);
|
||||||
buf.add16(EZSP_permitJoining);
|
buf.add16(EZSP_permitJoining);
|
||||||
buf.add8(duration);
|
buf.add8(duration);
|
||||||
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true);
|
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len());
|
||||||
|
|
||||||
// send ZDO_Mgmt_Permit_Joining_req to all routers
|
// send ZDO_Mgmt_Permit_Joining_req to all routers
|
||||||
buf.setLen(0);
|
buf.setLen(0);
|
||||||
buf.add8(duration);
|
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.
|
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
|
#endif // USE_ZIGBEE_EZSP
|
||||||
|
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
|
@ -1059,7 +1059,7 @@ void CmndZbEZSPListen(void) {
|
||||||
buf.add16(group); // group
|
buf.add16(group); // group
|
||||||
buf.add8(0x01); // endpoint
|
buf.add8(0x01); // endpoint
|
||||||
buf.add8(0x00); // network index
|
buf.add8(0x00); // network index
|
||||||
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true);
|
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len());
|
||||||
|
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
@ -1240,7 +1240,10 @@ bool Xdrv23(uint8_t function)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FUNC_LOOP:
|
case FUNC_LOOP:
|
||||||
if (ZigbeeSerial) { ZigbeeInputLoop(); }
|
if (ZigbeeSerial) {
|
||||||
|
ZigbeeInputLoop();
|
||||||
|
ZigbeeOutputLoop(); // send any outstanding data
|
||||||
|
}
|
||||||
if (zigbee.state_machine) {
|
if (zigbee.state_machine) {
|
||||||
ZigbeeStateMachine_Run();
|
ZigbeeStateMachine_Run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue