]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/turnout.cpp
Forgot to add the new files
[r2c2.git] / source / libmarklin / turnout.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 "control.h"
12 #include "reply.h"
13 #include "turnout.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 namespace Marklin {
19
20 Turnout::Turnout(Control &c, unsigned a, bool d):
21         control(c),
22         addr(a),
23         path(0),
24         pending_path(0),
25         pending_cmds(0),
26         dual(d),
27         on(false)
28 {
29         control.add_turnout(*this);
30
31         control.signal_turnout_event.connect(sigc::mem_fun(this, &Turnout::turnout_event));
32
33         unsigned char data[2];
34         data[0] = addr&0xFF;
35         data[1] = (addr>>8)&0xFF;
36         control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::status_reply), 1));
37         if(dual)
38         {
39                 data[0] = (addr+1)&0xFF;
40                 data[1] = ((addr+1)>>8)&0xFF;
41                 control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::status_reply), 2));
42         }
43 }
44
45 void Turnout::set_path(unsigned char p)
46 {
47         if(path==p || pending_cmds)
48                 return;
49
50         signal_path_changing.emit(p);
51
52         pending_path = p;
53         on = true;
54         command(3);
55 }
56
57 void Turnout::command(unsigned char mask)
58 {
59         unsigned char data[2];
60         if(mask&1)
61         {
62                 data[0] = addr&0xFF;
63                 data[1] = ((addr>>8)&0x7) | (on ? 0x40 : 0) | (pending_path&1 ? 0 : 0x80);
64                 control.command(CMD_TURNOUT, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::command_reply), 1));
65                 pending_cmds |= 1;
66         }
67         if(dual && (mask&2))
68         {
69                 data[0] = (addr+1)&0xFF;
70                 data[1] = (((addr+1)>>8)&0x7) | (on ? 0x40 : 0) | (pending_path&2 ? 0 : 0x80);
71                 control.command(CMD_TURNOUT, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::command_reply), 2));
72                 pending_cmds |= 2;
73         }
74 }
75
76 void Turnout::command_reply(const Reply &reply, unsigned char bit)
77 {
78         pending_cmds &= ~bit;
79         if(reply.get_error()==ERR_NO_ERROR)
80         {
81                 if(on && !pending_cmds)
82                 {
83                         path = pending_path;
84                         on = false;
85                         control.set_timer(500*Time::msec).signal_timeout.connect(
86                                 sigc::bind_return(sigc::bind(sigc::mem_fun(this, &Turnout::command), 3), false));
87                         signal_path_changed.emit(path);
88                 }
89         }
90         else if(reply.get_error()==ERR_NO_I2C_SPACE)
91         {
92                 control.set_timer(100*Time::msec).signal_timeout.connect(
93                         sigc::bind_return(sigc::bind(sigc::mem_fun(this, &Turnout::command), bit), false));
94         }
95 }
96
97 void Turnout::status_reply(const Reply &reply, unsigned char bit)
98 {
99         if(reply.get_error()==ERR_NO_ERROR)
100         {
101                 bool v = !(reply.get_data()[0]&0x04);
102                 path = (path&~bit)|(v?bit:0);
103                 signal_path_changed.emit(path);
104         }
105 }
106
107 void Turnout::turnout_event(unsigned a, bool p)
108 {
109         if(a==addr && p!=(path&1))
110         {
111                 path = (path&2)|(p?1:0);
112                 signal_path_changed.emit(path);
113         }
114         else if(dual && a==addr+1 && p!=((path>>1)&1))
115         {
116                 path = (path&1)|(p?2:0);
117                 signal_path_changed.emit(path);
118         }
119 }
120
121 } // namespace Marklin