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