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