Added project
This commit is contained in:
parent
fe9aa14dfd
commit
2d73cc8845
186 changed files with 21174 additions and 0 deletions
4
xnode-satellite/Makefile
Normal file
4
xnode-satellite/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Minimal makefile only includes the master and libs.
|
||||
MASTER_LIBS = rfm69 spi dht xnode-shared
|
||||
SKT_PDE_SRC = XnodeSatellite.cpp
|
||||
include ../lib-build/make/Makefile.master
|
||||
31
xnode-satellite/XnodeSatellite.cpp
Normal file
31
xnode-satellite/XnodeSatellite.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Xnode Satellite
|
||||
*/
|
||||
|
||||
#include <XnodeSerial.h>
|
||||
#include <XnodeSystem.h>
|
||||
#include <XnodeSatelliteHardware.h>
|
||||
#include <XnodeSatelliteRadio.h>
|
||||
#include <XnodeSatelliteSensor.h>
|
||||
|
||||
void setup() {
|
||||
// Build system modules
|
||||
XSystem.registrateSystemModule(&XSRadio);
|
||||
XSystem.registrateSystemModule(&XSSensor);
|
||||
|
||||
// Start system modules
|
||||
XSerial.begin();
|
||||
XSystem.begin(&XSHardware);
|
||||
XSRadio.begin();
|
||||
XSSensor.begin();
|
||||
|
||||
// Mark device booted
|
||||
XSystem.bootDone();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
XSerial.loop();
|
||||
XSystem.loop();
|
||||
XSRadio.loop();
|
||||
XSSensor.loop();
|
||||
}
|
||||
42
xnode-satellite/XnodeSatelliteHardware.cpp
Normal file
42
xnode-satellite/XnodeSatelliteHardware.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include <XnodeSatelliteHardware.h>
|
||||
|
||||
const char pmSystemHardwareType[] PROGMEM = "xnode-satellite";
|
||||
const char pmSystemHardwareVersion[] PROGMEM = XNODE_VERSION;
|
||||
|
||||
xnode_satellite_config_t config;
|
||||
xnode_satellite_config_t EEMEM eeprom;
|
||||
XnodeSatelliteHardware XSHardware;
|
||||
|
||||
const char* XnodeSatelliteHardware::getSystemHardwareTypeP() {
|
||||
return pmSystemHardwareType;
|
||||
}
|
||||
|
||||
const char* XnodeSatelliteHardware::getSystemHardwareVersionP() {
|
||||
return pmSystemHardwareVersion;
|
||||
}
|
||||
|
||||
unsigned long XnodeSatelliteHardware::getSystemHardwareRebootCount() {
|
||||
return config.sys_boot;
|
||||
}
|
||||
|
||||
bool XnodeSatelliteHardware::systemHardwareConfigBegin() {
|
||||
eeprom_read_block((void*) &config, (void*) &eeprom, sizeof(xnode_satellite_config_t));
|
||||
if (config.eeprom_struct_size != sizeof(xnode_satellite_config_t)) {
|
||||
return true;
|
||||
}
|
||||
config.sys_boot++;
|
||||
return false;
|
||||
}
|
||||
|
||||
void XnodeSatelliteHardware::systemHardwareConfigSave() {
|
||||
config.eeprom_struct_size = sizeof(xnode_satellite_config_t);
|
||||
eeprom_write_block((const void*) &config, (void*) &eeprom, sizeof(xnode_satellite_config_t));
|
||||
}
|
||||
|
||||
void XnodeSatelliteHardware::systemHardwareConfigReset() {
|
||||
config.sys_boot = ZERO;
|
||||
config.node_id = ZERO;
|
||||
for (byte i = ZERO; i < RF_KEY_SIZE; ++i) {
|
||||
config.rf_key[i] = ZERO;
|
||||
}
|
||||
}
|
||||
26
xnode-satellite/XnodeSatelliteHardware.h
Normal file
26
xnode-satellite/XnodeSatelliteHardware.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef XnodeSatelliteHardware_h
|
||||
#define XnodeSatelliteHardware_h
|
||||
|
||||
#include <XnodeSystem.h>
|
||||
#include <XnodeConstants.h>
|
||||
#include <XnodeSatelliteConfig.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
#define HW_PIN_DHT_WIRE 4
|
||||
|
||||
class XnodeSatelliteHardware: public XnodeSystemHardware {
|
||||
public:
|
||||
// from XnodeSystemHardware
|
||||
xnode_satellite_config_t config;
|
||||
const char* getSystemHardwareTypeP();
|
||||
const char* getSystemHardwareVersionP();
|
||||
unsigned long getSystemHardwareRebootCount();
|
||||
bool systemHardwareConfigBegin();
|
||||
void systemHardwareConfigSave();
|
||||
void systemHardwareConfigReset();
|
||||
};
|
||||
|
||||
extern XnodeSatelliteHardware XSHardware;
|
||||
|
||||
#endif
|
||||
|
||||
204
xnode-satellite/XnodeSatelliteRadio.cpp
Normal file
204
xnode-satellite/XnodeSatelliteRadio.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
#include <XnodeSatelliteRadio.h>
|
||||
|
||||
const char pmRadioChipInit[] PROGMEM = MSG_RF_CHIP_INIT;
|
||||
const char pmRadioChipError[] PROGMEM = MSG_RF_CHIP_ERROR;
|
||||
const char pmRadioExecutePrefix[] PROGMEM = "@";//MSG_REMOTE_PREFIX; // FIXME
|
||||
|
||||
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 pmRadioEncrypt[] PROGMEM = MSG_RF_ENCRYPT;
|
||||
const char pmRadioInfo[] PROGMEM = MSG_RF_INFO;
|
||||
|
||||
uint8_t rf_status_chip = ZERO;
|
||||
uint8_t rf_status_key = ZERO;
|
||||
|
||||
volatile unsigned long key_fetch_timer = ZERO;
|
||||
volatile unsigned long key_encrypt_timer = ZERO;
|
||||
|
||||
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;
|
||||
XnodeSatelliteRadio XSRadio;
|
||||
|
||||
void XnodeSatelliteRadio::begin() {
|
||||
XSerial.printCommentLineP(pmRadioChipInit);
|
||||
if (!radio.initialize(RF_FREQUENCY, XSHardware.config.node_id, RF_NETWORK_ID)) {
|
||||
XSerial.printCommentLineP(pmRadioChipError);
|
||||
rf_status_chip = ONE;
|
||||
return;
|
||||
}
|
||||
key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME;
|
||||
key_fetch_timer = millis() + (unsigned long) RF_KEY_FETCH_TIME;
|
||||
|
||||
// Print serial info
|
||||
XSerial.executeCommandP(pmRadioInfo);
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::loop() {
|
||||
if (rf_status_chip != ZERO) {
|
||||
return; // no chip
|
||||
}
|
||||
if (key_encrypt_timer != ZERO) {
|
||||
initEncryptionKey();
|
||||
}
|
||||
if (!radio.receiveDone()) {
|
||||
return;
|
||||
}
|
||||
//rf_status_data = ZERO;
|
||||
rf_data = *(xp_super_t*) radio.DATA;
|
||||
#ifdef DEBUG_RADIO
|
||||
Serial.print(F("#D rf_rx "));
|
||||
Serial.print(radio.SENDERID,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
|
||||
if (radio.ACK_REQUESTED) {
|
||||
#ifdef DEBUG_RADIO
|
||||
Serial.println(F("#D rf_sendACK"));
|
||||
#endif
|
||||
radio.sendACK();
|
||||
}
|
||||
if (rf_data.msg_type == RF_MSG_NODE_INIT) {
|
||||
handleNodeInit();
|
||||
} else if (rf_data.msg_type == RF_MSG_NODE_COMMAND) {
|
||||
handleNodeCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::handleNodeInit() {
|
||||
rf_msg_init = (xp_msg_init_t*) rf_data.msg_data;
|
||||
if (XSHardware.config.node_id != rf_msg_init->node_id) {
|
||||
#ifdef DEBUG_RADIO
|
||||
Serial.print(F("#D init "));
|
||||
Serial.print(rf_msg_init->node_id,DEC);
|
||||
Serial.print(CHAR_NEWLINE);
|
||||
#endif
|
||||
XSHardware.config.node_id = rf_msg_init->node_id; // allow new node_id
|
||||
}
|
||||
for (byte i = ZERO; i < RF_KEY_SIZE; ++i) {
|
||||
XSHardware.config.rf_key[i] = rf_msg_init->rf_key[i];
|
||||
}
|
||||
XSystem.configSave();
|
||||
key_fetch_timer = ZERO; // stop sending because we have reply
|
||||
if (XSHardware.config.node_id != rf_msg_init->node_id) {
|
||||
radio.initialize(RF_FREQUENCY, XSHardware.config.node_id, RF_NETWORK_ID); // re-init
|
||||
}
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::handleNodeCommand() {
|
||||
rf_msg_char = (xp_msg_char_t*) rf_data.msg_data;
|
||||
XSerial.print(CHAR_NEWLINE);
|
||||
XSerial.printCharP(pmRadioExecutePrefix);
|
||||
//XSerial.printPromtLine();
|
||||
//XSerial.processCommand(rf_msg_char->char_data);
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::initEncryptionKey() {
|
||||
if (millis() > key_encrypt_timer) {
|
||||
cmdClose(); // do once after timeout
|
||||
return;
|
||||
}
|
||||
if (key_fetch_timer==ZERO) {
|
||||
return; // we are done
|
||||
}
|
||||
if (millis() < key_fetch_timer) {
|
||||
return; // wait until next fetch
|
||||
}
|
||||
key_fetch_timer = millis() + (unsigned long) RF_KEY_FETCH_TIME;
|
||||
|
||||
// Setup first data package for fetching key rf_keys.
|
||||
rf_data.msg_type = RF_MSG_NODE_INIT;
|
||||
rf_msg_init = (xp_msg_init_t*) rf_data.msg_data;
|
||||
rf_msg_init->node_id = XSHardware.config.node_id; // send our id, so we fetch only once new id.
|
||||
send();
|
||||
}
|
||||
|
||||
byte XnodeSatelliteRadio::readTemperature() {
|
||||
return radio.readTemperature();
|
||||
}
|
||||
|
||||
bool XnodeSatelliteRadio::isSecure() {
|
||||
return key_encrypt_timer == ZERO;
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::cmdClose() {
|
||||
XSystem.buildReplyPValue(pmRadioEncrypt, ONE);
|
||||
radio.encrypt((const char*) XSHardware.config.rf_key);
|
||||
key_encrypt_timer = ZERO; // disable calling initEncrytion and this
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::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);
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::send() {
|
||||
//rf_tx++;
|
||||
if (radio.sendWithRetry(RF_BASE_NODE_ID, (const void*) &rf_data, sizeof(xp_super_t)), 5, 100) {
|
||||
// TODO make cnt
|
||||
Serial.println("# send ok");
|
||||
} else {
|
||||
Serial.println("# ERR: send failed");
|
||||
}
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::sendNodeData(char* data) {
|
||||
rf_data.msg_type = RF_MSG_NODE_DATA;
|
||||
rf_msg_char = (xp_msg_char_t*) rf_data.msg_data;
|
||||
|
||||
// TODO: add loop + cnt over data
|
||||
strcpy(rf_msg_char->char_data, data);
|
||||
send();
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::sendCommandP(const char* cmdName) {
|
||||
if (!isSecure()) {
|
||||
return; // wait until line is secure
|
||||
}
|
||||
char sendCommandBuff[32];
|
||||
strcpy(sendCommandBuff, XUtil.UNPSTR(cmdName)); // free buffer as gets used in strcmpP again..
|
||||
XSystem.executeCommand(sendCommandBuff);
|
||||
sendNodeData(XSystem.replyBuffer); // print result or error
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::cmdInfo() {
|
||||
// Print key
|
||||
XSystem.buildReplyPValueByteA(pmRadioInfoKey,XSHardware.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) XSHardware.config.node_id);
|
||||
XSystem.buildReplyPValue(pmRadioEncrypt,(int) key_encrypt_timer == ZERO ? ONE : ZERO);// if timer==0 then encrypted=1
|
||||
}
|
||||
|
||||
void XnodeSatelliteRadio::systemModuleCommandList() {
|
||||
XSystem.buildReplyCommandListP(pmRadioInfo);
|
||||
XSystem.buildReplyCommandListP(pmRadioEncrypt);
|
||||
}
|
||||
|
||||
bool XnodeSatelliteRadio::systemModuleCommandExecute(char* cmd, char** args) {
|
||||
if (XUtil.strcmpP(cmd, pmRadioInfo) == ZERO) {
|
||||
cmdInfo();
|
||||
return true;
|
||||
} else if (XUtil.strcmpP(cmd, pmRadioEncrypt) == ZERO) {
|
||||
if (key_encrypt_timer == ZERO) {
|
||||
cmdOpen();
|
||||
} else {
|
||||
cmdClose();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
34
xnode-satellite/XnodeSatelliteRadio.h
Normal file
34
xnode-satellite/XnodeSatelliteRadio.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef XnodeSatelliteRadio_h
|
||||
#define XnodeSatelliteRadio_h
|
||||
|
||||
#include <XnodeSatelliteHardware.h>
|
||||
#include <XnodeSystemModule.h>
|
||||
#include <XnodeProtocol.h>
|
||||
#include <XnodeSystem.h>
|
||||
#include <RFM69.h>
|
||||
|
||||
class XnodeSatelliteRadio: public XnodeSystemModule {
|
||||
public:
|
||||
void begin();
|
||||
void loop();
|
||||
void sendCommandP(const char* cmdName);
|
||||
void sendNodeData(char* data);
|
||||
byte readTemperature();
|
||||
private:
|
||||
bool isSecure();
|
||||
void cmdClose();
|
||||
void cmdOpen();
|
||||
void initEncryptionKey();
|
||||
void send();
|
||||
void handleNodeInit();
|
||||
void handleNodeCommand();
|
||||
void cmdInfo();
|
||||
|
||||
// from XnodeSystemModule
|
||||
virtual bool systemModuleCommandExecute(char* cmd, char** args);
|
||||
virtual void systemModuleCommandList();
|
||||
};
|
||||
|
||||
extern XnodeSatelliteRadio XSRadio;
|
||||
|
||||
#endif
|
||||
117
xnode-satellite/XnodeSatelliteSensor.cpp
Normal file
117
xnode-satellite/XnodeSatelliteSensor.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#include <XnodeSatelliteSensor.h>
|
||||
|
||||
const char pmSensorInit[] PROGMEM = "Init sensors";
|
||||
|
||||
const char pmSensorRadioTemp[] PROGMEM = "s_rt";
|
||||
const char pmSensorDHTTemp[] PROGMEM = "s_dt";
|
||||
const char pmSensorDHTWater[] PROGMEM = "s_dh";
|
||||
const char pmSensorSolarVoltage[] PROGMEM = "s_sv";
|
||||
const char pmSensorRotoCupsPPM[] PROGMEM = "s_rp";
|
||||
|
||||
#define READ_SENSOR_TIME 15000
|
||||
unsigned long read_sensor_timerA = ZERO;
|
||||
unsigned long read_sensor_timerB = ZERO;
|
||||
unsigned long read_sensor_timerC = ZERO;
|
||||
unsigned long read_sensor_timerD = ZERO;
|
||||
DHT dht(HW_PIN_DHT_WIRE,DHT22,6);
|
||||
XnodeSatelliteSensor XSSensor;
|
||||
|
||||
/*
|
||||
int valueRadioTemp = ZERO;
|
||||
int valueDHTTemp = ZERO;
|
||||
int valueDHTWater = ZERO;
|
||||
int valueSolarVoltage = ZERO;
|
||||
int rotoCupsPPM = ZERO;
|
||||
|
||||
byte valueRadioTemp = ZERO;
|
||||
float valueDHTTemp = ZEROf;
|
||||
float valueDHTWater = ZEROf;
|
||||
int valueSolarVoltage = ZERO;
|
||||
int rotoCupsPPM = ZERO;
|
||||
*/
|
||||
void XnodeSatelliteSensor::begin() {
|
||||
XSerial.printCommentLineP(pmSensorInit);
|
||||
|
||||
|
||||
//delay(1100); // chip needs 1 sec init time, else we get NAN returned.
|
||||
read_sensor_timerA = millis() + (unsigned long) READ_SENSOR_TIME; // temp redo with deep sleep
|
||||
read_sensor_timerB = millis() + (unsigned long) READ_SENSOR_TIME + 2000;
|
||||
read_sensor_timerC = millis() + (unsigned long) READ_SENSOR_TIME + 3000;
|
||||
read_sensor_timerD = millis() + (unsigned long) READ_SENSOR_TIME + 4000;
|
||||
XSerial.executeCommandP(pmSensorRadioTemp);
|
||||
XSerial.executeCommandP(pmSensorDHTTemp);
|
||||
XSerial.executeCommandP(pmSensorSolarVoltage);
|
||||
XSerial.executeCommandP(pmSensorDHTWater);
|
||||
}
|
||||
|
||||
void XnodeSatelliteSensor::loop() {
|
||||
loopA();
|
||||
loopB();
|
||||
loopC();
|
||||
loopD();
|
||||
}
|
||||
|
||||
void XnodeSatelliteSensor::loopA() {
|
||||
if (millis() < read_sensor_timerA) {
|
||||
return;
|
||||
}
|
||||
read_sensor_timerA = millis() + (unsigned long) READ_SENSOR_TIME;
|
||||
XSRadio.sendCommandP(pmSensorDHTTemp);
|
||||
}
|
||||
|
||||
void XnodeSatelliteSensor::loopB() {
|
||||
if (millis() < read_sensor_timerB) {
|
||||
return;
|
||||
}
|
||||
read_sensor_timerB = millis() + (unsigned long) READ_SENSOR_TIME;
|
||||
XSRadio.sendCommandP(pmSensorDHTWater);
|
||||
}
|
||||
|
||||
void XnodeSatelliteSensor::loopC() {
|
||||
if (millis() < read_sensor_timerC) {
|
||||
return;
|
||||
}
|
||||
read_sensor_timerC = millis() + (unsigned long) READ_SENSOR_TIME;
|
||||
XSRadio.sendCommandP(pmSensorSolarVoltage);
|
||||
}
|
||||
|
||||
void XnodeSatelliteSensor::loopD() {
|
||||
if (millis() < read_sensor_timerD) {
|
||||
return;
|
||||
}
|
||||
read_sensor_timerD = millis() + (unsigned long) READ_SENSOR_TIME;
|
||||
XSRadio.sendCommandP(pmSensorRadioTemp);
|
||||
}
|
||||
|
||||
void XnodeSatelliteSensor::systemModuleCommandList() {
|
||||
XSystem.buildReplyCommandListP(pmSensorRadioTemp);
|
||||
XSystem.buildReplyCommandListP(pmSensorDHTTemp);
|
||||
XSystem.buildReplyCommandListP(pmSensorDHTWater);
|
||||
XSystem.buildReplyCommandListP(pmSensorSolarVoltage);
|
||||
//XSystem.buildReplyCommandListP(pmSensorRotoCupsPPM);
|
||||
}
|
||||
|
||||
bool XnodeSatelliteSensor::systemModuleCommandExecute(char* cmd, char** args) {
|
||||
if (XUtil.strcmpP(cmd, pmSensorRadioTemp) == ZERO) {
|
||||
XSystem.buildReplyPValue(pmSensorRadioTemp,XSRadio.readTemperature());
|
||||
return true;
|
||||
}
|
||||
if (XUtil.strcmpP(cmd, pmSensorDHTTemp) == ZERO) {
|
||||
XSystem.buildReplyPValue(pmSensorDHTTemp,dht.readTemperature());// TODO: fixme
|
||||
return true;
|
||||
}
|
||||
if (XUtil.strcmpP(cmd, pmSensorDHTWater) == ZERO) {
|
||||
XSystem.buildReplyPValue(pmSensorDHTWater,dht.readHumidity());
|
||||
return true;
|
||||
}
|
||||
if (XUtil.strcmpP(cmd, pmSensorSolarVoltage) == ZERO) {
|
||||
XSystem.buildReplyPValue(pmSensorSolarVoltage,analogRead(A1));
|
||||
return true;
|
||||
}
|
||||
if (XUtil.strcmpP(cmd, pmSensorRotoCupsPPM) == ZERO) {
|
||||
//XSystem.buildReplyPValue(pmSensorRotoCupsPPM,readAnalog(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
28
xnode-satellite/XnodeSatelliteSensor.h
Normal file
28
xnode-satellite/XnodeSatelliteSensor.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef XnodeSatelliteSensor_h
|
||||
#define XnodeSatelliteSensor_h
|
||||
|
||||
#include <XnodeSatelliteRadio.h>
|
||||
#include <XnodeSatelliteHardware.h>
|
||||
#include <XnodeSystemModule.h>
|
||||
#include <DHT.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
class XnodeSatelliteSensor: public XnodeSystemModule {
|
||||
private:
|
||||
void loopA();
|
||||
void loopB();
|
||||
void loopC();
|
||||
void loopD();
|
||||
public:
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
// from XnodeSystemModule
|
||||
virtual bool systemModuleCommandExecute(char* cmd, char** args);
|
||||
virtual void systemModuleCommandList();
|
||||
};
|
||||
|
||||
extern XnodeSatelliteSensor XSSensor;
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue