send sucess message if command is processed sucessfully

This commit is contained in:
2022-01-19 22:35:55 +01:00
parent 6a02c2f8cd
commit ba67c5138d
5 changed files with 513 additions and 410 deletions

686
main.cpp
View File

@ -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;
} }

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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