3
0
Fork 0

Added project

This commit is contained in:
Willem Cazander 2022-11-13 01:46:38 +01:00
parent fe9aa14dfd
commit 2d73cc8845
186 changed files with 21174 additions and 0 deletions

View file

@ -0,0 +1,248 @@
/*
* Reflash a boot loader and a sketch an a second ATmega.
* MegaIspRepair
* 2014, Jan 21 <w.cazander@gmail.com> Rewrote to class and converted to boot pair with lcd.
* IspRepair
* 2010-05-29 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
* BootCloner
* adapted from http://www.arduino.cc/playground/BootCloner/BootCloner
* original copyright notice: 2007 by Amplificar <mailto:amplificar@gmail.com>
*/
#include <MegaIspRepair.h>
#include <MegaIspRepairConfig.h>
bool fastSPI = false; // don't start in fast mode right away
// transfer a byte using software SPI, using a faster mode when possible
byte MegaIspRepair::XferByte(byte v) {
byte result = 0;
if (fastSPI)
for (byte i = 0; i < 8; ++i) {
bitWrite(PORTC, 3, v & 0x80);
v <<= 1;
bitClear(PORTC, 0);
result <<= 1;
bitSet(PORTC, 0);
result |= bitRead(PIND, 4);
}
else
for (byte i = 0; i < 8; ++i) {
digitalWrite(PIN_MOSI, v & 0x80);
digitalWrite(PIN_SCK, 0); // slow pulse, max 60KHz
digitalWrite(PIN_SCK, 1);
v <<= 1;
result = (result << 1) | digitalRead(PIN_MISO);
}
return result;
}
// send 4 bytes to target microcontroller, returns the fourth MISO byte
byte MegaIspRepair::Send_ISP(word v01, byte v2, byte v3) {
XferByte(v01 >> 8);
XferByte(v01);
XferByte(v2);
return XferByte(v3);
}
// send 4 bytes to target microcontroller and wait for completion
void MegaIspRepair::Send_ISP_wait(word v01, byte v2, byte v3) {
Send_ISP(v01, v2, v3);
while (Send_ISP(CMD_Poll) & 1)
;
}
// reset the target microcontroller
void MegaIspRepair::Reset_Target() {
digitalWrite(RESET, 1);
digitalWrite(PIN_SCK, 0); // has to be set LOW at startup, or PE fails
delay(30);
digitalWrite(RESET, 0);
delay(30); // minimum delay here is 20ms for the ATmega8
}
// print the 16 signature bytes (device codes)
void MegaIspRepair::Read_Signature() {
Serial.print("Signatures:");
for (byte x = 0; x < 8; ++x) {
Serial.print(" ");
Serial.print(Send_ISP(CMD_Read_Signature, x), HEX);
}
Serial.println("");
}
// prints the lock and fuse bits (no leading zeros)
byte MegaIspRepair::Read_Fuses(byte flo, byte fhi) {
Serial.print("Lock Bits: ");
Serial.println(Send_ISP(CMD_Read_Lock), HEX);
Serial.print("Fuses: low ");
Serial.print(Send_ISP(CMD_Read_Fuse_Low), HEX);
Serial.print(", high ");
Serial.print(Send_ISP(CMD_Read_Fuse_High), HEX);
Serial.print(", extended ");
Serial.println(Send_ISP(CMD_Read_Fuse_Extended), HEX);
return Send_ISP(CMD_Read_Lock) == LOCK_BITS && Send_ISP(CMD_Read_Fuse_Low) == flo && Send_ISP(CMD_Read_Fuse_High) == fhi && Send_ISP(CMD_Read_Fuse_Extended) == FUSE_EXTENDED;
}
word MegaIspRepair::addr2page(word addr) {
return (word)(addr & ~(PAGE_BYTES - 1)) >> 1;
}
void MegaIspRepair::LoadPage(word addr, const byte* ptr) {
word cmd = addr & 1 ? CMD_Load_Page_High : CMD_Load_Page_Low;
Send_ISP(cmd | (addr >> 9), addr >> 1, pgm_read_byte(ptr));
}
void MegaIspRepair::WritePage(word page) {
Send_ISP_wait(CMD_Write_Page | (page >> 8), page);
}
void MegaIspRepair::WriteData(word start, const byte* data, word count) {
word page = addr2page(start);
for (word i = 0; i < count; i += 2) {
if (page != addr2page(start)) {
WritePage(page);
Serial.print('.');
page = addr2page(start);
}
LoadPage(start++, data + i);
LoadPage(start++, data + i + 1);
}
WritePage(page);
Serial.println();
}
byte MegaIspRepair::EnableProgramming() {
Reset_Target();
if (Send_ISP(CMD_Program_Enable, 0x22, 0x22) != 0x22) {
Serial.println("Program Enable FAILED");
return 0;
}
return 1;
}
void MegaIspRepair::blink() {
pinMode(DONE_LED, OUTPUT);
digitalWrite(DONE_LED, 0); // inverted logic
delay(100); // blink briefly
pinMode(DONE_LED, INPUT);
}
byte MegaIspRepair::readConfig() {
static byte pins[] = { CONFIG1, CONFIG2, CONFIG3, CONFIG4 };
byte switches = 0;
for (byte i = 0; i < 4; ++i) {
pinMode(pins[i], INPUT);
digitalWrite(pins[i], 1); // enable pull-up
bitWrite(switches, i, digitalRead(pins[i]));
digitalWrite(pins[i], 0); // disable pull-up
}
return switches; // a 4-bit value, i.e. 0..15
}
byte MegaIspRepair::programSection(byte index, mega_flash_data_struct sections[]) {
Serial.print(index, DEC);
byte f = EnableProgramming();
if (f) {
fastSPI = FAST_SPI && PIN_SCK == 14 && PIN_MISO == 4 && PIN_MOSI == 17;
WriteData(sections[index].start, sections[index].progdata + sections[index].off, sections[index].count);
fastSPI = false;
}
return f;
}
void MegaIspRepair::run(const char* typeTitle, mega_flash_data_struct sections[]) {
Serial.begin(57600);
Serial.println();
Serial.println("# Booting mega_isp_repair");
Serial.println("# Version=3.0");
Serial.print("# Type=");
Serial.print(typeTitle);
Serial.println();
blink();
digitalWrite(PIN_SCK, 1);
digitalWrite(PIN_MOSI, 1);
digitalWrite(RESET, 1);
pinMode(PIN_SCK, OUTPUT);
pinMode(PIN_MOSI, OUTPUT);
pinMode(RESET, OUTPUT);
byte config = readConfig();
byte xspeed = 0;
// Always burn a boot pair
byte bootld = (config * 2) + 0;
byte sketch = (config * 2) + 1;
Serial.print("Configuration: ");
Serial.print(config, HEX);
Serial.println(xspeed ? " (resonator)" : " (crystal)");
Serial.println();
Serial.println(sections[sketch].title);
Serial.println(sections[bootld].title);
Serial.println();
if (EnableProgramming()) {
Serial.println("Erasing Flash");
Send_ISP_wait(CMD_Erase_Flash, 0x22, 0x22);
if (EnableProgramming()) {
byte fuseLo = xspeed ? FUSE_LOW_FAST : FUSE_LOW_XTAL;
// derive the boot size from its starting address
byte fuseHi = FUSE_HIGH_2048;
switch (sections[bootld].start & 0x0FFF) {
case 0x0E00:
fuseHi = FUSE_HIGH_512;
break;
case 0x0C00:
fuseHi = FUSE_HIGH_1024;
break;
case 0x0800:
fuseHi = FUSE_HIGH_2048;
break;
case 0x0000:
fuseHi = FUSE_HIGH_4096;
break;
}
// set the fuses and lock bits
Serial.println("Setting Fuses");
Send_ISP_wait(CMD_Write_Fuse_Low, 0, fuseLo);
Send_ISP_wait(CMD_Write_Fuse_High, 0, fuseHi);
Send_ISP_wait(CMD_Write_Fuse_Extended, 0, FUSE_EXTENDED);
Send_ISP_wait(CMD_Write_Lock, 0, LOCK_BITS);
// burn the sketch and bootstrap code
if (programSection(sketch, sections) && programSection(bootld, sections)) {
Read_Signature();
if (Read_Fuses(fuseLo, fuseHi)) {
Serial.println("\nDone.");
blink();
} else
Serial.println("Fuses NOT OK!");
}
}
}
pinMode(PIN_SCK, INPUT);
pinMode(PIN_MOSI, INPUT);
pinMode(RESET, INPUT);
digitalWrite(PIN_SCK, 0);
digitalWrite(PIN_MOSI, 0);
digitalWrite(RESET, 0);
#if ARDUINO >= 100
Serial.flush();
#endif
delay(10); // let the serial port finish
cli(); // stop responding to interrupts
ADCSRA &= ~bit(ADEN); // disable the ADC
//PRR = 0xFF; // disable all subsystems
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_mode();
// total power down, can only wake up with a hardware reset
}

View file

@ -0,0 +1,39 @@
#ifndef IspRepair_h
#define IspRepair_h
#include <Arduino.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <inttypes.h>
#include <stdbool.h>
typedef struct {
const char* title;
const char* mdate;
const unsigned char* progdata;
unsigned start;
unsigned off;
unsigned count;
} mega_flash_data_struct;
class MegaIspRepair {
private:
static byte XferByte(byte v);
static byte Send_ISP(word v01, byte v2 = 0, byte v3 = 0);
static void Send_ISP_wait(word v01, byte v2 = 0, byte v3 = 0);
static void Reset_Target();
static void Read_Signature();
static byte Read_Fuses(byte flo, byte fhi);
static word addr2page(word addr);
static void LoadPage(word addr, const byte* ptr);
static void WritePage(word page);
static void WriteData(word start, const byte* data, word count);
static byte EnableProgramming();
static void blink();
static byte readConfig();
static byte programSection(byte index, mega_flash_data_struct sections[]);
public:
void run(const char* typeTitle, mega_flash_data_struct sections[]);
};
#endif

View file

@ -0,0 +1,49 @@
#define FAST_SPI 1 // comment out to revert to digitalWrite() calls
// pin definitions
#define PIN_SCK 14 // PC0 - AIO1 - serial clock to target avr
#define PIN_MISO 4 // PD4 - DIO1 - input from target avr
#define PIN_MOSI 17 // PC3 - AIO4 - output to target avr
#define RESET 7 // PD7 - DIO4 - reset pin of the target avr
#define DONE_LED 9 // B1 - blue LED on JN USB, blinks on start and when ok
// pins used for the optional config switches
#define CONFIG1 5 // DIO2
#define CONFIG2 15 // AIO2
#define CONFIG3 16 // AIO3
#define CONFIG4 6 // DIO3
// MPU-specific values
#define PAGE_BYTES 128 // ATmega168 and ATmega328
#define LOCK_BITS 0xCF
#define FUSE_LOW_XTAL 0xFF
#define FUSE_LOW_FAST 0xDE
#define FUSE_HIGH_512 0xDE
#define FUSE_HIGH_1024 0xDC
#define FUSE_HIGH_2048 0xDA
#define FUSE_HIGH_4096 0xD8 // not in ATmega168
#define FUSE_EXTENDED 0xFD
// ISP Command Words
#define CMD_Program_Enable 0xAC53
#define CMD_Erase_Flash 0xAC80
#define CMD_Poll 0xF000
#define CMD_Read_Flash_Low 0x2000
#define CMD_Read_Flash_High 0x2800
#define CMD_Load_Page_Low 0x4000
#define CMD_Load_Page_High 0x4800
#define CMD_Write_Page 0x4C00
#define CMD_Read_EEPROM 0xA000
#define CMD_Write_EEPROM 0xC000
#define CMD_Read_Lock 0x5800
#define CMD_Write_Lock 0xACE0
#define CMD_Read_Signature 0x3000
#define CMD_Write_Fuse_Low 0xACA0
#define CMD_Write_Fuse_High 0xACA8
#define CMD_Write_Fuse_Extended 0xACA4
#define CMD_Read_Fuse_Low 0x5000
#define CMD_Read_Fuse_High 0x5808
#define CMD_Read_Fuse_Extended 0x5008
#define CMD_Read_Fuse_High 0x5808
#define CMD_Read_Calibration 0x3800

44
lib/isp-repair/readme.txt Normal file
View file

@ -0,0 +1,44 @@
// This code is adapted from isp_prepare. It omits the button and run LED,
// and starts right away. To use, open a serial console and wait until done.
//
// The 6 ISP pins of the target board need to be connected to the board running
// this sketch as follows (using Arduino pin naming):
//
// ISP pin 1 <-> digital 4 (MISO) ISP CONNECTOR
// ISP pin 2 <-> VCC +---+---+
// ISP pin 3 <-> analog 0 (SCK) | 1 | 2 |
// ISP pin 4 <-> analog 3 (MOSI) | 3 | 4 |
// ISP pin 5 <-> digital 7 (RESET) | 5 | 6 |
// ISP pin 6 <-> ground +---+---+
//
// The same hookup, using JeeNode port/pin names:
//
// ISP pin 1 <-> DIO1
// ISP pin 2 <-> +3V
// ISP pin 3 <-> AIO1
// ISP pin 4 <-> AIO4
// ISP pin 5 <-> DIO4
// ISP pin 6 <-> GND
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/* Include code using a file generated in isp_prepare/ dir with this cmd:
./hex2c.tcl Blink.cpp.hex \
RF12demo.cpp.hex \
optiboot_atmega328.hex \
ATmegaBOOT_168_atmega328.hex \
optiboot_atmega328_1s.hex \
optiboot_atmega328.hex >../isp_repair2/data.h
Code choices are fixed: section 0 is RF12demo, section 1 is blink
Boot choices are entries 2..5 in the sections[] array in data.h
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View file

@ -0,0 +1,77 @@
#ifndef XnodeBaseConstants_h
#define XnodeBaseConstants_h
// Temp version here, todo move to makefile and use git --version
#define XNODE_VERSION "1.3"
// Default serial baudrate for all devices
#define SERIAL_SPEED 115200
// Default watchdog timeout
#define WDT_TIMEOUT WDTO_8S
// RF Settings
#define RF_BASE_NODE_ID 1
#define RF_NETWORK_ID 98
#define RF_FREQUENCY RF69_868MHZ
#define RF_KEY_SIZE 16
#define RF_KEY_FETCH_TIME 1000*5
#define RF_KEY_ENCRYPT_TIME 1000*60*2
#define RF_NO_DATA_FAIL_TIME RF_KEY_ENCRYPT_TIME*2
// Needed for total magic number free code
#define ZERO 0
#define ONE 1
// Net related sizes
#define NET_BYTE_IP_SIZE 4
#define NET_BYTE_MAC_SIZE 6
#define NET_BYTE_NET_KEY_SIZE 16
#define NET_BYTE_NET_ID_SIZE 6
// Net Xensit config
//define NET_XNODE_HOST "xng.xensit.com" // XNodeGateway
#define NET_XNODE_HOST "www.forwardfire.net"
#define NET_XNODE_MAC_DEFAULT {0x74,0x69,0x69,0x4D,0x33,0xB1}
#define NET_PING_BOOT_TIME 1000*3
#define NET_PING_HOST_TIME 1000*60*90
#define NET_DHCP_RETRY_TIME 1000*60*3
#define NET_DNS_LOOKUP_TIME 1000*3600*1
// TODO: make net time to secs as 1h is ~max for dns
// Net config for url; Input Xensit Node Version A
#define NET_URL_POST "_a"
#define NET_URL_PARA_POST_TYPE "pt="
#define NET_URL_PARA_REQ_CNT "&rc="
#define NET_URL_PARA_NET_ID "&ni="
#define NET_URL_PARA_NODE_DATA "&nd="
#define NET_URL_PARA_NODE_NUMBER "&nn="
// The different post types of the url
#define NET_URL_PT_PING 'p'
#define NET_URL_PT_INIT 'i'
#define NET_URL_PT_DATA 'd'
#define NET_URL_RESULT_OK 'X'
// Some characters for printing.
#define CHAR_NEWLINE '\n'
#define CHAR_SPACE ' '
#define CHAR_DOT '.'
#define CHAR_PROMT '$'
#define CHAR_COMMENT '#'
#define CHAR_EQUALS '='
// Full ascii messages
#define MSG_RF_CHIP_INIT "Init radio"
#define MSG_RF_CHIP_ERROR "ERR: No chip"
#define MSG_RF_INFO_FREQ "rf_freq"
#define MSG_RF_INFO_NETWORK "rf_network"
#define MSG_RF_INFO_NODE "rf_node"
#define MSG_RF_INFO_KEY "rf_key"
#define MSG_RF_INFO_TX "rf_tx"
#define MSG_RF_INFO_RX "rf_rx"
#define MSG_RF_INFO_TXE "rf_txe"
#define MSG_RF_INFO "rf_info"
#define MSG_RF_ENCRYPT "rf_encrypt"
#endif

View file

@ -0,0 +1,38 @@
#ifndef XnodeProtocol_h
#define XnodeProtocol_h
#include <Arduino.h>
#include <XnodeConstants.h>
#define RF_STRUCT_SUPER_SIZE 52
#define RF_STRUCT_FLASH_SIZE 32
#define RF_STRUCT_CHAR_SIZE 48
enum RFMessageType {
RF_MSG_NODE_INIT, // sat tx+rx init_t
RF_MSG_NODE_FLASH, // sat tx+rx flash_t
RF_MSG_NODE_COMMAND, // sat rx char_t
RF_MSG_NODE_DATA // sat tx char_t
};
typedef struct {
byte msg_type;
byte msg_data[RF_STRUCT_SUPER_SIZE];
} xp_super_t;
typedef struct {
byte rf_key[RF_KEY_SIZE];
byte node_id;
} xp_msg_init_t;
typedef struct {
uint16_t offset;
byte flash_data[RF_STRUCT_FLASH_SIZE];
} xp_msg_flash_t;
typedef struct {
char char_data[RF_STRUCT_CHAR_SIZE];
} xp_msg_char_t;
#endif

View file

@ -0,0 +1,14 @@
#ifndef XnodeSatelliteConfig_h
#define XnodeSatelliteConfig_h
// Config data
typedef struct {
uint16_t eeprom_struct_size; // Config size changes it data defaults to zeros
byte rf_key[RF_KEY_SIZE]; // rf key to encrypt radio
byte node_id; // this node id to transmit to base
unsigned long sys_boot; // boot counter
} xnode_satellite_config_t;
#endif

View file

@ -0,0 +1,104 @@
#include <XnodeSerial.h>
char cmd_buff[CMD_BUFF_SIZE];
volatile uint8_t cmd_process = ONE;
volatile uint8_t cmd_buff_idx = ZERO;
XnodeSerial XSerial;
void XnodeSerial::begin() {
Serial.begin(SERIAL_SPEED);
print(CHAR_NEWLINE);
}
void XnodeSerial::loop() {
if (cmd_process == ZERO) {
executeCommand(cmd_buff);
cmd_process = ONE;
}
while (Serial.available() > ZERO) {
processSerialByte(Serial.read());
}
}
// Parse the cmd from a buffer
void XnodeSerial::executeCommand(char* buff,bool echoBuff,bool echoPromt) {
#ifdef DEBUG_SERIAL
Serial.print(F("#D XSerial.processCommand buff="));
Serial.print(buff);
Serial.print(F(",echoBuff="));
Serial.print(echoBuff);
Serial.print(F(",echoPromt="));
Serial.print(echoPromt);
Serial.println();
#endif
if (echoBuff) {
printChar(buff);
print(CHAR_NEWLINE);
}
if (buff[ZERO] > ZERO) {
XSystem.executeCommand(buff); // exe cmd
printChar(XSystem.replyBuffer); // print result or error
}
if (echoPromt) {
printPromt();
}
}
void XnodeSerial::processSerialByte(uint8_t c) {
if (c < 0x07 || c > 0x7E) {
return; // only process ascii chars
}
if (cmd_process == ZERO) {
return; // skip serial data
}
if (cmd_buff_idx > CMD_BUFF_SIZE) {
cmd_buff_idx = ZERO; // protect against to long input
}
if (c == '\b') {
cmd_buff[cmd_buff_idx] = '\0'; // backspace
cmd_buff_idx--;
print(' ');
print(c); // reply the backspace char for console like experience
} else if (c == '\n') {
cmd_buff[cmd_buff_idx] = '\0'; // newline
cmd_buff_idx = ZERO;
cmd_process = ZERO; // Start processing line
} else {
cmd_buff[cmd_buff_idx] = c; // store in buffer
cmd_buff_idx++;
}
}
void XnodeSerial::executeCommandP(const char* cmd) {
strcpy(cmd_buff, XUtil.UNPSTR(cmd)); // free buffer as gets used in strcmpP again..
cmd_buff_idx = ZERO;
executeCommand(cmd_buff,false,false);
}
void XnodeSerial::printPromt() {
printCharP(XSystem.hardware->getSystemHardwareTypeP());
print(CHAR_PROMT);
print(CHAR_SPACE);
}
void XnodeSerial::printCommentLineP(const char* argu) {
print(CHAR_COMMENT);
print(CHAR_SPACE);
printCharP(argu);
print(CHAR_NEWLINE);
}
void XnodeSerial::printCharP(const char* argu) {
printChar(XUtil.UNPSTR(argu));
}
void XnodeSerial::printChar(char* dstring) {
while (*dstring != ZERO) {
print(*dstring);
dstring++;
}
}
void XnodeSerial::print(char value) {
Serial.print(value);
}

View file

@ -0,0 +1,32 @@
#ifndef XnodeSerial_h
#define XnodeSerial_h
#define CMD_BUFF_SIZE 40 // max command length (40 is rf_key=9A2EE3A293486E9FE73D77EFC8087D2F)
#include <XnodeSystemModule.h>
#include <XnodeSystemHardware.h>
#include <XnodeConstants.h>
#include <XnodeUtil.h>
#include <XnodeSystem.h>
class XnodeSerial {
private:
void executeCommand(char* buff,bool echoBuff = true,bool echoPromt = true);
void processSerialByte(uint8_t c);
public:
void begin();
void loop();
void executeCommandP(const char* cmd);
void printPromt();
void printCommentLineP(const char* argu);
void printCharP(const char* argu);
void printChar(char* argu);
void print(char value);
};
extern XnodeSerial XSerial;
#endif

View file

@ -0,0 +1,323 @@
#include <XnodeSystem.h>
#define CMD_MAX_ARGS 8 // max 8 arguments to command
#define CMD_WHITE_SPACE " \r\t\n" // All diffent white space chars to split commands on
const char pmCmdHelp[] PROGMEM = "help";
const char pmCmdReboot[] PROGMEM = "reboot";
const char pmCmdSysCnfRst[] PROGMEM = "sys__cnf__rst"; // (internal)
const char pmCmdSysInfo[] PROGMEM = "sys_info";
const char pmSysConfigSave[] PROGMEM = "Config saved";
const char pmSysConfigLoad[] PROGMEM = "Config loaded";
const char pmSysConfigReset[] PROGMEM = "Config reset";
const char pmSysInfoVNumber[] PROGMEM = "sys_vnum";
const char pmSysInfoVDate[] PROGMEM = "sys_vdate";
const char pmSysInfoVDateValue[] PROGMEM = __DATE__" "__TIME__; // Print compile date like; "Apr 22 2012 16:36:10"
const char pmSysInfoType[] PROGMEM = "sys_type";
const char pmSysInfoBoot[] PROGMEM = "sys_boot";
const char pmSysInfoDebugLevel[] PROGMEM = "sys_debug";
const char pmSysInfoFreeRam[] PROGMEM = "sys_sram";
const char pmSysBootDebugHeader[] PROGMEM = "==== DEBUGGING ENABLED ====";
const char pmSysBootStart[] PROGMEM = "Booting ";
const char pmSysBootDone[] PROGMEM = "boot done";
const char pmSysBootDoneHelp[] PROGMEM = "Available commands;";
const char pmCmdErrArgument[] PROGMEM = "#ERR Missing argument: ";
const char pmCmdErrUnknown[] PROGMEM = "#ERR Unknown command: ";
const char pmRemoteExecutePrefix[] PROGMEM = "remote@";
uint8_t reboot_requested = ZERO;
uint8_t debug_level = ZERO;
uint8_t replyBufferIndex = ZERO;
uint8_t systemModuleIndex = ZERO;
XnodeSystemModule* systemModules[SYSTEM_MODULE_ARRAY_SIZE];
XnodeSystemHardware* hardware;
XnodeSystem XSystem;
void XnodeSystem::begin(XnodeSystemHardware* hardwareNode) {
hardware = hardwareNode;
// Print first line of boot process
XSerial.print(CHAR_COMMENT);
XSerial.print(CHAR_SPACE);
XSerial.printCharP (pmSysBootStart); // has space
XSerial.printCharP(hardware->getSystemHardwareTypeP());
XSerial.print(CHAR_NEWLINE);
// Start debug asp
beginDebug();
// Fixup config
XSerial.printCommentLineP(pmSysConfigLoad);
if (hardware->systemHardwareConfigBegin()) {
hardware->systemHardwareConfigReset();
XSerial.printCommentLineP(pmSysConfigReset);
}
hardware->systemHardwareConfigSave();
// Print system info
XSerial.executeCommandP(pmCmdSysInfo);
// Enable the watchdog
wdt_enable(WDT_TIMEOUT);
}
void XnodeSystem::loop() {
// Tickle the watchdog
wdt_reset();
// Reboot countdown and action so reply can be send.
if (reboot_requested > ONE) {
reboot_requested--;
} else if (reboot_requested > ZERO) {
wdt_enable (WDTO_15MS); // reboot in 15ms.
delay(30);
}
}
void XnodeSystem::beginDebug() {
// Make sure human and machine are notified when debugging is turned on.
#ifdef DEBUG_NETWORK
// shift every flag on its on bit so machine can readout which flags is enabled.
debug_level+=ONE << 0; // 1
#endif
#ifdef DEBUG_RADIO
debug_level+=ONE << 1; // 2
#endif
#ifdef DEBUG_SYSTEM
debug_level+=ONE << 2; // 4
#endif
#ifdef DEBUG_SERIAL
debug_level+=ONE << 3; // 8
#endif
#ifdef DEBUG_SENSOR
debug_level+=ONE << 4; // 16, all = 31
#endif
if (debug_level > ZERO) {
XSerial.printCommentLineP(pmSysBootDebugHeader); // print line for human,machine version is in serialPrintInfo.
}
}
void XnodeSystem::bootDone() {
XSerial.printCommentLineP(pmSysBootDoneHelp);
XSerial.executeCommandP(pmCmdHelp);
XSerial.printCommentLineP(pmSysBootDone);
XSerial.printPromt();
}
void XnodeSystem::configSave() {
#ifdef DEBUG_SYSTEM
Serial.println(F("#D XSystem.configSave"));
#endif
wdt_disable();
hardware->systemHardwareConfigSave();
wdt_enable (WDT_TIMEOUT);
}
void XnodeSystem::cmdSysInfo() {
buildReplyPValueP(pmSysInfoVNumber,hardware->getSystemHardwareVersionP());
buildReplyPValueP(pmSysInfoVDate,pmSysInfoVDateValue);
buildReplyPValue(pmSysInfoBoot,hardware->getSystemHardwareRebootCount());
buildReplyPValueP(pmSysInfoType,hardware->getSystemHardwareTypeP());
buildReplyPValue(pmSysInfoDebugLevel,debug_level);
buildReplyPValue(pmSysInfoFreeRam,XUtil.freeRam());
}
void XnodeSystem::cmdHelp() {
for (uint8_t i = ZERO; i < SYSTEM_MODULE_ARRAY_SIZE; i++) {
if (systemModules[i] == ZERO) {
continue;
}
systemModules[i]->systemModuleCommandList();
}
buildReplyCommandListP(pmCmdSysInfo);
buildReplyCommandListP(pmCmdReboot);
buildReplyCommandListP(pmCmdHelp);
}
void XnodeSystem::registrateSystemModule(XnodeSystemModule* module) {
systemModules[systemModuleIndex++] = module;
}
// execute cmd with the supplied argument
bool XnodeSystem::executeCommandModule(char* cmd, char** args) {
// Check for system build in commands.
if (XUtil.strcmpP(cmd, pmCmdHelp) == ZERO) {
cmdHelp();
return true;
}
if (XUtil.strcmpP(cmd, pmCmdReboot) == ZERO) {
buildReplyPValue(pmCmdReboot,ONE);
reboot_requested = 100; // let reply be send out/back
return true;
}
if (XUtil.strcmpP(cmd, pmCmdSysInfo) == ZERO) {
cmdSysInfo();
return true;
}
if (XUtil.strcmpP(cmd, pmCmdSysCnfRst) == ZERO) {
hardware->systemHardwareConfigReset();
buildReplyPValue(pmCmdSysCnfRst,ONE);
configSave();
buildReplyPValue(pmCmdReboot,ONE);
reboot_requested = 100;
return true;
}
// Check registated parses.
for (uint8_t i = ZERO; i < SYSTEM_MODULE_ARRAY_SIZE; i++) {
if (systemModules[i] == ZERO) {
continue;
}
if (systemModules[i]->systemModuleCommandExecute(cmd, args)) {
return true;
}
}
return false; // no command found
}
// Parse the cmd from a buffer
void XnodeSystem::executeCommand(char* input,bool isRemote) {
#ifdef DEBUG_SYSTEM
Serial.print(F("#D XSystem.executeCommand input="));
Serial.print(input);
Serial.println();
#endif
if (isRemote) {
XSerial.printCharP(pmRemoteExecutePrefix);
XSerial.printPromt();
XSerial.printChar(input);
XSerial.print(CHAR_NEWLINE);
}
replyBufferIndex = ZERO;
uint8_t idx = ZERO;
char *cmd, *ptr, *args[CMD_MAX_ARGS];
if (strtok((char *) input, CMD_WHITE_SPACE) == NULL) {
// no command given so just print new promt.
buildReplyCharP(pmCmdErrUnknown); // TODO: replace with key+value
buildReply(CHAR_NEWLINE);
buildReply('\0');
return;
}
cmd = (char *) input;
while ((ptr = strtok(NULL, CMD_WHITE_SPACE)) != NULL) {
args[idx] = ptr;
if (++idx == (CMD_MAX_ARGS - ONE)) {
break;
}
}
args[idx] = NULL;
bool parsed = executeCommandModule(cmd, args);
if (!parsed) {
buildReplyCharP(pmCmdErrUnknown);
buildReplyChar(cmd); // TODO: add args
buildReply(CHAR_NEWLINE);
}
buildReply('\0');
}
void XnodeSystem::buildReply(unsigned long value, int base) {
char buf[8 * sizeof(long) + ONE]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - ONE];
*str = ZERO; // reverse printing so start with termination.
if (base < 2) {
base = 10;// fix base 1 or 0 default to decimals
}
do {
unsigned long m = value;
value /= base;
char c = m - base * value;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while(value);
return buildReplyChar(str);
}
void XnodeSystem::buildReply(float value,int digitsFull,int digitsDot) {
dtostrf(value, digitsFull, digitsDot, (char*)replyBuffer+replyBufferIndex);
replyBufferIndex += (digitsFull + 1 + digitsDot) - 1; // "999.9" "-99.9" and remove terminating zero.
}
void XnodeSystem::buildReply(char value) {
replyBuffer[replyBufferIndex++] = value;
if (replyBufferIndex > SYSTEM_REPLY_ARRAY_SIZE) {
replyBufferIndex--;
replyBuffer[replyBufferIndex] = ZERO; // terminate last char
#ifdef DEBUG_SYSTEM
Serial.print("#D+");
Serial.print(value); // print overflow chars
Serial.print("-");
#endif
}
}
void XnodeSystem::buildReplyChar(char* value) {
while (*value != ZERO) {
buildReply(*value);
value++;
}
}
void XnodeSystem::buildReplyCharP(const char* value) {
buildReplyChar(XUtil.UNPSTR(value));
}
void XnodeSystem::buildReplyCommandListP(const char* cmdName) {
buildReplyCharP(cmdName);
buildReply(CHAR_NEWLINE);
}
bool XnodeSystem::buildReplyCommandArgumentError(char* cmd, char** args) {
if (args[ZERO] != NULL) {
return false; // nothing printed
}
buildReplyCharP(pmCmdErrArgument);
buildReplyChar(cmd);
buildReply(CHAR_NEWLINE);
return true;
}
void XnodeSystem::buildReplyPValueIP(const char* valueName,uint8_t ip[4]) {
buildReplyCharP(valueName);
buildReply(CHAR_EQUALS);
buildReply(ip[0], DEC);
buildReply(CHAR_DOT);
buildReply(ip[1], DEC);
buildReply(CHAR_DOT);
buildReply(ip[2], DEC);
buildReply(CHAR_DOT);
buildReply(ip[3], DEC);
buildReply(CHAR_NEWLINE);
}
void XnodeSystem::buildReplyPValue(const char* valueName,unsigned long value) {
buildReplyCharP(valueName);
buildReply(CHAR_EQUALS);
buildReply(value);
buildReply(CHAR_NEWLINE);
}
void XnodeSystem::buildReplyPValue(const char* valueName,int value) {
buildReplyPValue(valueName,(unsigned long)value);
}
void XnodeSystem::buildReplyPValue(const char* valueName,float value,int digitsFull,int digitsDot) {
buildReplyCharP(valueName);
buildReply(CHAR_EQUALS);
buildReply(value,digitsFull,digitsDot);
buildReply(CHAR_NEWLINE);
}
void XnodeSystem::buildReplyPValueP(const char* valueName,const char* valueP) {
buildReplyCharP(valueName);
buildReply(CHAR_EQUALS);
buildReplyCharP(valueP);
buildReply(CHAR_NEWLINE);
}
void XnodeSystem::buildReplyPValueByteA(const char* valueName,byte* value, byte data_len) {
buildReplyCharP(valueName);
buildReply(CHAR_EQUALS);
for (byte i = ZERO; i < data_len; ++i) {
byte d = value[i];
if (d<0xF) {
buildReply('0'); // exta zero to have two chars
}
buildReply(d, HEX);
}
buildReply(CHAR_NEWLINE);
}

View file

@ -0,0 +1,49 @@
#ifndef XnodeSystem_h
#define XnodeSystem_h
#include <XnodeSystemHardware.h>
#include <XnodeSystemModule.h>
#include <XnodeConstants.h>
#include <XnodeProtocol.h>
#include <XnodeSerial.h>
#include <XnodeUtil.h>
#include <avr/wdt.h>
#define SYSTEM_MODULE_ARRAY_SIZE 4
#define SYSTEM_REPLY_ARRAY_SIZE 250
class XnodeSystem {
private:
void beginDebug();
bool executeCommandModule(char* cmd, char** args);
void cmdHelp();
void cmdSysInfo();
void buildReply(char value);
void buildReplyChar(char* value);
void buildReply(unsigned long value, int = DEC);
void buildReply(float value,int digitsFull,int digitsDot);
public:
char replyBuffer[SYSTEM_REPLY_ARRAY_SIZE];
XnodeSystemHardware* hardware;
void begin(XnodeSystemHardware* hardware);
void loop();
void bootDone();
void configSave();
void executeCommand(char* input,bool isRemote=false);
void registrateSystemModule(XnodeSystemModule* module);
void buildReplyCommandListP(const char* cmdName);
bool buildReplyCommandArgumentError(char* cmd, char** args);
void buildReplyCharP(const char* value);
void buildReplyPValueIP(const char* valueName,uint8_t ip[4]);
void buildReplyPValue(const char* valueName,unsigned long value);
void buildReplyPValue(const char* valueName,int value);
void buildReplyPValue(const char* valueName,float value,int digitsFull = 3,int digitsDot = 1);
void buildReplyPValueP(const char* valueName,const char* valueP);
void buildReplyPValueByteA(const char* valueName,byte* value, byte data_len);
};
extern XnodeSystem XSystem;
#endif

View file

@ -0,0 +1,15 @@
#ifndef XnodeSystemHardware_h
#define XnodeSystemHardware_h
class XnodeSystemHardware {
public:
virtual const char* getSystemHardwareTypeP();
virtual const char* getSystemHardwareVersionP();
virtual unsigned long getSystemHardwareRebootCount();
virtual bool systemHardwareConfigBegin();
virtual void systemHardwareConfigSave();
virtual void systemHardwareConfigReset();
};
#endif

View file

@ -0,0 +1,11 @@
#ifndef XnodeSystemModule_h
#define XnodeSystemModule_h
class XnodeSystemModule {
public:
virtual bool systemModuleCommandExecute(char* cmd, char** args);
virtual void systemModuleCommandList();
};
#endif

View file

@ -0,0 +1,85 @@
#include <XnodeUtil.h>
char unpstr_buff[UNPSTR_BUFF_SIZE]; // buffer to copy progmem data into
// Uncopy from program/flash memory to sram
char* XnodeUtil::UNPSTR(const char* ptr) {
for (uint8_t i = ZERO; i < UNPSTR_BUFF_SIZE; i++) {
unpstr_buff[i] = '\0'; // clean buffer
}
uint8_t i = ZERO;
uint8_t c = ZERO;
do {
c = pgm_read_byte(ptr++);
unpstr_buff[i++] = c;
} while (c != ZERO);
return unpstr_buff;
}
// Fill pstr_buff from pointer
char* XnodeUtil::UNPSTRA(const uint16_t* argu) {
// rm readByte use word which auto size ptr
uint8_t msb = pgm_read_byte((const char*) argu + 1);
uint8_t lsb = pgm_read_byte((const char*) argu);
const char*p = (const char*) ((msb * 256) + lsb);
return UNPSTR(p);
}
uint8_t XnodeUtil::strcmp(char *s1, char *s2) {
while (*s1 && *s2 && *s1 == *s2) {
s1++;
s2++;
}
if (*s1 == *s2) {
return 0;
}
if (*s1 < *s2) {
return -1;
}
return 1;
}
uint8_t XnodeUtil::strcmpP(char *s1, const char* s2) {
return strcmp(s1, UNPSTR(s2));
}
void XnodeUtil::charsToByteA(char* input,byte* data, byte data_len) {
for (byte i = ZERO; i < data_len; i++) {
data[i] = ZERO; // clear array
}
byte charIdx = ZERO;
for (byte i = ZERO; i < data_len; i++) {
char c1 = input[charIdx];
char c2 = input[charIdx + ONE];
if (c1 == ZERO || c2 == ZERO) {
break;
}
data[i] = charsToByte(c1, c2);
charIdx++;
charIdx++;
}
}
byte XnodeUtil::charsToByte(char c1, char c2) {
byte result = ZERO;
result += charToNibble(c1) * 16;
result += charToNibble(c2);
return result;
}
byte XnodeUtil::charToNibble(char c) {
uint8_t result = ZERO;
if (c > '0' && c <= '9') {
result = c - '0';
} else if (c >= 'A' && c <= 'F') {
result = c - 'A' + 10;
}
return result;
}
int XnodeUtil::freeRam() {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

View file

@ -0,0 +1,27 @@
#ifndef XnodeUtil_h
#define XnodeUtil_h
#include <XnodeConstants.h>
#include <avr/pgmspace.h>
#include <Arduino.h>
#define UNPSTR_BUFF_SIZE 32
class XnodeUtil {
public:
static char* UNPSTR(const char* ptr);
static char* UNPSTRA(const uint16_t* argu);
static uint8_t strcmp(char *s1, char *s2);
static uint8_t strcmpP(char *s1, const char* s2);
static void charsToByteA(char* input,byte* data, byte data_len);
static byte charsToByte(char c1, char c2);
static byte charToNibble(char s);
static int freeRam();
};
extern XnodeUtil XUtil;
#endif