]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/locomotive.cpp
Add locomotive types
[r2c2.git] / source / libmarklin / locomotive.cpp
1 #include <msp/time/timer.h>
2 #include <msp/time/units.h>
3 #include "command.h"
4 #include "constants.h"
5 #include "control.h"
6 #include "locomotive.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace Marklin {
12
13 Locomotive::Locomotive(const LocoType &t, Control &c, unsigned a):
14         type(t),
15         control(c),
16         addr(a),
17         speed(0),
18         reverse(false),
19         funcs(0)
20 {
21         control.add_locomotive(*this);
22
23         refresh_status();
24 }
25
26 void Locomotive::set_speed(unsigned spd)
27 {
28         speed=min(spd, 14U);
29
30         send_command(false);
31
32         signal_speed_changed.emit(speed);
33 }
34
35 void Locomotive::set_reverse(bool rev)
36 {
37         if(rev==reverse)
38                 return;
39
40         if(speed)
41         {
42                 control.set_timer((500+speed*150)*Time::msec).signal_timeout.connect(sigc::mem_fun(this, &Locomotive::reverse_timeout));
43                 set_speed(0);
44         }
45         else
46         {
47                 reverse=rev;
48                 send_command(false);
49         }
50 }
51
52 void Locomotive::set_function(unsigned func, bool state)
53 {
54         if(state)
55                 funcs|=1<<func;
56         else
57                 funcs&=~(1<<func);
58
59         send_command(true);
60
61         signal_function_changed.emit(func, state);
62 }
63
64 void Locomotive::refresh_status()
65 {
66         char cmd[3];
67         cmd[0]=CMD_LOK_STATUS;
68         cmd[1]=addr&0xFF;
69         cmd[2]=(addr>>8)&0xFF;
70         control.command(string(cmd, 3)).signal_done.connect(sigc::mem_fun(this, &Locomotive::status_reply));
71 }
72
73 void Locomotive::send_command(bool setf)
74 {
75         char cmd[16];
76         cmd[0]=CMD_LOK;
77         cmd[1]=addr&0xFF;
78         cmd[2]=(addr>>8)&0xFF;
79
80         if(speed==0)
81                 cmd[3]=0;
82         else if(speed==1)
83                 cmd[3]=2;
84         else
85                 cmd[3]=(speed*19-18)/2;
86         
87         cmd[4]=(reverse?0:0x20) | ((funcs&1)?0x10:0);
88
89         if(setf)
90         {
91                 cmd[4]|=0x80;
92                 for(unsigned i=0; i<4; ++i)
93                         if((funcs>>i)&2)
94                                 cmd[4]|=(1<<i);
95         }
96         control.command(string(cmd, 5));
97 }
98
99 void Locomotive::status_reply(Error err, const string &reply)
100 {
101         if(err==ERR_NO_ERROR)
102         {
103                 if(static_cast<unsigned char>(reply[0])<=1)
104                         speed=0;
105                 else
106                         speed=static_cast<unsigned char>(reply[0])*2/19+1;
107                 reverse=(reply[1]&0x20)?false:true;
108                 funcs=(reply[1]&0xF)<<1;
109                 if(reply[1]&0x10)
110                         funcs|=1;
111
112                 for(unsigned i=0; i<5; ++i)
113                         signal_function_changed.emit(i, (funcs>>i)&1);
114         }
115 }
116
117 bool Locomotive::reverse_timeout()
118 {
119         reverse=!reverse;
120         send_command(true);
121         return false;
122 }
123
124 } // namespace Marklin