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