Subversion Repositories HomeAutomation

Rev

Rev 1595 | Rev 1597 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
1595 runge 1
/*
2
 *
3
 *  Copyright (C) 2010  Mattias Runge
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License along
16
 *  with this program; if not, write to the Free Software Foundation, Inc.,
17
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 */
20
 
21
#include "Network.h"
22
 
23
#include <vector>
24
 
25
#include <boost/algorithm/string.hpp>
26
#include <boost/lexical_cast.hpp>
27
 
28
#include "net/Manager.h"
29
 
1596 runge 30
#include "broker/Manager.h"
31
 
32
#include "Protocol.h"
33
#include "Message.h"
34
 
35
#include "type/Bitset.h"
36
 
1595 runge 37
namespace atom {
38
namespace can {
39
 
1596 runge 40
enum
1595 runge 41
{
1596 runge 42
    PACKET_START = 253,
43
    PACKET_END   = 250,
44
    PACKET_PING  = 251
45
};
46
 
47
Network::Network(std::string address): Subscriber(false), LOG("can::Network"), buffer_(2048)
48
{
1595 runge 49
    this->address_ = address;
50
    this->client_id_ = 0;
51
 
52
    net::Manager::Instance()->ConnectSlots(net::Client::SignalOnNewState::slot_type(&Network::SlotOnNewState, this, _1, _2, _3).track(this->tracker_),
53
                                           net::Client::SignalOnNewData::slot_type(&Network::SlotOnNewData, this, _1, _2, _3).track(this->tracker_));
54
 
55
    // Examples of address
56
    // udp:192.168.1.250:1100
57
    // serial:/dev/ttyUSB0:38400
58
 
59
    std::vector<std::string> parts;
60
    boost::algorithm::split(parts, address, boost::is_any_of(":"), boost::algorithm::token_compress_off);
61
 
62
    if (parts.size() < 3)
63
    {
64
        LOG.Error("Malformed address string: " + address);
65
        return;
66
    }
67
 
68
    boost::algorithm::to_lower(parts[0]);
69
 
70
    if (parts[0] == "udp")
71
    {
72
        this->protocol_ = net::PROTOCOL_UDP;
73
    }
74
    else if (parts[0] == "serial")
75
    {
76
        this->protocol_ = net::PROTOCOL_SERIAL;
77
    }
78
    else
79
    {
80
        LOG.Error("Unknown protocol, only support udp and serial, got " + parts[0]);
81
        return;
82
    }
83
 
84
    this->address_ = parts[1];
85
    this->port_or_baud_ = boost::lexical_cast<unsigned int>(parts[2]);
86
 
87
    try
88
    {
89
        this->client_id_ = net::Manager::Instance()->Connect(this->protocol_, this->address_, this->port_or_baud_);
1596 runge 90
        LOG.Info("Connected to " + address);
1595 runge 91
 
1596 runge 92
        LOG.Info("Sending ping.");
93
        type::Byteset buffer(1);
94
 
95
        buffer[0] = PACKET_PING;
96
 
97
        net::Manager::Instance()->SendTo(this->client_id_, buffer);
1595 runge 98
    }
99
    catch (std::exception e)
100
    {
101
        LOG.Error(e.what());
102
    }
103
}
104
 
105
Network::~Network()
106
{
107
    net::Manager::Instance()->Disconnect(this->client_id_);
108
}
109
 
1596 runge 110
void Network::SlotOnNewData(net::ClientId client_id, net::ServerId server_id, type::Byteset data)
1595 runge 111
{
112
    if (client_id == this->client_id_)
113
    {
1596 runge 114
        type::Byteset temp_buffer = data;
115
        this->io_service_.post(boost::bind(&Network::SlotOnNewDataHandler, this, client_id, server_id, temp_buffer));
1595 runge 116
    }
117
}
118
 
119
void Network::SlotOnNewState(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
120
{
121
    if (client_id == this->client_id_)
122
    {
123
        this->io_service_.post(boost::bind(&Network::SlotOnNewStateHandler, this, client_id, server_id, client_state));
124
    }
125
}
126
 
1596 runge 127
void Network::SlotOnTimeout(timer::TimerId timer_id)
128
{
129
    if (timer_id == this->timer_id_)
130
    {
131
        this->io_service_.post(boost::bind(&Network::SlotOnTimeoutHandler, this, timer_id));
132
    }
133
}
134
 
1595 runge 135
void Network::SlotOnMessageHandler(broker::Message::Pointer message)
136
{
1596 runge 137
    if (message->GetType() == broker::Message::CAN_MESSAGE)
138
    {
139
        Message* payload = static_cast<Message*>(message->GetPayload().get());
140
 
141
 
142
 
143
    }
1595 runge 144
}
145
 
1596 runge 146
void Network::SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, type::Byteset data)
1595 runge 147
{
1596 runge 148
    static bool have_start = false;
149
 
150
    for (unsigned int n = 0; n < data.GetSize(); n++)
151
    {
152
        if (have_start)
153
        {
154
            if (data[n] == PACKET_END && this->buffer_.GetSize() == 15)
155
            {
156
                //LOG.Debug("Received packet end and size is 15.");
157
                this->ProcessBuffer();
158
                have_start = false;
159
            }
160
            else
161
            {
162
                this->buffer_.Append(data[n]);
163
            }
164
        }
165
        else if (data[n] == PACKET_START)
166
        {
167
            //LOG.Debug("Received packet start.");
168
            this->buffer_.Clear();
169
            have_start = true;
170
        }
171
        else if (data[n] == PACKET_PING)
172
        {
173
            LOG.Info("Received pong.");
174
        }
175
    }
1595 runge 176
}
177
 
178
void Network::SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
179
{
180
    if (client_state == net::CLIENT_STATE_DISCONNECTED)
181
    {
1596 runge 182
        LOG.Warning("Got disconnected, setting reconnect timer...");
183
 
184
        this->timer_id_ = timer::Manager::Instance()->Set(10000, true);
1595 runge 185
        this->client_id_ = 0;
1596 runge 186
    }
187
    else
188
    {
189
        LOG.Debug("Got state: " + boost::lexical_cast<std::string>((int)client_state));
190
    }
191
}
192
 
193
void Network::SlotOnTimeoutHandler(timer::TimerId timer_id)
194
{
195
    try
196
    {
197
        this->client_id_ = net::Manager::Instance()->Connect(this->protocol_, this->address_, this->port_or_baud_);
198
        LOG.Info("Connected again.");
1595 runge 199
 
1596 runge 200
        timer::Manager::Instance()->Cancel(timer_id);
201
        this->timer_id_ = 0;
202
    }
203
    catch (std::exception e)
204
    {
205
        LOG.Error(e.what());
206
        LOG.Warning("Will try again soon...");
207
    }
208
}
209
 
210
void Network::ProcessBuffer()
211
{
212
    try
213
    {
214
        std::string class_name = "";
215
        std::string direction_name = "";
216
        std::string module_name = "";
217
        unsigned int id = 0;
218
        std::string command_name = "";
219
 
220
        unsigned int class_id = (this->buffer_[3] >> 1) & 0x0F;
221
 
222
        //LOG.Debug("class_id=" + boost::lexical_cast<std::string>(class_id) + ", byte[3] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[3]));
223
 
224
        class_name = Protocol::Instance()->LookupClassName(class_id);
225
 
226
        //LOG.Debug("class_name=" + class_name);
227
 
228
        if (class_name == "nmt")
1595 runge 229
        {
1596 runge 230
            unsigned int command_id = this->buffer_[2];
231
            //LOG.Debug("command_id=" + boost::lexical_cast<std::string>(command_id) + ", byte[2] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[2]));
232
 
233
            command_name = Protocol::Instance()->LookupNMTCommandName(command_id);
234
            //LOG.Debug("command_name=" + command_name);
1595 runge 235
        }
1596 runge 236
        else
1595 runge 237
        {
1596 runge 238
            unsigned int direction_flag = this->buffer_[3] & 0x01;
239
            //LOG.Debug("direction_flag=" + boost::lexical_cast<std::string>(direction_flag) + ", byte[3] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[3]));
240
 
241
            direction_name = Protocol::Instance()->LookupDirectionFlag(direction_flag);
242
            //LOG.Debug("direction_name=" + direction_name);
243
 
244
            unsigned int module_id = this->buffer_[2];
245
            //LOG.Debug("module_id=" + boost::lexical_cast<std::string>(module_id) + ", byte[2] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[2]));
246
 
247
            module_name = Protocol::Instance()->LookupModuleName(module_id);
248
            //LOG.Debug("module_name=" + module_name);
249
 
250
            id = this->buffer_[1];
251
            //LOG.Debug("id=" + boost::lexical_cast<std::string>(id) + ", byte[1] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[1]));
252
 
253
            unsigned int command_id = this->buffer_[0];
254
            //LOG.Debug("command_id=" + boost::lexical_cast<std::string>(command_id) + ", byte[0] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[0]));
255
 
256
            command_name = Protocol::Instance()->LookupCommandName(command_id, module_name);
257
            //LOG.Debug("command_name=" + command_name);
1595 runge 258
        }
1596 runge 259
 
260
        Message* payload = new Message(class_name, direction_name, module_name, id, command_name);
261
 
262
        unsigned int length = this->buffer_[6];
263
        //LOG.Debug("Data length = " + boost::lexical_cast<std::string>(length));
264
 
265
        type::Byteset data_set(length);
266
 
267
        for (unsigned int n = 0; n < length; n++)
268
        {
269
            //LOG.Debug("add byte[" + boost::lexical_cast<std::string>(n + 7) + "] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[n + 7]));
270
            data_set.Append(this->buffer_[n + 7]);
271
        }
272
 
273
        /*for (unsigned int n = 0; n < this->buffer_.GetSize(); n++)
274
        {
275
            LOG.Debug("byte[" + boost::lexical_cast<std::string>(n) + "] = " + boost::lexical_cast<std::string>((unsigned int)this->buffer_[n]));
276
        }*/
277
 
278
        type::Bitset databits(data_set);
279
 
280
 
281
        std::string temp = "";
282
        for (unsigned int n = 0; n < databits.GetCount(); n ++)
283
        {
284
            temp += boost::lexical_cast<std::string>(databits.Get(n));
285
        }
286
 
287
        //LOG.Debug("databits = " + temp);
288
 
289
        xml::Node::NodeList variable_nodes;
290
 
291
        if (class_name == "nmt")
292
        {
293
            variable_nodes = Protocol::Instance()->GetNMTCommandVariables(command_name);
294
        }
295
        else
296
        {
297
            variable_nodes = Protocol::Instance()->GetCommandVariables(command_name, module_name);
298
        }
299
 
300
        for (unsigned int n = 0; n < variable_nodes.size(); n++)
301
        {
302
            unsigned int start_bit = boost::lexical_cast<unsigned int>(variable_nodes[n].GetAttributeValue("start_bit"));
303
            unsigned int bit_length = boost::lexical_cast<unsigned int>(variable_nodes[n].GetAttributeValue("bit_length"));
304
            std::string type = variable_nodes[n].GetAttributeValue("type");
305
 
306
            std::string value = boost::lexical_cast<std::string>(databits.Read(start_bit, bit_length));
307
 
308
            if (type == "enum")
309
            {
310
                value = variable_nodes[n].SelectChild("id", value).GetAttributeValue("name");
311
            }
312
 
313
            // TODO handle all datatypes!
314
 
315
            //LOG.Debug("start_bit=" + boost::lexical_cast<std::string>(start_bit) + ",bit_length=" + boost::lexical_cast<std::string>(bit_length));
316
 
317
            payload->SetVariable(variable_nodes[n].GetAttributeValue("name"), value);
318
            //LOG.Debug("Variable:" + variable_nodes[n].GetAttributeValue("name") + " = " + value);
319
        }
320
 
321
        broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), this)));
1595 runge 322
    }
1596 runge 323
    catch (std::runtime_error& e)
1595 runge 324
    {
1596 runge 325
        LOG.Error("Malformed message received, " + std::string(e.what()));
1595 runge 326
    }
1596 runge 327
 
328
    this->buffer_.Clear();
1595 runge 329
}
330
 
331
}; // namespace can
332
}; // namespace atom