send sucess message if command is processed sucessfully
This commit is contained in:
686
main.cpp
686
main.cpp
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#define MAX_TRAINS 16
|
#define MAX_TRAINS 16
|
||||||
#define COMMAND_BUFFER_SIZE 64
|
#define COMMAND_BUFFER_SIZE 64
|
||||||
#define SNPRINTF_BUFFER_SIZE 64
|
#define SNPRINTF_BUFFER_SIZE 128
|
||||||
#define EPPROM_SIZE 1024
|
#define EPPROM_SIZE 1024
|
||||||
|
|
||||||
char buffer[SNPRINTF_BUFFER_SIZE];
|
char buffer[SNPRINTF_BUFFER_SIZE];
|
||||||
@ -30,344 +30,414 @@ volatile bool resendEvent = false;
|
|||||||
|
|
||||||
ISR(TIMER0_OVF_vect)
|
ISR(TIMER0_OVF_vect)
|
||||||
{
|
{
|
||||||
++tick;
|
++tick;
|
||||||
if(tick == 0) resendEvent = true;
|
if(tick == 0)
|
||||||
if((tick & 0b00000111) < 1) Train::setOutput(Train::HIGH);
|
resendEvent = true;
|
||||||
else Train::setOutput(Train::LOW);
|
if((tick & 0b00000111) < 1) Train::setOutput(Train::HIGH);
|
||||||
|
else Train::setOutput(Train::LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer0InterruptEnable(const bool enable)
|
void timer0InterruptEnable(const bool enable)
|
||||||
{
|
{
|
||||||
if(enable) TIMSK0 = 0b00000001;
|
if(enable) TIMSK0 = 0b00000001;
|
||||||
else TIMSK0 = 0b00000000;
|
else TIMSK0 = 0b00000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_state()
|
void save_state()
|
||||||
{
|
{
|
||||||
cli();
|
cli();
|
||||||
EEPROM_write_char( 0, storedTrains );
|
EEPROM_write_char( 0, storedTrains );
|
||||||
EEPROM_write_char( 1, autoff );
|
EEPROM_write_char( 1, autoff );
|
||||||
for(uint16_t i = 0; i < storedTrains; i++)
|
for(uint16_t i = 0; i < storedTrains; i++)
|
||||||
{
|
{
|
||||||
EEPROM_write_char( i*2+32, trains[i].getAddress());
|
EEPROM_write_char( i*2+32, trains[i].getAddress());
|
||||||
EEPROM_write_char( i*2+32+1, trains[i].getProtocol());
|
EEPROM_write_char( i*2+32+1, trains[i].getFunctionMask());
|
||||||
}
|
}
|
||||||
sei();
|
sei();
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_state()
|
void restore_state()
|
||||||
{
|
{
|
||||||
storedTrains = EEPROM_read_char(0);
|
storedTrains = EEPROM_read_char(0);
|
||||||
autoff = EEPROM_read_char(1);
|
autoff = EEPROM_read_char(1);
|
||||||
if(storedTrains > MAX_TRAINS )
|
if(storedTrains > MAX_TRAINS )
|
||||||
{
|
{
|
||||||
for(uint16_t i = 0; i < EPPROM_SIZE; i++) EEPROM_write_char(i, 0);
|
for(uint16_t i = 0; i < EPPROM_SIZE; i++) EEPROM_write_char(i, 0);
|
||||||
storedTrains = 0;
|
storedTrains = 0;
|
||||||
}
|
}
|
||||||
else for(uint8_t i = 0; i < storedTrains; i++)
|
else for(uint8_t i = 0; i < storedTrains; i++)
|
||||||
{
|
{
|
||||||
trains[i].setAddress(EEPROM_read_char(32+i*2));
|
trains[i].setAddress(EEPROM_read_char(32+i*2));
|
||||||
trains[i].setProtocol(EEPROM_read_char(32+1+i*2));
|
trains[i].setFunctionMask(EEPROM_read_char(32+1+i*2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void printHelp(Serial* serial)
|
inline static void printHelp(Serial* serial)
|
||||||
{
|
{
|
||||||
serial->write_p(PSTR("Available Commands: \n\
|
serial->write_p(PSTR("Available Commands: \n\
|
||||||
help : Show this prompt.\n\
|
help : Show this prompt.\n\
|
||||||
train add [address] : Add train.\n\
|
train add [address] [functionmask] : Add train.\n\
|
||||||
train delete : Delete last train.\n\
|
train delete : Delete last train.\n\
|
||||||
train list : Print list of saved trains.\n\
|
train list : Print list of saved trains.\n\
|
||||||
train [nn] stop : Stop nth train.\n\
|
train [nn] s(top) : Stop nth train.\n\
|
||||||
train [nn] speed [sp] : Set nth train speed.\n\
|
train [nn] s(peed) [sp] : Set nth train speed.\n\
|
||||||
train [nn] function [x] : Toggle x'ed fuction on train n.\n\
|
train [nn] function [x] : Toggle x'ed fuction on train n.\n\
|
||||||
train [nn] reverse : Reverse train n.\n\
|
train [nn] r(everse) : Reverse train n.\n\
|
||||||
stop : stop all trains\n\
|
stop : stop all trains\n\
|
||||||
power off : power off the rail\n\
|
power off : power off the rail\n\
|
||||||
power on : power on the rail\n\
|
power on : power on the rail\n\
|
||||||
power auto : power off the rail when no trains are moveing\n\
|
power auto : power off the rail when no trains are moveing\n\
|
||||||
dump : prints epprom contence\n\
|
dump : prints epprom contence\n\
|
||||||
erase : Erase epprom.\n"));
|
erase : Erase epprom.\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void trainDispatch(char* inBuffer, Serial* serial)
|
int trainDispatch(char* inBuffer, Serial* serial)
|
||||||
{
|
{
|
||||||
cli();
|
if( strcmp(inBuffer, "add") == 0 )
|
||||||
if( strcmp(inBuffer, "add") == 0 )
|
{
|
||||||
{
|
char* token = strtok(NULL, " ");
|
||||||
char* token = strtok(NULL, " ");
|
uint8_t address = 0;
|
||||||
uint8_t address = 0;
|
if(token != NULL)
|
||||||
if(token != NULL) address = strtol(token, nullptr, 2 );
|
address = strtol(token, nullptr, 10);
|
||||||
if(address != 0 && storedTrains < MAX_TRAINS)
|
if(address != 0 && storedTrains < MAX_TRAINS)
|
||||||
{
|
{
|
||||||
trains[storedTrains].setAddress(address);
|
trains[storedTrains].setAddress(address);
|
||||||
|
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
if(token != NULL && strcmp(token, "delta") == 0 ) trains[storedTrains].setProtocol(Train::M_DELTA);
|
if(token != NULL)
|
||||||
else trains[storedTrains].setProtocol(Train::M_DIGITAL);
|
trains[storedTrains].setFunctionMask(strtol(token, nullptr, 2 ));
|
||||||
|
|
||||||
uint8_t size = snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRAIN saved! NUMBER: %u ADRESS: %s%s PROTCOL: %s\n", storedTrains, bit_rep[address >> 4], bit_rep[address & 0x0F], trains[storedTrains].getProtocol() == Train::M_DELTA ? "delta" : "digital" );
|
uint8_t size = snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRAIN saved! NUMBER: %u ADDRESS: %u FUNCTIONS: %u FUNCTIONMASK: %u\n",
|
||||||
serial->write(buffer, size);
|
storedTrains,
|
||||||
|
address,
|
||||||
storedTrains++;
|
trains[storedTrains].getFunctions(),
|
||||||
save_state();
|
trains[storedTrains].getFunctionMask());
|
||||||
}
|
serial->write(buffer, size);
|
||||||
serial->write_p(PSTR("Usage: train add [address]"));
|
|
||||||
}
|
storedTrains++;
|
||||||
else if( strcmp(inBuffer, "delete") == 0)
|
save_state();
|
||||||
{
|
return 0;
|
||||||
serial->write_p(PSTR("Train: "));
|
}
|
||||||
serial->write(storedTrains);
|
serial->write_p(PSTR("Usage: train add [address] [functionmask]"));
|
||||||
serial->write_p(PSTR(" deleted\n"));
|
}
|
||||||
storedTrains--;
|
else if( strcmp(inBuffer, "delete") == 0)
|
||||||
}
|
{
|
||||||
else if( strcmp(inBuffer, "list") == 0 )
|
serial->write_p(PSTR("Train: "));
|
||||||
{
|
serial->write(storedTrains-1);
|
||||||
serial->write_p(PSTR("Trains:\n"));
|
serial->write_p(PSTR(" deleted\n"));
|
||||||
for(uint8_t i = 0; i < storedTrains; i++)
|
storedTrains--;
|
||||||
{
|
if(storedTrains < 0)
|
||||||
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "NUMBER: %u ID: %s%s CURRENT PACKET: %x SPEED: %u", i, bit_rep[trains[i].getAddress() >> 4], bit_rep[trains[i].getAddress() & 0x0F], trains[i].getLastPacket(), trains[i].getSpeed());
|
storedTrains = 0;
|
||||||
serial->write(buffer, SNPRINTF_BUFFER_SIZE);
|
save_state();
|
||||||
serial->write_p(PSTR(" PROTOCOL: "));
|
return 0;
|
||||||
if(trains[i].getProtocol() == Train::M_DELTA)serial->write_p(PSTR("delta\n"));
|
}
|
||||||
else serial->write_p(PSTR("digital\n"));
|
else if( strcmp(inBuffer, "list") == 0 )
|
||||||
}
|
{
|
||||||
serial->putChar('\n');
|
serial->write_p(PSTR("Trains:\n"));
|
||||||
}
|
for(uint8_t i = 0; i < storedTrains; i++)
|
||||||
else
|
{
|
||||||
{
|
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "NUMBER: %u ID: %u CURRENT PACKET: %x SPEED: %i FUNCTIONS: %u FUNCTIONMASK: %u\n",
|
||||||
uint8_t id = strtol(inBuffer, nullptr, 10);
|
i, trains[i].getAddress(),
|
||||||
if(id < storedTrains )
|
trains[i].getLastPacket(), trains[i].getSpeed(),
|
||||||
{
|
trains[i].getFunctions(), trains[i].getFunctionMask());
|
||||||
if(powerIsOn == false)
|
serial->write(buffer, SNPRINTF_BUFFER_SIZE);
|
||||||
{
|
}
|
||||||
powerIsOn = true;
|
serial->putChar('\n');
|
||||||
Train::setOutput(Train::LOW);
|
return 0;
|
||||||
_delay_ms(100);
|
}
|
||||||
timer0InterruptEnable(true);
|
else if( strcmp(inBuffer, "probe") == 0 )
|
||||||
}
|
{
|
||||||
char* token = strtok(NULL, " ");
|
for(uint16_t j = 0; j < 255; j++)
|
||||||
if( token != NULL && (strcmp(token, "speed") == 0 || strcmp(token, "s") == 0) )
|
{
|
||||||
{
|
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING ADDR: %x\n", j);
|
||||||
token = strtok(NULL, " ");
|
serial->write(buffer, strlen(buffer));
|
||||||
trains[id].setSpeed(atoi(token));
|
cli();
|
||||||
serial->write_p(PSTR("Set Train speed\n"));
|
for(uint8_t k = 0; k < 10; k++)
|
||||||
}
|
{
|
||||||
else if(token != NULL && strcmp(token, "function") == 0 )
|
Train::sendRawAddr(j, 60);
|
||||||
{
|
_delay_ms(20);
|
||||||
token = strtok(NULL, " ");
|
}
|
||||||
char* boolToken = strtok(NULL, " ");
|
for(uint8_t k = 0; k < 3; k++)
|
||||||
if(token != NULL && boolToken != NULL)
|
{
|
||||||
{
|
Train::sendRawAddr(j, 0);
|
||||||
uint8_t functionId = atoi(token);
|
_delay_ms(20);
|
||||||
bool on = (strcmp(boolToken, "on") == 0);
|
}
|
||||||
trains[id].sendFunction(functionId, on );
|
sei();
|
||||||
serial->write_p(PSTR("Set Train function "));
|
}
|
||||||
serial->write(functionId);
|
return 0;
|
||||||
serial->write(on ? " on\n" : " off\n");
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
else if(token != NULL && strcmp(token, "probe") == 0 )
|
uint8_t id = strtol(inBuffer, nullptr, 10);
|
||||||
{
|
if(id < storedTrains )
|
||||||
for(uint16_t j = 0; j < 1024; j++)
|
{
|
||||||
{
|
if(powerIsOn == false)
|
||||||
trains[id].sendRaw(j);
|
{
|
||||||
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING: %x\n", j);
|
powerIsOn = true;
|
||||||
serial->write(buffer, strlen(buffer));
|
Train::setOutput(Train::LOW);
|
||||||
sei();
|
_delay_ms(100);
|
||||||
_delay_ms(250);
|
timer0InterruptEnable(true);
|
||||||
cli();
|
}
|
||||||
|
char* token = strtok(NULL, " ");
|
||||||
}
|
if( token != NULL && (strcmp(token, "speed") == 0 || strcmp(token, "s") == 0) )
|
||||||
}
|
{
|
||||||
else if(token != NULL && strcmp(token, "raw") == 0 )
|
token = strtok(NULL, " ");
|
||||||
{
|
trains[id].setSpeed(atoi(token));
|
||||||
token = strtok(NULL, " ");
|
serial->write_p(PSTR("Set Train speed\n"));
|
||||||
if(token != NULL)
|
return 0;
|
||||||
{
|
}
|
||||||
cli();
|
else if(token != NULL && strcmp(token, "function") == 0 )
|
||||||
uint16_t i = strtol(token, nullptr, 16 );
|
{
|
||||||
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "SENDING: %x\n", i);
|
token = strtok(NULL, " ");
|
||||||
serial->write(buffer, strlen(buffer));
|
char* boolToken = strtok(NULL, " ");
|
||||||
for(uint8_t j = 0; j < 100; j++)
|
if(token != NULL && boolToken != NULL)
|
||||||
{
|
{
|
||||||
trains[id].sendRaw(i);
|
uint8_t functionId = atoi(token);
|
||||||
_delay_ms(20);
|
bool on = (strcmp(boolToken, "on") == 0);
|
||||||
}
|
trains[id].sendFunction(functionId, on );
|
||||||
serial->write_p(PSTR("Finished\n"));
|
serial->write_p(PSTR("Set Train function "));
|
||||||
sei();
|
serial->write(functionId);
|
||||||
}
|
serial->write(on ? " on\n" : " off\n");
|
||||||
}
|
return 0;
|
||||||
else if( token != NULL && (strcmp(token, "reverse") == 0 || strcmp(token, "r") == 0) )
|
}
|
||||||
{
|
}
|
||||||
trains[id].reverse();
|
else if(token != NULL && strcmp(token, "probe") == 0 )
|
||||||
serial->write_p(PSTR("Reversed Train\n"));
|
{
|
||||||
}
|
for(uint16_t j = 0; j < 1024; j++)
|
||||||
else if( token != NULL && (strcmp(token, "stop") == 0 || strcmp(token, "p") == 0)) trains[id].stop();
|
{
|
||||||
else serial->write_p(PSTR("Not a valid command\n"));
|
trains[id].sendRaw(j);
|
||||||
}
|
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING: %x\n", j);
|
||||||
else serial->write_p(PSTR("Id out of range.\n"));
|
serial->write(buffer, strlen(buffer));
|
||||||
}
|
sei();
|
||||||
sei();
|
_delay_ms(250);
|
||||||
|
cli();
|
||||||
|
}
|
||||||
|
sei();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if(token != NULL && strcmp(token, "raw") == 0 )
|
||||||
|
{
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
if(token != NULL)
|
||||||
|
{
|
||||||
|
cli();
|
||||||
|
uint16_t i = strtol(token, nullptr, 16 );
|
||||||
|
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "SENDING: %x to %x\n", i, trains[id].getAddress());
|
||||||
|
serial->write(buffer, strlen(buffer));
|
||||||
|
for(uint8_t j = 0; j < 100; j++)
|
||||||
|
{
|
||||||
|
trains[id].sendRaw(i);
|
||||||
|
_delay_ms(20);
|
||||||
|
}
|
||||||
|
serial->write_p(PSTR("Finished\n"));
|
||||||
|
sei();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( token != NULL && (strcmp(token, "reverse") == 0 || strcmp(token, "r") == 0) )
|
||||||
|
{
|
||||||
|
trains[id].reverse();
|
||||||
|
serial->write_p(PSTR("Reversed Train\n"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if( token != NULL && (strcmp(token, "stop") == 0 || strcmp(token, "p") == 0))
|
||||||
|
{
|
||||||
|
trains[id].stop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Not a valid command\n"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Id out of range.\n"));
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void powerDispatch(char* token, Serial* serial)
|
int powerDispatch(char* token, Serial* serial)
|
||||||
{
|
{
|
||||||
if(strcmp(token, "off") == 0)
|
if(strcmp(token, "off") == 0)
|
||||||
{
|
{
|
||||||
timer0InterruptEnable(false);
|
timer0InterruptEnable(false);
|
||||||
Train::setOutput(Train::OFF);
|
Train::setOutput(Train::OFF);
|
||||||
powerIsOn = false;
|
powerIsOn = false;
|
||||||
}
|
return 0;
|
||||||
else if( strcmp(token, "on") == 0)
|
}
|
||||||
{
|
else if( strcmp(token, "on") == 0)
|
||||||
for(uint16_t i = 0; i < storedTrains; i++)
|
{
|
||||||
{
|
for(uint16_t i = 0; i < storedTrains; i++)
|
||||||
trains[i].setSpeed(0);
|
{
|
||||||
}
|
trains[i].setSpeed(0);
|
||||||
Train::setOutput(Train::LOW);
|
}
|
||||||
timer0InterruptEnable(true);
|
Train::setOutput(Train::LOW);
|
||||||
}
|
timer0InterruptEnable(true);
|
||||||
else if(strcmp(token, "auto") == 0)
|
return 0;
|
||||||
{
|
}
|
||||||
token = strtok(NULL, " ");
|
else if(strcmp(token, "auto") == 0)
|
||||||
if(token != NULL && strcmp(token, "on") == 0)
|
{
|
||||||
{
|
token = strtok(NULL, " ");
|
||||||
autoff = true;
|
if(token != NULL && strcmp(token, "on") == 0)
|
||||||
serial->write_p(PSTR("auto power off turned on.\n"));
|
{
|
||||||
save_state();
|
autoff = true;
|
||||||
}
|
serial->write_p(PSTR("auto power off turned on.\n"));
|
||||||
else if(token != NULL && strcmp(token, "off") == 0)
|
save_state();
|
||||||
{
|
}
|
||||||
autoff = false;
|
else if(token != NULL && strcmp(token, "off") == 0)
|
||||||
serial->write_p(PSTR("auto power off turned off.\n"));
|
{
|
||||||
save_state();
|
autoff = false;
|
||||||
}
|
serial->write_p(PSTR("auto power off turned off.\n"));
|
||||||
else
|
save_state();
|
||||||
{
|
}
|
||||||
serial->write_p(PSTR("argument must be \"on\" or \"off\". This feature is currently "));
|
else
|
||||||
autoff ? serial->write_p(PSTR("on.\n")) : serial->write_p(PSTR("off.\n"));
|
{
|
||||||
}
|
serial->write_p(PSTR("argument must be \"on\" or \"off\". This feature is currently "));
|
||||||
}
|
autoff ? serial->write_p(PSTR("on.\n")) : serial->write_p(PSTR("off.\n"));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void serialDispatch(Serial* serial)
|
void serialDispatch(Serial* serial)
|
||||||
{
|
{
|
||||||
if(serial->dataIsWaiting())
|
if(serial->dataIsWaiting())
|
||||||
{
|
{
|
||||||
char buffer[COMMAND_BUFFER_SIZE];
|
char buffer[COMMAND_BUFFER_SIZE];
|
||||||
unsigned int length = serial->getString(buffer, COMMAND_BUFFER_SIZE);
|
unsigned int length = serial->getString(buffer, COMMAND_BUFFER_SIZE);
|
||||||
if(length > 0)
|
if(length > 0)
|
||||||
{
|
{
|
||||||
serial->write_p(PSTR("Got: "));
|
int ret = -1;
|
||||||
serial->putChar('\"');
|
char* token = strtok(buffer, " ");
|
||||||
serial->write(buffer, length);
|
if(length > 4 && (strcmp(token, "train") == 0 || strcmp(token, "t") == 0 ))
|
||||||
serial->write("\"\n");
|
{
|
||||||
char* token = strtok(buffer, " ");
|
token = strtok(NULL, " ");
|
||||||
if(length > 4 && (strcmp(token, "train") == 0 || strcmp(token, "t") == 0 ))
|
if(token != NULL)
|
||||||
{
|
ret = trainDispatch(token, serial);
|
||||||
token = strtok(NULL, " ");
|
}
|
||||||
if(token != NULL)
|
else if(strncmp(token, "erase", 4) == 0)
|
||||||
trainDispatch(token, serial);
|
{
|
||||||
}
|
for(uint16_t i = 0; i < EPPROM_SIZE; i++) EEPROM_write_char(i, 0);
|
||||||
else if(strncmp(token, "erase", 4) == 0)
|
serial->write_p(PSTR("EEPROM erased\n"));
|
||||||
{
|
storedTrains = 0;
|
||||||
for(uint16_t i = 0; i < EPPROM_SIZE; i++) EEPROM_write_char(i, 0);
|
ret = 0;
|
||||||
serial->write_p(PSTR("EEPROM erased\n"));
|
}
|
||||||
storedTrains = 0;
|
else if(strcmp(token, "dump") == 0)
|
||||||
}
|
{
|
||||||
else if(strcmp(token, "dump") == 0)
|
for(uint16_t i = 0; i < EPPROM_SIZE; i++)
|
||||||
{
|
{
|
||||||
for(uint16_t i = 0; i < EPPROM_SIZE; i++)
|
if(i != 0) serial->putChar(',');
|
||||||
{
|
serial->write((uint16_t)EEPROM_read_char(i));
|
||||||
if(i != 0) serial->putChar(',');
|
}
|
||||||
serial->write((uint16_t)EEPROM_read_char(i));
|
serial->putChar('\n');
|
||||||
}
|
ret = 0;
|
||||||
serial->putChar('\n');
|
}
|
||||||
}
|
else if((strcmp(token, "stop") == 0 || strcmp(token, "s") == 0 ))
|
||||||
else if((strcmp(token, "stop") == 0 || strcmp(token, "s") == 0 ))
|
{
|
||||||
{
|
for(uint16_t i = 0; i < storedTrains; i++)
|
||||||
for(uint16_t i = 0; i < storedTrains; i++)
|
{
|
||||||
{
|
cli();
|
||||||
cli();
|
trains[i].stop();
|
||||||
trains[i].stop();
|
sei();
|
||||||
sei();
|
}
|
||||||
}
|
ret = 0;
|
||||||
}
|
}
|
||||||
else if(strcmp(token, "power") == 0)
|
else if(strcmp(token, "power") == 0)
|
||||||
{
|
{
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
if(token != NULL)powerDispatch(token, serial);
|
if(token != NULL)
|
||||||
}
|
ret = powerDispatch(token, serial);
|
||||||
else if(strcmp(token, "help") == 0)
|
}
|
||||||
{
|
else if(strcmp(token, "help") == 0)
|
||||||
printHelp(serial);
|
{
|
||||||
}
|
printHelp(serial);
|
||||||
else
|
ret = 0;
|
||||||
{
|
}
|
||||||
serial->putChar('\"');
|
else
|
||||||
serial->write(buffer, length);
|
{
|
||||||
serial->putChar('\"');
|
serial->putChar('\"');
|
||||||
serial->write_p(PSTR(" is not a valid command\n"));
|
serial->write(buffer, length);
|
||||||
}
|
serial->putChar('\"');
|
||||||
}
|
serial->write_p(PSTR(" is not a valid command\n"));
|
||||||
}
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret < 0)
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Command Failed\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Sucess \""));
|
||||||
|
serial->write(buffer, length);
|
||||||
|
serial->write("\"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
TCNT0 = 0;
|
TCNT0 = 0;
|
||||||
TCCR0B = (1<<CS01) /*| (1<<CS00)*/; // run timer0 with /64 scaler
|
TCCR0B = (1<<CS01) /*| (1<<CS00)*/; // run timer0 with /64 scaler
|
||||||
|
|
||||||
DDRD = (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5);
|
|
||||||
|
|
||||||
restore_state();
|
|
||||||
|
|
||||||
if(autoff)
|
|
||||||
{
|
|
||||||
timer0InterruptEnable(false);
|
|
||||||
Train::setOutput(Train::OFF);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timer0InterruptEnable(true);
|
|
||||||
Train::setOutput(Train::LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
sei();
|
|
||||||
|
|
||||||
Serial serial;
|
|
||||||
|
|
||||||
serial.write_p(PSTR("TrainController v0.1 starting\n"));
|
DDRD = (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5);
|
||||||
|
|
||||||
uint8_t trainToResend = 0;
|
restore_state();
|
||||||
|
|
||||||
while(true)
|
if(autoff)
|
||||||
{
|
{
|
||||||
if(resendEvent && storedTrains > 0)
|
timer0InterruptEnable(false);
|
||||||
{
|
Train::setOutput(Train::OFF);
|
||||||
timer0InterruptEnable(false);
|
}
|
||||||
trains[trainToResend].resendData();
|
else
|
||||||
trainToResend++;
|
{
|
||||||
if(storedTrains <= trainToResend) trainToResend = 0;
|
timer0InterruptEnable(true);
|
||||||
resendEvent = false;
|
Train::setOutput(Train::LOW);
|
||||||
timer0InterruptEnable(true);
|
}
|
||||||
}
|
|
||||||
|
sei();
|
||||||
if(autoff)
|
|
||||||
{
|
Serial serial;
|
||||||
bool trainsRunning = false;
|
|
||||||
for(uint16_t i = 0; i < storedTrains; i++) trainsRunning = trainsRunning || trains[i].isActive();
|
serial.write_p(PSTR("TrainController v0.5 starting\n"));
|
||||||
if(!trainsRunning)
|
|
||||||
{
|
uint8_t trainToResend = 0;
|
||||||
powerIsOn = false;
|
|
||||||
timer0InterruptEnable(false);
|
while(true)
|
||||||
Train::setOutput(Train::OFF);
|
{
|
||||||
}
|
if(resendEvent && storedTrains > 0)
|
||||||
}
|
{
|
||||||
serialDispatch(&serial);
|
timer0InterruptEnable(false);
|
||||||
}
|
_delay_us(255);
|
||||||
return 0;
|
trains[trainToResend].resendData();
|
||||||
|
trainToResend++;
|
||||||
|
if(storedTrains <= trainToResend)
|
||||||
|
trainToResend = 0;
|
||||||
|
resendEvent = false;
|
||||||
|
timer0InterruptEnable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(autoff)
|
||||||
|
{
|
||||||
|
bool trainsRunning = false;
|
||||||
|
for(uint16_t i = 0; i < storedTrains; i++)
|
||||||
|
trainsRunning = trainsRunning || trains[i].isActive();
|
||||||
|
if(!trainsRunning)
|
||||||
|
{
|
||||||
|
powerIsOn = false;
|
||||||
|
timer0InterruptEnable(false);
|
||||||
|
Train::setOutput(Train::OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serialDispatch(&serial);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
2
serial.h
2
serial.h
@ -2,7 +2,7 @@
|
|||||||
#define SERIAL_H
|
#define SERIAL_H
|
||||||
|
|
||||||
#define BAUD 38400
|
#define BAUD 38400
|
||||||
#define SERIAL_BUFFER_SIZE 256
|
#define SERIAL_BUFFER_SIZE 512
|
||||||
|
|
||||||
#include <util/setbaud.h>
|
#include <util/setbaud.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
176
train.cpp
176
train.cpp
@ -1,8 +1,9 @@
|
|||||||
#include "train.h"
|
#include "train.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
static volatile unsigned char *_port = &PORTD;
|
static volatile unsigned char *_port = &PORTD;
|
||||||
|
|
||||||
Train::Train(const uint8_t address, uint8_t protocol): _address(address), _protocol(protocol)
|
Train::Train(const uint8_t address, uint8_t functionmask): _address(address), _functionmask(functionmask)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,16 +24,11 @@ uint8_t Train::getAddress()
|
|||||||
|
|
||||||
void Train::stop()
|
void Train::stop()
|
||||||
{
|
{
|
||||||
lastDataPacket = 0;
|
_speed = 0;
|
||||||
|
_function = 0;
|
||||||
resendData();
|
resendData();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Train::isActive()
|
|
||||||
{
|
|
||||||
return lastDataPacket & 0b0000000111111111;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Train::off()
|
void Train::off()
|
||||||
{
|
{
|
||||||
writePin(_port, _pinHighA, false);
|
writePin(_port, _pinHighA, false);
|
||||||
@ -81,19 +77,20 @@ void Train::sendBit(const bool bit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::sendAddress()
|
void Train::sendAddress(uint8_t address)
|
||||||
{
|
{
|
||||||
for(uint8_t i = 0; i < 8; i++)
|
for(uint8_t i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
sendBit(_address & (1 << i));
|
sendBit(address & (1 << i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::sendRaw(const uint16_t data)
|
|
||||||
|
void Train::sendRawAddr(const uint16_t address, const uint16_t data)
|
||||||
{
|
{
|
||||||
for(uint8_t j = 0; j < SEND_COUNT; j++)
|
for(uint8_t j = 0; j < SEND_COUNT; j++)
|
||||||
{
|
{
|
||||||
sendAddress();
|
sendAddress(address);
|
||||||
for(uint8_t i = 0; i < 10; i++)
|
for(uint8_t i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
sendBit(data & (1 << i));
|
sendBit(data & (1 << i));
|
||||||
@ -102,97 +99,130 @@ void Train::sendRaw(const uint16_t data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::setSpeed(uint8_t speed)
|
void Train::sendRaw(const uint16_t data)
|
||||||
{
|
{
|
||||||
if(speed != 0)speed = speed + 1;
|
sendRawAddr(_address, data);
|
||||||
else if(speed > 15) speed = 15;
|
}
|
||||||
|
|
||||||
|
uint16_t Train::packetAddSpeed()
|
||||||
|
{
|
||||||
|
uint16_t packet = 0;
|
||||||
|
if(_speed > 14)
|
||||||
|
_speed = 14;
|
||||||
for(uint8_t i = 0; i < 4; i++)
|
for(uint8_t i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
lastDataPacket = (lastDataPacket & ~(1 << (i+1)*2)) | (((uint16_t)speed & (1 << i)) << (i+1)*2-i);
|
packet |= ((bool)((_speed+1) & (1 << i))) << (i*2+2);
|
||||||
if(_protocol == M_DELTA) lastDataPacket = (lastDataPacket & ~(1 << ((i+1)*2+1))) | (((uint16_t)speed & (1 << i)) << ((i+1)*2+1-i));
|
|
||||||
}
|
}
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Train::packetAddDirection()
|
||||||
|
{
|
||||||
|
uint16_t packet = 0;
|
||||||
|
|
||||||
|
uint8_t data = 0;
|
||||||
|
if(!_direction)
|
||||||
|
{
|
||||||
|
if(_speed > 6)
|
||||||
|
data = 0b0100;
|
||||||
|
else if(_speed > 0)
|
||||||
|
data = 0b0101;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_speed > 0)
|
||||||
|
data = 0b1011;
|
||||||
|
else if (_speed > 6)
|
||||||
|
data = 0b1010;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_speed == 0)
|
||||||
|
data = !_direction ? 0b0101 : 0b1011;
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
uint8_t bit = (data & (1 << (3-i))) >> (3-i);
|
||||||
|
packet |= bit << ((i*2)+3);
|
||||||
|
}
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Train::packetAddFunction(const uint8_t function)
|
||||||
|
{
|
||||||
|
uint16_t packet = 0;
|
||||||
|
bool enabled = _function & (1 << function);
|
||||||
|
if(function == 0)
|
||||||
|
{
|
||||||
|
packet |= enabled ? 0b00000011 : 0b00000000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(enabled)
|
||||||
|
packet |= 0b1000000000;
|
||||||
|
for(uint8_t i = 0; i < 4; ++i )
|
||||||
|
{
|
||||||
|
if(function > i)
|
||||||
|
packet = packet | (1 << (7-i*2));
|
||||||
|
else
|
||||||
|
packet = packet & ~(1 << (7-i*2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Train::setSpeed(uint8_t speed)
|
||||||
|
{
|
||||||
|
_speed = speed;
|
||||||
resendData();
|
resendData();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Train::getSpeed()
|
uint8_t Train::getSpeed()
|
||||||
{
|
{
|
||||||
uint8_t speed = 0;
|
return _speed;
|
||||||
for(uint8_t i = 0; i < 4; i++)
|
}
|
||||||
speed |= ((bool)(lastDataPacket & (1 << (i+1)*2))) << i;
|
|
||||||
return speed;
|
uint16_t Train::assemblePacket()
|
||||||
|
{
|
||||||
|
uint16_t packet = packetAddSpeed() | packetAddFunction(0) | packetAddDirection();
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::resendData()
|
void Train::resendData()
|
||||||
{
|
{
|
||||||
sendRaw(lastDataPacket);
|
sendRaw(assemblePacket());
|
||||||
if(functionTimer > 0)
|
for(uint8_t i = 1; i < 4; ++i)
|
||||||
{
|
{
|
||||||
--functionTimer;
|
if(_functionmask & (1 << i))
|
||||||
}
|
sendRaw(packetAddSpeed() | packetAddFunction(i) | packetAddFunction(0));
|
||||||
else if(functionTimer == 0)
|
|
||||||
{
|
|
||||||
functionClear();
|
|
||||||
--functionTimer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Train::getLastPacket()
|
uint16_t Train::getLastPacket()
|
||||||
{
|
{
|
||||||
return lastDataPacket;
|
return assemblePacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::reverse()
|
void Train::reverse()
|
||||||
{
|
{
|
||||||
functionClear();
|
_direction = !_direction;
|
||||||
resendData();
|
resendData();
|
||||||
resendData();
|
|
||||||
if(getSpeed() > 0)
|
|
||||||
{
|
|
||||||
setSpeed(0);
|
|
||||||
resendData();
|
|
||||||
resendData();
|
|
||||||
_delay_ms(2000);
|
|
||||||
}
|
|
||||||
sendRaw(0b000001100);
|
|
||||||
sendRaw(0b000001100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::functionClear()
|
|
||||||
|
uint8_t Train::getFunctions()
|
||||||
{
|
{
|
||||||
lastDataPacket = lastDataPacket & ~(0b10101010);
|
return _function;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Train::getFunctionMask()
|
||||||
|
{
|
||||||
|
return _functionmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Train::sendFunction(const uint8_t function, bool enable)
|
void Train::sendFunction(const uint8_t function, bool enable)
|
||||||
{
|
{
|
||||||
if(function == 0)
|
if(function > 3)
|
||||||
{
|
return;
|
||||||
lastDataPacket = (lastDataPacket & ~0b00000001) | (enable ? 0b00000001 : 0b00000000);
|
_function = (_function & ~(1 << function)) | (enable << function);
|
||||||
//lastDataPacket = (lastDataPacket & ~0b1100000000) | (enable ? 0b1100000000 : 0);
|
|
||||||
}
|
|
||||||
else if(_protocol == M_DIGITAL && function <= 3)
|
|
||||||
{
|
|
||||||
if(enable)
|
|
||||||
lastDataPacket |= 0b1000000000;
|
|
||||||
else
|
|
||||||
lastDataPacket &= ~0b1000000000;
|
|
||||||
for(uint8_t i = 0; i < 4; ++i )
|
|
||||||
{
|
|
||||||
if(function > i)
|
|
||||||
lastDataPacket = lastDataPacket | (1 << (7-i*2));
|
|
||||||
else
|
|
||||||
lastDataPacket = lastDataPacket & ~(1 << (7-i*2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resendData();
|
resendData();
|
||||||
functionTimer = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Train::setProtocol(const uint8_t protocol)
|
|
||||||
{
|
|
||||||
_protocol = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Train::getProtocol()
|
|
||||||
{
|
|
||||||
return _protocol;
|
|
||||||
}
|
}
|
||||||
|
51
train.h
51
train.h
@ -8,61 +8,62 @@
|
|||||||
class Train
|
class Train
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const uint8_t M_DELTA = 0;
|
|
||||||
static const uint8_t M_DIGITAL = 1;
|
|
||||||
|
|
||||||
static const uint8_t HIGH = 2;
|
static constexpr uint8_t HIGH = 2;
|
||||||
static const uint8_t LOW = 1;
|
static constexpr uint8_t LOW = 1;
|
||||||
static const uint8_t OFF = 0;
|
static constexpr uint8_t OFF = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static constexpr unsigned char _pinHighA = PD5;
|
||||||
|
static constexpr unsigned char _pinLowA = PD4;
|
||||||
|
static constexpr unsigned char _pinHighB = PD2;
|
||||||
|
static constexpr unsigned char _pinLowB = PD3;
|
||||||
|
|
||||||
uint8_t _address;
|
uint8_t _address;
|
||||||
uint8_t _function = 0;
|
uint8_t _function = 0;
|
||||||
|
uint8_t _functionmask;
|
||||||
uint8_t _speed = 0;
|
uint8_t _speed = 0;
|
||||||
|
bool _direction = false;
|
||||||
static const unsigned char _pinHighA = PD5;
|
|
||||||
static const unsigned char _pinLowA = PD4;
|
|
||||||
static const unsigned char _pinHighB = PD2;
|
|
||||||
static const unsigned char _pinLowB = PD3;
|
|
||||||
|
|
||||||
static const uint8_t SEND_COUNT = 2;
|
static const uint8_t SEND_COUNT = 2;
|
||||||
|
|
||||||
uint8_t _protocol = M_DIGITAL;
|
|
||||||
|
|
||||||
uint16_t lastDataPacket = 0;
|
|
||||||
int8_t functionTimer = -1;
|
|
||||||
|
|
||||||
inline static void off();
|
inline static void off();
|
||||||
void sendBit(const bool bit);
|
static void sendBit(const bool bit);
|
||||||
void sendAddress();
|
static void sendAddress(uint8_t address);
|
||||||
void functionClear();
|
uint16_t packetAddSpeed();
|
||||||
|
uint16_t packetAddDirection();
|
||||||
|
uint16_t packetAddFunction(const uint8_t function);
|
||||||
|
uint16_t assemblePacket();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void setOutput(const uint8_t state);
|
static void setOutput(const uint8_t state);
|
||||||
|
|
||||||
Train(const uint8_t address, uint8_t protocol = M_DIGITAL);
|
Train(const uint8_t address, uint8_t functionmask = 0b1111);
|
||||||
Train();
|
Train();
|
||||||
|
|
||||||
void resendData();
|
void resendData();
|
||||||
|
|
||||||
void reverse();
|
void reverse();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
bool isActive();
|
bool isActive() {return _speed || _function;}
|
||||||
|
|
||||||
uint8_t getAddress();
|
uint8_t getAddress();
|
||||||
|
|
||||||
uint16_t getLastPacket();
|
uint16_t getLastPacket();
|
||||||
|
|
||||||
uint8_t getProtocol();
|
|
||||||
|
|
||||||
void setSpeed(uint8_t speed);
|
void setSpeed(uint8_t speed);
|
||||||
|
|
||||||
uint8_t getSpeed();
|
uint8_t getSpeed();
|
||||||
|
|
||||||
void setProtocol(const uint8_t protocol);
|
void setFunctionMask(uint8_t functionmask) {_functionmask = functionmask;}
|
||||||
|
|
||||||
|
uint8_t getFunctions();
|
||||||
|
|
||||||
|
uint8_t getFunctionMask();
|
||||||
|
|
||||||
void setAddress(const uint8_t address);
|
void setAddress(const uint8_t address);
|
||||||
|
|
||||||
@ -70,4 +71,6 @@ public:
|
|||||||
|
|
||||||
void sendRaw(const uint16_t data);
|
void sendRaw(const uint16_t data);
|
||||||
|
|
||||||
|
static void sendRawAddr(const uint16_t address, const uint16_t data);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
8
trains
8
trains
@ -1,4 +1,4 @@
|
|||||||
NUMBER: 0 ID: 01010100 CURRENT SPD: 0
|
NUMBER: 0 ID: 01010100 CURRENT PACKET: 220 SPEED: 0 PROTOCOL: digital
|
||||||
NUMBER: 1 ID: 01010000 CURRENT SPD: 0
|
NUMBER: 1 ID: 01010000 CURRENT PACKET: 220 SPEED: 0 PROTOCOL: digital
|
||||||
NUMBER: 2 ID: 01000100 CURRENT SPD: 0
|
NUMBER: 2 ID: 01000100 CURRENT PACKET: 237 SPEED: 3 PROTOCOL: digital
|
||||||
NUMBER: 3 ID: 00010100 CURRENT SPD: 0
|
NUMBER: 3 ID: 00010100 CURRENT PACKET: 220 SPEED: 0 PROTOCOL: digital
|
||||||
|
Reference in New Issue
Block a user