1 #include <msp/core/application.h>
2 #include <msp/core/getopt.h>
3 #include <msp/io/console.h>
4 #include <msp/io/eventdispatcher.h>
5 #include <msp/io/print.h>
6 #include <msp/io/serial.h>
7 #include <msp/time/timestamp.h>
8 #include <msp/time/utils.h>
13 class ArduProgram: public RegisteredApplication<ArduProgram>
20 Options(int, char **);
45 OutputState out_state;
46 Time::TimeStamp timeout;
51 IO::EventDispatcher ev_disp;
54 ArduProgram(int, char **);
59 void send_command(const string &);
61 void set_input_state(InputState);
62 void user_input_available();
63 void set_output_state(OutputState);
64 void serial_input_available();
68 ArduProgram::Options::Options(int argc, char **argv)
71 getopt.add_argument("port", serial_port).set_help("Serial port to use");
76 ArduProgram::ArduProgram(int argc, char **argv):
78 serial(options.serial_port)
80 IO::cin.signal_data_available.connect(sigc::mem_fun(this, &ArduProgram::user_input_available));
82 serial.signal_data_available.connect(sigc::mem_fun(this, &ArduProgram::serial_input_available));
86 int ArduProgram::main()
88 IO::print("Putting locomotive in programming mode (this will take a few seconds)\n");
91 Time::sleep(Time::sec);
94 set_output_state(INIT);
95 set_input_state(WAIT);
99 Time::TimeStamp t = Time::now();
104 timeout = Time::TimeStamp();
109 timeout = t+Time::sec;
111 else if(out_state==SEND_REG)
114 set_output_state(SEND_VALUE);
118 set_output_state(IDLE);
119 set_input_state(MENU);
123 ev_disp.tick(timeout-t);
129 IO::print("Resetting locomotive\n");
131 send_command("\x02");
132 Time::sleep(Time::sec);
133 send_command("\x01");
138 void ArduProgram::send_command(const string &cmd)
140 serial.put(cmd.size()^0xFF);
144 void ArduProgram::set_output()
148 cmd += (out_active ? 0x12 : 0x11);
156 void ArduProgram::set_input_state(InputState s)
162 IO::print("Do what [a/r/p/q/?] ");
165 IO::print("Enter new address: ");
168 IO::print("Enter register: ");
171 IO::print("Enter value: ");
174 IO::print("Please wait...\n");
180 void ArduProgram::user_input_available()
183 if(!IO::cin.getline(line))
190 int c = tolower(line[0]);
196 set_output_state(SEND_REG);
197 set_input_state(PROG_ADDR);
200 set_input_state(PROG_REG);
204 set_output_state(SEND_REG);
205 set_input_state(WAIT);
209 IO::print("a: Enter new address\n"
210 "r: Reset to factory settings\n"
211 "p: Program other CV\n"
213 set_input_state(MENU);
217 set_input_state(in_state);
223 value = lexical_cast<unsigned>(line);
225 if(in_state==PROG_REG)
227 set_output_state(SEND_REG);
228 set_input_state(PROG_VALUE);
230 else if(in_state==PROG_ADDR || in_state==PROG_VALUE)
232 value = lexical_cast<unsigned>(line);
234 set_output_state(SEND_VALUE);
235 set_input_state(WAIT);
238 catch(const lexical_error &e)
240 IO::print("Bad input, try again");
241 set_input_state(in_state);
246 void ArduProgram::set_output_state(OutputState s)
255 timeout = Time::now()+2*Time::sec;
266 timeout = Time::now()+Time::sec;
272 void ArduProgram::serial_input_available()
274 int c = serial.get();
278 throw runtime_error(format("Command error: %x\n", c));