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