diff --git a/CMakeLists.txt b/CMakeLists.txt index a2c7a20..5bee39c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ set(PORT_SPEED "57600" CACHE STRING "Serial Port Speed") set(PROGRAMMER "stk500v1" CACHE STRING "Programmer Type") set(COMPILE_FLAGS "" CACHE STRING "Additional Compiler Flags") -set(SRC_FILES main.cpp serial.cpp train.cpp item.cpp turnout.cpp) +set(SRC_FILES main.cpp serial.cpp train.cpp item.cpp turnout.cpp signal.cpp) # Compiler suite specification set(CMAKE_C_COMPILER /usr/bin/avr-gcc) diff --git a/main.cpp b/main.cpp index e7aa135..b87633c 100644 --- a/main.cpp +++ b/main.cpp @@ -11,6 +11,7 @@ #include "ringbuffer.h" #include "staticvector.h" #include "turnout.h" +#include "signal.h" #define COMMAND_BUFFER_SIZE 64 #define SNPRINTF_BUFFER_SIZE 128 @@ -18,8 +19,12 @@ char buffer[SNPRINTF_BUFFER_SIZE]; -SVector trains; +static constexpr uint8_t EEPROM_RESERVE = 32; +static constexpr uint8_t BLOCK = 4; + +SVector trains; SVector turnouts; +SVector signals; bool autoff = true; bool powerIsOn = true; @@ -31,6 +36,13 @@ volatile bool resendEvent = false; constexpr bool USE_PULSES = false; +void setPower(bool on); +void save_state(); + +#include "traindispatch.h" +#include "turnoutdispatch.h" +#include "signaldispatch.h" + ISR(TIMER0_OVF_vect) { ++tick; @@ -60,15 +72,30 @@ void save_state() EEPROM_write_char( 2, trains.maxSize()); EEPROM_write_char( 3, turnouts.count()); EEPROM_write_char( 4, turnouts.maxSize()); - for(uint16_t i = 0; i < trains.count(); i++) + EEPROM_write_char( 5, signals.count()); + EEPROM_write_char( 6, signals.maxSize()); + + const uint16_t trainOffset = EEPROM_RESERVE; + for(uint8_t i = 0; i < trains.count(); i++) { - EEPROM_write_char( i*2+32, trains[i].getAddress()); - EEPROM_write_char( i*2+32+1, trains[i].getFunctionMask()); + EEPROM_write_char( i*BLOCK+trainOffset, trains[i].getAddress()); + EEPROM_write_char( i*BLOCK+trainOffset+1, trains[i].getFunctionMask()); + EEPROM_write_char( i*BLOCK+trainOffset+2, trains[i].getQuirks()); } - for(uint16_t i = 0; i < turnouts.count(); i++) + + const uint16_t turnoutOffset = trains.maxSize()*BLOCK+EEPROM_RESERVE; + for(uint8_t i = 0; i < turnouts.count(); i++) { - EEPROM_write_char( i*2+32+trains.maxSize()*2, turnouts[i].getAddress()); - EEPROM_write_char( i*2+32+1+trains.maxSize()*2, turnouts[i].getSubaddress()); + EEPROM_write_char( i*BLOCK+turnoutOffset, turnouts[i].getAddress()); + EEPROM_write_char( i*BLOCK+turnoutOffset+1, turnouts[i].getSubaddress()); + } + + const uint16_t signalOffset = trains.maxSize()*BLOCK+turnouts.maxSize()*BLOCK+EEPROM_RESERVE; + for(uint8_t i = 0; i < signals.count(); i++) + { + EEPROM_write_char( i*4+signalOffset, signals[i].getAddress()); + EEPROM_write_char( i*4+signalOffset+1, signals[i].getSubaddress()); + EEPROM_write_char( i*4+signalOffset+2, signals[i].getType()); } sei(); } @@ -77,44 +104,65 @@ void restore_state() { uint8_t trainCount = EEPROM_read_char(0); uint8_t turnoutCount = EEPROM_read_char(3); + uint8_t signalCount = EEPROM_read_char(5); autoff = EEPROM_read_char(1); trains.clear(); - if(trainCount > trains.maxSize() || trains.maxSize() != EEPROM_read_char(2) ) + turnouts.clear(); + signals.clear(); + if(trainCount > trains.maxSize() || trains.maxSize() != EEPROM_read_char(2) || + turnoutCount > turnouts.maxSize() || turnouts.maxSize() != EEPROM_read_char(4) || + signalCount > signals.maxSize() || signals.maxSize() != EEPROM_read_char(6)) { for(uint16_t i = 0; i < EPPROM_SIZE; i++) EEPROM_write_char(i, 0); } else { + const uint16_t trainOffset = EEPROM_RESERVE; + const uint16_t turnoutOffset = trains.maxSize()*BLOCK+EEPROM_RESERVE; + const uint16_t signalOffset = trains.maxSize()*BLOCK+turnouts.maxSize()*BLOCK+EEPROM_RESERVE; + for(uint8_t i = 0; i < trainCount; i++) - trains.push_back(Train(EEPROM_read_char(32+i*2), EEPROM_read_char(32+1+i*2))); + trains.push_back(Train(EEPROM_read_char(trainOffset+i*4), + EEPROM_read_char(trainOffset+1+i*4), + EEPROM_read_char(trainOffset+2+i*4))); for(uint8_t i = 0; i < turnoutCount; i++) - turnouts.push_back(Turnout(EEPROM_read_char(32+i*2+trains.maxSize()*2), EEPROM_read_char(32+1+i*2+trains.maxSize()*2))); + turnouts.push_back(Turnout(EEPROM_read_char(i*4+turnoutOffset), + EEPROM_read_char(1+i*4+turnoutOffset))); + for(uint8_t i = 0; i < signalCount; i++) + signals.push_back(Signal(EEPROM_read_char(i*4+signalOffset), + EEPROM_read_char(1+i*4+signalOffset), + EEPROM_read_char(2+i*4+signalOffset))); } } inline static void printHelp(Serial* serial) { serial->write_p(PSTR("Available Commands: \n\ - help : Show this prompt.\n\ - train add [address] [functionmask] : Add train.\n\ - train [nn] delete : Delete last train.\n\ - train list : Print list of saved trains.\n\ - train [nn] s(top) : Stop nth train.\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] r(everse) : Reverse train n.\n\ - turnout add [address] [subaddress] : Add a turnout\n\ - turnout list : List turnouts\n\ - turnout set [left/right] : Set turnout direction\n\ - turnout delete [nn] : Delete Turnout\n\ - stop : stop all trains\n\ - power off : power off the rail\n\ - power on : power on the rail\n\ - power auto : power off the rail when no trains are moveing\n\ - dump : prints epprom contence\n\ - erase : Erase epprom.\n")); + help : Show this prompt.\n\ + train add [address] [functionmask] [quriks] : Add train.\n\ + train [nn] delete : Delete last train.\n\ + train list : Print list of saved trains.\n\ + train [nn] s(top) : Stop nth train.\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] r(everse) : Reverse train n.\n\ + train [nn] edit [functionmask] [quriks] : Edit train n.\n\ + turnout add [address] [subaddress] : Add a turnout\n\ + turnout list : List turnouts\n\ + turnout [nn] set [left/right] : Set turnout direction\n\ + turnout [nn] delete : Delete Turnout\n\ + signal add [address] [subaddress] [type] : Add a signal\n\ + signal list : List signal\n\ + signal [nn] set [status] : Set signal direction\n\ + signal [nn] delete : Delete signal\n\ + stop : stop all trains\n\ + power off : power off the rail\n\ + power on : power on the rail\n\ + power auto : power off the rail when no trains are moveing\n\ + dump : prints epprom contence\n\ + erase : Erase epprom.\n")); } void setPower(bool on) @@ -137,282 +185,6 @@ void setPower(bool on) } } -void printTurnoutState(uint8_t id, Serial* serial) -{ - snprintf(buffer, SNPRINTF_BUFFER_SIZE, - "TURNOUT NUMBER: %u ADDRESS: %u SUBADDRESS: %u CURRENT PACKET: %x DIRECTION: %u\n", - id, turnouts[id].getAddress(), turnouts[id].getSubaddress(), - turnouts[id].getPacket(), turnouts[id].getDirection()); - serial->write(buffer, SNPRINTF_BUFFER_SIZE); -} - -int turnoutDispatch(char* inBuffer, Serial* serial) -{ - if( strcmp(inBuffer, "add") == 0 ) - { - char* token = strtok(NULL, " "); - uint8_t address = 0; - if(token != NULL) - address = strtol(token, nullptr, 10); - if(address != 0 && turnouts.remainingCapacity() > 0) - { - uint8_t subaddress = 0; - - token = strtok(NULL, " "); - if(token != NULL) - subaddress = strtol(token, nullptr, 10); - - turnouts.push_back(Turnout(address, subaddress)); - serial->write_p(PSTR("TUNROUT saved! ")); - printTurnoutState(turnouts.count()-1, serial); - - save_state(); - return 0; - } - serial->write_p(PSTR("Usage: turnout add [address] [subaddress]")); - } - else if( strcmp(inBuffer, "list") == 0 ) - { - serial->write_p(PSTR("Turnouts:\n")); - for(uint8_t i = 0; i < turnouts.count(); i++) - printTurnoutState(i, serial); - serial->putChar('\n'); - return 0; - } - else - { - uint8_t id = strtol(inBuffer, nullptr, 10); - if(id < turnouts.count() ) - { - setPower(true); - char* token = strtok(NULL, " "); - if(token != NULL && strcmp(token, "set") == 0 ) - { - char* boolToken = strtok(NULL, " "); - if(token != NULL && boolToken != NULL) - { - bool direction = (strcmp(boolToken, "right") == 0); - turnouts[id].setDirection(direction); - serial->write_p(PSTR("Set turnout direction ")); - serial->write(direction ? "right\n" : "left\n"); - printTurnoutState(id, serial); - return 0; - } - } - else if(token != NULL && strcmp(token, "raw") == 0 ) - { - token = strtok(NULL, " "); - serial->flush(); - if(token != NULL) - { - cli(); - uint16_t i = strtol(token, nullptr, 16 ); - snprintf(buffer, SNPRINTF_BUFFER_SIZE, "SENDING: %x to %x\n", i, turnouts[id].getAddress()); - serial->write(buffer, strlen(buffer)); - while(!serial->dataIsWaiting()) - { - turnouts[id].sendRaw(i); - sei(); - _delay_ms(20); - cli(); - } - serial->write_p(PSTR("Finished\n")); - serial->flush(); - sei(); - return 0; - } - } - else if(token != NULL && strcmp(token, "delete") == 0) - { - turnouts.erase(id); - serial->write_p(PSTR("Turnout: ")); - serial->write(id); - serial->write_p(PSTR(" deleted\n")); - save_state(); - 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 printTrainState(int id, Serial* serial) -{ - snprintf(buffer, SNPRINTF_BUFFER_SIZE, - "TRAIN NUMBER: %u ADDRESS: %u CURRENT PACKET: %x SPEED: %i FUNCTIONS: %s FUNCTIONMASK: %s\n", - id, trains[id].getAddress(), - trains[id].getLastPacket(), trains[id].getSpeed(), - bit_rep[trains[id].getFunctions() & 0x0F], bit_rep[trains[id].getFunctionMask() & 0x0F]); - serial->write(buffer, SNPRINTF_BUFFER_SIZE); -} - -int trainDispatch(char* inBuffer, Serial* serial) -{ - if( strcmp(inBuffer, "add") == 0 ) - { - char* token = strtok(NULL, " "); - uint8_t address = 0; - if(token != NULL) - address = strtol(token, nullptr, 10); - if(address != 0 && trains.remainingCapacity() > 0) - { - uint8_t functionMask = 0; - - token = strtok(NULL, " "); - if(token != NULL) - functionMask = strtol(token, nullptr, 2); - - trains.push_back(Train(address, functionMask)); - - serial->write_p(PSTR("TRAIN saved! ")); - printTrainState(trains.count()-1, serial); - - save_state(); - return 0; - } - serial->write_p(PSTR("Usage: train add [address] [functionmask]")); - } - else if( strcmp(inBuffer, "list") == 0 ) - { - serial->write_p(PSTR("Trains:\n")); - for(uint8_t i = 0; i < trains.count(); i++) - printTrainState(i, serial); - serial->putChar('\n'); - return 0; - } - else if( strcmp(inBuffer, "probe") == 0 ) - { - for(uint16_t j = 0; j < 255; j++) - { - snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING ADDR: %x\n", j); - serial->write(buffer, strlen(buffer)); - cli(); - for(uint8_t k = 0; k < 10; k++) - { - Train::sendRawAddr(j, 60); - _delay_ms(20); - } - for(uint8_t k = 0; k < 3; k++) - { - Train::sendRawAddr(j, 0); - _delay_ms(20); - } - sei(); - } - return 0; - } - else - { - uint8_t id = strtol(inBuffer, nullptr, 10); - if(id < trains.count() ) - { - setPower(true); - char* token = strtok(NULL, " "); - if( token != NULL && (strcmp(token, "speed") == 0 || strcmp(token, "s") == 0) ) - { - token = strtok(NULL, " "); - trains[id].setSpeed(atoi(token)); - serial->write_p(PSTR("Set Train speed\n")); - printTrainState(id, serial); - return 0; - } - else if(token != NULL && strcmp(token, "function") == 0 ) - { - token = strtok(NULL, " "); - char* boolToken = strtok(NULL, " "); - if(token != NULL && boolToken != NULL) - { - uint8_t functionId = atoi(token); - bool on = (strcmp(boolToken, "on") == 0); - trains[id].sendFunction(functionId, on ); - serial->write_p(PSTR("Set Train function ")); - serial->write(functionId); - serial->write(on ? " on\n" : " off\n"); - printTrainState(id, serial); - return 0; - } - } - else if(token != NULL && strcmp(token, "probe") == 0 ) - { - serial->flush(); - for(uint16_t j = 0; j < 1024 && !serial->dataIsWaiting(); j++) - { - trains[id].sendRaw(j); - snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING: %x\n", j); - serial->write(buffer, strlen(buffer)); - sei(); - _delay_ms(250); - cli(); - } - sei(); - serial->flush(); - 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(); - printTrainState(id, serial); - return 0; - } - else if( token != NULL && strcmp(token, "delete") == 0) - { - trains.erase(id); - serial->write_p(PSTR("Train: ")); - serial->write(id); - serial->write_p(PSTR(" deleted\n")); - save_state(); - 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; -} - int powerDispatch(char* token, Serial* serial) { if(strcmp(token, "off") == 0) @@ -477,6 +249,12 @@ void serialDispatch(Serial* serial) if(token != NULL) ret = turnoutDispatch(token, serial); } + else if(strcmp(token, "signal") == 0) + { + token = strtok(NULL, " "); + if(token != NULL) + ret = signalDispatch(token, serial); + } else if(strncmp(token, "erase", 4) == 0) { for(uint16_t i = 0; i < EPPROM_SIZE; i++) EEPROM_write_char(i, 0); @@ -500,6 +278,7 @@ void serialDispatch(Serial* serial) { cli(); trains[i].stop(); + printTrainState(i, serial); sei(); } ret = 0; @@ -580,8 +359,10 @@ int main() trains[itemToResend].sendData(); else if(itemToResend < trains.count() + turnouts.count()) turnouts[itemToResend-trains.count()].sendData(); + else if(itemToResend < trains.count() + turnouts.count()+signals.count()) + signals[itemToResend-trains.count()-turnouts.count()].sendData(); itemToResend++; - if(trains.count()+turnouts.count() <= itemToResend) + if(trains.count()+turnouts.count()+signals.count() <= itemToResend) itemToResend = 0; resendEvent = false; timer0InterruptEnable(true); diff --git a/signal.cpp b/signal.cpp new file mode 100644 index 0000000..ab4a76a --- /dev/null +++ b/signal.cpp @@ -0,0 +1,50 @@ +#include "signal.h" + +Signal::Signal(uint8_t address, uint8_t subaddress, uint8_t type): Item(address), _subaddress(subaddress), _type(type) +{ +} + +void Signal::setState(uint8_t state) +{ + _state = state; + sendData(); +} + +uint8_t Signal::getState() +{ + return _state; +} + +uint8_t Signal::getSubaddress() +{ + return _subaddress; +} +uint16_t Signal::getPacket() +{ + uint16_t data; + if(!(_type & 1)) + { + data = _state | _subaddress << 6; + } + else + { + data = 0; + data |= ((_state == GO) << 9) | ((_state == GO) << 8); + for (uint8_t i = 0; i < 2; ++i) + { + uint8_t bit = (_subaddress & (1 << i)) >> i; + data |= (bit << (7-i*2)) | (bit << (6-i*2)); + } + } + return data; +} + +void Signal::sendData() +{ + sendRaw(getPacket()); +} + +uint8_t Signal::getType() +{ + return _type; +} diff --git a/signal.h b/signal.h new file mode 100644 index 0000000..58bebb9 --- /dev/null +++ b/signal.h @@ -0,0 +1,32 @@ +#pragma once +#include "item.h" +#include + +class Signal: public Item +{ +public: + static constexpr uint8_t GO = 0; + static constexpr uint8_t STOP = 1; + static constexpr uint8_t SLOW = 2; + static constexpr uint8_t EXPECT_GO = 0; + static constexpr uint8_t EXPECT_STOP = 1 << 3; + static constexpr uint8_t RIGHT = 2 << 3; + static constexpr uint8_t TYPE_NORMAL = 0; + static constexpr uint8_t TYPE_RELAY = 1; + static constexpr uint8_t TYPE_HAS_SLOW = 1 << 1; + static constexpr uint8_t TYPE_HAS_EXPECT = 1 << 2; + +private: + uint8_t _state = GO; + uint8_t _subaddress; + uint8_t _type; + +public: + Signal(uint8_t address, uint8_t subaddress, uint8_t type = TYPE_NORMAL | TYPE_HAS_SLOW); + void setState(uint8_t state); + uint8_t getState(); + uint8_t getSubaddress(); + uint16_t getPacket(); + void sendData(); + uint8_t getType(); +}; diff --git a/signaldispatch.h b/signaldispatch.h new file mode 100644 index 0000000..7b1fbbf --- /dev/null +++ b/signaldispatch.h @@ -0,0 +1,116 @@ +#pragma once + +void printSignalState(uint8_t id, Serial* serial) +{ + snprintf(buffer, SNPRINTF_BUFFER_SIZE, + "SIGNAL NUMBER: %u ADDRESS: %u SUBADDRESS: %u TYPE: %u CURRENT PACKET: %x STATE: %u\n", + id, signals[id].getAddress(), signals[id].getSubaddress(), signals[id].getType(), + signals[id].getPacket(), signals[id].getState()); + serial->write(buffer, SNPRINTF_BUFFER_SIZE); +} + +int signalDispatch(char* inBuffer, Serial* serial) +{ + if( strcmp(inBuffer, "add") == 0 ) + { + char* token = strtok(NULL, " "); + uint8_t address = 0; + if(token != NULL) + address = strtol(token, nullptr, 10); + if(address != 0 && signals.remainingCapacity() > 0) + { + uint8_t subaddress = 0; + uint8_t type = 0; + + token = strtok(NULL, " "); + if(token != NULL) + subaddress = strtol(token, nullptr, 10); + + token = strtok(NULL, " "); + if(token != NULL) + type = strtol(token, nullptr, 10); + + signals.push_back(Signal(address, subaddress, type)); + serial->write_p(PSTR("SIGNAL saved! ")); + printSignalState(signals.count()-1, serial); + + save_state(); + return 0; + } + serial->write_p(PSTR("Usage: signal add [address] [subaddress] [type]")); + } + else if( strcmp(inBuffer, "list") == 0 ) + { + serial->write_p(PSTR("Signals:\n")); + for(uint8_t i = 0; i < signals.count(); i++) + printSignalState(i, serial); + serial->putChar('\n'); + return 0; + } + else + { + uint8_t id = strtol(inBuffer, nullptr, 10); + if(id < signals.count() ) + { + setPower(true); + char* token = strtok(NULL, " "); + if(token != NULL && strcmp(token, "set") == 0 ) + { + token = strtok(NULL, " "); + if(token != NULL) + { + uint8_t state = strtol(token, nullptr, 10);; + signals[id].setState(state); + serial->write_p(PSTR("Set signal state")); + serial->write((int)state); + serial->putChar('\n'); + printSignalState(id, serial); + return 0; + } + } + else if(token != NULL && strcmp(token, "raw") == 0 ) + { + token = strtok(NULL, " "); + serial->flush(); + if(token != NULL) + { + cli(); + uint16_t i = strtol(token, nullptr, 16 ); + snprintf(buffer, SNPRINTF_BUFFER_SIZE, "SENDING: %x to %x\n", i, signals[id].getAddress()); + serial->write(buffer, strlen(buffer)); + while(!serial->dataIsWaiting()) + { + signals[id].sendRaw(i); + sei(); + _delay_ms(20); + cli(); + } + serial->write_p(PSTR("Finished\n")); + serial->flush(); + sei(); + return 0; + } + } + else if(token != NULL && strcmp(token, "delete") == 0) + { + signals.erase(id); + serial->write_p(PSTR("Signal: ")); + serial->write(id); + serial->write_p(PSTR(" deleted\n")); + save_state(); + 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; +} diff --git a/train.cpp b/train.cpp index 2e81525..66ce359 100644 --- a/train.cpp +++ b/train.cpp @@ -1,7 +1,9 @@ #include "train.h" #include +#include -Train::Train(const uint8_t address, uint8_t functionmask): Item(address), _functionmask(functionmask) +Train::Train(const uint8_t address, uint8_t functionmask, uint8_t quirks): +Item(address), _functionmask(functionmask), _quirks(quirks) { } @@ -71,15 +73,48 @@ uint16_t Train::packetAddFunction(const uint8_t function) return packet; } -void Train::setSpeed(uint8_t speed) +void Train::setSpeed(int8_t speed) { - _speed = speed; - sendData(); + bool direction = _direction; + + if(_quirks & (1 << 1)) + speed = 0-speed; + + if(speed < 0) + _direction = true; + else if(speed > 0) + _direction = false; + + _speed = abs(speed); + + if((_quirks & 1) && direction != _direction) + { + cli(); + for(uint8_t i = 0; i < 2; ++i) + { + sendRaw(0x28c); + _delay_ms(4); + } + if(!_direction) + { + for(uint8_t i = 0; i < 2; ++i) + { + sendRaw(0x224); + _delay_ms(4); + } + } + sei(); + } + else + { + sendData(); + } } -uint8_t Train::getSpeed() +int8_t Train::getSpeed() { - return _speed; + int8_t speed = _direction ? 0-_speed : _speed; + return _quirks & (1 << 1) ? 0-speed : speed; } void Train::stop() @@ -144,3 +179,13 @@ void Train::sendFunction(const uint8_t function, bool enable) _function = (_function & ~(1 << function)) | (enable << function); sendData(); } + +uint8_t Train::getQuirks() +{ + return _quirks; +} + +void Train::setQuirks(uint8_t quirks) +{ + _quirks = quirks; +} diff --git a/train.h b/train.h index e6e4303..f5c35e6 100644 --- a/train.h +++ b/train.h @@ -8,6 +8,7 @@ private: uint8_t _function = 0; uint8_t _functionmask; uint8_t _speed = 0; + uint8_t _quirks = 0; bool _direction = false; uint16_t packetAddSpeed(); @@ -17,27 +18,24 @@ private: public: - Train(const uint8_t address, uint8_t functionmask = 0b0000); + Train(const uint8_t address, uint8_t functionmask = 0, uint8_t quirks = 0); void sendData(); void reverse(); - void stop(); bool isActive() {return getSpeed() || getFunctions();} - uint16_t getLastPacket(); - void setSpeed(uint8_t speed); - - uint8_t getSpeed(); + void setSpeed(int8_t speed); + int8_t getSpeed(); void setFunctionMask(uint8_t functionmask) {_functionmask = functionmask;} - uint8_t getFunctions(); - - uint8_t getFunctionMask(); - + uint8_t getFunctionMask(); void sendFunction(const uint8_t function, bool enable = true); + + uint8_t getQuirks(); + void setQuirks(uint8_t quirks); }; diff --git a/traindispatch.h b/traindispatch.h new file mode 100644 index 0000000..580a665 --- /dev/null +++ b/traindispatch.h @@ -0,0 +1,198 @@ +#pragma once + +void printTrainState(int id, Serial* serial) +{ + snprintf(buffer, SNPRINTF_BUFFER_SIZE, + "TRAIN NUMBER: %u ADDRESS: %u CURRENT PACKET: %x SPEED: %i FUNCTIONS: %s FUNCTIONMASK: %s QUIRKS: %s\n", + id, trains[id].getAddress(), + trains[id].getLastPacket(), trains[id].getSpeed(), + bit_rep[trains[id].getFunctions() & 0x0F], bit_rep[trains[id].getFunctionMask() & 0x0F], + bit_rep[trains[id].getQuirks() & 0x0F]); + serial->write(buffer, SNPRINTF_BUFFER_SIZE); +} + +int trainDispatch(char* inBuffer, Serial* serial) +{ + if( strcmp(inBuffer, "add") == 0 ) + { + char* token = strtok(NULL, " "); + uint8_t address = 0; + if(token != NULL) + address = strtol(token, nullptr, 10); + if(address != 0 && trains.remainingCapacity() > 0) + { + uint8_t functionMask = 0; + uint8_t quirks = 0; + + token = strtok(NULL, " "); + if(token != NULL) + { + functionMask = strtol(token, nullptr, 2); + token = strtok(NULL, " "); + if(token != NULL) + { + quirks = strtol(token, nullptr, 2); + } + } + + trains.push_back(Train(address, functionMask, quirks)); + + serial->write_p(PSTR("TRAIN saved! ")); + printTrainState(trains.count()-1, serial); + + save_state(); + return 0; + } + serial->write_p(PSTR("Usage: train add [address] [functionmask] [quirks]")); + } + else if( strcmp(inBuffer, "list") == 0 ) + { + serial->write_p(PSTR("Trains:\n")); + for(uint8_t i = 0; i < trains.count(); i++) + printTrainState(i, serial); + serial->putChar('\n'); + return 0; + } + else if( strcmp(inBuffer, "probe") == 0 ) + { + for(uint16_t j = 0; j < 255; j++) + { + snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING ADDR: %x\n", j); + serial->write(buffer, strlen(buffer)); + cli(); + for(uint8_t k = 0; k < 10; k++) + { + Train::sendRawAddr(j, 60); + _delay_ms(20); + } + for(uint8_t k = 0; k < 3; k++) + { + Train::sendRawAddr(j, 0); + _delay_ms(20); + } + sei(); + } + return 0; + } + else + { + uint8_t id = strtol(inBuffer, nullptr, 10); + if(id < trains.count() ) + { + setPower(true); + char* token = strtok(NULL, " "); + if( token != NULL && (strcmp(token, "speed") == 0 || strcmp(token, "s") == 0) ) + { + token = strtok(NULL, " "); + trains[id].setSpeed(atoi(token)); + serial->write_p(PSTR("Set Train speed\n")); + printTrainState(id, serial); + return 0; + } + else if(token != NULL && strcmp(token, "function") == 0 ) + { + token = strtok(NULL, " "); + char* boolToken = strtok(NULL, " "); + if(token != NULL && boolToken != NULL) + { + uint8_t functionId = atoi(token); + bool on = (strcmp(boolToken, "on") == 0); + trains[id].sendFunction(functionId, on ); + serial->write_p(PSTR("Set Train function ")); + serial->write(functionId); + serial->write(on ? " on\n" : " off\n"); + printTrainState(id, serial); + return 0; + } + } + else if(token != NULL && strcmp(token, "probe") == 0 ) + { + serial->flush(); + for(uint16_t j = 0; j < 1024 && !serial->dataIsWaiting(); j++) + { + trains[id].sendRaw(j); + snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRYING: %x\n", j); + serial->write(buffer, strlen(buffer)); + sei(); + _delay_ms(250); + cli(); + } + sei(); + serial->flush(); + 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(); + printTrainState(id, serial); + return 0; + } + else if( token != NULL && strcmp(token, "edit") == 0) + { + uint8_t functionMask = 0; + uint8_t quirks = 0; + token = strtok(NULL, " "); + if(token != NULL) + { + functionMask = strtol(token, nullptr, 2); + token = strtok(NULL, " "); + if(token != NULL) + { + quirks = strtol(token, nullptr, 2); + } + } + trains[id].stop(); + trains[id].setFunctionMask(functionMask); + trains[id].setQuirks(quirks); + save_state(); + printTrainState(id, serial); + return 0; + } + else if( token != NULL && strcmp(token, "delete") == 0) + { + trains.erase(id); + serial->write_p(PSTR("Train: ")); + serial->write(id); + serial->write_p(PSTR(" deleted\n")); + save_state(); + 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; +} diff --git a/trains b/trains index e69c618..1d1cc36 100644 --- a/trains +++ b/trains @@ -1,5 +1,5 @@ -NUMBER: 0 ID: 84 CURRENT PACKET: 28c SPEED: 0 FUNCTIONS: 0 FUNCTIONMASK: 0 //rangier dampf lok -NUMBER: 1 ID: 4 CURRENT PACKET: 227 SPEED: 0 FUNCTIONS: 0 FUNCTIONMASK: 0 //dampf lok -NUMBER: 2 ID: 68 CURRENT PACKET: 224 SPEED: 0 FUNCTIONS: 0 FUNCTIONMASK: 7 //rangier lok -NUMBER: 3 ID: 64 CURRENT PACKET: 274 SPEED: 0 FUNCTIONS: 0 FUNCTIONMASK: 0 //ICE -NUMBER: 4 ID: 40 CURRENT PACKET: 260 SPEED: 0 FUNCTIONS: 0 FUNCTIONMASK: 0 //br143 +TRAIN NUMBER: 0 ADDRESS: 84 CURRENT PACKET: 224 SPEED: 0 FUNCTIONS: 0000 FUNCTIONMASK: 0000 //rangier dampf lok +TRAIN NUMBER: 1 ADDRESS: 4 CURRENT PACKET: 224 SPEED: 0 FUNCTIONS: 0000 FUNCTIONMASK: 0000 //dampf lok +TRAIN NUMBER: 2 ADDRESS: 68 CURRENT PACKET: 28c SPEED: 0 FUNCTIONS: 0000 FUNCTIONMASK: 0111 //rangier lok +TRAIN NUMBER: 3 ADDRESS: 64 CURRENT PACKET: 224 SPEED: 0 FUNCTIONS: 0000 FUNCTIONMASK: 0000 //ICE 2 +TRAIN NUMBER: 4 ADDRESS: 20 CURRENT PACKET: 224 SPEED: 0 FUNCTIONS: 0000 FUNCTIONMASK: 0000 //br143 diff --git a/turnoutdispatch.h b/turnoutdispatch.h new file mode 100644 index 0000000..3008769 --- /dev/null +++ b/turnoutdispatch.h @@ -0,0 +1,110 @@ +#pragma once + +void printTurnoutState(uint8_t id, Serial* serial) +{ + snprintf(buffer, SNPRINTF_BUFFER_SIZE, + "TURNOUT NUMBER: %u ADDRESS: %u SUBADDRESS: %u CURRENT PACKET: %x DIRECTION: %u\n", + id, turnouts[id].getAddress(), turnouts[id].getSubaddress(), + turnouts[id].getPacket(), turnouts[id].getDirection()); + serial->write(buffer, SNPRINTF_BUFFER_SIZE); +} + +int turnoutDispatch(char* inBuffer, Serial* serial) +{ + if( strcmp(inBuffer, "add") == 0 ) + { + char* token = strtok(NULL, " "); + uint8_t address = 0; + if(token != NULL) + address = strtol(token, nullptr, 10); + if(address != 0 && turnouts.remainingCapacity() > 0) + { + uint8_t subaddress = 0; + + token = strtok(NULL, " "); + if(token != NULL) + subaddress = strtol(token, nullptr, 10); + + turnouts.push_back(Turnout(address, subaddress)); + serial->write_p(PSTR("TUNROUT saved! ")); + printTurnoutState(turnouts.count()-1, serial); + + save_state(); + return 0; + } + serial->write_p(PSTR("Usage: turnout add [address] [subaddress]")); + } + else if( strcmp(inBuffer, "list") == 0 ) + { + serial->write_p(PSTR("Turnouts:\n")); + for(uint8_t i = 0; i < turnouts.count(); i++) + printTurnoutState(i, serial); + serial->putChar('\n'); + return 0; + } + else + { + uint8_t id = strtol(inBuffer, nullptr, 10); + if(id < turnouts.count() ) + { + setPower(true); + char* token = strtok(NULL, " "); + if(token != NULL && strcmp(token, "set") == 0 ) + { + char* boolToken = strtok(NULL, " "); + if(token != NULL && boolToken != NULL) + { + bool direction = (strcmp(boolToken, "right") == 0); + turnouts[id].setDirection(direction); + serial->write_p(PSTR("Set turnout direction ")); + serial->write(direction ? "right\n" : "left\n"); + printTurnoutState(id, serial); + return 0; + } + } + else if(token != NULL && strcmp(token, "raw") == 0 ) + { + token = strtok(NULL, " "); + serial->flush(); + if(token != NULL) + { + cli(); + uint16_t i = strtol(token, nullptr, 16 ); + snprintf(buffer, SNPRINTF_BUFFER_SIZE, "SENDING: %x to %x\n", i, turnouts[id].getAddress()); + serial->write(buffer, strlen(buffer)); + while(!serial->dataIsWaiting()) + { + turnouts[id].sendRaw(i); + sei(); + _delay_ms(20); + cli(); + } + serial->write_p(PSTR("Finished\n")); + serial->flush(); + sei(); + return 0; + } + } + else if(token != NULL && strcmp(token, "delete") == 0) + { + turnouts.erase(id); + serial->write_p(PSTR("Turnout: ")); + serial->write(id); + serial->write_p(PSTR(" deleted\n")); + save_state(); + 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; +}