Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
11 andreas 1
/*
21 andreas 2
 * Copyright (C) 2018 to 2021 by Andreas Theofilu <andreas@theosys.at>
11 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <sys/utsname.h>
20
#ifdef __APPLE__
21
#include <boost/asio/buffer.hpp>
22
#include <boost/asio/io_context.hpp>
23
#include <boost/asio/ip/tcp.hpp>
24
#include <boost/asio/read_until.hpp>
25
#include <boost/asio/steady_timer.hpp>
26
#include <boost/asio/write.hpp>
27
#include <boost/asio/read.hpp>
28
#else
29
#include <asio/buffer.hpp>
30
#include <asio/io_context.hpp>
31
#include <asio/ip/tcp.hpp>
32
#include <asio/read_until.hpp>
33
#include <asio/steady_timer.hpp>
34
#include <asio/write.hpp>
35
#include <asio/read.hpp>
36
#endif
37
#include <functional>
38
#include <iostream>
39
#include <fstream>
40
#include <cstring>
41
#include <string>
42
#include <chrono>
43
#include <thread>
15 andreas 44
#include <map>
11 andreas 45
 
46
#include <sys/stat.h>
47
#include <sys/types.h>
48
#include <unistd.h>
49
 
50
#include "tamxnet.h"
51
#include "terror.h"
52
#include "tconfig.h"
53
#include "tdirectory.h"
54
#include "tresources.h"
55
#include "texpand.h"
56
 
57
#ifdef __APPLE__
58
using namespace boost;
59
#endif
60
 
61
using asio::steady_timer;
62
using asio::ip::tcp;
63
 
64
using namespace amx;
65
using namespace std;
66
 
67
using placeholders::_1;
68
using placeholders::_2;
69
 
70
string cmdList[] =
71
{
72
    "@WLD-", "@AFP-", "@GCE-", "@APG-", "@CPG-", "@DPG-", "@PDR-", "@PHE-",
73
    "@PHP-", "@PHT-", "@PPA-", "@PPF-", "@PPG-", "@PPK-", "@PPM-", "@PPN-",
74
    "@PPT-", "@PPX", "@PSE-", "@PSP-", "@PST-", "PAGE-", "PPOF-", "PPOG-",
75
    "PPON-", "^ANI-", "^APF-", "^BAT-", "^BAU-", "^BCB-", "^BCF-", "^BCT-",
76
    "^BDO-", "^BFB-", "^BIM-", "^BLN-", "^BMC-", "^BMF-", "^BMI-", "^BML-",
77
    "^BMP-", "^BNC-", "^BNN-", "^BNT-", "^BOP-", "^BOR-", "^BOS-", "^BPP-",
78
    "^BRD-", "^BSF-", "^BSP-", "^BSM-", "^BSO-", "^BVL-", "^BVN-", "^BVP-",
79
    "^BVT-", "^BWW-", "^CPF-", "^DLD-", "^DPF-", "^ENA-", "^FON-", "^GDI-",
80
    "^GIV-", "^GLH-", "^GLL-", "^GRD-", "^GRU-", "^GSC-", "^GSN-", "^ICO-",
81
    "^IRM-", "^JSB-", "^JSI-", "^JST-", "^MBT-", "^MDC-", "^SHO-", "^TEC-",
82
    "^TEF-", "^TOP-", "^TXT-", "^UNI-", "^LPC-", "^LPR-", "^LPS-", "?BCB-",
83
    "?BCF-", "?BCT-", "?BMP-", "?BOP-", "?BRD-", "?BWW-", "?FON-", "?ICO-",
84
    "?JSB-", "?JSI-", "?JST-", "?TEC-", "?TEF-", "?TXT-", "ABEEP", "ADBEEP",
85
    "@AKB-", "AKEYB-", "AKEYP-", "AKEYR-", "@AKP-", "@AKR", "BEEP", "BRIT-",
86
    "@BRT-", "DBEEP", "@EKP-", "PKEYP-", "@PKP-", "SETUP", "SHUTDOWN", "SLEEP",
87
    "@SOU-", "@TKP-", "TPAGEON", "TPAGEOFF", "@VKB", "WAKE", "^CAL", "^KPS-",
88
    "^VKS-", "@PWD-", "^PWD-", "^BBR-", "^RAF-", "^RFR-", "^RMF-", "^RSR-",
89
    "^MODEL?", "^ICS-", "^ICE-", "^ICM-", "^PHN-", "?PHN-", "LEVON", "RXON",
15 andreas 90
    "BLINK", "\0"
11 andreas 91
};
92
 
93
#define NUMBER_CMDS     144
94
 
95
std::atomic<bool> killed;
14 andreas 96
amx::TAmxNet *gAmxNet = nullptr;
11 andreas 97
 
98
TAmxNet::TAmxNet()
99
    : deadline_(io_context),
100
      heartbeat_timer_(io_context),
101
      socket_(io_context)
102
{
103
    DECL_TRACER("TAmxNet::TAmxNet()");
104
    init();
105
}
106
 
107
TAmxNet::TAmxNet(const string& sn)
108
    : deadline_(io_context),
109
      heartbeat_timer_(io_context),
110
      socket_(io_context),
111
      serNum(sn)
112
{
113
    DECL_TRACER("TAmxNet::TAmxNet(const string& sn)");
114
    init();
115
}
116
 
117
TAmxNet::TAmxNet(const string& sn, const string& nm)
118
    : deadline_(io_context),
119
      heartbeat_timer_(io_context),
120
      socket_(io_context),
121
      panName(nm),
122
      serNum(sn)
123
{
124
    DECL_TRACER("TAmxNet::TAmxNet(const string& sn)");
125
    size_t pos = nm.find(" (TPC)");
126
 
127
    if (pos != string::npos)
128
    {
129
        panName = nm.substr(0, pos) + "i";
130
        MSG_TRACE("Converted TP name: " << panName);
131
    }
132
 
133
    init();
134
}
135
 
136
TAmxNet::~TAmxNet()
137
{
138
    DECL_TRACER("TAmxNet::~TAmxNet()");
139
    devInfo.clear();
140
    comStack.clear();
141
    callback = 0;
142
    stop();
143
    io_context.stop();
144
}
145
 
146
void TAmxNet::init()
147
{
148
    DECL_TRACER("TAmxNet::init()");
149
 
150
    callback = 0;
151
    stopped_ = false;
152
    sendCounter = 0;
153
    initSend = false;
154
    ready = false;
155
    write_busy = false;
156
    string version = "v2.01.00";        // A version > 2.0 is needed for file transfer!
157
    int devID = 0x0163, fwID = 0x0290;
158
 
159
    if (TConfig::getPanelType().length() > 0)
160
        panName = TConfig::getPanelType();
161
    else if (panName.empty())
162
        panName.assign("TheoSys");
163
 
164
    if (panName.find("MVP") != string::npos && panName.find("5200") != string::npos)
165
    {
166
        devID = 0x0149;
167
        fwID = 0x0310;
168
    }
169
 
170
    // Initialize the devive info structure
171
    DEVICE_INFO di;
172
    // Answer to MC = 0x0017 --> MC = 0x0097
173
    di.objectID = 0;
174
    di.parentID = 0;
175
    di.manufacturerID = 1;
176
    di.deviceID = devID;
177
    memset(di.serialNum, 0x20, sizeof(di.serialNum));
178
 
179
    if (!serNum.empty())
180
        memcpy(di.serialNum, serNum.c_str(), serNum.length());
181
 
182
    di.firmwareID = fwID;
183
    memset(di.versionInfo, 0, sizeof(di.versionInfo));
184
    strncpy(di.versionInfo, version.c_str(), version.length());
185
    memset(di.deviceInfo, 0, sizeof(di.deviceInfo));
186
    strncpy(di.deviceInfo, panName.c_str(), min(panName.length(), sizeof(di.deviceInfo) - 1));
187
    memset(di.manufacturerInfo, 0, sizeof(di.manufacturerInfo));
188
    strncpy(di.manufacturerInfo, "TheoSys", 7);
189
    di.format = 2;
190
    di.len = 4;
191
    memset(di.addr, 0, sizeof(di.addr));
192
    devInfo.push_back(di);
193
    // Kernel info
194
    di.objectID = 2;
195
    di.firmwareID = fwID + 1;
196
    memset(di.serialNum, 0x20, sizeof(di.serialNum));
197
    memcpy(di.serialNum, "N/A", 3);
198
    memset(di.deviceInfo, 0, sizeof(di.deviceInfo));
199
    strncpy(di.deviceInfo, "Kernel", 6);
200
    memset(di.versionInfo, 0, sizeof(di.versionInfo));
201
#ifdef __linux__
202
    struct utsname kinfo;
203
    uname(&kinfo);
204
    strncpy(di.versionInfo, kinfo.release, sizeof(di.versionInfo));
205
#else
206
    strncpy(di.versionInfo, "4.00.00", 7);
207
#endif
208
    devInfo.push_back(di);
209
}
210
 
15 andreas 211
void TAmxNet::registerNetworkState(function<void (int)> registerNetwork, ulong handle)
212
{
213
    DECL_TRACER("TAmxNet::registerNetworkState(function<void (int)> registerNetwork, ulong handle)");
214
 
215
    map<ulong, FUNC_NETWORK_t>::iterator iter = mFuncsNetwork.find(handle);
216
 
217
    if (iter == mFuncsNetwork.end())
218
    {
219
        FUNC_NETWORK_t fn;
220
        fn.handle = handle;
221
        fn.func = registerNetwork;
222
        mFuncsNetwork.insert(pair<ulong, FUNC_NETWORK_t>(handle, fn));
223
    }
224
 
225
    registerNetwork((isRunning() ? 6 : 0));
226
}
227
 
228
void TAmxNet::registerTimer(function<void (const ANET_BLINK &)> registerBlink, ulong handle)
229
{
230
    DECL_TRACER("TAmxNet::registerTimer(function<void (const ANET_BLINK &)> registerBlink, ulong handle)");
231
 
232
    map<ulong, FUNC_TIMER_t>::iterator iter = mFuncsTimer.find(handle);
233
 
234
    if (iter == mFuncsTimer.end())
235
    {
236
        FUNC_TIMER_t ft;
237
        ft.handle = handle;
238
        ft.func = registerBlink;
239
        mFuncsTimer.insert(pair<ulong, FUNC_TIMER_t>(handle, ft));
240
    }
241
}
242
 
243
void TAmxNet::deregNetworkState(ulong handle)
244
{
245
    DECL_TRACER("TAmxNet::deregNetworkState(ulong handle)");
246
 
247
    map<ulong, FUNC_NETWORK_t>::iterator iter = mFuncsNetwork.find(handle);
248
 
17 andreas 249
    if (iter != mFuncsNetwork.end())
15 andreas 250
        mFuncsNetwork.erase(iter);
251
}
252
 
253
void TAmxNet::deregTimer(ulong handle)
254
{
255
    DECL_TRACER("TAmxNet::deregTimer(ulong handle)");
256
 
257
    map<ulong, FUNC_TIMER_t>::iterator iter = mFuncsTimer.find(handle);
258
 
17 andreas 259
    if (iter != mFuncsTimer.end())
15 andreas 260
        mFuncsTimer.erase(iter);
261
}
262
 
11 andreas 263
void TAmxNet::start(asio::ip::tcp::resolver::results_type endpoints, int id)
264
{
265
    DECL_TRACER("TAmxNet::start(asio::ip::tcp::resolver::results_type endpoints, int id)");
266
    endpoints_ = endpoints;
267
    panelID = id;
268
 
269
    try
270
    {
271
        start_connect(endpoints_.begin());
272
        deadline_.async_wait(bind(&TAmxNet::check_deadline, this));
273
    }
274
    catch (std::exception& e)
275
    {
276
        MSG_ERROR("Error: " << e.what());
277
    }
278
}
279
 
280
bool TAmxNet::isConnected()
281
{
282
    DECL_TRACER("TAmxNet::isConnected()");
14 andreas 283
 
11 andreas 284
    MSG_INFO("isConnected: " << ((socket_.is_open()) ? "TRUE" : "FALSE"));
285
    return socket_.is_open();
286
}
287
 
288
void TAmxNet::stop()
289
{
290
    DECL_TRACER("TAmxNet::stop: Stopping the client...");
291
 
292
    if (stopped_)
293
        return;
294
 
295
    stopped_ = true;
296
#ifdef __APPLE__
297
    system::error_code ignored_error;
298
#else
299
    error_code ignored_error;
300
#endif
301
 
14 andreas 302
    gAmxNet = nullptr;
303
 
11 andreas 304
    try
305
    {
306
        deadline_.cancel();
307
        heartbeat_timer_.cancel();
308
        socket_.shutdown(asio::socket_base::shutdown_both, ignored_error);
309
        socket_.close(ignored_error);
310
        MSG_TRACE("Client was stopped.");
311
    }
312
    catch (std::exception& e)
313
    {
314
        MSG_ERROR("Error: " << e.what());
315
    }
316
}
317
 
318
void TAmxNet::Run()
319
{
320
    DECL_TRACER("TAmxNet::Run()");
321
 
322
    while (reconCounter < 3)
323
    {
324
        try
325
        {
326
            asio::ip::tcp::resolver r(io_context);
327
            start(r.resolve(TConfig::getController(), to_string(TConfig::getPort())), panelID);
328
            io_context.run();
329
            MSG_TRACE("Thread ended.");
330
 
21 andreas 331
            if (stopped_ || prg_stopped || killed)
11 andreas 332
                break;
333
        }
334
        catch (std::exception& e)
335
        {
336
            MSG_ERROR("Error connecting to " << TConfig::getController() << ":" << to_string(TConfig::getPort()) << " [" << e.what() << "]");
337
        }
338
 
339
        reconCounter++;
340
    }
341
 
342
    stopped_ = true;
343
}
344
 
345
void TAmxNet::start_connect(asio::ip::tcp::resolver::results_type::iterator endpoint_iter)
346
{
347
    DECL_TRACER("TAmxNet::start_connect(asio::ip::tcp::resolver::results_type::iterator endpoint_iter)");
348
 
349
    if (socket_.is_open())
350
    {
351
        stop();
352
        return;
353
    }
354
 
355
    if (endpoint_iter != endpoints_.end())
356
    {
357
        MSG_TRACE("Trying " << endpoint_iter->endpoint().address().to_string() << ":" << endpoint_iter->endpoint().port() << " ...");
358
 
359
        // Set a deadline for the connect operation.
360
        deadline_.expires_after(chrono::seconds(120));
361
        stopped_ = false;
14 andreas 362
        gAmxNet = this;
11 andreas 363
        // Start the asynchronous connect operation.
364
        socket_.async_connect(endpoint_iter->endpoint(), bind(&TAmxNet::handle_connect, this, _1, endpoint_iter));
365
    }
366
    else
367
    {
368
        // There are no more endpoints to try. Shut down the client.
369
        stop();
370
    }
371
}
372
 
373
void TAmxNet::handle_connect(const error_code& error, asio::ip::tcp::resolver::results_type::iterator endpoint_iter)
374
{
375
    DECL_TRACER("TAmxNet::handle_connect(const error_code& error, asio::ip::tcp::resolver::results_type::iterator endpoint_iter)");
376
 
377
    reconCounter = 0;
378
 
379
    if (stopped_)
380
        return;
381
 
382
    // The async_connect() function automatically opens the socket at the start
383
    // of the asynchronous operation. If the socket is closed at this time then
384
    // the timeout handler must have run first.
385
    if (!socket_.is_open())
386
    {
387
        MSG_TRACE("Connect timed out");
15 andreas 388
        sendAllFuncNetwork(9);
11 andreas 389
 
390
        // Try the next available endpoint.
391
        start_connect(++endpoint_iter);
392
    }
393
    else if (error)     // Check if the connect operation failed before the deadline expired.
394
    {
395
        MSG_ERROR("Connect error: " << error.message());
396
 
397
        // We need to close the socket used in the previous connection attempt
398
        // before starting a new one.
399
        socket_.close();
15 andreas 400
        sendAllFuncNetwork(0);
11 andreas 401
 
402
        // Try the next available endpoint.
403
        start_connect(++endpoint_iter);
404
    }
405
    else
406
    {
407
        MSG_INFO("Connected to " << endpoint_iter->endpoint().address().to_string() << ":" << endpoint_iter->endpoint().port());
15 andreas 408
        sendAllFuncNetwork(6);
11 andreas 409
 
410
        try
411
        {
412
            while (isRunning())
413
            {
414
                // Start the input actor.
415
                start_read();
416
 
417
                // Start the output actor.
418
                if (isRunning())
419
                    start_write();
420
            }
421
 
21 andreas 422
            if (!stopped_ && (killed || prg_stopped))
11 andreas 423
                stop();
424
        }
425
        catch (std::exception& e)
426
        {
427
            MSG_ERROR("Error: " << e.what());
428
        }
429
    }
430
}
431
 
432
void TAmxNet::start_read()
433
{
434
    DECL_TRACER("TAmxNet::start_read()");
435
 
436
    if (!isRunning())
437
        return;
438
 
439
    // Set a deadline for the read operation.
440
    deadline_.expires_after(chrono::seconds(120));
441
    protError = false;
442
    comm.clear();
443
#ifdef __APPLE__
444
    system::error_code error;
445
#else
446
    asio::error_code error;
447
#endif
448
 
449
    // Start an asynchronous operation to read a message.
450
    // Read the first byte. It should be 0x02
451
    if (asio::read(socket_, asio::buffer(buff_, 1), asio::transfer_exactly(1), error) == 1)
452
        handle_read(error, 1, RT_ID);
453
    else
454
        throw invalid_argument(error.message());
455
 
456
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
457
        handle_read(error, 2, RT_LEN);
458
    else
459
        throw invalid_argument(error.message());
460
 
461
    if (asio::read(socket_, asio::buffer(buff_, 1), asio::transfer_exactly(1), error) == 1)
462
        handle_read(error, 1, RT_SEP1);
463
    else
464
        throw invalid_argument(error.message());
465
 
466
    if (asio::read(socket_, asio::buffer(buff_, 1), asio::transfer_exactly(1), error) == 1)
467
        handle_read(error, 1, RT_TYPE);
468
    else
469
        throw invalid_argument(error.message());
470
 
471
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
472
        handle_read(error, 2, RT_WORD1);
473
    else
474
        throw invalid_argument(error.message());
475
 
476
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
477
        handle_read(error, 2, RT_DEVICE);
478
    else
479
        throw invalid_argument(error.message());
480
 
481
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
482
        handle_read(error, 2, RT_WORD2);
483
    else
484
        throw invalid_argument(error.message());
485
 
486
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
487
        handle_read(error, 2, RT_WORD3);
488
    else
489
        throw invalid_argument(error.message());
490
 
491
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
492
        handle_read(error, 2, RT_WORD4);
493
    else
494
        throw invalid_argument(error.message());
495
 
496
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
497
        handle_read(error, 2, RT_WORD5);
498
    else
499
        throw invalid_argument(error.message());
500
 
501
    if (asio::read(socket_, asio::buffer(buff_, 1), asio::transfer_exactly(1), error) == 1)
502
        handle_read(error, 1, RT_SEP2);
503
    else
504
        throw invalid_argument(error.message());
505
 
506
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
507
        handle_read(error, 2, RT_COUNT);
508
    else
509
        throw invalid_argument(error.message());
510
 
511
    if (asio::read(socket_, asio::buffer(buff_, 2), asio::transfer_exactly(2), error) == 2)
512
        handle_read(error, 2, RT_MC);
513
    else
514
        throw invalid_argument(error.message());
515
 
516
    // Calculate the length of the data block. This is the rest of the total length
517
    size_t len = (comm.hlen + 3) - 0x0015;
518
 
519
    if (len > BUF_SIZE)
520
    {
521
        MSG_ERROR("Length to read is " << len << " bytes, but the buffer is only " << BUF_SIZE << " bytes!");
522
        return;
523
    }
524
 
525
    if (asio::read(socket_, asio::buffer(buff_, len), asio::transfer_exactly(len), error) == len)
526
        handle_read(error, len, RT_DATA);
527
    else
528
        throw invalid_argument(error.message());
529
}
530
 
531
#ifdef __APPLE__
532
void TAmxNet::handle_read(const system::error_code& error, size_t n, R_TOKEN tk)
533
#else
534
void TAmxNet::handle_read(const asio::error_code& error, size_t n, R_TOKEN tk)
535
#endif
536
{
537
    DECL_TRACER("TAmxNet::handle_read(const error_code& error, size_t n, R_TOKEN tk)");
538
 
539
    if (!isRunning())
540
        return;
541
 
21 andreas 542
    if (killed || prg_stopped)
11 andreas 543
    {
544
        stop();
545
        return;
546
    }
547
 
548
    uint32_t dw;
549
    int val, pos;
550
    size_t len;
551
    bool ignore = false;
552
    ANET_SEND s;        // Used to answer system requests
553
    string cmd;
554
 
555
    if (!error)
556
    {
557
        len = (n < BUF_SIZE) ? n : BUF_SIZE - 1;
558
        input_buffer_.assign((char *)&buff_[0], len);
559
 
13 andreas 560
//        MSG_DEBUG("read:");
561
//        TError::logHex((char *)&buff_[0], len);
11 andreas 562
        MSG_DEBUG("Token: " << tk << ", " << len << " bytes");
563
 
564
        switch (tk)
565
        {
566
            case RT_ID:
567
                if (buff_[0] != 0x02)
568
                    protError = true;
569
                else
570
                    comm.ID = buff_[0];
13 andreas 571
            break;
11 andreas 572
 
573
            case RT_LEN:    comm.hlen = makeWord(buff_[0], buff_[1]); break;
574
 
575
            case RT_SEP1:
576
                if (buff_[0] != 0x02)
577
                    protError = true;
578
                else
579
                    comm.sep1 = buff_[0];
13 andreas 580
            break;
11 andreas 581
 
582
            case RT_TYPE:   comm.type = buff_[0]; break;
583
            case RT_WORD1:  comm.unk1 = makeWord(buff_[0], buff_[1]); break;
584
            case RT_DEVICE: comm.device1 = makeWord(buff_[0], buff_[1]); break;
585
            case RT_WORD2:  comm.port1 = makeWord(buff_[0], buff_[1]); break;
586
            case RT_WORD3:  comm.system = makeWord(buff_[0], buff_[1]); break;
587
            case RT_WORD4:  comm.device2 = makeWord(buff_[0], buff_[1]); break;
588
            case RT_WORD5:  comm.port2 = makeWord(buff_[0], buff_[1]); break;
589
 
590
            case RT_SEP2:
591
                if (buff_[0] != 0x0f)
592
                    protError = true;
593
                else
594
                    comm.unk6 = buff_[0];
13 andreas 595
            break;
11 andreas 596
 
597
            case RT_COUNT:  comm.count = makeWord(buff_[0], buff_[1]); break;
598
            case RT_MC:     comm.MC = makeWord(buff_[0], buff_[1]); break;
599
 
600
            case RT_DATA:
601
                if (protError || !isRunning())
602
                    break;
603
 
604
                MSG_TRACE("Received message type: 0x" << std::setw(4) << std::setfill('0') << std::hex << comm.MC);
605
 
606
                switch (comm.MC)
607
                {
608
                    case 0x0001:    // ACK
609
                    case 0x0002:    // NAK
610
                        comm.checksum = buff_[0];
14 andreas 611
                    break;
11 andreas 612
 
613
                    case 0x0084:    // input channel ON
614
                    case 0x0085:    // input channel OFF
615
                    case 0x0006:    // output channel ON
616
                    case 0x0086:    // output channel ON status
617
                    case 0x0007:    // output channel OFF
618
                    case 0x0087:    // output channel OFF status
619
                    case 0x0088:    // input/output channel ON status
620
                    case 0x0089:    // input/output channel OFF status
621
                    case 0x0018:    // feedback channel ON
622
                    case 0x0019:    // feedback channel OFF
623
                        comm.data.chan_state.device = makeWord(buff_[0], buff_[1]);
624
                        comm.data.chan_state.port = makeWord(buff_[2], buff_[3]);
625
                        comm.data.chan_state.system = makeWord(buff_[4], buff_[5]);
626
                        comm.data.chan_state.channel = makeWord(buff_[6], buff_[7]);
627
                        comm.checksum = buff_[8];
628
 
629
                        s.channel = comm.data.chan_state.channel;
630
                        s.level = 0;
631
                        s.port = comm.data.chan_state.port;
632
                        s.value = 0;
633
 
634
                        switch (comm.MC)
635
                        {
636
                            case 0x0006: s.MC = 0x0086; break;
637
                            case 0x0007: s.MC = 0x0087; break;
638
                        }
639
 
640
                        if (comm.MC < 0x0020)
641
                        {
642
                            if (callback)
643
                                callback(comm);
13 andreas 644
                            else
645
                                MSG_WARNING("Missing callback function!");
11 andreas 646
                        }
647
                        else
648
                            sendCommand(s);
13 andreas 649
                    break;
11 andreas 650
 
651
                    case 0x000a:    // level value change
652
                    case 0x008a:
653
                        comm.data.message_value.device = makeWord(buff_[0], buff_[1]);
654
                        comm.data.message_value.port = makeWord(buff_[2], buff_[3]);
655
                        comm.data.message_value.system = makeWord(buff_[4], buff_[5]);
656
                        comm.data.message_value.value = makeWord(buff_[6], buff_[7]);
657
                        comm.data.message_value.type = buff_[8];
658
                        val = (int)buff_[8];
659
 
660
                        switch (val)
661
                        {
662
                            case 0x010: comm.data.message_value.content.byte = buff_[9]; comm.checksum = buff_[10]; break;
663
                            case 0x011: comm.data.message_value.content.ch = buff_[9]; comm.checksum = buff_[10]; break;
664
                            case 0x020: comm.data.message_value.content.integer = makeWord(buff_[9], buff_[10]); comm.checksum = buff_[11]; break;
665
                            case 0x021: comm.data.message_value.content.sinteger = makeWord(buff_[9], buff_[10]); comm.checksum = buff_[11]; break;
666
                            case 0x040: comm.data.message_value.content.dword = makeDWord(buff_[9], buff_[10], buff_[11], buff_[12]); comm.checksum = buff_[13]; break;
667
                            case 0x041: comm.data.message_value.content.sdword = makeDWord(buff_[9], buff_[10], buff_[11], buff_[12]); comm.checksum = buff_[13]; break;
668
 
669
                            case 0x04f:
670
                                dw = makeDWord(buff_[9], buff_[10], buff_[11], buff_[12]);
671
                                memcpy(&comm.data.message_value.content.fvalue, &dw, 4);
672
                                comm.checksum = buff_[13];
13 andreas 673
                            break;
11 andreas 674
 
675
                            case 0x08f:
676
                                memcpy(&comm.data.message_value.content.dvalue, &buff_[9], 8);  // FIXME: wrong byte order on Intel CPU?
677
                                comm.checksum = buff_[17];
13 andreas 678
                            break;
11 andreas 679
                        }
680
 
681
                        if (callback)
682
                            callback(comm);
13 andreas 683
                        else
684
                            MSG_WARNING("Missing callback function!");
685
                    break;
11 andreas 686
 
687
                    case 0x000b:    // string value change
688
                    case 0x008b:
689
                    case 0x000c:    // command string
690
                    case 0x008c:
691
                        comm.data.message_string.device = makeWord(buff_[0], buff_[1]);
692
                        comm.data.message_string.port = makeWord(buff_[2], buff_[3]);
693
                        comm.data.message_string.system = makeWord(buff_[4], buff_[5]);
694
                        comm.data.message_string.type = buff_[6];
695
                        comm.data.message_string.length = makeWord(buff_[7], buff_[8]);
696
                        memset(&comm.data.message_string.content[0], 0, sizeof(comm.data.message_string.content));
697
                        len = (buff_[6] == 0x01) ? comm.data.message_string.length : comm.data.message_string.length * 2;
698
 
699
                        if (len >= sizeof(comm.data.message_string.content))
700
                        {
701
                            len = sizeof(comm.data.message_string.content) - 1;
702
                            comm.data.message_string.length = (buff_[6] == 0x01) ? len : len / 2;
703
                        }
704
 
705
                        memcpy(&comm.data.message_string.content[0], &buff_[9], len);
706
                        pos = (int)(len + 10);
707
                        comm.checksum = buff_[pos];
708
                        cmd.assign((char *)&comm.data.message_string.content[0], len);
709
                        MSG_DEBUG("cmd=" << cmd);
710
 
711
                        if (isCommand(cmd))
712
                        {
713
                            MSG_DEBUG("Command found!");
714
                            oldCmd.assign(cmd);
715
                        }
716
                        else
717
                        {
718
                            oldCmd.append(cmd);
719
                            MSG_DEBUG("Concatenated cmd=" << oldCmd);
720
                            memset(&comm.data.message_string.content[0], 0, sizeof(comm.data.message_string.content));
721
                            memcpy(&comm.data.message_string.content[0], oldCmd.c_str(), sizeof(comm.data.message_string.content) - 1);
722
                            comm.data.message_string.length = oldCmd.length();
723
                            oldCmd.clear();
724
                        }
725
 
726
                        if (callback)
727
                            callback(comm);
13 andreas 728
                        else
729
                            MSG_WARNING("Missing callback function!");
730
                    break;
11 andreas 731
 
732
                    case 0x000e:    // request level value
733
                        comm.data.level.device = makeWord(buff_[0], buff_[1]);
734
                        comm.data.level.port = makeWord(buff_[2], buff_[3]);
735
                        comm.data.level.system = makeWord(buff_[4], buff_[5]);
736
                        comm.data.level.level = makeWord(buff_[6], buff_[7]);
737
                        comm.checksum = buff_[8];
738
 
739
                        if (callback)
740
                            callback(comm);
13 andreas 741
                        else
742
                            MSG_WARNING("Missing callback function!");
743
                    break;
11 andreas 744
 
745
                    case 0x000f:    // request output channel status
746
                        comm.data.channel.device = makeWord(buff_[0], buff_[1]);
747
                        comm.data.channel.port = makeWord(buff_[2], buff_[3]);
748
                        comm.data.channel.system = makeWord(buff_[4], buff_[5]);
749
                        comm.data.channel.channel = makeWord(buff_[6], buff_[7]);
750
                        comm.checksum = buff_[8];
751
 
752
                        if (callback)
753
                            callback(comm);
13 andreas 754
                        else
755
                            MSG_WARNING("Missing callback function!");
756
                    break;
11 andreas 757
 
758
                    case 0x0010:    // request port count
759
                    case 0x0017:    // request device info
760
                        comm.data.reqPortCount.device = makeWord(buff_[0], buff_[1]);
761
                        comm.data.reqPortCount.system = makeWord(buff_[2], buff_[3]);
762
                        comm.checksum = buff_[4];
763
                        s.channel = false;
764
                        s.level = 0;
765
                        s.port = 0;
766
                        s.value = 0x0015;
767
                        s.MC = (comm.MC == 0x0010) ? 0x0090 : 0x0097;
768
 
769
                        if (s.MC == 0x0097)
770
                        {
771
                            comm.data.srDeviceInfo.device = comm.device2;
772
                            comm.data.srDeviceInfo.system = comm.system;
773
                            comm.data.srDeviceInfo.flag = 0x0000;
774
                            comm.data.srDeviceInfo.parentID = 0;
775
                            comm.data.srDeviceInfo.herstID = 1;
776
                            msg97fill(&comm);
777
                        }
778
                        else
779
                            sendCommand(s);
13 andreas 780
                    break;
11 andreas 781
 
782
                    case 0x0011:    // request output channel count
783
                    case 0x0012:    // request level count
784
                    case 0x0013:    // request string size
785
                    case 0x0014:    // request command size
786
                        comm.data.reqOutpChannels.device = makeWord(buff_[0], buff_[1]);
787
                        comm.data.reqOutpChannels.port = makeWord(buff_[2], buff_[3]);
788
                        comm.data.reqOutpChannels.system = makeWord(buff_[4], buff_[5]);
789
                        comm.checksum = buff_[6];
790
                        s.channel = false;
791
                        s.level = 0;
792
                        s.port = comm.data.reqOutpChannels.port;
793
                        s.value = 0;
794
 
795
                        switch (comm.MC)
796
                        {
797
                            case 0x0011:
798
                                s.MC = 0x0091;
799
                                s.value = 0x0f75;   // # channels
13 andreas 800
                            break;
11 andreas 801
 
802
                            case 0x0012:
803
                                s.MC = 0x0092;
804
                                s.value = 0x000d;   // # levels
13 andreas 805
                            break;
11 andreas 806
 
807
                            case 0x0013:
808
                                s.MC = 0x0093;
809
                                s.value = 0x00c7;   // string size
13 andreas 810
                            break;
11 andreas 811
 
812
                            case 0x0014:
813
                                s.MC = 0x0094;
814
                                s.value = 0x00c7;   // command size
13 andreas 815
                            break;
11 andreas 816
                        }
817
 
818
                        sendCommand(s);
13 andreas 819
                    break;
11 andreas 820
 
821
                    case 0x0015:    // request level size
822
                        comm.data.reqLevels.device = makeWord(buff_[0], buff_[1]);
823
                        comm.data.reqLevels.port = makeWord(buff_[2], buff_[3]);
824
                        comm.data.reqLevels.system = makeWord(buff_[4], buff_[5]);
825
                        comm.data.reqLevels.level = makeWord(buff_[6], buff_[7]);
826
                        comm.checksum = buff_[8];
827
                        s.channel = false;
828
                        s.level = comm.data.reqLevels.level;
829
                        s.port = comm.data.reqLevels.port;
830
                        s.value = 0;
831
                        s.MC = 0x0095;
832
                        sendCommand(s);
13 andreas 833
                    break;
11 andreas 834
 
835
                    case 0x0016:    // request status code
836
                        comm.data.sendStatusCode.device = makeWord(buff_[0], buff_[1]);
837
                        comm.data.sendStatusCode.port = makeWord(buff_[2], buff_[3]);
838
                        comm.data.sendStatusCode.system = makeWord(buff_[4], buff_[5]);
839
 
840
                        if (callback)
841
                            callback(comm);
13 andreas 842
                        else
843
                            MSG_WARNING("Missing callback function!");
844
                    break;
11 andreas 845
 
846
                    case 0x0097:    // receive device info
847
                        comm.data.srDeviceInfo.device = makeWord(buff_[0], buff_[1]);
848
                        comm.data.srDeviceInfo.system = makeWord(buff_[2], buff_[3]);
849
                        comm.data.srDeviceInfo.flag = makeWord(buff_[4], buff_[5]);
850
                        comm.data.srDeviceInfo.objectID = buff_[6];
851
                        comm.data.srDeviceInfo.parentID = buff_[7];
852
                        comm.data.srDeviceInfo.herstID = makeWord(buff_[8], buff_[9]);
853
                        comm.data.srDeviceInfo.deviceID = makeWord(buff_[10], buff_[11]);
854
                        memcpy(comm.data.srDeviceInfo.serial, &buff_[12], 16);
855
                        comm.data.srDeviceInfo.fwid = makeWord(buff_[28], buff_[29]);
856
                        memset(comm.data.srDeviceInfo.info, 0, sizeof(comm.data.srDeviceInfo.info));
857
                        memcpy(comm.data.srDeviceInfo.info, &buff_[30], comm.hlen - 0x0015 - 29);
858
                        comm.checksum = buff_[comm.hlen + 3];
859
                        // Prepare answer
860
                        s.channel = false;
861
                        s.level = 0;
862
                        s.port = 0;
863
                        s.value = 0;
864
 
865
                        if (!initSend)
866
                        {
867
                            s.MC = 0x0097;
868
                            initSend = true;
869
                        }
870
                        else if (!ready)
871
                        {
872
                            // Send counts
873
                            s.MC = 0x0090;
874
                            s.value = 0x0015;   // # ports
875
                            sendCommand(s);
876
                            s.MC = 0x0091;
877
                            s.value = 0x0f75;   // # channels
878
                            sendCommand(s);
879
                            s.MC = 0x0092;
880
                            s.value = 0x000d;   // # levels
881
                            sendCommand(s);
882
                            s.MC = 0x0093;
883
                            s.value = 0x00c7;   // string size
884
                            sendCommand(s);
885
                            s.MC = 0x0094;
886
                            s.value = 0x00c7;   // command size
887
                            sendCommand(s);
888
                            s.MC = 0x0098;
889
                            ready = true;
890
                        }
891
                        else
892
                            break;
893
 
894
                        sendCommand(s);
895
 
896
                        MSG_TRACE("S/N: " << comm.data.srDeviceInfo.serial << " | " << comm.data.srDeviceInfo.info);
13 andreas 897
                    break;
11 andreas 898
 
899
                    case 0x00a1:    // request status
900
                        reqDevStatus = makeWord(buff_[0], buff_[1]);
901
                        comm.checksum = buff_[2];
13 andreas 902
                    break;
11 andreas 903
 
904
                    case 0x0204:    // file transfer
905
                        s.device = comm.device2;
906
                        comm.data.filetransfer.ftype = makeWord(buff_[0], buff_[1]);
907
                        comm.data.filetransfer.function = makeWord(buff_[2], buff_[3]);
908
                        pos = 4;
909
 
910
                        if (comm.data.filetransfer.ftype == 0 && comm.data.filetransfer.function == 0x0105)         // Directory exist?
911
                        {
912
                            for (size_t i = 0; i < 0x0104; i++)
913
                            {
914
                                comm.data.filetransfer.data[i] = buff_[pos];
915
                                pos++;
916
                            }
917
 
918
                            comm.data.filetransfer.data[0x0103] = 0;
919
                            handleFTransfer(s, comm.data.filetransfer);
920
                        }
921
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0100)    // Controller have more files
922
                            handleFTransfer(s, comm.data.filetransfer);
923
                        else if (comm.data.filetransfer.ftype == 0 && comm.data.filetransfer.function == 0x0100)    // Request directory listing
924
                        {
925
                            comm.data.filetransfer.unk = makeWord(buff_[4], buff_[5]);
926
                            pos = 6;
927
 
928
                            for (size_t i = 0; i < 0x0104; i++)
929
                            {
930
                                comm.data.filetransfer.data[i] = buff_[pos];
931
                                pos++;
932
                            }
933
 
934
                            comm.data.filetransfer.data[0x0103] = 0;
935
                            handleFTransfer(s, comm.data.filetransfer);
936
                        }
937
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0102)    // controller will send a file
938
                        {
939
                            comm.data.filetransfer.unk = makeDWord(buff_[4], buff_[5], buff_[6], buff_[7]);
940
                            comm.data.filetransfer.unk1 = makeDWord(buff_[8], buff_[9], buff_[10], buff_[11]);
941
                            pos = 12;
942
 
943
                            for (size_t i = 0; i < 0x0104; i++)
944
                            {
945
                                comm.data.filetransfer.data[i] = buff_[pos];
946
                                pos++;
947
                            }
948
 
949
                            comm.data.filetransfer.data[0x0103] = 0;
950
                            handleFTransfer(s, comm.data.filetransfer);
951
                        }
952
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0103)    // file or part of a file
953
                        {
954
                            comm.data.filetransfer.unk = makeWord(buff_[4], buff_[5]);
955
                            pos = 6;
956
 
957
                            for (size_t i = 0; i < comm.data.filetransfer.unk; i++)
958
                            {
959
                                comm.data.filetransfer.data[i] = buff_[pos];
960
                                pos++;
961
                            }
962
 
963
                            handleFTransfer(s, comm.data.filetransfer);
964
                        }
965
                        else if (comm.data.filetransfer.ftype == 0 && comm.data.filetransfer.function == 0x0104)    // Does file exist;
966
                        {
967
                            for (size_t i = 0; i < 0x0104; i++)
968
                            {
969
                                comm.data.filetransfer.data[i] = buff_[pos];
970
                                pos++;
971
                            }
972
 
973
                            comm.data.filetransfer.data[0x0103] = 0;
974
                            handleFTransfer(s, comm.data.filetransfer);
975
                        }
976
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0104)    // request a file
977
                        {
978
                            comm.data.filetransfer.unk = makeWord(buff_[4], buff_[5]);
979
                            pos = 6;
980
 
981
                            for (size_t i = 0; i < 0x0104; i++)
982
                            {
983
                                comm.data.filetransfer.data[i] = buff_[pos];
984
                                pos++;
985
                            }
986
 
987
                            comm.data.filetransfer.data[0x0103] = 0;
988
                            handleFTransfer(s, comm.data.filetransfer);
989
                        }
990
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0106)    // ACK for 0x0105
991
                        {
992
                            comm.data.filetransfer.unk = makeDWord(buff_[4], buff_[5], buff_[6], buff_[7]);
993
                            pos = 8;
994
                            handleFTransfer(s, comm.data.filetransfer);
995
                        }
996
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0002)    // request next part of file
997
                            handleFTransfer(s, comm.data.filetransfer);
998
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0003)    // File content from controller
999
                        {
1000
                            comm.data.filetransfer.unk = makeWord(buff_[4], buff_[5]);  // length of data block
1001
                            pos = 6;
1002
 
1003
                            for (size_t i = 0; i < comm.data.filetransfer.unk; i++)
1004
                            {
1005
                                comm.data.filetransfer.data[i] = buff_[pos];
1006
                                pos++;
1007
                            }
1008
 
1009
                            handleFTransfer(s, comm.data.filetransfer);
1010
                        }
1011
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0004)    // End of file
1012
                            handleFTransfer(s, comm.data.filetransfer);
1013
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0005)    // End of file ACK
1014
                            handleFTransfer(s, comm.data.filetransfer);
1015
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0006)    // End of directory listing ACK
1016
                        {
1017
                            comm.data.filetransfer.unk = makeWord(buff_[4], buff_[5]);  // length of received data block
1018
                            pos = 6;
1019
                            handleFTransfer(s, comm.data.filetransfer);
1020
                        }
1021
                        else if (comm.data.filetransfer.ftype == 4 && comm.data.filetransfer.function == 0x0007)    // End of file transfer
1022
                            handleFTransfer(s, comm.data.filetransfer);
1023
 
13 andreas 1024
                    break;
11 andreas 1025
 
1026
                    case 0x0501:    // ping
1027
                        comm.data.chan_state.device = makeWord(buff_[0], buff_[1]);
1028
                        comm.data.chan_state.system = makeWord(buff_[2], buff_[3]);
1029
                        s.channel = 0;
1030
                        s.level = 0;
1031
                        s.port = 0;
1032
                        s.value = 0;
1033
                        s.MC = 0x0581;
1034
                        sendCommand(s);
13 andreas 1035
                    break;
15 andreas 1036
 
1037
                    case 0x0502:    // Date and time
1038
                        comm.data.blinkMessage.heartBeat = buff_[0];
1039
                        comm.data.blinkMessage.LED = buff_[1];
1040
                        comm.data.blinkMessage.month = buff_[2];
1041
                        comm.data.blinkMessage.day = buff_[3];
1042
                        comm.data.blinkMessage.year = makeWord(buff_[4], buff_[5]);
1043
                        comm.data.blinkMessage.hour = buff_[6];
1044
                        comm.data.blinkMessage.minute = buff_[7];
1045
                        comm.data.blinkMessage.second = buff_[8];
1046
                        comm.data.blinkMessage.weekday = buff_[9];
1047
                        comm.data.blinkMessage.extTemp = makeWord(buff_[10], buff_[11]);
1048
                        memset(comm.data.blinkMessage.dateTime, 0, sizeof(comm.data.blinkMessage.dateTime));
1049
                        memcpy(comm.data.blinkMessage.dateTime, &buff_[12], comm.hlen - 0x0015 - 11);
1050
                        comm.checksum = buff_[comm.hlen + 3];
1051
 
1052
                        sendAllFuncTimer(comm.data.blinkMessage);
1053
/*                        if (callback)
1054
                            callback(comm);
1055
                        else
1056
                            MSG_WARNING("Missing callback function!"); */
1057
                    break;
11 andreas 1058
                }
13 andreas 1059
            break;
11 andreas 1060
 
1061
            default:        // Every unknown or unsupported command/request should be ignored.
1062
                ignore = true;
1063
        }
14 andreas 1064
 
1065
//        if (mSendReady)
1066
//            start_write();
11 andreas 1067
    }
1068
    else
1069
    {
1070
        MSG_ERROR("Error on receive: " << error.message());
1071
        stop();
1072
    }
1073
}
1074
 
1075
bool TAmxNet::sendCommand(const ANET_SEND& s)
1076
{
1077
    DECL_TRACER("TAmxNet::sendCommand (const ANET_SEND& s)");
1078
 
1079
    size_t len, size;
1080
    ANET_COMMAND com;
1081
    com.clear();
1082
    com.MC = s.MC;
1083
 
1084
    if (s.MC == 0x0204)     // file transfer
1085
        com.device1 = s.device;
1086
    else
1087
        com.device1 = 0;
1088
 
1089
    com.device2 = panelID;
1090
    com.port1 = 1;
1091
    com.system = TConfig::getSystem();
1092
    com.port2 = s.port;
1093
    sendCounter++;
1094
    com.count = sendCounter;
1095
 
1096
    switch (s.MC)
1097
    {
1098
        case 0x0084:        // push button
1099
            com.data.channel.device = com.device2;
1100
            com.data.channel.port = s.port;
1101
            com.data.channel.system = com.system;
1102
            com.data.channel.channel = s.channel;
1103
            com.hlen = 0x0016 - 0x0003 + sizeof(ANET_CHANNEL);
1104
            comStack.push_back(com);
14 andreas 1105
            mSendReady = true;
13 andreas 1106
        break;
11 andreas 1107
 
1108
        case 0x0085:        // release button
1109
            com.data.channel.device = com.device2;
1110
            com.data.channel.port = s.port;
1111
            com.data.channel.system = com.system;
1112
            com.data.channel.channel = s.channel;
1113
            com.hlen = 0x0016 - 0x0003 + sizeof(ANET_CHANNEL);
1114
            comStack.push_back(com);
14 andreas 1115
            mSendReady = true;
13 andreas 1116
        break;
11 andreas 1117
 
1118
        case 0x0086:    // output channel on
1119
        case 0x0088:    // feedback/input channel on
1120
            com.data.channel.device = com.device2;
1121
            com.data.channel.port = s.port;
1122
            com.data.channel.system = com.system;
1123
            com.data.channel.channel = s.channel;
1124
            com.hlen = 0x0016 - 0x0003 + sizeof(ANET_CHANNEL);
1125
            comStack.push_back(com);
14 andreas 1126
            mSendReady = true;
13 andreas 1127
        break;
11 andreas 1128
 
1129
        case 0x0087:    // output channel off
1130
        case 0x0089:    // feedback/input channel off
1131
            com.data.channel.device = com.device2;
1132
            com.data.channel.port = s.port;
1133
            com.data.channel.system = com.system;
1134
            com.data.channel.channel = s.channel;
1135
            com.hlen = 0x0016 - 0x0003 + sizeof(ANET_CHANNEL);
1136
            comStack.push_back(com);
14 andreas 1137
            mSendReady = true;
13 andreas 1138
        break;
11 andreas 1139
 
1140
        case 0x008a:        // level value changed
1141
            com.data.message_value.device = com.device2;
1142
            com.data.message_value.port = s.port;
1143
            com.data.message_value.system = com.system;
1144
            com.data.message_value.value = s.level;
1145
            com.data.message_value.type = 0x20;     // unsigned integer
1146
            com.data.message_value.content.integer = s.value;
1147
            com.hlen = 0x0016 - 0x0003 + 11;
1148
            comStack.push_back(com);
14 andreas 1149
            mSendReady = true;
13 andreas 1150
        break;
11 andreas 1151
 
1152
        case 0x008b:        // string command
1153
        case 0x008c:        // send command string
1154
            com.data.message_string.device = com.device2;
1155
            com.data.message_string.port = s.port;
1156
            com.data.message_string.system = com.system;
1157
            com.data.message_string.type = 0x01;    // char string
1158
 
1159
            if (s.msg.length() >= sizeof(com.data.message_string.content))
1160
                len = sizeof(com.data.message_string.content) - 1;
1161
            else
1162
                len = s.msg.length();
1163
 
1164
            com.data.message_string.length = len;
1165
            strncpy((char *)&com.data.message_string.content[0], s.msg.c_str(), len);
1166
            com.hlen = 0x0016 - 3 + 9 + len;
1167
            comStack.push_back(com);
14 andreas 1168
            mSendReady = true;
13 andreas 1169
        break;
11 andreas 1170
 
1171
        case 0x008d:    // Custom event
1172
            com.data.customEvent.device = com.device2;
1173
            com.data.customEvent.port = s.port;
1174
            com.data.customEvent.system = com.system;
1175
            com.data.customEvent.ID = s.ID;
1176
            com.data.customEvent.type = s.type;
1177
            com.data.customEvent.flag = s.flag;
1178
            com.data.customEvent.value1 = s.value1;
1179
            com.data.customEvent.value2 = s.value2;
1180
            com.data.customEvent.value3 = s.value3;
1181
            com.data.customEvent.dtype = s.dtype;
1182
 
1183
            if (s.msg.length() >= sizeof(com.data.customEvent.data))
1184
                len = sizeof(com.data.customEvent.data) - 1;
1185
            else
1186
                len = s.msg.length();
1187
 
1188
            com.data.customEvent.length = len;
1189
            memset(com.data.customEvent.data, 0, sizeof(com.data.customEvent.data));
1190
            memcpy(&com.data.customEvent.data[0], s.msg.c_str(), s.msg.length());
1191
            com.hlen = 0x0016 - 3 + 29 + s.msg.length();
1192
            comStack.push_back(com);
14 andreas 1193
            mSendReady = true;
13 andreas 1194
        break;
11 andreas 1195
 
1196
        case 0x0090:        // port count
1197
            com.data.sendPortNumber.device = com.device2;
1198
            com.data.sendPortNumber.system = com.system;
1199
            com.data.sendPortNumber.pcount = s.value;
1200
            com.hlen = 0x0016 - 3 + 6;
1201
            comStack.push_back(com);
14 andreas 1202
            mSendReady = true;
13 andreas 1203
        break;
11 andreas 1204
 
1205
        case 0x0091:        // output channel count
1206
        case 0x0092:        // send level count
1207
            com.data.sendOutpChannels.device = com.device2;
1208
            com.data.sendOutpChannels.port = s.port;
1209
            com.data.sendOutpChannels.system = com.system;
1210
            com.data.sendOutpChannels.count = s.value;
1211
            com.hlen = 0x0016 - 3 + 8;
1212
            comStack.push_back(com);
14 andreas 1213
            mSendReady = true;
13 andreas 1214
        break;
11 andreas 1215
 
1216
        case 0x0093:        // string size
1217
        case 0x0094:        // command size
1218
            com.data.sendSize.device = com.device2;
1219
            com.data.sendSize.port = s.port;
1220
            com.data.sendSize.system = com.system;
1221
            com.data.sendSize.type = 0x01;
1222
            com.data.sendSize.length = s.value;
1223
            com.hlen = 0x0016 - 3 + 9;
1224
            comStack.push_back(com);
14 andreas 1225
            mSendReady = true;
13 andreas 1226
        break;
11 andreas 1227
 
1228
        case 0x0095:        // suported level types
1229
            com.data.sendLevSupport.device = com.device2;
1230
            com.data.sendLevSupport.port = s.port;
1231
            com.data.sendLevSupport.system = com.system;
1232
            com.data.sendLevSupport.level = s.level;
1233
            com.data.sendLevSupport.num = 6;
1234
            com.data.sendLevSupport.types[0] = 0x10;
1235
            com.data.sendLevSupport.types[1] = 0x11;
1236
            com.data.sendLevSupport.types[2] = 0x20;
1237
            com.data.sendLevSupport.types[3] = 0x21;
1238
            com.data.sendLevSupport.types[4] = 0x40;
1239
            com.data.sendLevSupport.types[5] = 0x41;
1240
            com.hlen = 0x0016 - 0x0003 + sizeof(ANET_LEVSUPPORT);
1241
            comStack.push_back(com);
14 andreas 1242
            mSendReady = true;
13 andreas 1243
        break;
11 andreas 1244
 
1245
        case 0x0096:        // Status code
1246
            com.data.sendStatusCode.device = com.device2;
1247
            com.data.sendStatusCode.port = s.port;
1248
            com.data.sendStatusCode.system = com.system;
1249
            com.data.sendStatusCode.status = 0;
1250
            com.data.sendStatusCode.type = 0x11;
1251
            com.data.sendStatusCode.length = 2;
1252
            com.data.sendStatusCode.str[0] = 'O';
1253
            com.data.sendStatusCode.str[1] = 'K';
1254
            com.hlen = 0x0016 - 3 + 13;
1255
            comStack.push_back(com);
14 andreas 1256
            mSendReady = true;
13 andreas 1257
        break;
11 andreas 1258
 
1259
        case 0x0097:        // device info
1260
            com.data.srDeviceInfo.device = com.device2;
1261
            com.data.srDeviceInfo.system = com.system;
1262
            com.data.srDeviceInfo.flag = 0x0000;
1263
            com.data.srDeviceInfo.objectID = 0;
1264
            com.data.srDeviceInfo.parentID = 0;
1265
            com.data.srDeviceInfo.herstID = 1;
1266
            msg97fill(&com);
14 andreas 1267
            mSendReady = true;
13 andreas 1268
        break;
11 andreas 1269
 
1270
        case 0x0098:
1271
            com.data.reqPortCount.device = com.device2;
1272
            com.data.reqPortCount.system = com.system;
1273
            com.hlen = 0x0016 - 3 + 4;
1274
            comStack.push_back(com);
14 andreas 1275
            mSendReady = true;
13 andreas 1276
        break;
11 andreas 1277
 
1278
        case 0x0204:        // File transfer
1279
            com.port1 = 0;
1280
            com.port2 = 0;
1281
            com.data.filetransfer.ftype = s.dtype;
1282
            com.data.filetransfer.function = s.type;
1283
            com.data.filetransfer.info1 = s.value;
1284
            com.data.filetransfer.info2 = s.level;
1285
            com.data.filetransfer.unk = s.value1;
1286
            com.data.filetransfer.unk1 = s.value2;
1287
            com.data.filetransfer.unk2 = s.value3;
1288
            size = min(s.msg.length(), sizeof(com.data.filetransfer.data) - 1);
1289
            memcpy(com.data.filetransfer.data, s.msg.c_str(), size);
1290
            com.data.filetransfer.data[size] = 0;
1291
            len = 4;
1292
 
1293
            if (s.dtype == 0)
1294
            {
1295
                switch (s.type)
1296
                {
1297
                    case 0x0001: len += 2; break;
1298
                    case 0x0101: len += 16 + size + 1; break;
1299
                    case 0x0102: len += 19 + size + 1; break;
1300
                }
1301
            }
1302
            else
1303
            {
1304
                switch (s.type)
1305
                {
1306
                    case 0x0003: len += 2 + s.value1; break;
1307
                    case 0x0101: len += 8; break;
1308
                    case 0x0103: len += 6; break;
1309
                    case 0x0105: len += 8; break;
1310
                }
1311
            }
1312
 
1313
            com.hlen = 0x0016 - 3 + len;
1314
            comStack.push_back(com);
14 andreas 1315
            mSendReady = true;
13 andreas 1316
        break;
11 andreas 1317
 
1318
        case 0x0581:        // Pong
1319
            com.data.srDeviceInfo.device = panelID; // Configuration->getAMXChannel();
1320
            com.data.srDeviceInfo.system = TConfig::getSystem();
1321
            com.data.srDeviceInfo.herstID = devInfo[0].manufacturerID;
1322
            com.data.srDeviceInfo.deviceID = devInfo[0].deviceID;
1323
            com.data.srDeviceInfo.info[0] = 2;  // Type: IPv4 address
1324
            com.data.srDeviceInfo.info[1] = 4;  // length of following data
1325
 
1326
            {
1327
                string addr = socket_.local_endpoint().address().to_string();
1328
                vector<string> parts = StrSplit(addr, ".");
1329
 
1330
                for (size_t i = 0; i < parts.size(); i++)
1331
                    com.data.srDeviceInfo.info[i + 2] = (unsigned char)atoi(parts[i].c_str());
1332
            }
1333
 
1334
            com.hlen = 0x0016 - 3 + 14;
1335
            comStack.push_back(com);
14 andreas 1336
            mSendReady = true;
13 andreas 1337
        break;
11 andreas 1338
    }
1339
 
14 andreas 1340
    if (mSendReady)
11 andreas 1341
        start_write();
1342
 
14 andreas 1343
    return mSendReady;
11 andreas 1344
}
1345
 
1346
void TAmxNet::handleFTransfer(ANET_SEND &s, ANET_FILETRANSFER &ft)
1347
{
1348
    DECL_TRACER("TAmxNet::handleFTransfer (ANET_SEND &s, ANET_FILETRANSFER &ft)");
1349
 
1350
    int len;
1351
    ANET_COMMAND ftr;
1352
    ftr.MC = 0x1000;
1353
    ftr.device1 = s.device;
1354
    ftr.device2 = s.device;
1355
    ftr.port1 = 0;
1356
    ftr.port2 = 0;
1357
    ftr.count = 0;
1358
    ftr.data.filetransfer.ftype = ft.ftype;
1359
    ftr.data.filetransfer.function = ft.function;
1360
    ftr.data.filetransfer.data[0] = 0;
1361
 
1362
    if (ft.ftype == 0 && ft.function == 0x0105)     // Create directory
1363
    {
1364
        s.channel = 0;
1365
        s.level = 0;
1366
        s.port = 0;
1367
        s.value = 0;
1368
        s.MC = 0x0204;
1369
        s.dtype = 0;                // ftype --> function type
1370
        s.type = 0x0001;            // function
1371
        s.value1 = 0;               // 1st data byte 0x00
1372
        s.value2 = 0x10;            // 2nd data byte 0x10
1373
        string f((char *)&ft.data);
1374
        MSG_TRACE("0x0000/0x0105: Directory " << f << " exist?");
1375
 
1376
        if (f.compare(0, 8, "AMXPanel") == 0)
1377
        {
1378
            if (f.find("/images") > 0)
1379
                mkdir(string(TConfig::getProjectPath() + "/images").c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1380
            else if (f.find("/sounds") > 0)
1381
                mkdir(string(TConfig::getProjectPath() + "/sounds").c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1382
            else if (f.find("/fonts") > 0)
1383
                mkdir(string(TConfig::getProjectPath() + "/fonts").c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1384
        }
1385
        else if (f.compare(0, 8, "__system") == 0)
1386
        {
1387
            if (access(string(TConfig::getProjectPath() + "/__system").c_str(), R_OK | W_OK | X_OK))
1388
            {
1389
                mkdir(string(TConfig::getProjectPath() + "/__system").c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1390
                mkdir(string(TConfig::getProjectPath() + "/__system/graphics").c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1391
            }
1392
        }
1393
 
1394
        sendCommand(s);
1395
 
1396
        if (!receiveSetup)
1397
        {
1398
            receiveSetup = true;
1399
            ftransfer.maxFiles = countFiles();
1400
 
1401
            if (callback)
1402
                callback(ftr);
13 andreas 1403
            else
1404
                MSG_WARNING("Missing callback function!");
11 andreas 1405
        }
1406
    }
1407
    else if (ft.ftype == 0 && ft.function == 0x0100)    // Request directory
1408
    {
1409
        string fname((char *)&ft.data);
1410
        string amxpath(fname);
1411
        string realPath;
1412
        size_t pos = 0;
1413
        len = 0;
1414
        dir::TDirectory dr;
1415
 
1416
        if (fname.compare("AMXPanel/") == 0)
1417
        {
1418
            realPath.assign(TConfig::getProjectPath());
1419
            amxpath.assign("/opt/amx/user/AMXPanel");
1420
        }
1421
        else if ((pos = fname.find("AMXPanel/")) != string::npos)
1422
        {
1423
            if (pos == 0)
1424
                amxpath = "/opt/amx/user/" + fname;
1425
 
1426
            realPath = dr.stripPath("AMXPanel", fname);
1427
            realPath = TConfig::getProjectPath() + "/" + realPath;
1428
 
1429
            if (dr.isFile(realPath))
1430
                len = dr.getFileSize(realPath);
1431
        }
1432
 
1433
        MSG_TRACE("0x0000/0x0100: Request directory " << fname);
1434
        snprintf((char *)&ftr.data.filetransfer.data[0], sizeof(ftr.data.filetransfer.data), "Syncing %d files ...", ftransfer.maxFiles);
1435
 
1436
        if (callback)
1437
            callback(ftr);
13 andreas 1438
        else
1439
            MSG_WARNING("Missing callback function!");
14 andreas 1440
 
11 andreas 1441
        s.channel = 0;
1442
        s.level = 0;
1443
        s.port = 0;
1444
        s.value = 0;
1445
        s.MC = 0x0204;
1446
        s.dtype = 0x0000;
1447
        s.type = 0x0101;
1448
        s.value1 = len;     // File length
1449
        s.value2 = 0x0000be42;
1450
        s.value3 = 0x00003e75;
1451
        s.msg = amxpath;
1452
        sendCommand(s);
1453
        // Read the directory tree
1454
        dr.setStripPath(true);
1455
        dr.readDir(realPath);
1456
        amxpath = fname;
1457
 
1458
        if (amxpath.length() > 1 && amxpath.at(amxpath.length() - 1) == '/')
1459
            amxpath = amxpath.substr(0, amxpath.length() - 1);
1460
 
1461
        for (pos = 0; pos < dr.getNumEntries(); pos++)
1462
        {
1463
            dir::DFILES_T df = dr.getEntry(pos);
1464
            s.type = 0x0102;
1465
 
1466
            s.value = (dr.testDirectory(df.attr)) ? 1 : 0;  // Depends on type of entry
1467
            s.level = dr.getNumEntries();       // # entries
1468
            s.value1 = df.count;                // counter
1469
            s.value2 = df.size;                 // Size of file
1470
            s.value3 = df.date;                 // Last modification date (epoch)
1471
            s.msg.assign(amxpath + "/" + df.name);
1472
            sendCommand(s);
1473
        }
1474
    }
1475
    else if (ft.ftype == 4 && ft.function == 0x0100)    // Have more files to send.
1476
    {
1477
        MSG_TRACE("0x0004/0x0100: Have more files to send.");
1478
        s.channel = 0;
1479
        s.level = 0;
1480
        s.port = 0;
1481
        s.value = 0;
1482
        s.MC = 0x0204;
1483
        s.dtype = 4;                // ftype --> function type
1484
        s.type = 0x0101;            // function:
1485
        s.value1 = 0x01bb3000;      // ?
1486
        s.value2 = 0;               // ?
1487
        sendCommand(s);
1488
    }
1489
    else if (ft.ftype == 4 && ft.function == 0x0102)    // Controller will send a file
1490
    {
1491
        string f((char*)&ft.data);
1492
        size_t pos;
1493
        rcvFileName.assign(TConfig::getProjectPath());
1494
 
1495
        if (f.find("AMXPanel") != string::npos)
1496
        {
1497
            pos = f.find_first_of("/");
1498
            rcvFileName.append(f.substr(pos));
1499
        }
1500
        else
1501
        {
1502
            rcvFileName.append("/");
1503
            rcvFileName.append((char*)&ft.data);
1504
        }
1505
 
1506
        if (rcvFile != nullptr)
1507
            fclose(rcvFile);
1508
 
1509
        rcvFile = fopen(rcvFileName.c_str(), "w+");
1510
 
1511
        if (!rcvFile)
1512
        {
1513
            MSG_ERROR("Error creating file " << rcvFileName);
1514
            isOpenRcv = false;
1515
        }
1516
        else
1517
            isOpenRcv = true;
1518
 
1519
        MSG_TRACE("0x0004/0x0102: Controller will send file " << rcvFileName);
1520
        ftransfer.actFileNum++;
1521
        ftransfer.lengthFile = ft.unk;
1522
 
1523
        if (ftransfer.actFileNum > ftransfer.maxFiles)
1524
            ftransfer.maxFiles = ftransfer.actFileNum;
1525
 
1526
        ftransfer.percent = (int)(100.0 / (double)ftransfer.maxFiles * (double)ftransfer.actFileNum);
1527
        pos = rcvFileName.find_last_of("/");
1528
        string shfn;
1529
 
1530
        if (pos != string::npos)
1531
            shfn = cp1250ToUTF8(rcvFileName.substr(pos + 1));
1532
        else
1533
            shfn = cp1250ToUTF8(rcvFileName);
1534
 
1535
        snprintf((char*)&ftr.data.filetransfer.data[0], sizeof(ftr.data.filetransfer.data), "[%d/%d]&nbsp;%s", ftransfer.actFileNum, ftransfer.maxFiles, shfn.c_str());
1536
        ftr.count = ftransfer.percent;
1537
        ftr.data.filetransfer.info1 = 0;
1538
 
1539
        if (callback)
1540
            callback(ftr);
13 andreas 1541
        else
1542
            MSG_WARNING("Missing callback function!");
11 andreas 1543
 
1544
        posRcv = 0;
1545
        lenRcv = ft.unk;
1546
        s.channel = 0;
1547
        s.level = 0;
1548
        s.port = 0;
1549
        s.value = 0;
1550
        s.MC = 0x0204;
1551
        s.dtype = 4;                // ftype --> function type
1552
        s.type = 0x0103;            // function: ready for receiving file
1553
        s.value1 = MAX_CHUNK;       // Maximum length of a chunk
1554
        s.value2 = ft.unk1;         // ID?
1555
        sendCommand(s);
1556
    }
1557
    else if (ft.ftype == 0 && ft.function == 0x0104)    // Delete file <name>
1558
    {
1559
        dir::TDirectory dr;
1560
        s.channel = 0;
1561
        s.level = 0;
1562
        s.port = 0;
1563
        s.value = 0;
1564
        s.MC = 0x0204;
1565
        string f((char*)&ft.data[0]);
1566
        size_t pos = 0;
1567
 
1568
        if ((pos = f.find("AMXPanel/")) == string::npos)
1569
            pos = f.find("__system/");
1570
 
1571
        MSG_TRACE("0x0000/0x0104: Delete file " << f);
1572
 
1573
        if (pos != string::npos)
1574
            f = TConfig::getProjectPath() + "/" + f.substr(pos + 9);
1575
        else
1576
            f = TConfig::getProjectPath() + "/" + f;
1577
 
1578
        if (dr.exists(f))
1579
        {
1580
            s.dtype = 0;                // ftype --> function type
1581
            s.type = 0x0002;            // function: yes file exists
1582
            remove(f.c_str());
1583
        }
1584
        else    // Send: file was deleted although it does not exist.
1585
        {
1586
            MSG_ERROR("[DELETE] File " << f << " not found!");
1587
            s.dtype = 0;                // ftype --> function type
1588
            s.type = 0x0002;            // function: yes file exists
1589
        }
1590
 
1591
        sendCommand(s);
1592
 
1593
        if (ftransfer.actDelFile == 0)
1594
        {
1595
            ftransfer.actDelFile++;
1596
            ftransfer.percent = (int)(100.0 / (double)ftransfer.maxFiles * (double)ftransfer.actDelFile);
1597
            ftr.count = ftransfer.percent;
1598
 
1599
            if (callback)
1600
                callback(ftr);
13 andreas 1601
            else
1602
                MSG_WARNING("Missing callback function!");
11 andreas 1603
        }
1604
        else
1605
        {
1606
            ftransfer.actDelFile++;
1607
            int prc = (int)(100.0 / (double)ftransfer.maxFiles * (double)ftransfer.actDelFile);
1608
 
1609
            if (prc != ftransfer.percent)
1610
            {
1611
                ftransfer.percent = prc;
1612
                ftr.count = prc;
1613
 
1614
                if (callback)
1615
                    callback(ftr);
13 andreas 1616
                else
1617
                    MSG_WARNING("Missing callback function!");
11 andreas 1618
            }
1619
        }
1620
    }
1621
    else if (ft.ftype == 4 && ft.function == 0x0104)    // request a file
1622
    {
1623
        string f((char*)&ft.data);
1624
        size_t pos;
1625
        len = 0;
1626
        sndFileName.assign(TConfig::getProjectPath());
1627
        MSG_TRACE("0x0004/0x0104: Request file " << f);
1628
 
1629
        if (f.find("AMXPanel") != string::npos)
1630
        {
1631
            pos = f.find_first_of("/");
1632
            sndFileName.append(f.substr(pos));
1633
        }
1634
        else
1635
        {
1636
            sndFileName.append("/");
1637
            sndFileName.append(f);
1638
        }
1639
 
1640
        if (!access(sndFileName.c_str(), R_OK))
1641
        {
1642
            struct stat s;
1643
 
1644
            if (stat(sndFileName.c_str(), &s) == 0)
1645
                len = s.st_size;
1646
            else
1647
                len = 0;
1648
        }
1649
        else if (sndFileName.find("/version.xma") > 0)
1650
            len = 0x0015;
1651
        else
1652
            len = 0;
1653
 
1654
        MSG_TRACE("0x0004/0x0104: (" << len << ") File: " << sndFileName);
1655
 
1656
        s.channel = 0;
1657
        s.level = 0;
1658
        s.port = 0;
1659
        s.value = 0;
1660
        s.MC = 0x0204;
1661
        s.dtype = 4;                // ftype --> function type
1662
        s.type = 0x0105;            // function
1663
        s.value1 = len;             // length of file to send
1664
        s.value2 = 0x00001388;      // ID for device when sending a file.
1665
        sendCommand(s);
1666
    }
1667
    else if (ft.ftype == 4 && ft.function == 0x0106)    // Controller is ready for receiving file
1668
    {
1669
        MSG_TRACE("0x0004/0x0106: Controller is ready for receiving file.");
1670
 
1671
        if (!access(sndFileName.c_str(), R_OK))
1672
        {
1673
            struct stat st;
1674
            stat(sndFileName.c_str(), &st);
1675
            len = st.st_size;
1676
            lenSnd = len;
1677
            posSnd = 0;
1678
            sndFile = fopen(sndFileName.c_str(), "r");
1679
 
1680
            if (!sndFile)
1681
            {
1682
                MSG_ERROR("Error reading file " << sndFileName);
1683
                len = 0;
1684
                isOpenSnd = false;
1685
            }
1686
            else
1687
                isOpenSnd = true;
1688
 
1689
            if (isOpenSnd && len <= MAX_CHUNK)
1690
            {
1691
                char *buf = new char[len + 1];
1692
                fread(buf, 1, len, sndFile);
1693
                s.msg.assign(buf, len);
1694
                delete[] buf;
1695
                posSnd = len;
1696
            }
1697
            else if (isOpenSnd)
1698
            {
1699
                char *buf = new char[MAX_CHUNK + 1];
1700
                fread(buf, 1, MAX_CHUNK, sndFile);
1701
                s.msg.assign(buf, MAX_CHUNK);
1702
                delete[] buf;
1703
                posSnd = MAX_CHUNK;
1704
                len = MAX_CHUNK;
1705
            }
1706
        }
1707
        else if (sndFileName.find("/version.xma") > 0)
1708
        {
1709
            s.msg.assign("<version>9</version>\n");
1710
            len = s.msg.length();
1711
            posSnd = len;
1712
        }
1713
        else
1714
            len = 0;
1715
 
1716
        s.channel = 0;
1717
        s.level = 0;
1718
        s.port = 0;
1719
        s.value = 0;
1720
        s.MC = 0x0204;
1721
        s.dtype = 4;                // ftype --> function type
1722
        s.type = 0x0003;            // function: Sending file with length <len>
1723
        s.value1 = len;             // length of content to send
1724
        sendCommand(s);
1725
    }
1726
    else if (ft.ftype == 4 && ft.function == 0x0002)    // request next part of file
1727
    {
1728
        MSG_TRACE("0x0004/0x0002: Request next part of file.");
1729
        s.channel = 0;
1730
        s.level = 0;
1731
        s.port = 0;
1732
        s.value = 0;
1733
        s.MC = 0x0204;
1734
        s.dtype = 4;                // ftype --> function type
1735
 
1736
        if (posSnd < lenSnd)
1737
        {
1738
            s.type = 0x0003;        // Next part of file
1739
 
1740
            if ((posSnd + MAX_CHUNK) > lenSnd)
1741
                len = lenSnd - posSnd;
1742
            else
1743
                len = MAX_CHUNK;
1744
 
1745
            s.value1 = len;
1746
 
1747
            if (isOpenSnd)
1748
            {
1749
                char *buf = new char[len + 1];
1750
                fread(buf, 1, len, sndFile);
1751
                s.msg.assign(buf, len);
1752
                delete[] buf;
1753
                posSnd += len;
1754
            }
1755
            else
1756
                s.value1 = 0;
1757
        }
1758
        else
1759
            s.type = 0x0004;        // function: End of file reached
1760
 
1761
        sendCommand(s);
1762
    }
1763
    else if (ft.ftype == 4 && ft.function == 0x0003)    // File content
1764
    {
1765
        MSG_TRACE("0x0004/0x0003: Received (part of) file.");
1766
        len = ft.unk;
1767
 
1768
        if (isOpenRcv)
1769
        {
1770
            fwrite(ft.data, 1, len, rcvFile);
1771
            posRcv += ft.unk;
1772
        }
1773
        else
1774
            MSG_WARNING("No open file to write to!");
1775
 
1776
        s.channel = 0;
1777
        s.level = 0;
1778
        s.port = 0;
1779
        s.value = 0;
1780
        s.MC = 0x0204;
1781
        s.dtype = 4;                // ftype --> function type
1782
        s.type = 0x0002;            // function: Request next part of file
1783
        sendCommand(s);
1784
 
1785
        int prc = (int)(100.0 / (double)ftransfer.lengthFile * (double)posRcv);
1786
 
1787
        if (prc != ftr.data.filetransfer.info1)
1788
        {
1789
            ftr.data.filetransfer.info1 = (int)(100.0 / (double)ftransfer.lengthFile * (double)posRcv);
1790
            ftr.count = ftransfer.percent;
1791
 
1792
            if (callback)
1793
                callback(ftr);
13 andreas 1794
            else
1795
                MSG_WARNING("Missing callback function!");
11 andreas 1796
        }
1797
    }
1798
    else if (ft.ftype == 4 && ft.function == 0x0004)    // End of file
1799
    {
1800
        MSG_TRACE("0x0004/0x0004: End of file.");
1801
 
1802
        if (isOpenRcv)
1803
        {
1804
            unsigned char buf[8];
1805
            fseek(rcvFile, 0, SEEK_SET);
1806
            fread(buf, 1, sizeof(buf), rcvFile);
1807
            fclose(rcvFile);
1808
            isOpenRcv = false;
1809
            rcvFile = nullptr;
1810
            posRcv = 0;
1811
 
1812
            if (buf[0] == 0x1f && buf[1] == 0x8b)   // GNUzip compressed?
1813
            {
1814
                TExpand exp(rcvFileName);
1815
                exp.unzip();
1816
            }
1817
        }
1818
 
1819
        ftr.count = ftransfer.percent;
1820
        ftr.data.filetransfer.info1 = 100;
1821
 
1822
        if (callback)
1823
            callback(ftr);
13 andreas 1824
        else
1825
            MSG_WARNING("Missing callback functiom!");
11 andreas 1826
 
1827
        s.channel = 0;
1828
        s.level = 0;
1829
        s.port = 0;
1830
        s.value = 0;
1831
        s.MC = 0x0204;
1832
        s.dtype = 4;                // ftype --> function type
1833
        s.type = 0x0005;            // function: ACK, file received. No answer expected.
1834
        sendCommand(s);
1835
    }
1836
    else if (ft.ftype == 4 && ft.function == 0x0005)    // ACK, controller received file, no answer
1837
    {
1838
        MSG_TRACE("0x0004/0x0005: Controller received file.");
1839
        posSnd = 0;
1840
        lenSnd = 0;
1841
 
1842
        if (isOpenSnd && sndFile != nullptr)
1843
            fclose(sndFile);
1844
 
1845
        ftransfer.lengthFile = 0;
1846
        sndFile = nullptr;
1847
    }
1848
    else if (ft.ftype == 4 && ft.function == 0x0006)    // End of directory transfer ACK
1849
    {
1850
        MSG_TRACE("0x0004/0x0006: End of directory transfer.");
1851
    }
1852
    else if (ft.ftype == 4 && ft.function == 0x0007)    // End of file transfer
1853
    {
1854
        MSG_TRACE("0x0004/0x0007: End of file transfer.");
1855
 
1856
        if (callback)
1857
            callback(ftr);
13 andreas 1858
        else
1859
            MSG_WARNING("Missing callback function!");
11 andreas 1860
 
1861
        receiveSetup = false;
1862
    }
1863
}
1864
 
1865
int TAmxNet::msg97fill(ANET_COMMAND *com)
1866
{
1867
    DECL_TRACER("TAmxNet::msg97fill(ANET_COMMAND *com)");
1868
 
1869
    int pos = 0;
1870
    unsigned char buf[512];
1871
 
1872
    for (size_t i = 0; i < devInfo.size(); i++)
1873
    {
1874
        pos = 0;
1875
 
1876
        if (i == 0)
1877
            com->sep1 = 0x12;
1878
        else
1879
            com->sep1 = 0x02;
1880
 
1881
        memset(buf, 0, sizeof(buf));
1882
        com->data.srDeviceInfo.objectID = devInfo[i].objectID;
1883
        com->data.srDeviceInfo.parentID = devInfo[i].parentID;
1884
        com->data.srDeviceInfo.herstID = devInfo[i].manufacturerID;
1885
        com->data.srDeviceInfo.deviceID = devInfo[i].deviceID;
1886
        memcpy(com->data.srDeviceInfo.serial, devInfo[i].serialNum, 16);
1887
        com->data.srDeviceInfo.fwid = devInfo[i].firmwareID;
1888
        memcpy(buf, devInfo[i].versionInfo, strlen(devInfo[i].versionInfo));
1889
        pos = (int)strlen(devInfo[i].versionInfo) + 1;
1890
        memcpy(buf + pos, devInfo[i].deviceInfo, strlen(devInfo[i].deviceInfo));
1891
        pos += strlen(devInfo[i].deviceInfo) + 1;
1892
        memcpy(buf + pos, devInfo[i].manufacturerInfo, strlen(devInfo[i].manufacturerInfo));
1893
        pos += strlen(devInfo[i].manufacturerInfo) + 1;
1894
        *(buf + pos) = 0x02; // type IP address
1895
        pos++;
1896
        *(buf + pos) = 0x04; // field length: 4 bytes
1897
        // Now the IP Address
1898
        string addr = socket_.local_endpoint().address().to_string();
1899
        vector<string> parts = StrSplit(addr, ".");
1900
 
1901
        for (size_t i = 0; i < parts.size(); i++)
1902
        {
1903
            pos++;
1904
            *(buf + pos) = (unsigned char)atoi(parts[i].c_str());
1905
        }
1906
 
1907
        pos++;
1908
        com->data.srDeviceInfo.len = pos;
1909
        memcpy(com->data.srDeviceInfo.info, buf, pos);
1910
        com->hlen = 0x0016 - 3 + 31 + pos - 1;
1911
        comStack.push_back(*com);
1912
        sendCounter++;
1913
        com->count = sendCounter;
1914
    }
1915
 
1916
    return pos;
1917
}
1918
 
1919
void TAmxNet::start_write()
1920
{
1921
    DECL_TRACER("TAmxNet::start_write()");
1922
 
1923
    if (!isRunning())
1924
        return;
1925
 
1926
    if (write_busy)
1927
        return;
1928
 
1929
    write_busy = true;
1930
 
1931
    while (comStack.size() > 0)
1932
    {
1933
        if (!isRunning())
1934
        {
1935
            comStack.clear();
1936
            write_busy = false;
1937
            return;
1938
        }
1939
 
1940
        send = comStack.at(0);
1941
        comStack.erase(comStack.begin());   // delete oldest element
1942
        unsigned char *buf = makeBuffer(send);
1943
 
1944
        if (buf == 0)
1945
        {
1946
            MSG_ERROR("Error creating a buffer! Token number: " << send.MC);
1947
            continue;
1948
        }
1949
 
14 andreas 1950
        MSG_DEBUG("Wrote buffer with " << (send.hlen + 4) << " bytes.");
11 andreas 1951
        asio::async_write(socket_, asio::buffer(buf, send.hlen + 4), bind(&TAmxNet::handle_write, this, _1));
1952
        delete[] buf;
1953
    }
1954
 
14 andreas 1955
    mSendReady = false;
11 andreas 1956
    write_busy = false;
1957
}
1958
 
1959
void TAmxNet::handle_write(const error_code& error)
1960
{
1961
    DECL_TRACER("TAmxNet::handle_write(const error_code& error)");
1962
 
1963
    if (!isRunning())
1964
        return;
1965
 
1966
    if (!error)
1967
    {
1968
        while (comStack.size() == 0)
1969
            heartbeat_timer_.expires_after(chrono::microseconds(150));
1970
 
1971
        heartbeat_timer_.async_wait(bind(&TAmxNet::start_write, this));
1972
    }
1973
    else
1974
    {
1975
        MSG_TRACE("Error on heartbeat: " << error.message());
1976
        stop();
1977
    }
1978
}
1979
 
1980
void TAmxNet::check_deadline()
1981
{
1982
    DECL_TRACER("TAmxNet::check_deadline()");
1983
 
1984
    if (!isRunning())
1985
        return;
1986
 
1987
    // Check whether the deadline has passed. We compare the deadline against
1988
    // the current time since a new asynchronous operation may have moved the
1989
    // deadline before this actor had a chance to run.
1990
    if (deadline_.expiry() <= steady_timer::clock_type::now())
1991
    {
1992
        // The deadline has passed. The socket is closed so that any outstanding
1993
        // asynchronous operations are cancelled.
1994
        if (socket_.is_open())
1995
            socket_.close();
1996
 
1997
        // There is no longer an active deadline. The expiry is set to the
1998
        // maximum time point so that the actor takes no action until a new
1999
        // deadline is set.
2000
        deadline_.expires_at(steady_timer::time_point::max());
2001
    }
2002
 
2003
    // Put the actor back to sleep.
2004
    deadline_.async_wait(bind(&TAmxNet::check_deadline, this));
2005
}
2006
 
2007
uint16_t TAmxNet::swapWord(uint16_t w)
2008
{
2009
    uint16_t word = 0;
2010
    word = ((w << 8) & 0xff00) | ((w >> 8) & 0x00ff);
2011
    return word;
2012
}
2013
 
2014
uint32_t TAmxNet::swapDWord(uint32_t dw)
2015
{
2016
    uint32_t dword = 0;
2017
    dword = ((dw << 24) & 0xff000000) | ((dw << 8) & 0x00ff0000) | ((dw >> 8) & 0x0000ff00) | ((dw >> 24) & 0x000000ff);
2018
    return dword;
2019
}
2020
 
2021
unsigned char TAmxNet::calcChecksum(const unsigned char* buffer, size_t len)
2022
{
2023
    DECL_TRACER("TAmxNet::calcChecksum(const unsigned char* buffer, size_t len)");
2024
    unsigned long sum = 0;
2025
 
2026
    for (size_t i = 0; i < len; i++)
2027
        sum += (unsigned long)(*(buffer + i)) & 0x000000ff;
2028
 
2029
    sum &= 0x000000ff;
2030
    MSG_TRACE("Checksum=" << std::setw(2) << std::setfill('0') << std::hex << sum << ", #bytes=" << len << " bytes.");
2031
    return (unsigned char)sum;
2032
}
2033
 
2034
uint16_t TAmxNet::makeWord(unsigned char b1, unsigned char b2)
2035
{
2036
    return ((b1 << 8) & 0xff00) | b2;
2037
}
2038
 
2039
uint32_t TAmxNet::makeDWord(unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4)
2040
{
2041
    return ((b1 << 24) & 0xff000000) | ((b2 << 16) & 0x00ff0000) | ((b3  << 8) & 0x0000ff00) | b4;
2042
}
2043
 
2044
bool TAmxNet::isCommand(const string& cmd)
2045
{
2046
    DECL_TRACER("TAmxNet::isCommand(string& cmd)");
2047
 
2048
    int i = 0;
2049
 
2050
    while (cmdList[i][0] != 0)
2051
    {
2052
        if (cmd.find(cmdList[i]) == 0)
2053
            return true;
2054
 
2055
        i++;
2056
    }
2057
 
2058
    return false;
2059
}
2060
 
2061
unsigned char *TAmxNet::makeBuffer(const ANET_COMMAND& s)
2062
{
2063
    DECL_TRACER("TAmxNet::makeBuffer (const ANET_COMMAND& s)");
2064
 
2065
    int pos = 0;
2066
    int len;
2067
    bool valid = false;
2068
    unsigned char *buf;
2069
 
2070
    try
2071
    {
2072
        buf = new unsigned char[s.hlen + 5];
2073
        memset(buf, 0, s.hlen + 5);
2074
    }
2075
    catch (std::exception& e)
2076
    {
2077
        MSG_ERROR("Error allocating memory: " << e.what());
2078
        return nullptr;
2079
    }
2080
 
2081
    *buf = s.ID;
2082
    *(buf + 1) = s.hlen >> 8;
2083
    *(buf + 2) = s.hlen;
2084
    *(buf + 3) = s.sep1;
2085
    *(buf + 4) = s.type;
2086
    *(buf + 5) = s.unk1 >> 8;
2087
    *(buf + 6) = s.unk1;
2088
    *(buf + 7) = s.device1 >> 8;
2089
    *(buf + 8) = s.device1;
2090
    *(buf + 9) = s.port1 >> 8;
2091
    *(buf + 10) = s.port1;
2092
    *(buf + 11) = s.system >> 8;
2093
    *(buf + 12) = s.system;
2094
    *(buf + 13) = s.device2 >> 8;
2095
    *(buf + 14) = s.device2;
2096
    *(buf + 15) = s.port2 >> 8;
2097
    *(buf + 16) = s.port2;
2098
    *(buf + 17) = s.unk6;
2099
    *(buf + 18) = s.count >> 8;
2100
    *(buf + 19) = s.count;
2101
    *(buf + 20) = s.MC >> 8;
2102
    *(buf + 21) = s.MC;
2103
 
2104
    // Here the fixed block is complete. The data are following.
2105
    switch (s.MC)
2106
    {
2107
        case 0x0006:
2108
        case 0x0007:
2109
        case 0x0018:
2110
        case 0x0019:
2111
        case 0x0084:
2112
        case 0x0085:
2113
        case 0x0086:
2114
        case 0x0087:
2115
        case 0x0088:
2116
        case 0x0089:
2117
            *(buf + 22) = s.data.chan_state.device >> 8;
2118
            *(buf + 23) = s.data.chan_state.device;
2119
            *(buf + 24) = s.data.chan_state.port >> 8;
2120
            *(buf + 25) = s.data.chan_state.port;
2121
            *(buf + 26) = s.data.chan_state.system >> 8;
2122
            *(buf + 27) = s.data.chan_state.system;
2123
            *(buf + 28) = s.data.chan_state.channel >> 8;
2124
            *(buf + 29) = s.data.chan_state.channel;
2125
            *(buf + 30) = calcChecksum(buf, 30);
2126
            valid = true;
2127
            break;
2128
 
2129
        case 0x000a:
2130
        case 0x008a:
2131
            *(buf + 22) = s.data.message_value.device >> 8;
2132
            *(buf + 23) = s.data.message_value.device;
2133
            *(buf + 24) = s.data.message_value.port >> 8;
2134
            *(buf + 25) = s.data.message_value.port;
2135
            *(buf + 26) = s.data.message_value.system >> 8;
2136
            *(buf + 27) = s.data.message_value.system;
2137
            *(buf + 28) = s.data.message_value.value >> 8;
2138
            *(buf + 29) = s.data.message_value.value;
2139
            *(buf + 30) = s.data.message_value.type;
2140
            pos = 31;
2141
 
2142
            switch (s.data.message_value.type)
2143
            {
2144
                case 0x10: *(buf + pos) = s.data.message_value.content.byte; break;
2145
 
2146
                case 0x11: *(buf + pos) = s.data.message_value.content.ch; break;
2147
 
2148
                case 0x20:
2149
                    *(buf + pos) = s.data.message_value.content.integer >> 8;
2150
                    pos++;
2151
                    *(buf + pos) = s.data.message_value.content.integer;
2152
                    break;
2153
 
2154
                case 0x21:
2155
                    *(buf + pos) = s.data.message_value.content.sinteger >> 8;
2156
                    pos++;
2157
                    *(buf + pos) = s.data.message_value.content.sinteger;
2158
                    break;
2159
 
2160
                case 0x40:
2161
                    *(buf + pos) = s.data.message_value.content.dword >> 24;
2162
                    pos++;
2163
                    *(buf + pos) = s.data.message_value.content.dword >> 16;
2164
                    pos++;
2165
                    *(buf + pos) = s.data.message_value.content.dword >> 8;
2166
                    pos++;
2167
                    *(buf + pos) = s.data.message_value.content.dword;
2168
                    break;
2169
 
2170
                case 0x41:
2171
                    *(buf + pos) = s.data.message_value.content.sdword >> 24;
2172
                    pos++;
2173
                    *(buf + pos) = s.data.message_value.content.sdword >> 16;
2174
                    pos++;
2175
                    *(buf + pos) = s.data.message_value.content.sdword >> 8;
2176
                    pos++;
2177
                    *(buf + pos) = s.data.message_value.content.sdword;
2178
                    break;
2179
 
2180
                case 0x4f:
2181
                    memcpy(buf + pos, &s.data.message_value.content.fvalue, 4);
2182
                    pos += 3;
2183
                    break;
2184
 
2185
                case 0x8f:
2186
                    memcpy(buf + pos, &s.data.message_value.content.fvalue, 8);
2187
                    pos += 3;
2188
                    break;
2189
            }
2190
 
2191
            pos++;
2192
            *(buf + pos) = calcChecksum(buf, pos);
2193
            valid = true;
13 andreas 2194
        break;
11 andreas 2195
 
2196
        case 0x000b:
2197
        case 0x000c:
2198
        case 0x008b:
2199
        case 0x008c:
2200
            *(buf + 22) = s.data.message_string.device >> 8;
2201
            *(buf + 23) = s.data.message_string.device;
2202
            *(buf + 24) = s.data.message_string.port >> 8;
2203
            *(buf + 25) = s.data.message_string.port;
2204
            *(buf + 26) = s.data.message_string.system >> 8;
2205
            *(buf + 27) = s.data.message_string.system;
2206
            *(buf + 28) = s.data.message_string.type;
2207
            *(buf + 29) = s.data.message_string.length >> 8;
2208
            *(buf + 30) = s.data.message_string.length;
2209
            pos = 31;
2210
            memcpy(buf + pos, s.data.message_string.content, s.data.message_string.length);
2211
            pos += s.data.message_string.length;
2212
            *(buf + pos) = calcChecksum(buf, pos);
2213
            valid = true;
13 andreas 2214
        break;
11 andreas 2215
 
2216
        case 0x008d:    // Custom event
2217
            *(buf + 22) = s.data.customEvent.device >> 8;
2218
            *(buf + 23) = s.data.customEvent.device;
2219
            *(buf + 24) = s.data.customEvent.port >> 8;
2220
            *(buf + 25) = s.data.customEvent.port;
2221
            *(buf + 26) = s.data.customEvent.system >> 8;
2222
            *(buf + 27) = s.data.customEvent.system;
2223
            *(buf + 28) = s.data.customEvent.ID >> 8;
2224
            *(buf + 29) = s.data.customEvent.ID;
2225
            *(buf + 30) = s.data.customEvent.type >> 8;
2226
            *(buf + 31) = s.data.customEvent.type;
2227
            *(buf + 32) = s.data.customEvent.flag >> 8;
2228
            *(buf + 33) = s.data.customEvent.flag;
2229
            *(buf + 34) = s.data.customEvent.value1 >> 24;
2230
            *(buf + 35) = s.data.customEvent.value1 >> 16;
2231
            *(buf + 36) = s.data.customEvent.value1 >> 8;
2232
            *(buf + 37) = s.data.customEvent.value1;
2233
            *(buf + 38) = s.data.customEvent.value2 >> 24;
2234
            *(buf + 39) = s.data.customEvent.value2 >> 16;
2235
            *(buf + 40) = s.data.customEvent.value2 >> 8;
2236
            *(buf + 41) = s.data.customEvent.value2;
2237
            *(buf + 42) = s.data.customEvent.value3 >> 24;
2238
            *(buf + 43) = s.data.customEvent.value3 >> 16;
2239
            *(buf + 44) = s.data.customEvent.value3 >> 8;
2240
            *(buf + 45) = s.data.customEvent.value3;
2241
            *(buf + 46) = s.data.customEvent.dtype;
2242
            *(buf + 47) = s.data.customEvent.length >> 8;
2243
            *(buf + 48) = s.data.customEvent.length;
2244
            pos = 49;
2245
 
2246
            if (s.data.customEvent.length > 0)
2247
            {
2248
                memcpy(buf + pos, s.data.customEvent.data, s.data.customEvent.length);
2249
                pos += s.data.customEvent.length;
2250
            }
2251
 
2252
            *(buf + pos) = 0;
2253
            *(buf + pos + 1) = 0;
2254
            pos += 2;
2255
            *(buf + pos) = calcChecksum(buf, pos);
2256
            valid = true;
13 andreas 2257
        break;
11 andreas 2258
 
2259
        case 0x0090:
2260
            *(buf + 22) = s.data.sendPortNumber.device >> 8;
2261
            *(buf + 23) = s.data.sendPortNumber.device;
2262
            *(buf + 24) = s.data.sendPortNumber.system >> 8;
2263
            *(buf + 25) = s.data.sendPortNumber.system;
2264
            *(buf + 26) = s.data.sendPortNumber.pcount >> 8;
2265
            *(buf + 27) = s.data.sendPortNumber.pcount;
2266
            *(buf + 28) = calcChecksum(buf, 28);
2267
            valid = true;
13 andreas 2268
        break;
11 andreas 2269
 
2270
        case 0x0091:
2271
        case 0x0092:
2272
            *(buf + 22) = s.data.sendOutpChannels.device >> 8;
2273
            *(buf + 23) = s.data.sendOutpChannels.device;
2274
            *(buf + 24) = s.data.sendOutpChannels.port >> 8;
2275
            *(buf + 25) = s.data.sendOutpChannels.port;
2276
            *(buf + 26) = s.data.sendOutpChannels.system >> 8;
2277
            *(buf + 27) = s.data.sendOutpChannels.system;
2278
            *(buf + 28) = s.data.sendOutpChannels.count >> 8;
2279
            *(buf + 29) = s.data.sendOutpChannels.count;
2280
            *(buf + 30) = calcChecksum(buf, 30);
2281
            valid = true;
13 andreas 2282
        break;
11 andreas 2283
 
2284
        case 0x0093:
2285
        case 0x0094:
2286
            *(buf + 22) = s.data.sendSize.device >> 8;
2287
            *(buf + 23) = s.data.sendSize.device;
2288
            *(buf + 24) = s.data.sendSize.port >> 8;
2289
            *(buf + 25) = s.data.sendSize.port;
2290
            *(buf + 26) = s.data.sendSize.system >> 8;
2291
            *(buf + 27) = s.data.sendSize.system;
2292
            *(buf + 28) = s.data.sendSize.type;
2293
            *(buf + 29) = s.data.sendSize.length >> 8;
2294
            *(buf + 30) = s.data.sendSize.length;
2295
            *(buf + 31) = calcChecksum(buf, 31);
2296
            valid = true;
13 andreas 2297
        break;
11 andreas 2298
 
2299
        case 0x0095:
2300
            *(buf + 22) = s.data.sendLevSupport.device >> 8;
2301
            *(buf + 23) = s.data.sendLevSupport.device;
2302
            *(buf + 24) = s.data.sendLevSupport.port >> 8;
2303
            *(buf + 25) = s.data.sendLevSupport.port;
2304
            *(buf + 26) = s.data.sendLevSupport.system >> 8;
2305
            *(buf + 27) = s.data.sendLevSupport.system;
2306
            *(buf + 28) = s.data.sendLevSupport.level >> 8;
2307
            *(buf + 29) = s.data.sendLevSupport.level;
2308
            *(buf + 30) = s.data.sendLevSupport.num;
2309
            *(buf + 31) = s.data.sendLevSupport.types[0];
2310
            *(buf + 32) = s.data.sendLevSupport.types[1];
2311
            *(buf + 33) = s.data.sendLevSupport.types[2];
2312
            *(buf + 34) = s.data.sendLevSupport.types[3];
2313
            *(buf + 35) = s.data.sendLevSupport.types[4];
2314
            *(buf + 36) = s.data.sendLevSupport.types[5];
2315
            *(buf + 37) = calcChecksum(buf, 37);
2316
            valid = true;
13 andreas 2317
        break;
11 andreas 2318
 
2319
        case 0x0096:
2320
            *(buf + 22) = s.data.sendStatusCode.device >> 8;
2321
            *(buf + 23) = s.data.sendStatusCode.device;
2322
            *(buf + 24) = s.data.sendStatusCode.port >> 8;
2323
            *(buf + 25) = s.data.sendStatusCode.port;
2324
            *(buf + 26) = s.data.sendStatusCode.system >> 8;
2325
            *(buf + 27) = s.data.sendStatusCode.system;
2326
            *(buf + 28) = s.data.sendStatusCode.status >> 8;
2327
            *(buf + 29) = s.data.sendStatusCode.status;
2328
            *(buf + 30) = s.data.sendStatusCode.type;
2329
            *(buf + 31) = s.data.sendStatusCode.length >> 8;
2330
            *(buf + 32) = s.data.sendStatusCode.length;
2331
            pos = 33;
2332
            memset((void*)&s.data.sendStatusCode.str[0], 0, sizeof(s.data.sendStatusCode.str));
2333
            memcpy(buf + pos, s.data.sendStatusCode.str, s.data.sendStatusCode.length);
2334
            pos += s.data.sendStatusCode.length;
2335
            *(buf + pos) = calcChecksum(buf, pos);
2336
            valid = true;
13 andreas 2337
        break;
11 andreas 2338
 
2339
        case 0x0097:
2340
            *(buf + 22) = s.data.srDeviceInfo.device >> 8;
2341
            *(buf + 23) = s.data.srDeviceInfo.device;
2342
            *(buf + 24) = s.data.srDeviceInfo.system >> 8;
2343
            *(buf + 25) = s.data.srDeviceInfo.system;
2344
            *(buf + 26) = s.data.srDeviceInfo.flag >> 8;
2345
            *(buf + 27) = s.data.srDeviceInfo.flag;
2346
            *(buf + 28) = s.data.srDeviceInfo.objectID;
2347
            *(buf + 29) = s.data.srDeviceInfo.parentID;
2348
            *(buf + 30) = s.data.srDeviceInfo.herstID >> 8;
2349
            *(buf + 31) = s.data.srDeviceInfo.herstID;
2350
            *(buf + 32) = s.data.srDeviceInfo.deviceID >> 8;
2351
            *(buf + 33) = s.data.srDeviceInfo.deviceID;
2352
            pos = 34;
2353
            memcpy(buf + pos, s.data.srDeviceInfo.serial, 16);
2354
            pos += 16;
2355
            *(buf + pos) = s.data.srDeviceInfo.fwid >> 8;
2356
            pos++;
2357
            *(buf + pos) = s.data.srDeviceInfo.fwid;
2358
            pos++;
2359
            memcpy(buf + pos, s.data.srDeviceInfo.info, s.data.srDeviceInfo.len);
2360
            pos += s.data.srDeviceInfo.len;
2361
            *(buf + pos) = calcChecksum(buf, pos);
2362
            valid = true;
13 andreas 2363
        break;
11 andreas 2364
 
2365
        case 0x0098:
2366
            *(buf + 22) = s.data.reqPortCount.device >> 8;
2367
            *(buf + 23) = s.data.reqPortCount.device;
2368
            *(buf + 24) = s.data.reqPortCount.system >> 8;
2369
            *(buf + 25) = s.data.reqPortCount.system;
2370
            *(buf + 26) = calcChecksum(buf, 26);
2371
            valid = true;
13 andreas 2372
        break;
11 andreas 2373
 
2374
        case 0x0204:    // file transfer
2375
            *(buf + 22) = s.data.filetransfer.ftype >> 8;
2376
            *(buf + 23) = s.data.filetransfer.ftype;
2377
            *(buf + 24) = s.data.filetransfer.function >> 8;
2378
            *(buf + 25) = s.data.filetransfer.function;
2379
            pos = 26;
2380
 
2381
            switch (s.data.filetransfer.function)
2382
            {
2383
                case 0x0001:
2384
                    *(buf + 26) = s.data.filetransfer.unk;
2385
                    *(buf + 27) = s.data.filetransfer.unk1;
2386
                    pos = 28;
13 andreas 2387
                break;
11 andreas 2388
 
2389
                case 0x0003:
2390
                    *(buf + 26) = s.data.filetransfer.unk >> 8;
2391
                    *(buf + 27) = s.data.filetransfer.unk;
2392
                    pos = 28;
2393
 
2394
                    for (uint32_t i = 0; i < s.data.filetransfer.unk && pos < (s.hlen + 3); i++)
2395
                    {
2396
                        *(buf + pos) = s.data.filetransfer.data[i];
2397
                        pos++;
2398
                    }
13 andreas 2399
                break;
11 andreas 2400
 
2401
                case 0x0101:
2402
                    if (s.data.filetransfer.ftype == 0)
2403
                    {
2404
                        *(buf + 26) = s.data.filetransfer.unk >> 24;
2405
                        *(buf + 27) = s.data.filetransfer.unk >> 16;
2406
                        *(buf + 28) = s.data.filetransfer.unk >> 8;
2407
                        *(buf + 29) = s.data.filetransfer.unk;
2408
                        *(buf + 30) = s.data.filetransfer.unk1 >> 24;
2409
                        *(buf + 31) = s.data.filetransfer.unk1 >> 16;
2410
                        *(buf + 32) = s.data.filetransfer.unk1 >> 8;
2411
                        *(buf + 33) = s.data.filetransfer.unk1;
2412
                        *(buf + 34) = s.data.filetransfer.unk2 >> 24;
2413
                        *(buf + 35) = s.data.filetransfer.unk2 >> 16;
2414
                        *(buf + 36) = s.data.filetransfer.unk2 >> 8;
2415
                        *(buf + 37) = s.data.filetransfer.unk2;
2416
                        *(buf + 38) = 0x00;
2417
                        *(buf + 39) = 0x00;
2418
                        *(buf + 40) = 0x3e;
2419
                        *(buf + 41) = 0x75;
2420
                        pos = 42;
2421
                        len = 0;
2422
 
2423
                        while (s.data.filetransfer.data[len] != 0)
2424
                        {
2425
                            *(buf + pos) = s.data.filetransfer.data[len];
2426
                            len++;
2427
                            pos++;
2428
                        }
2429
 
2430
                        *(buf + pos) = 0;
2431
                        pos++;
2432
                    }
2433
                    else
2434
                    {
2435
                        *(buf + 26) = s.data.filetransfer.unk >> 24;
2436
                        *(buf + 27) = s.data.filetransfer.unk >> 16;
2437
                        *(buf + 28) = s.data.filetransfer.unk >> 8;
2438
                        *(buf + 29) = s.data.filetransfer.unk;
2439
                        *(buf + 30) = 0x00;
2440
                        *(buf + 31) = 0x00;
2441
                        *(buf + 32) = 0x00;
2442
                        *(buf + 33) = 0x00;
2443
                        pos = 34;
2444
                    }
2445
 
13 andreas 2446
                break;
11 andreas 2447
 
2448
                case 0x0102:
2449
                    *(buf + 26) = 0x00;
2450
                    *(buf + 27) = 0x00;
2451
                    *(buf + 28) = 0x00;
2452
                    *(buf + 29) = s.data.filetransfer.info1;        // dir flag
2453
                    *(buf + 30) = s.data.filetransfer.info2 >> 8;   // # entries
2454
                    *(buf + 31) = s.data.filetransfer.info2;
2455
                    *(buf + 32) = s.data.filetransfer.unk >> 8;     // counter
2456
                    *(buf + 33) = s.data.filetransfer.unk;
2457
                    *(buf + 34) = s.data.filetransfer.unk1 >> 24;   // file size
2458
                    *(buf + 35) = s.data.filetransfer.unk1 >> 16;
2459
                    *(buf + 36) = s.data.filetransfer.unk1 >> 8;
2460
                    *(buf + 37) = s.data.filetransfer.unk1;
2461
                    *(buf + 38) = (s.data.filetransfer.info1 == 1) ? 0x0c : 0x0b;
2462
                    *(buf + 39) = (s.data.filetransfer.info1 == 1) ? 0x0e : 0x13;
2463
                    *(buf + 40) = 0x07;
2464
                    *(buf + 41) = s.data.filetransfer.unk2 >> 24;   // Date
2465
                    *(buf + 42) = s.data.filetransfer.unk2 >> 16;
2466
                    *(buf + 43) = s.data.filetransfer.unk2 >> 8;
2467
                    *(buf + 44) = s.data.filetransfer.unk2;
2468
                    pos = 45;
2469
                    len = 0;
2470
 
2471
                    while (s.data.filetransfer.data[len] != 0)
2472
                    {
2473
                        *(buf + pos) = s.data.filetransfer.data[len];
2474
                        pos++;
2475
                        len++;
2476
                    }
2477
 
2478
                    *(buf + pos) = 0;
2479
                    pos++;
13 andreas 2480
                break;
11 andreas 2481
 
2482
                case 0x0103:
2483
                    *(buf + 26) = s.data.filetransfer.unk >> 8;
2484
                    *(buf + 27) = s.data.filetransfer.unk;
2485
                    *(buf + 28) = s.data.filetransfer.unk1 >> 24;
2486
                    *(buf + 29) = s.data.filetransfer.unk1 >> 16;
2487
                    *(buf + 30) = s.data.filetransfer.unk1 >> 8;
2488
                    *(buf + 31) = s.data.filetransfer.unk1;
2489
                    pos = 32;
13 andreas 2490
                break;
11 andreas 2491
 
2492
                case 0x105:
2493
                    *(buf + 26) = s.data.filetransfer.unk >> 24;
2494
                    *(buf + 27) = s.data.filetransfer.unk >> 16;
2495
                    *(buf + 28) = s.data.filetransfer.unk >> 8;
2496
                    *(buf + 29) = s.data.filetransfer.unk;
2497
                    *(buf + 30) = s.data.filetransfer.unk1 >> 24;
2498
                    *(buf + 31) = s.data.filetransfer.unk1 >> 16;
2499
                    *(buf + 32) = s.data.filetransfer.unk1 >> 8;
2500
                    *(buf + 33) = s.data.filetransfer.unk1;
2501
                    pos = 34;
13 andreas 2502
                break;
11 andreas 2503
            }
2504
 
2505
            *(buf + pos) = calcChecksum(buf, pos);
2506
            valid = true;
13 andreas 2507
        break;
11 andreas 2508
 
2509
        case 0x0581:    // Pong
2510
            *(buf + 22) = s.data.srDeviceInfo.device >> 8;
2511
            *(buf + 23) = s.data.srDeviceInfo.device;
2512
            *(buf + 24) = s.data.srDeviceInfo.system >> 8;
2513
            *(buf + 25) = s.data.srDeviceInfo.system;
2514
            *(buf + 26) = s.data.srDeviceInfo.herstID >> 8;
2515
            *(buf + 27) = s.data.srDeviceInfo.herstID;
2516
            *(buf + 28) = s.data.srDeviceInfo.deviceID >> 8;
2517
            *(buf + 29) = s.data.srDeviceInfo.deviceID;
2518
            *(buf + 30) = s.data.srDeviceInfo.info[0];
2519
            *(buf + 31) = s.data.srDeviceInfo.info[1];
2520
            *(buf + 32) = s.data.srDeviceInfo.info[2];
2521
            *(buf + 33) = s.data.srDeviceInfo.info[3];
2522
            *(buf + 34) = s.data.srDeviceInfo.info[4];
2523
            *(buf + 35) = s.data.srDeviceInfo.info[5];
2524
            *(buf + 36) = calcChecksum(buf, 36);
2525
            valid = true;
13 andreas 2526
        break;
11 andreas 2527
    }
2528
 
2529
    if (!valid)
2530
    {
2531
        delete[] buf;
2532
        return 0;
2533
    }
2534
 
13 andreas 2535
//    MSG_TRACE("Buffer:");
2536
//    TError::logHex((char *)buf, s.hlen + 4);
11 andreas 2537
    return buf;
2538
}
2539
 
2540
void TAmxNet::setSerialNum(const string& sn)
2541
{
2542
    DECL_TRACER("TAmxNet::setSerialNum(const string& sn)");
2543
 
2544
    serNum = sn;
2545
    size_t len = (sn.length() > 15) ? 15 : sn.length();
2546
 
2547
    for (size_t i = 0; i < devInfo.size(); i++)
2548
        memcpy(devInfo[i].serialNum, sn.c_str(), len);
2549
}
2550
 
2551
int TAmxNet::countFiles()
2552
{
2553
    DECL_TRACER("TAmxNet::countFiles()");
2554
 
2555
    int count = 0;
2556
    ifstream in;
2557
 
2558
    try
2559
    {
2560
        in.open(TConfig::getProjectPath() + "/manifest.xma", fstream::in);
2561
 
2562
        if (!in)
2563
            return 0;
2564
 
2565
        for (string line; getline(in, line);)
2566
            count++;
2567
 
2568
        in.close();
2569
    }
2570
    catch (exception& e)
2571
    {
2572
        MSG_ERROR("Error: " << e.what());
2573
        return 0;
2574
    }
2575
 
2576
    return count;
2577
}
15 andreas 2578
 
2579
void TAmxNet::sendAllFuncNetwork(int state)
2580
{
2581
    DECL_TRACER("TAmxNet::sendAllFuncNetwork(int state)");
2582
 
17 andreas 2583
    if (mFuncsNetwork.empty())
2584
        return;
2585
 
15 andreas 2586
    map<ulong, FUNC_NETWORK_t>::iterator iter;
2587
 
2588
    for (iter = mFuncsNetwork.begin(); iter != mFuncsNetwork.end(); iter++)
2589
        iter->second.func(state);
2590
}
2591
 
2592
void TAmxNet::sendAllFuncTimer(const ANET_BLINK& blink)
2593
{
2594
    DECL_TRACER("TAmxNet::sendAllFuncTimer(const ANET_BLINK& blink)");
2595
 
17 andreas 2596
    if (mFuncsTimer.empty())
2597
        return;
2598
 
15 andreas 2599
    map<ulong, FUNC_TIMER_t>::iterator iter;
2600
 
2601
    for (iter = mFuncsTimer.begin(); iter != mFuncsTimer.end(); iter++)
2602
        iter->second.func(blink);
2603
}