3
0
Fork 0
xnode/xnode-base/XnodeBaseRadio.cpp

244 lines
7.3 KiB
C++
Raw Normal View History

2022-11-13 00:46:38 +00:00
#include <XnodeBaseRadio.h>
const char pmRadioChipInit[] PROGMEM = MSG_RF_CHIP_INIT;
const char pmRadioChipError[] PROGMEM = MSG_RF_CHIP_ERROR;
const char pmRadioInfoFreq[] PROGMEM = MSG_RF_INFO_FREQ;
const char pmRadioInfoNetwork[] PROGMEM = MSG_RF_INFO_NETWORK;
const char pmRadioInfoNode[] PROGMEM = MSG_RF_INFO_NODE;
const char pmRadioInfoKey[] PROGMEM = MSG_RF_INFO_KEY;
const char pmRadioInfoTx[] PROGMEM = MSG_RF_INFO_TX;
const char pmRadioInfoRx[] PROGMEM = MSG_RF_INFO_RX;
const char pmRadioInfoTxe[] PROGMEM = MSG_RF_INFO_TXE;
const char pmRadioInfoNextNode[] PROGMEM = "rf_next_node";
//const char pmRadioInfoNextNode[] PROGMEM = "rf_sat";
const char pmRadioEncrypt[] PROGMEM = MSG_RF_ENCRYPT;
const char pmRadioInfo[] PROGMEM = MSG_RF_INFO;
const char pmRadioSendFailRf[] PROGMEM = "rf_fail=1";
volatile unsigned long key_encrypt_timer = ZERO;
volatile unsigned long rf_no_data_timer = ZERO;
unsigned long rf_tx = ZERO;
unsigned long rf_rx = ZERO;
unsigned long rf_txe = ZERO;
uint16_t rf_ping_count = ZERO;
uint8_t rf_status_data = ZERO;
uint8_t rf_status_ping = ZERO;
uint8_t rf_status_chip = ZERO;
byte rf_data_sender_id;
xp_super_t rf_data;
xp_msg_init_t* rf_msg_init;
xp_msg_flash_t* rf_msg_flash;
xp_msg_char_t* rf_msg_char;
RFM69 radio;
XnodeBaseRadio XBRadio;
void XnodeBaseRadio::begin() {
XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_ON);
// Init radio chip
XSerial.printCommentLineP(pmRadioChipInit);
if (!radio.initialize(RF_FREQUENCY, RF_BASE_NODE_ID, RF_NETWORK_ID)) {
XSerial.printCommentLineP(pmRadioChipError);
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK);
rf_status_chip = ONE;
return;
}
radio.promiscuous(true);
XSerial.executeCommandP(pmRadioInfo);
// init of time window until rf is encrypted and idle timeout
key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME;
rf_no_data_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME + (unsigned long) RF_NO_DATA_FAIL_TIME;
}
void XnodeBaseRadio::loop() {
if (rf_status_chip != ZERO) {
return; // no chip
}
if (key_encrypt_timer != ZERO && millis() > key_encrypt_timer) {
cmdClose();
}
checkNoDataTimeout();
if (!radio.receiveDone()) {
return;
}
XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_ON);
rf_no_data_timer = millis() + (unsigned long) RF_NO_DATA_FAIL_TIME;
rf_rx++;
rf_status_data = ZERO;
rf_data = *(xp_super_t*) radio.DATA;
rf_data_sender_id = radio.SENDERID;
#ifdef DEBUG_RADIO
Serial.print(F("#D rf_rx "));
Serial.print(rf_data_sender_id,DEC);
Serial.print(CHAR_SPACE);
Serial.print(rf_data.msg_type,DEC);
Serial.print(CHAR_NEWLINE);
#endif
// always reply ack if requested, see sendWithRetry impl (before reply with sendWithRetry)
if (radio.ACK_REQUESTED) {
#ifdef DEBUG_RADIO
Serial.println(F("#D rf_sendACK"));
#endif
radio.sendACK();
}
if (rf_data.msg_type == RF_MSG_NODE_DATA) {
rf_msg_char = (xp_msg_char_t*) rf_data.msg_data;
XBNetwork.sendNodeData(rf_data_sender_id, rf_msg_char->char_data);
} else if (rf_data.msg_type == RF_MSG_NODE_INIT) {
rf_msg_init = (xp_msg_init_t*) rf_data.msg_data;
handleCmdInit();
} else if (rf_data.msg_type == RF_MSG_NODE_FLASH) {
rf_msg_flash = (xp_msg_flash_t*) rf_data.msg_data;
handleCmdFlash();
}
checkPing(); // sets radio.SENDERID to zero because it sends data
XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_OFF);
}
void XnodeBaseRadio::checkPing() {
rf_ping_count++;
if (rf_ping_count % 10 != ZERO) {
return;
}
rf_status_ping = ZERO; // reset good
#ifdef DEBUG_RADIO
Serial.print(F("#D rf_ping "));
Serial.print(radio.SENDERID);
Serial.print(CHAR_NEWLINE);
#endif
delay(3); //need this when sending right after reception .. ?
rf_tx++;
if (!radio.sendWithRetry(radio.SENDERID, "ACK TEST", 8, 0)) { // 0 = only 1 attempt, no retries
rf_txe++;
rf_status_ping = ONE; // bad
}
}
void XnodeBaseRadio::checkNoDataTimeout() {
if (millis() < rf_no_data_timer) {
return; // wait until time is passed
}
rf_no_data_timer = millis() + (unsigned long) RF_NO_DATA_FAIL_TIME;
rf_msg_char = (xp_msg_char_t*) rf_data.msg_data; // hacky reuse sensor buffer to send data
strcpy(rf_msg_char->char_data, XUtil.UNPSTR(pmRadioSendFailRf)); // because send also used unpstr buffer
XBNetwork.sendNodeData(RF_BASE_NODE_ID, rf_msg_char->char_data);
}
void XnodeBaseRadio::sendReply() {
rf_tx++;
if (!radio.sendWithRetry(rf_data_sender_id, (const void*) &rf_data, sizeof(xp_super_t))) {
rf_txe++;
}
}
void XnodeBaseRadio::handleCmdFlash() {
sendReply();
}
void XnodeBaseRadio::handleCmdInit() {
for (byte i = ZERO; i < RF_KEY_SIZE; ++i) {
rf_msg_init->rf_key[i] = XBHardware.config.rf_key[i];
}
#ifdef DEBUG_RADIO
Serial.print(F("#D rf_init "));
Serial.print(rf_msg_init->node_id);
Serial.print(CHAR_NEWLINE);
#endif
if (rf_msg_init->node_id == ZERO) {
rf_msg_init->node_id = XBHardware.config.rf_next_node_id;
// Save next node id
XBHardware.config.rf_next_node_id++;
XSystem.configSave();
}
sendReply();
// update open encrypt timer so user can init multiple devices one at the time
key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME;
}
void XnodeBaseRadio::cmdClose() {
XSystem.buildReplyPValue(pmRadioEncrypt, ONE);
radio.encrypt((const char*) XBHardware.config.rf_key);
key_encrypt_timer = ZERO; // flag encrypted
XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_OFF);
}
void XnodeBaseRadio::cmdOpen() {
if (key_encrypt_timer != ZERO) {
return; // only open if it is encrypted already
}
radio.encrypt(ZERO);
key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME;
XSystem.buildReplyPValue(pmRadioEncrypt, ZERO);
XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_BLINK); // rf blink = open for key requests
}
void XnodeBaseRadio::cmdInfo() {
// Print key
XSystem.buildReplyPValueByteA(pmRadioInfoKey,XBHardware.config.rf_key, RF_KEY_SIZE);
// Print radio config
XSystem.buildReplyPValue(pmRadioInfoFreq,(int) RF_FREQUENCY == RF69_433MHZ ? 433 : RF_FREQUENCY == RF69_868MHZ ? 868 : 915);
XSystem.buildReplyPValue(pmRadioInfoNetwork,(int) RF_NETWORK_ID);
XSystem.buildReplyPValue(pmRadioInfoNode,(int) RF_BASE_NODE_ID);
XSystem.buildReplyPValue(pmRadioEncrypt,(int) key_encrypt_timer == ZERO ? ONE : ZERO);// if timer==0 then encrypted=1
// Print base radio stuff
XSystem.buildReplyPValue(pmRadioInfoRx, rf_rx);
XSystem.buildReplyPValue(pmRadioInfoTx, rf_tx);
XSystem.buildReplyPValue(pmRadioInfoTxe, rf_txe);
XSystem.buildReplyPValue(pmRadioInfoNextNode, (int) XBHardware.config.rf_next_node_id);
}
void XnodeBaseRadio::systemModuleCommandList() {
XSystem.buildReplyCommandListP(pmRadioInfoKey);
XSystem.buildReplyCommandListP(pmRadioInfo);
XSystem.buildReplyCommandListP(pmRadioEncrypt);
}
bool XnodeBaseRadio::systemModuleCommandExecute(char* cmd, char** args) {
if (XUtil.strcmpP(cmd, pmRadioInfo) == ZERO) {
cmdInfo();
return true;
} else if (XUtil.strcmpP(cmd, pmRadioInfoKey) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
XUtil.charsToByteA(args[ZERO],XBHardware.config.rf_key, RF_KEY_SIZE);
XSystem.buildReplyPValueByteA(pmRadioInfoKey,XBHardware.config.rf_key, RF_KEY_SIZE);
XSystem.configSave();
return true;
} else if (XUtil.strcmpP(cmd, pmRadioEncrypt) == ZERO) {
if (key_encrypt_timer == ZERO) {
cmdOpen();
} else {
cmdClose();
}
return true;
}
return false;
}