+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/net/resolve.h>
+#include "serial.h"
+
+#include <msp/io/print.h>
+
+using namespace std;
+using namespace Msp;
+using namespace Marklin;
+
+Application::RegApp<Serial> Serial::reg;
+
+Serial::Serial(int, char **argv):
+ client(catalogue),
+ serial_port(argv[2]),
+ train(0),
+ rx_fill(0)
+{
+ DataFile::load(catalogue, "locos.dat");
+
+ client.use_event_dispatcher(event_disp);
+ client.signal_train_added.connect(sigc::mem_fun(this, &Serial::train_added));
+ client.signal_error.connect(sigc::mem_fun(this, &Serial::error));
+
+ string addr_str = argv[1];
+ if(addr_str.find(':')==string::npos)
+ addr_str += ":8315";
+ Net::SockAddr *addr = Net::resolve(addr_str);
+ client.connect(*addr);
+ delete addr;
+
+ serial_port.set_parameters("9600,8N1");
+ event_disp.add(serial_port);
+ serial_port.signal_data_available.connect(sigc::mem_fun(this, &Serial::data_available));
+}
+
+void Serial::tick()
+{
+ event_disp.tick();
+}
+
+void Serial::train_added(NetTrain &t)
+{
+ if(!train)
+ set_train(&t);
+}
+
+void Serial::error(const string &e)
+{
+ IO::print("%s\n", e);
+}
+
+void Serial::set_train(NetTrain *t)
+{
+ train = t;
+ serial_port.write(format("A%02d", train->get_address()));
+}
+
+void Serial::next_train()
+{
+ const map<unsigned, NetTrain *> &trains = client.get_trains();
+
+ map<unsigned, NetTrain *>::const_iterator i = trains.find(train->get_address());
+ ++i;
+ if(i==trains.end())
+ i = trains.begin();
+
+ set_train(i->second);
+}
+
+void Serial::prev_train()
+{
+ const map<unsigned, NetTrain *> &trains = client.get_trains();
+
+ map<unsigned, NetTrain *>::const_iterator i = trains.find(train->get_address());
+ if(i==trains.begin())
+ i = trains.end();
+ --i;
+
+ set_train(i->second);
+}
+
+void Serial::data_available()
+{
+ char c;
+ serial_port.read(&c, 1);
+ if(rx_fill==0)
+ {
+ if(c=='S' || c=='H' || c=='L')
+ rx_buf[rx_fill++] = c;
+ else if(c=='R')
+ {
+ IO::print("Reverse\n");
+ train->set_reverse(!train->get_reverse());
+ }
+ else if(c=='N')
+ next_train();
+ else if(c=='P')
+ prev_train();
+ }
+ else
+ {
+ rx_buf[rx_fill++] = c;
+ if(rx_buf[0]=='H' && rx_fill==2)
+ {
+ train->set_function(rx_buf[1]-'0', true);
+ IO::print("Func %d on\n", rx_buf[1]-'0');
+ rx_fill = 0;
+ }
+ else if(rx_buf[0]=='L' && rx_fill==2)
+ {
+ train->set_function(rx_buf[1]-'0', false);
+ IO::print("Func %d off\n", rx_buf[1]-'0');
+ rx_fill = 0;
+ }
+ else if(rx_buf[0]=='S' && rx_fill==3)
+ {
+ unsigned speed = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
+ IO::print("Set speed %d\n", speed);
+ train->set_speed(speed);
+ rx_fill = 0;
+ }
+ }
+}