Added project
This commit is contained in:
parent
fe9aa14dfd
commit
2d73cc8845
186 changed files with 21174 additions and 0 deletions
5
xnode-base/Makefile
Normal file
5
xnode-base/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Minimal makefile only includes the master and libs.
|
||||
MASTER_LIBS = rfm69 spi dht ethercard xnode-shared
|
||||
SKT_PDE_SRC = XnodeBase.cpp
|
||||
include ../lib-build/make/Makefile.master
|
||||
|
||||
34
xnode-base/XnodeBase.cpp
Normal file
34
xnode-base/XnodeBase.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Xnode Base
|
||||
*/
|
||||
|
||||
#include <XnodeSerial.h>
|
||||
#include <XnodeSystem.h>
|
||||
#include <XnodeBaseHardware.h>
|
||||
#include <XnodeBaseNetwork.h>
|
||||
#include <XnodeBaseRadio.h>
|
||||
|
||||
void setup() {
|
||||
// Build system modules
|
||||
XSystem.registrateSystemModule(&XBNetwork);
|
||||
XSystem.registrateSystemModule(&XBRadio);
|
||||
|
||||
// Init system modules
|
||||
XSerial.begin();
|
||||
XSystem.begin(&XBHardware);
|
||||
XBHardware.begin();
|
||||
XBNetwork.begin();
|
||||
XBRadio.begin();
|
||||
|
||||
// Mark device booted
|
||||
XSystem.bootDone();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
XSerial.loop();
|
||||
XSystem.loop();
|
||||
XBHardware.loop();
|
||||
XBNetwork.loop();
|
||||
XBRadio.loop();
|
||||
}
|
||||
|
||||
32
xnode-base/XnodeBaseConfig.h
Normal file
32
xnode-base/XnodeBaseConfig.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef XnodeBaseConfig_h
|
||||
#define XnodeBaseConfig_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
union NetKey_t {
|
||||
unsigned long int u32[NET_BYTE_NET_KEY_SIZE / 4];
|
||||
unsigned char u8[NET_BYTE_NET_KEY_SIZE];
|
||||
};
|
||||
typedef union NetKey_t NetKey;
|
||||
|
||||
// Config data
|
||||
typedef struct {
|
||||
uint16_t eeprom_struct_size; // Config size changes it data defaults to zeros
|
||||
|
||||
byte net_mac[NET_BYTE_MAC_SIZE];
|
||||
byte net_ip[NET_BYTE_IP_SIZE];
|
||||
byte net_mask[NET_BYTE_IP_SIZE];
|
||||
byte net_gate[NET_BYTE_IP_SIZE];
|
||||
byte net_dns[NET_BYTE_IP_SIZE];
|
||||
NetKey net_key;
|
||||
byte net_id[NET_BYTE_NET_ID_SIZE];
|
||||
|
||||
byte rf_key[RF_KEY_SIZE];
|
||||
byte rf_next_node_id;
|
||||
|
||||
unsigned long sys_boot; // boot counter
|
||||
|
||||
} xnode_base_config_t;
|
||||
|
||||
#endif
|
||||
|
||||
172
xnode-base/XnodeBaseHardware.cpp
Normal file
172
xnode-base/XnodeBaseHardware.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#include <XnodeBaseHardware.h>
|
||||
|
||||
const char pmSystemHardwareType[] PROGMEM = "xnode-base";
|
||||
const char pmSystemHardwareVersion[] PROGMEM = XNODE_VERSION;
|
||||
const char pmSysTestLeds[] PROGMEM = "System leds test";
|
||||
|
||||
byte CONFIG_DEFAULT_NET_MAC[] = NET_XNODE_MAC_DEFAULT;
|
||||
unsigned long blink_timer = ZERO;
|
||||
uint8_t blink_led = ZERO;
|
||||
uint8_t blink_status = ZERO;
|
||||
|
||||
xnode_base_config_t config;
|
||||
xnode_base_config_t EEMEM eeprom;
|
||||
XnodeBaseHardware XBHardware;
|
||||
|
||||
void XnodeBaseHardware::begin() {
|
||||
pinMode(HW_PIN_ERROR_LED, OUTPUT);
|
||||
pinMode(HW_PIN_RADIO_LED, OUTPUT);
|
||||
pinMode(HW_PIN_NETWORK_LED, OUTPUT);
|
||||
|
||||
changeLed(SYS_LED_ERROR, SYS_LED_STATUS_ON);
|
||||
changeLed(SYS_LED_RADIO, SYS_LED_STATUS_ON);
|
||||
changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON);
|
||||
|
||||
XSerial.printCommentLineP(pmSysTestLeds);
|
||||
delay(SYS_LED_TEST_TIME); // let users see all leds
|
||||
|
||||
changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF);
|
||||
changeLed(SYS_LED_RADIO, SYS_LED_STATUS_OFF);
|
||||
changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF);
|
||||
}
|
||||
|
||||
void XnodeBaseHardware::loop() {
|
||||
loopBlink();
|
||||
}
|
||||
|
||||
bool XnodeBaseHardware::systemHardwareConfigBegin() {
|
||||
eeprom_read_block((void*) &config, (void*) &eeprom, sizeof(xnode_base_config_t));
|
||||
if (config.eeprom_struct_size != sizeof(xnode_base_config_t)) {
|
||||
return true;
|
||||
}
|
||||
config.sys_boot++;
|
||||
return false;
|
||||
}
|
||||
|
||||
void XnodeBaseHardware::systemHardwareConfigSave() {
|
||||
config.eeprom_struct_size = sizeof(xnode_base_config_t);
|
||||
eeprom_write_block((const void*) &config, (void*) &eeprom, sizeof(xnode_base_config_t));
|
||||
}
|
||||
|
||||
void XnodeBaseHardware::systemHardwareConfigReset() {
|
||||
// Temp code way
|
||||
config.net_mac[0] = ZERO;
|
||||
config.net_mac[1] = ZERO;
|
||||
config.net_mac[2] = ZERO;
|
||||
config.net_mac[3] = ZERO;
|
||||
config.net_mac[4] = ZERO;
|
||||
config.net_mac[5] = ZERO;
|
||||
|
||||
config.net_ip[0] = ZERO;
|
||||
config.net_ip[1] = ZERO;
|
||||
config.net_ip[2] = ZERO;
|
||||
config.net_ip[3] = ZERO;
|
||||
|
||||
config.net_mask[0] = ZERO;
|
||||
config.net_mask[1] = ZERO;
|
||||
config.net_mask[2] = ZERO;
|
||||
config.net_mask[3] = ZERO;
|
||||
|
||||
config.net_gate[0] = ZERO;
|
||||
config.net_gate[1] = ZERO;
|
||||
config.net_gate[2] = ZERO;
|
||||
config.net_gate[3] = ZERO;
|
||||
|
||||
config.net_dns[0] = ZERO;
|
||||
config.net_dns[1] = ZERO;
|
||||
config.net_dns[2] = ZERO;
|
||||
config.net_dns[3] = ZERO;
|
||||
|
||||
config.sys_boot = ZERO;
|
||||
// end Temp
|
||||
|
||||
// TODO: Temp fix cast~~ so clear config zering all in one go.
|
||||
//for (uint16_t i=ZERO;i<sizeof(xnode_base_config_t);i++) {
|
||||
//((void *)config)+i = ZERO;
|
||||
//}
|
||||
|
||||
// Copy some defaults into config
|
||||
for (byte i = ZERO; i < NET_BYTE_MAC_SIZE; ++i) {
|
||||
config.net_mac[i] = CONFIG_DEFAULT_NET_MAC[i];
|
||||
}
|
||||
|
||||
// Add default mask
|
||||
config.net_mask[0] = 255;
|
||||
config.net_mask[1] = 255;
|
||||
config.net_mask[2] = 255;
|
||||
config.net_mask[3] = ZERO;
|
||||
|
||||
config.rf_next_node_id = ONE + ONE;
|
||||
for (byte i = ZERO; i < RF_KEY_SIZE; ++i) {
|
||||
config.rf_key[i] = ZERO;
|
||||
}
|
||||
for (byte i = ZERO; i < NET_BYTE_NET_KEY_SIZE; ++i) {
|
||||
config.net_key.u8[i] = ZERO;
|
||||
}
|
||||
for (byte i = ZERO; i < NET_BYTE_NET_ID_SIZE; ++i) {
|
||||
config.net_id[i] = ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long XnodeBaseHardware::getSystemHardwareRebootCount() {
|
||||
return config.sys_boot;
|
||||
}
|
||||
|
||||
const char* XnodeBaseHardware::getSystemHardwareTypeP() {
|
||||
return pmSystemHardwareType;
|
||||
}
|
||||
|
||||
const char* XnodeBaseHardware::getSystemHardwareVersionP() {
|
||||
return pmSystemHardwareVersion;
|
||||
}
|
||||
|
||||
|
||||
void XnodeBaseHardware::writeLed(uint8_t led, uint8_t status) {
|
||||
int out = LOW;
|
||||
if (status != SYS_LED_STATUS_OFF) {
|
||||
out = HIGH;
|
||||
}
|
||||
|
||||
if (led == SYS_LED_ERROR) {
|
||||
digitalWrite(HW_PIN_ERROR_LED, out);
|
||||
} else if (led == SYS_LED_RADIO) {
|
||||
digitalWrite(HW_PIN_RADIO_LED, out);
|
||||
} else {
|
||||
digitalWrite(HW_PIN_NETWORK_LED, out);
|
||||
}
|
||||
}
|
||||
|
||||
void XnodeBaseHardware::changeLed(uint8_t led, uint8_t status) {
|
||||
#ifdef DEBUG_SYSTEM
|
||||
Serial.print(F("#D XBHardware.changeLed led="));
|
||||
Serial.print(led);
|
||||
Serial.print(F(",status="));
|
||||
Serial.print(status);
|
||||
Serial.println();
|
||||
#endif
|
||||
if (status == SYS_LED_STATUS_BLINK) {
|
||||
blink_led = led; // start blinking this led
|
||||
}
|
||||
if (blink_led == led && status != SYS_LED_STATUS_BLINK) {
|
||||
blink_led = SYS_LED_NONE; // clear blinking
|
||||
}
|
||||
writeLed(led, status);
|
||||
}
|
||||
|
||||
// blink led, note only single led can blink at once.
|
||||
void XnodeBaseHardware::loopBlink() {
|
||||
if (blink_led == SYS_LED_NONE) {
|
||||
return; // no led to blink
|
||||
}
|
||||
unsigned long time = millis();
|
||||
if (time < blink_timer) {
|
||||
return; // wait until time is passed
|
||||
}
|
||||
blink_timer = time + SYS_LED_BLINK_TIME;
|
||||
if (blink_status == ZERO) {
|
||||
blink_status = ONE;
|
||||
} else {
|
||||
blink_status = ZERO;
|
||||
}
|
||||
writeLed(blink_led, blink_status);
|
||||
}
|
||||
56
xnode-base/XnodeBaseHardware.h
Normal file
56
xnode-base/XnodeBaseHardware.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef XnodeBaseHardware_h
|
||||
#define XnodeBaseHardware_h
|
||||
|
||||
#include <XnodeConstants.h>
|
||||
#include <XnodeSystemHardware.h>
|
||||
#include <XnodeBaseConfig.h>
|
||||
#include <XnodeSerial.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <Arduino.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#define HW_PIN_ERROR_LED 7
|
||||
#define HW_PIN_RADIO_LED A2
|
||||
#define HW_PIN_NETWORK_LED A3
|
||||
#define HW_PIN_SPI_ETH0_CS 9
|
||||
|
||||
#define SYS_LED_TEST_TIME 666 // ms of on time in boot to see if all leds are on.
|
||||
#define SYS_LED_BLINK_TIME 100 // ms delay of blink freq.
|
||||
|
||||
enum ShieldLED {
|
||||
SYS_LED_NONE, // = 0 is used for blink led idx
|
||||
SYS_LED_ERROR,
|
||||
SYS_LED_RADIO,
|
||||
SYS_LED_NETWORK
|
||||
};
|
||||
|
||||
enum ShieldLEDStatus {
|
||||
SYS_LED_STATUS_OFF, SYS_LED_STATUS_ON, SYS_LED_STATUS_BLINK
|
||||
};
|
||||
|
||||
class XnodeBaseHardware: public XnodeSystemHardware {
|
||||
private:
|
||||
void loopBlink();
|
||||
void writeLed(uint8_t led, uint8_t status);
|
||||
public:
|
||||
void begin();
|
||||
void loop();
|
||||
void changeLed(uint8_t led, uint8_t status);
|
||||
|
||||
// from XnodeSystemHardware
|
||||
xnode_base_config_t config;
|
||||
const char* getSystemHardwareTypeP();
|
||||
const char* getSystemHardwareVersionP();
|
||||
unsigned long getSystemHardwareRebootCount();
|
||||
bool systemHardwareConfigBegin();
|
||||
void systemHardwareConfigSave();
|
||||
void systemHardwareConfigReset();
|
||||
};
|
||||
|
||||
extern XnodeBaseHardware XBHardware;
|
||||
|
||||
#endif
|
||||
625
xnode-base/XnodeBaseNetwork.cpp
Normal file
625
xnode-base/XnodeBaseNetwork.cpp
Normal file
|
|
@ -0,0 +1,625 @@
|
|||
#include <XnodeBaseNetwork.h>
|
||||
|
||||
const char pmNetworkChipBoot[] PROGMEM = "Init eth0";
|
||||
const char pmNetworkChipError[] PROGMEM = "ERR: No chip";
|
||||
const char pmNetworkLinkError[] PROGMEM = "ERR: No link";
|
||||
const char pmNetworkStaticBoot[] PROGMEM = "Static IP";
|
||||
const char pmNetworkDhcpBoot[] PROGMEM = "Request dhcp";
|
||||
const char pmNetworkDhcpDone[] PROGMEM = "dhcp done";
|
||||
const char pmNetworkDhcpError[] PROGMEM = "ERR: dhcp failed";
|
||||
const char pmNetworkDnsLookup[] PROGMEM = "Lookup dns";
|
||||
const char pmNetworkResultError[] PROGMEM = "# Invalid result:0x";
|
||||
const char pmNetworkResultPing[] PROGMEM = "Server replied";
|
||||
|
||||
const char pmNetworkUsePrefix[] PROGMEM = "eth0_";
|
||||
const char pmNetworkConfigInfo[] PROGMEM = "net_info";
|
||||
const char pmNetworkConfigInfoEth0[] PROGMEM = "net_info_eth0";
|
||||
const char pmNetworkConfigMac[] PROGMEM = "net_mac";
|
||||
const char pmNetworkConfigIp[] PROGMEM = "net_ip";
|
||||
const char pmNetworkConfigMask[] PROGMEM = "net_mask";
|
||||
const char pmNetworkConfigGate[] PROGMEM = "net_gate";
|
||||
const char pmNetworkConfigDns[] PROGMEM = "net_dns";
|
||||
const char pmNetworkConfigKey[] PROGMEM = "net_key";
|
||||
const char pmNetworkConfigId[] PROGMEM = "net_id";
|
||||
|
||||
const char pmNetworkServerHost[] PROGMEM = "net_srv_host";
|
||||
const char pmNetworkServerIp[] PROGMEM = "net_srv_ip";
|
||||
const char pmNetworkServerLookup[] PROGMEM = "net_srv_lup";
|
||||
|
||||
const char pmNetworkServer[] PROGMEM = NET_XNODE_HOST;
|
||||
const char pmNetworkUrlPost[] PROGMEM = NET_URL_POST;
|
||||
const char pmNetworkUrlParaPostType[] PROGMEM = NET_URL_PARA_POST_TYPE;
|
||||
const char pmNetworkUrlParaReqCnt[] PROGMEM = NET_URL_PARA_REQ_CNT;
|
||||
const char pmNetworkUrlParaNetId[] PROGMEM = NET_URL_PARA_NET_ID;
|
||||
const char pmNetworkUrlParaNodeData[] PROGMEM = NET_URL_PARA_NODE_DATA;
|
||||
const char pmNetworkUrlParaNodeNumber[] PROGMEM = NET_URL_PARA_NODE_NUMBER;
|
||||
|
||||
const char pmNetworkInfoTXOpen[] PROGMEM = "net_tx_open";
|
||||
const char pmNetworkInfoTX[] PROGMEM = "net_tx";
|
||||
const char pmNetworkInfoRX[] PROGMEM = "net_rx";
|
||||
|
||||
const char pmNetworkPing[] PROGMEM = "net_ping";
|
||||
|
||||
unsigned long net_ping_boot_timer = ZERO;
|
||||
unsigned long net_ping_host_timer = ZERO;
|
||||
unsigned long net_dhcp_retry_timer = ZERO;
|
||||
unsigned long net_dns_lookup_timer = ZERO;
|
||||
uint8_t net_status_eth = ZERO;
|
||||
uint8_t net_status_ip = ZERO;
|
||||
uint8_t net_status_dns = ZERO;
|
||||
uint8_t net_status_data = ZERO;
|
||||
uint8_t net_status_ping = ZERO;
|
||||
uint8_t net_status_reply = ZERO;
|
||||
|
||||
uint8_t net_tx_open = ZERO;
|
||||
unsigned long net_tx = ZERO;
|
||||
unsigned long net_rx = ZERO;
|
||||
|
||||
char line_buf[128];
|
||||
#define ETH_BUFFER_SIZE 450
|
||||
byte Ethernet::buffer[ETH_BUFFER_SIZE];
|
||||
Stash stash;
|
||||
byte stashStart;
|
||||
byte stashSession;
|
||||
XnodeBaseNetwork XBNetwork;
|
||||
|
||||
void XnodeBaseNetwork::begin() {
|
||||
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON);
|
||||
setupChip();
|
||||
setupIp();
|
||||
XSerial.printCommentLineP(pmNetworkDnsLookup);
|
||||
XSerial.executeCommandP(pmNetworkServerLookup);
|
||||
XSerial.executeCommandP(pmNetworkConfigInfo);
|
||||
XSerial.executeCommandP(pmNetworkConfigInfoEth0);
|
||||
unsigned long time = millis();
|
||||
net_dhcp_retry_timer = time + (unsigned long) NET_DHCP_RETRY_TIME;
|
||||
net_dns_lookup_timer = time + (unsigned long) NET_DNS_LOOKUP_TIME;
|
||||
net_ping_boot_timer = time + (unsigned long) NET_PING_BOOT_TIME;
|
||||
net_ping_host_timer = time + (unsigned long) NET_PING_HOST_TIME;
|
||||
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF);
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::loop() {
|
||||
if (net_status_eth != ZERO) {
|
||||
return; // no chip
|
||||
}
|
||||
loopAutoSetup(); // auto dhcp and dns refresh
|
||||
if (net_status_ip != ZERO || net_status_dns != ZERO) {
|
||||
return; // no ip or dns
|
||||
}
|
||||
ether.packetLoop(ether.packetReceive());
|
||||
loopDataRX(); // rx first so that on tx-req packetLoop is runned first before RX code.
|
||||
loopDataTX();
|
||||
loopPingBoot();
|
||||
loopPingHost();
|
||||
}
|
||||
|
||||
// prev version needed about ~32 requests before network is working, now it works direct but we keep ping.
|
||||
void XnodeBaseNetwork::loopPingBoot() {
|
||||
if (net_status_ping == ONE) {
|
||||
return;
|
||||
}
|
||||
unsigned long time = millis();
|
||||
if (time < net_ping_boot_timer) {
|
||||
return; // wait
|
||||
}
|
||||
net_ping_boot_timer = time + (unsigned long) NET_PING_BOOT_TIME;
|
||||
if (net_status_reply == ZERO) {
|
||||
line_buf[ZERO] = ZERO;
|
||||
sendPing(); // keep sending ping requests.
|
||||
return;
|
||||
}
|
||||
if (net_status_ping == ZERO) {
|
||||
XSerial.print(CHAR_NEWLINE);// new line bacause the dot progress bar
|
||||
XSerial.printCommentLineP(pmNetworkResultPing); // let user know network is up.
|
||||
XSerial.printPromt();
|
||||
net_tx_open = ZERO; // reset open request counter
|
||||
}
|
||||
net_status_ping = ONE+ONE; // print once
|
||||
if (XBHardware.config.net_key.u8[ZERO] == ZERO) {
|
||||
sendInit(); // send init request.
|
||||
net_ping_boot_timer += (unsigned long) NET_PING_BOOT_TIME; // add extra wait time
|
||||
return;
|
||||
}
|
||||
net_status_ping = ONE; // never run this function again.
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::loopPingHost() {
|
||||
if (millis() < net_ping_host_timer) {
|
||||
return; // wait
|
||||
}
|
||||
sendPing();
|
||||
net_ping_host_timer = millis() + (unsigned long) NET_PING_HOST_TIME;
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::xxteaEncrypt(unsigned long v[2]) {
|
||||
unsigned int i;
|
||||
unsigned long v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
|
||||
for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
|
||||
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]);
|
||||
sum += delta;
|
||||
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]);
|
||||
}
|
||||
v[0]=v0; v[1]=v1;
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::xxteaDecrypt(unsigned long v[2]) {
|
||||
unsigned int i;
|
||||
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*XXTEA_NUM_ROUNDS;
|
||||
for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
|
||||
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]);
|
||||
sum -= delta;
|
||||
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]);
|
||||
}
|
||||
v[0]=v0; v[1]=v1;
|
||||
}
|
||||
|
||||
int XnodeBaseNetwork::parseReplyData(word off) {
|
||||
memset(line_buf, NULL, sizeof(line_buf));
|
||||
if (off != 0) {
|
||||
uint16_t pos = off;
|
||||
int line_pos = 0;
|
||||
|
||||
// Skip over header until data part is found
|
||||
while (Ethernet::buffer[pos]) {
|
||||
if (Ethernet::buffer[pos - 1] == '\n' && Ethernet::buffer[pos] == '\r') {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
pos += 2;
|
||||
while (Ethernet::buffer[pos]) {
|
||||
if (line_pos < 49) {
|
||||
line_buf[line_pos] = Ethernet::buffer[pos];
|
||||
line_pos++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
line_buf[line_pos] = '\0';
|
||||
return line_pos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::sendStart(char postType) {
|
||||
if (stashSession != ZERO) {
|
||||
int maxWait = 100;
|
||||
while (stashSession != ZERO) {
|
||||
loop();
|
||||
maxWait--;
|
||||
if (maxWait == ZERO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NETWORK
|
||||
if (stashSession != ZERO) {
|
||||
Serial.println(F("#D kill prev tcp req"));
|
||||
}
|
||||
#endif
|
||||
//return; // data is already sending (TODO: move ??)
|
||||
}
|
||||
|
||||
stashStart = stash.create();
|
||||
stash.print(XUtil.UNPSTR(pmNetworkUrlParaPostType));
|
||||
stash.print(postType);
|
||||
stash.print(XUtil.UNPSTR(pmNetworkUrlParaReqCnt));
|
||||
stash.print(net_tx++);
|
||||
stash.print(XUtil.UNPSTR(pmNetworkUrlParaNetId));
|
||||
for (byte i = ZERO; i < NET_BYTE_NET_ID_SIZE; ++i) {
|
||||
byte data = XBHardware.config.net_id[i];
|
||||
if (data<0xF) {
|
||||
stash.print(ZERO); // extra zero to have fixed length hex string
|
||||
}
|
||||
stash.print(data, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::sendPing() {
|
||||
sendStart(NET_URL_PT_PING);
|
||||
net_status_data = NET_URL_PT_PING;
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::sendInit() {
|
||||
#ifdef DEBUG_NETWORK
|
||||
Serial.println(F("#D req init"));
|
||||
#endif
|
||||
sendStart(NET_URL_PT_INIT);
|
||||
net_status_data = NET_URL_PT_INIT;
|
||||
}
|
||||
|
||||
NetKey x_data;
|
||||
|
||||
void XnodeBaseNetwork::sendNodeData(byte senderId, char* data) {
|
||||
sendStart(NET_URL_PT_DATA);
|
||||
stash.print(XUtil.UNPSTR(pmNetworkUrlParaNodeNumber));
|
||||
stash.print((int) senderId);
|
||||
stash.print(XUtil.UNPSTR(pmNetworkUrlParaNodeData));
|
||||
|
||||
char* dstring = data;
|
||||
while (*dstring != 0) {
|
||||
char value = *dstring;
|
||||
dstring++;
|
||||
stash.print(value);
|
||||
}
|
||||
|
||||
/*
|
||||
byte i = 0;
|
||||
char* dstring = data;
|
||||
while (*dstring != 0) {
|
||||
x_data.u8[i] = *dstring;
|
||||
dstring++;
|
||||
i++;
|
||||
if (i==8) {
|
||||
i = 0;
|
||||
xxteaEncrypt(x_data.u32);
|
||||
for (byte i = 0; i < 8; ++i) {
|
||||
char value = x_data.u8[i];
|
||||
if (value == 0) {
|
||||
stash.print('00');
|
||||
continue;
|
||||
}
|
||||
if (value <= 0xF) {
|
||||
stash.print('0');
|
||||
}
|
||||
stash.print(value,HEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
while(i < 8) {
|
||||
x_data.u8[i] = 0;
|
||||
i++;
|
||||
}
|
||||
xxteaEncrypt(x_data.u32);
|
||||
for (byte i = 0; i < 8; ++i) {
|
||||
char value = x_data.u8[i];
|
||||
if (value == 0) {
|
||||
stash.print('00');
|
||||
continue;
|
||||
}
|
||||
if (value <= 0xF) {
|
||||
stash.print('0');
|
||||
}
|
||||
stash.print(value,HEX);
|
||||
}
|
||||
*/
|
||||
net_status_data = NET_URL_PT_DATA;
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::loopDataTX() {
|
||||
if (net_status_data == ZERO) {
|
||||
return; // no data to send
|
||||
}
|
||||
if (!ether.isLinkUp()) {
|
||||
if (net_status_ip == ZERO) {
|
||||
XSerial.printCommentLineP(pmNetworkLinkError);
|
||||
}
|
||||
net_status_ip = ONE;
|
||||
return; // link down; request new ip when link gets up.
|
||||
}
|
||||
|
||||
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON);
|
||||
|
||||
#ifdef DEBUG_NETWORK
|
||||
Serial.print(F("#D sendHttp pt="));
|
||||
Serial.print((char)net_status_data);
|
||||
Serial.print(F(" size="));
|
||||
Serial.println((char)stash.size(),DEC);
|
||||
#endif
|
||||
|
||||
stash.save();
|
||||
Stash::prepare(PSTR("POST http://$F/$F HTTP/1.1" "\r\n"
|
||||
"Host: $F" "\r\n"
|
||||
"Cache-Control: no-cache" "\r\n"
|
||||
"Content-type: application/x-www-form-urlencoded;\r\n"
|
||||
"Accept: application/xhtml+xml" "\r\n"
|
||||
"Content-Length: $D" "\r\n"
|
||||
"\r\n"
|
||||
"$H"), pmNetworkServer, pmNetworkUrlPost, pmNetworkServer, stash.size(), stashStart);
|
||||
net_tx_open++;
|
||||
net_status_data = ZERO;
|
||||
stashSession = ether.tcpSend(); // releases also stash buf
|
||||
//stash.release();
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::loopDataRX() {
|
||||
if (stashSession == ZERO) {
|
||||
return; // no reply to search for
|
||||
}
|
||||
const char* msgStart = ether.tcpReply(stashSession);
|
||||
if (msgStart == ZERO) {
|
||||
#ifdef DEBUG_NETWORK
|
||||
Serial.println(F("#D wait tcpReply"));
|
||||
#endif
|
||||
delay(100);
|
||||
return; // no reply yet
|
||||
}
|
||||
|
||||
net_rx++;
|
||||
stashSession = ZERO;
|
||||
parseReplyData((int) *msgStart);
|
||||
handleServerResult();
|
||||
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF);
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::handleServerResult() {
|
||||
if (line_buf[ZERO] != NET_URL_RESULT_OK) {
|
||||
XSerial.printCharP(pmNetworkResultError);
|
||||
Serial.print(line_buf[ZERO], HEX); // TODO: check
|
||||
#ifdef DEBUG_NETWORK
|
||||
Serial.print(CHAR_SPACE);
|
||||
for (int i=0;i<10;i++) {
|
||||
if (line_buf[i] != ZERO) {
|
||||
Serial.print(line_buf[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
XSerial.print(CHAR_NEWLINE);
|
||||
return;
|
||||
}
|
||||
net_tx_open--; // valid result
|
||||
net_status_reply = ONE; // we have reply
|
||||
|
||||
if (line_buf[ONE] == ZERO) {
|
||||
return; // Only X returns so nop.
|
||||
}
|
||||
|
||||
if (line_buf[ONE] == NET_URL_PT_INIT) {
|
||||
XSystem.executeCommand(line_buf + ONE + ONE,true); // skip Xi chars
|
||||
loop(); // Else we miss most of the time the second init request.
|
||||
loop(); // an other extra to be sure we done miss the second request.
|
||||
sendInit(); // request next init command
|
||||
return;
|
||||
}
|
||||
if (line_buf[ONE] == NET_URL_RESULT_OK) {
|
||||
XSystem.executeCommand(line_buf + ONE + ONE,true); // skip XX chars
|
||||
loop();
|
||||
loop();
|
||||
sendNodeData(RF_BASE_NODE_ID,XSystem.replyBuffer); // send reply as
|
||||
}
|
||||
}
|
||||
|
||||
bool XnodeBaseNetwork::isUp() {
|
||||
return ZERO == (net_status_eth + net_status_ip + net_status_dns);
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::loopAutoSetup() {
|
||||
unsigned long time = millis();
|
||||
// auto dhcp
|
||||
if (net_status_ip == ONE) {
|
||||
if (time < net_dhcp_retry_timer) {
|
||||
return; // wait
|
||||
}
|
||||
net_dhcp_retry_timer = millis() + (unsigned long) NET_DHCP_RETRY_TIME;
|
||||
setupIp();
|
||||
if (net_status_ip == ONE) {
|
||||
return; // failed dhcp
|
||||
}
|
||||
net_status_dns = ONE; // when link plugs in later
|
||||
net_dns_lookup_timer = ONE; // then do direct dns lookup
|
||||
}
|
||||
// auto dns
|
||||
if (net_status_dns == ONE) {
|
||||
if (time < net_dns_lookup_timer) {
|
||||
return; // wait
|
||||
}
|
||||
net_dns_lookup_timer = time + (unsigned long) NET_DNS_LOOKUP_TIME;
|
||||
XSerial.executeCommandP(pmNetworkServerLookup);
|
||||
}
|
||||
// auto dns refresh
|
||||
if (net_status_dns == ZERO && time > net_dns_lookup_timer) {
|
||||
net_status_dns = ONE;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: without chip it takes 3 watchdog reboots before no chip result ?? (prev lib version)
|
||||
void XnodeBaseNetwork::setupChip() {
|
||||
XSerial.printCommentLineP(pmNetworkChipBoot);
|
||||
if (ether.begin(sizeof Ethernet::buffer, XBHardware.config.net_mac, HW_PIN_SPI_ETH0_CS) == ZERO) {
|
||||
XSerial.printCommentLineP(pmNetworkChipError);
|
||||
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK);
|
||||
net_status_eth = ONE;
|
||||
return;
|
||||
}
|
||||
ether.disableBroadcast();
|
||||
ether.disableMulticast();
|
||||
delay(100); // needed for link isLinkUp to return valid value.
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::setupIp() {
|
||||
net_status_ip = ZERO;
|
||||
if (net_status_eth != ZERO) {
|
||||
return; // no chip
|
||||
}
|
||||
if (!ether.isLinkUp()) {
|
||||
net_status_ip = ONE; // do again
|
||||
XSerial.printCommentLineP(pmNetworkLinkError);
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup static if ip is given.
|
||||
if (XBHardware.config.net_ip[ZERO] != ZERO) {
|
||||
XSerial.printCommentLineP(pmNetworkStaticBoot);
|
||||
ether.staticSetup(XBHardware.config.net_ip, XBHardware.config.net_gate, XBHardware.config.net_dns);
|
||||
ether.copyIp(ether.netmask, XBHardware.config.net_mask);
|
||||
return;
|
||||
}
|
||||
XSerial.printCommentLineP(pmNetworkDhcpBoot);
|
||||
wdt_disable();
|
||||
if (!ether.dhcpSetup()) {
|
||||
net_status_ip = ONE; // do again
|
||||
XSerial.printCommentLineP(pmNetworkDhcpError);
|
||||
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_ON); // TODO: fix led blinking on timer int.
|
||||
} else {
|
||||
XSerial.printCommentLineP(pmNetworkDhcpDone);
|
||||
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF); // set led off after recovery
|
||||
}
|
||||
wdt_enable(WDT_TIMEOUT); // no link or no dhcp will take long timeout ~30s
|
||||
|
||||
#ifdef DEBUG_NET_GATE
|
||||
if (net_status_ip == ZERO) {
|
||||
byte debug_gate[NET_BYTE_IP_SIZE] = DEBUG_NET_GATE; // transparent http proxy network config.
|
||||
ether.copyIp(ether.gwip, debug_gate);
|
||||
Serial.println(F("#D Used debug gate ip"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::cmdDnsLookup() {
|
||||
net_status_dns = ZERO;
|
||||
if (net_status_eth != ZERO) {
|
||||
return; // no chip
|
||||
}
|
||||
if (net_status_ip != ZERO) {
|
||||
net_status_dns = ONE;
|
||||
return; // no ip
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NET_HISIP
|
||||
byte debug_hisip[NET_BYTE_IP_SIZE] = DEBUG_NET_HISIP;
|
||||
ether.copyIp(ether.hisip, debug_hisip);
|
||||
Serial.println(F("#D Used debug dns ip"));
|
||||
return;
|
||||
#endif
|
||||
|
||||
wdt_disable();
|
||||
if (!ether.dnsLookup(pmNetworkServer)) {
|
||||
net_status_dns = ONE;
|
||||
XSystem.buildReplyPValue(pmNetworkServerLookup,ZERO);
|
||||
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK);
|
||||
} else {
|
||||
XSystem.buildReplyPValue(pmNetworkServerLookup,ONE);
|
||||
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF);
|
||||
}
|
||||
wdt_enable (WDT_TIMEOUT);
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::cmdInfoEth0() {
|
||||
// Print currently used config
|
||||
XSystem.buildReplyCharP(pmNetworkUsePrefix);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigIp, ether.myip);
|
||||
XSystem.buildReplyCharP(pmNetworkUsePrefix);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigMask, ether.netmask);
|
||||
XSystem.buildReplyCharP(pmNetworkUsePrefix);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigGate, ether.gwip);
|
||||
XSystem.buildReplyCharP(pmNetworkUsePrefix);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigDns, ether.dnsip);
|
||||
XSystem.buildReplyCharP(pmNetworkUsePrefix);
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigMac,ether.mymac, NET_BYTE_MAC_SIZE);
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::cmdInfo() {
|
||||
// Print server value and lookup
|
||||
XSystem.buildReplyPValueP(pmNetworkServerHost,pmNetworkServer);
|
||||
XSystem.buildReplyPValueIP(pmNetworkServerIp, ether.hisip);
|
||||
|
||||
// Print config
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigMac,XBHardware.config.net_mac, NET_BYTE_MAC_SIZE);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigIp, XBHardware.config.net_ip);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigMask, XBHardware.config.net_mask);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigGate, XBHardware.config.net_gate);
|
||||
XSystem.buildReplyPValueIP(pmNetworkConfigDns, XBHardware.config.net_dns);
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigKey,XBHardware.config.net_key.u8, NET_BYTE_NET_KEY_SIZE);
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigId,XBHardware.config.net_id, NET_BYTE_NET_ID_SIZE);
|
||||
|
||||
XSystem.buildReplyPValue(pmNetworkInfoTXOpen, (int) net_tx_open);
|
||||
XSystem.buildReplyPValue(pmNetworkInfoTX, net_tx);
|
||||
XSystem.buildReplyPValue(pmNetworkInfoRX, net_rx);
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::parseCommandIp(const char* pmName, char** args, byte* ip_conf) {
|
||||
ether.parseIp(ip_conf, args[ZERO]);
|
||||
XSystem.buildReplyPValueIP(pmName, ip_conf);
|
||||
XSystem.configSave(); // auto save on change
|
||||
}
|
||||
|
||||
void XnodeBaseNetwork::systemModuleCommandList() {
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigInfo);
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigInfoEth0);
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigMac);
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigIp);
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigMask);
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigGate);
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigDns);
|
||||
XSystem.buildReplyCommandListP(pmNetworkPing);
|
||||
XSystem.buildReplyCommandListP(pmNetworkServerLookup);
|
||||
#ifdef DEBUG_NETWORK
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigId); // keep secret that these cmd work
|
||||
XSystem.buildReplyCommandListP(pmNetworkConfigKey); // for init over network with this.
|
||||
#endif
|
||||
}
|
||||
|
||||
bool XnodeBaseNetwork::systemModuleCommandExecute(char* cmd, char** args) {
|
||||
if (XUtil.strcmpP(cmd, pmNetworkConfigInfo) == ZERO) {
|
||||
cmdInfo();
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigInfoEth0) == ZERO) {
|
||||
cmdInfoEth0();
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigId) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
XUtil.charsToByteA(args[ZERO],XBHardware.config.net_id, NET_BYTE_NET_ID_SIZE);
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigId,XBHardware.config.net_id,NET_BYTE_NET_ID_SIZE);
|
||||
XSystem.configSave();
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigKey) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
XUtil.charsToByteA(args[ZERO],XBHardware.config.net_key.u8, NET_BYTE_NET_KEY_SIZE);
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigKey,XBHardware.config.net_key.u8,NET_BYTE_NET_KEY_SIZE);
|
||||
XSystem.configSave();
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigMac) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
XUtil.charsToByteA(args[ZERO],XBHardware.config.net_mac, NET_BYTE_MAC_SIZE);
|
||||
XSystem.buildReplyPValueByteA(pmNetworkConfigMac,XBHardware.config.net_mac, NET_BYTE_MAC_SIZE);
|
||||
XSystem.configSave();
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigIp) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
parseCommandIp(pmNetworkConfigIp, args, XBHardware.config.net_ip);
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigMask) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
parseCommandIp(pmNetworkConfigMask, args, XBHardware.config.net_mask);
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigGate) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
parseCommandIp(pmNetworkConfigGate, args, XBHardware.config.net_gate);
|
||||
return true;
|
||||
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkConfigDns) == ZERO) {
|
||||
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
|
||||
return true;
|
||||
}
|
||||
parseCommandIp(pmNetworkConfigDns, args, XBHardware.config.net_dns);
|
||||
return true;
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkPing) == ZERO) {
|
||||
sendPing();
|
||||
return true;
|
||||
} else if (XUtil.strcmpP(cmd, pmNetworkServerLookup) == ZERO) {
|
||||
cmdDnsLookup();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
53
xnode-base/XnodeBaseNetwork.h
Normal file
53
xnode-base/XnodeBaseNetwork.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef XnodeBaseNetwork_h
|
||||
#define XnodeBaseNetwork_h
|
||||
|
||||
#include <XnodeBaseHardware.h>
|
||||
#include <XnodeSerial.h>
|
||||
#include <XnodeSystem.h>
|
||||
#include <XnodeSystemModule.h>
|
||||
#include <XnodeBaseConfig.h>
|
||||
#include <XnodeUtil.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <Arduino.h>
|
||||
#include <EtherCard.h>
|
||||
|
||||
#define XXTEA_NUM_ROUNDS 32
|
||||
|
||||
class XnodeBaseNetwork: public XnodeSystemModule {
|
||||
private:
|
||||
int parseReplyData(word off);
|
||||
|
||||
void sendStart(char postType);
|
||||
void loopAutoSetup();
|
||||
void loopDataTX();
|
||||
void loopDataRX();
|
||||
void loopPingBoot();
|
||||
void loopPingHost();
|
||||
void handleServerResult();
|
||||
void setupChip();
|
||||
void setupIp();
|
||||
void sendPing();
|
||||
void sendInit();
|
||||
void parseCommandIp(const char* pmName, char** args, byte* ip_conf);
|
||||
void xxteaEncrypt(unsigned long v[2]);
|
||||
void xxteaDecrypt(unsigned long v[2]);
|
||||
|
||||
void cmdDnsLookup();
|
||||
void cmdInfo();
|
||||
void cmdInfoEth0();
|
||||
public:
|
||||
void begin();
|
||||
void loop();
|
||||
bool isUp();
|
||||
|
||||
void sendNodeData(byte senderId, char* data);
|
||||
|
||||
// from XnodeSystemModule
|
||||
bool systemModuleCommandExecute(char* cmd, char** args);
|
||||
void systemModuleCommandList();
|
||||
};
|
||||
|
||||
extern XnodeBaseNetwork XBNetwork;
|
||||
|
||||
#endif
|
||||
|
||||
243
xnode-base/XnodeBaseRadio.cpp
Normal file
243
xnode-base/XnodeBaseRadio.cpp
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
33
xnode-base/XnodeBaseRadio.h
Normal file
33
xnode-base/XnodeBaseRadio.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef XnodeBaseRadio_h
|
||||
#define XnodeBaseRadio_h
|
||||
|
||||
#include <XnodeBaseHardware.h>
|
||||
#include <XnodeSerial.h>
|
||||
#include <XnodeSystem.h>
|
||||
#include <XnodeSystemModule.h>
|
||||
#include <XnodeBaseNetwork.h>
|
||||
#include <XnodeProtocol.h>
|
||||
#include <RFM69.h>
|
||||
|
||||
class XnodeBaseRadio: public XnodeSystemModule {
|
||||
private:
|
||||
void checkNoDataTimeout();
|
||||
void checkPing();
|
||||
void cmdOpen();
|
||||
void cmdClose();
|
||||
void cmdInfo();
|
||||
void handleCmdInit();
|
||||
void handleCmdFlash();
|
||||
void sendReply();
|
||||
public:
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
// from XnodeSystemModule
|
||||
bool systemModuleCommandExecute(char* cmd, char** args);
|
||||
void systemModuleCommandList();
|
||||
};
|
||||
|
||||
extern XnodeBaseRadio XBRadio;
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue