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
        }
23 andreas 1474
 
1475
        if (dr.getNumEntries() == 0)
1476
        {
1477
            s.type = 0x0102;
1478
 
1479
            s.value = 0;
1480
            s.level = 0;       // # entries
1481
            s.value1 = 0;                // counter
1482
            s.value2 = 0;                 // Size of file
1483
            s.value3 = 0;                 // Last modification date (epoch)
1484
            s.msg.assign(amxpath + "/");
1485
            sendCommand(s);
1486
        }
11 andreas 1487
    }
1488
    else if (ft.ftype == 4 && ft.function == 0x0100)    // Have more files to send.
1489
    {
1490
        MSG_TRACE("0x0004/0x0100: Have more files to send.");
1491
        s.channel = 0;
1492
        s.level = 0;
1493
        s.port = 0;
1494
        s.value = 0;
1495
        s.MC = 0x0204;
1496
        s.dtype = 4;                // ftype --> function type
1497
        s.type = 0x0101;            // function:
1498
        s.value1 = 0x01bb3000;      // ?
1499
        s.value2 = 0;               // ?
1500
        sendCommand(s);
1501
    }
1502
    else if (ft.ftype == 4 && ft.function == 0x0102)    // Controller will send a file
1503
    {
1504
        string f((char*)&ft.data);
1505
        size_t pos;
1506
        rcvFileName.assign(TConfig::getProjectPath());
1507
 
1508
        if (f.find("AMXPanel") != string::npos)
1509
        {
1510
            pos = f.find_first_of("/");
1511
            rcvFileName.append(f.substr(pos));
1512
        }
1513
        else
1514
        {
1515
            rcvFileName.append("/");
1516
            rcvFileName.append((char*)&ft.data);
1517
        }
1518
 
1519
        if (rcvFile != nullptr)
1520
            fclose(rcvFile);
1521
 
1522
        rcvFile = fopen(rcvFileName.c_str(), "w+");
1523
 
1524
        if (!rcvFile)
1525
        {
1526
            MSG_ERROR("Error creating file " << rcvFileName);
1527
            isOpenRcv = false;
1528
        }
1529
        else
1530
            isOpenRcv = true;
1531
 
1532
        MSG_TRACE("0x0004/0x0102: Controller will send file " << rcvFileName);
1533
        ftransfer.actFileNum++;
1534
        ftransfer.lengthFile = ft.unk;
1535
 
1536
        if (ftransfer.actFileNum > ftransfer.maxFiles)
1537
            ftransfer.maxFiles = ftransfer.actFileNum;
1538
 
1539
        ftransfer.percent = (int)(100.0 / (double)ftransfer.maxFiles * (double)ftransfer.actFileNum);
1540
        pos = rcvFileName.find_last_of("/");
1541
        string shfn;
1542
 
1543
        if (pos != string::npos)
1544
            shfn = cp1250ToUTF8(rcvFileName.substr(pos + 1));
1545
        else
1546
            shfn = cp1250ToUTF8(rcvFileName);
1547
 
1548
        snprintf((char*)&ftr.data.filetransfer.data[0], sizeof(ftr.data.filetransfer.data), "[%d/%d]&nbsp;%s", ftransfer.actFileNum, ftransfer.maxFiles, shfn.c_str());
1549
        ftr.count = ftransfer.percent;
1550
        ftr.data.filetransfer.info1 = 0;
1551
 
1552
        if (callback)
1553
            callback(ftr);
13 andreas 1554
        else
1555
            MSG_WARNING("Missing callback function!");
11 andreas 1556
 
1557
        posRcv = 0;
1558
        lenRcv = ft.unk;
1559
        s.channel = 0;
1560
        s.level = 0;
1561
        s.port = 0;
1562
        s.value = 0;
1563
        s.MC = 0x0204;
1564
        s.dtype = 4;                // ftype --> function type
1565
        s.type = 0x0103;            // function: ready for receiving file
1566
        s.value1 = MAX_CHUNK;       // Maximum length of a chunk
1567
        s.value2 = ft.unk1;         // ID?
1568
        sendCommand(s);
1569
    }
1570
    else if (ft.ftype == 0 && ft.function == 0x0104)    // Delete file <name>
1571
    {
1572
        dir::TDirectory dr;
1573
        s.channel = 0;
1574
        s.level = 0;
1575
        s.port = 0;
1576
        s.value = 0;
1577
        s.MC = 0x0204;
1578
        string f((char*)&ft.data[0]);
1579
        size_t pos = 0;
1580
 
1581
        if ((pos = f.find("AMXPanel/")) == string::npos)
1582
            pos = f.find("__system/");
1583
 
1584
        MSG_TRACE("0x0000/0x0104: Delete file " << f);
1585
 
1586
        if (pos != string::npos)
1587
            f = TConfig::getProjectPath() + "/" + f.substr(pos + 9);
1588
        else
1589
            f = TConfig::getProjectPath() + "/" + f;
1590
 
1591
        if (dr.exists(f))
1592
        {
1593
            s.dtype = 0;                // ftype --> function type
1594
            s.type = 0x0002;            // function: yes file exists
1595
            remove(f.c_str());
1596
        }
1597
        else    // Send: file was deleted although it does not exist.
1598
        {
1599
            MSG_ERROR("[DELETE] File " << f << " not found!");
1600
            s.dtype = 0;                // ftype --> function type
1601
            s.type = 0x0002;            // function: yes file exists
1602
        }
1603
 
1604
        sendCommand(s);
1605
 
1606
        if (ftransfer.actDelFile == 0)
1607
        {
1608
            ftransfer.actDelFile++;
1609
            ftransfer.percent = (int)(100.0 / (double)ftransfer.maxFiles * (double)ftransfer.actDelFile);
1610
            ftr.count = ftransfer.percent;
1611
 
1612
            if (callback)
1613
                callback(ftr);
13 andreas 1614
            else
1615
                MSG_WARNING("Missing callback function!");
11 andreas 1616
        }
1617
        else
1618
        {
1619
            ftransfer.actDelFile++;
1620
            int prc = (int)(100.0 / (double)ftransfer.maxFiles * (double)ftransfer.actDelFile);
1621
 
1622
            if (prc != ftransfer.percent)
1623
            {
1624
                ftransfer.percent = prc;
1625
                ftr.count = prc;
1626
 
1627
                if (callback)
1628
                    callback(ftr);
13 andreas 1629
                else
1630
                    MSG_WARNING("Missing callback function!");
11 andreas 1631
            }
1632
        }
1633
    }
1634
    else if (ft.ftype == 4 && ft.function == 0x0104)    // request a file
1635
    {
1636
        string f((char*)&ft.data);
1637
        size_t pos;
1638
        len = 0;
1639
        sndFileName.assign(TConfig::getProjectPath());
1640
        MSG_TRACE("0x0004/0x0104: Request file " << f);
1641
 
1642
        if (f.find("AMXPanel") != string::npos)
1643
        {
1644
            pos = f.find_first_of("/");
1645
            sndFileName.append(f.substr(pos));
1646
        }
1647
        else
1648
        {
1649
            sndFileName.append("/");
1650
            sndFileName.append(f);
1651
        }
1652
 
1653
        if (!access(sndFileName.c_str(), R_OK))
1654
        {
1655
            struct stat s;
1656
 
1657
            if (stat(sndFileName.c_str(), &s) == 0)
1658
                len = s.st_size;
1659
            else
1660
                len = 0;
1661
        }
1662
        else if (sndFileName.find("/version.xma") > 0)
1663
            len = 0x0015;
1664
        else
1665
            len = 0;
1666
 
1667
        MSG_TRACE("0x0004/0x0104: (" << len << ") File: " << sndFileName);
1668
 
1669
        s.channel = 0;
1670
        s.level = 0;
1671
        s.port = 0;
1672
        s.value = 0;
1673
        s.MC = 0x0204;
1674
        s.dtype = 4;                // ftype --> function type
1675
        s.type = 0x0105;            // function
1676
        s.value1 = len;             // length of file to send
1677
        s.value2 = 0x00001388;      // ID for device when sending a file.
1678
        sendCommand(s);
1679
    }
1680
    else if (ft.ftype == 4 && ft.function == 0x0106)    // Controller is ready for receiving file
1681
    {
1682
        MSG_TRACE("0x0004/0x0106: Controller is ready for receiving file.");
1683
 
1684
        if (!access(sndFileName.c_str(), R_OK))
1685
        {
1686
            struct stat st;
1687
            stat(sndFileName.c_str(), &st);
1688
            len = st.st_size;
1689
            lenSnd = len;
1690
            posSnd = 0;
1691
            sndFile = fopen(sndFileName.c_str(), "r");
1692
 
1693
            if (!sndFile)
1694
            {
1695
                MSG_ERROR("Error reading file " << sndFileName);
1696
                len = 0;
1697
                isOpenSnd = false;
1698
            }
1699
            else
1700
                isOpenSnd = true;
1701
 
1702
            if (isOpenSnd && len <= MAX_CHUNK)
1703
            {
1704
                char *buf = new char[len + 1];
1705
                fread(buf, 1, len, sndFile);
1706
                s.msg.assign(buf, len);
1707
                delete[] buf;
1708
                posSnd = len;
1709
            }
1710
            else if (isOpenSnd)
1711
            {
1712
                char *buf = new char[MAX_CHUNK + 1];
1713
                fread(buf, 1, MAX_CHUNK, sndFile);
1714
                s.msg.assign(buf, MAX_CHUNK);
1715
                delete[] buf;
1716
                posSnd = MAX_CHUNK;
1717
                len = MAX_CHUNK;
1718
            }
1719
        }
1720
        else if (sndFileName.find("/version.xma") > 0)
1721
        {
1722
            s.msg.assign("<version>9</version>\n");
1723
            len = s.msg.length();
1724
            posSnd = len;
1725
        }
1726
        else
1727
            len = 0;
1728
 
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
        s.type = 0x0003;            // function: Sending file with length <len>
1736
        s.value1 = len;             // length of content to send
1737
        sendCommand(s);
1738
    }
1739
    else if (ft.ftype == 4 && ft.function == 0x0002)    // request next part of file
1740
    {
1741
        MSG_TRACE("0x0004/0x0002: Request next part of file.");
1742
        s.channel = 0;
1743
        s.level = 0;
1744
        s.port = 0;
1745
        s.value = 0;
1746
        s.MC = 0x0204;
1747
        s.dtype = 4;                // ftype --> function type
1748
 
1749
        if (posSnd < lenSnd)
1750
        {
1751
            s.type = 0x0003;        // Next part of file
1752
 
1753
            if ((posSnd + MAX_CHUNK) > lenSnd)
1754
                len = lenSnd - posSnd;
1755
            else
1756
                len = MAX_CHUNK;
1757
 
1758
            s.value1 = len;
1759
 
1760
            if (isOpenSnd)
1761
            {
1762
                char *buf = new char[len + 1];
1763
                fread(buf, 1, len, sndFile);
1764
                s.msg.assign(buf, len);
1765
                delete[] buf;
1766
                posSnd += len;
1767
            }
1768
            else
1769
                s.value1 = 0;
1770
        }
1771
        else
1772
            s.type = 0x0004;        // function: End of file reached
1773
 
1774
        sendCommand(s);
1775
    }
1776
    else if (ft.ftype == 4 && ft.function == 0x0003)    // File content
1777
    {
1778
        MSG_TRACE("0x0004/0x0003: Received (part of) file.");
1779
        len = ft.unk;
1780
 
1781
        if (isOpenRcv)
1782
        {
1783
            fwrite(ft.data, 1, len, rcvFile);
1784
            posRcv += ft.unk;
1785
        }
1786
        else
1787
            MSG_WARNING("No open file to write to!");
1788
 
1789
        s.channel = 0;
1790
        s.level = 0;
1791
        s.port = 0;
1792
        s.value = 0;
1793
        s.MC = 0x0204;
1794
        s.dtype = 4;                // ftype --> function type
1795
        s.type = 0x0002;            // function: Request next part of file
1796
        sendCommand(s);
1797
 
1798
        int prc = (int)(100.0 / (double)ftransfer.lengthFile * (double)posRcv);
1799
 
1800
        if (prc != ftr.data.filetransfer.info1)
1801
        {
1802
            ftr.data.filetransfer.info1 = (int)(100.0 / (double)ftransfer.lengthFile * (double)posRcv);
1803
            ftr.count = ftransfer.percent;
1804
 
1805
            if (callback)
1806
                callback(ftr);
13 andreas 1807
            else
1808
                MSG_WARNING("Missing callback function!");
11 andreas 1809
        }
1810
    }
1811
    else if (ft.ftype == 4 && ft.function == 0x0004)    // End of file
1812
    {
1813
        MSG_TRACE("0x0004/0x0004: End of file.");
1814
 
1815
        if (isOpenRcv)
1816
        {
1817
            unsigned char buf[8];
1818
            fseek(rcvFile, 0, SEEK_SET);
1819
            fread(buf, 1, sizeof(buf), rcvFile);
1820
            fclose(rcvFile);
1821
            isOpenRcv = false;
1822
            rcvFile = nullptr;
1823
            posRcv = 0;
1824
 
1825
            if (buf[0] == 0x1f && buf[1] == 0x8b)   // GNUzip compressed?
1826
            {
1827
                TExpand exp(rcvFileName);
1828
                exp.unzip();
1829
            }
1830
        }
1831
 
1832
        ftr.count = ftransfer.percent;
1833
        ftr.data.filetransfer.info1 = 100;
1834
 
1835
        if (callback)
1836
            callback(ftr);
13 andreas 1837
        else
1838
            MSG_WARNING("Missing callback functiom!");
11 andreas 1839
 
1840
        s.channel = 0;
1841
        s.level = 0;
1842
        s.port = 0;
1843
        s.value = 0;
1844
        s.MC = 0x0204;
1845
        s.dtype = 4;                // ftype --> function type
1846
        s.type = 0x0005;            // function: ACK, file received. No answer expected.
1847
        sendCommand(s);
1848
    }
1849
    else if (ft.ftype == 4 && ft.function == 0x0005)    // ACK, controller received file, no answer
1850
    {
1851
        MSG_TRACE("0x0004/0x0005: Controller received file.");
1852
        posSnd = 0;
1853
        lenSnd = 0;
1854
 
1855
        if (isOpenSnd && sndFile != nullptr)
1856
            fclose(sndFile);
1857
 
1858
        ftransfer.lengthFile = 0;
1859
        sndFile = nullptr;
1860
    }
1861
    else if (ft.ftype == 4 && ft.function == 0x0006)    // End of directory transfer ACK
1862
    {
1863
        MSG_TRACE("0x0004/0x0006: End of directory transfer.");
1864
    }
1865
    else if (ft.ftype == 4 && ft.function == 0x0007)    // End of file transfer
1866
    {
1867
        MSG_TRACE("0x0004/0x0007: End of file transfer.");
1868
 
1869
        if (callback)
1870
            callback(ftr);
13 andreas 1871
        else
1872
            MSG_WARNING("Missing callback function!");
11 andreas 1873
 
1874
        receiveSetup = false;
1875
    }
1876
}
1877
 
1878
int TAmxNet::msg97fill(ANET_COMMAND *com)
1879
{
1880
    DECL_TRACER("TAmxNet::msg97fill(ANET_COMMAND *com)");
1881
 
1882
    int pos = 0;
1883
    unsigned char buf[512];
1884
 
1885
    for (size_t i = 0; i < devInfo.size(); i++)
1886
    {
1887
        pos = 0;
1888
 
1889
        if (i == 0)
1890
            com->sep1 = 0x12;
1891
        else
1892
            com->sep1 = 0x02;
1893
 
1894
        memset(buf, 0, sizeof(buf));
1895
        com->data.srDeviceInfo.objectID = devInfo[i].objectID;
1896
        com->data.srDeviceInfo.parentID = devInfo[i].parentID;
1897
        com->data.srDeviceInfo.herstID = devInfo[i].manufacturerID;
1898
        com->data.srDeviceInfo.deviceID = devInfo[i].deviceID;
1899
        memcpy(com->data.srDeviceInfo.serial, devInfo[i].serialNum, 16);
1900
        com->data.srDeviceInfo.fwid = devInfo[i].firmwareID;
1901
        memcpy(buf, devInfo[i].versionInfo, strlen(devInfo[i].versionInfo));
1902
        pos = (int)strlen(devInfo[i].versionInfo) + 1;
1903
        memcpy(buf + pos, devInfo[i].deviceInfo, strlen(devInfo[i].deviceInfo));
1904
        pos += strlen(devInfo[i].deviceInfo) + 1;
1905
        memcpy(buf + pos, devInfo[i].manufacturerInfo, strlen(devInfo[i].manufacturerInfo));
1906
        pos += strlen(devInfo[i].manufacturerInfo) + 1;
1907
        *(buf + pos) = 0x02; // type IP address
1908
        pos++;
1909
        *(buf + pos) = 0x04; // field length: 4 bytes
1910
        // Now the IP Address
1911
        string addr = socket_.local_endpoint().address().to_string();
1912
        vector<string> parts = StrSplit(addr, ".");
1913
 
1914
        for (size_t i = 0; i < parts.size(); i++)
1915
        {
1916
            pos++;
1917
            *(buf + pos) = (unsigned char)atoi(parts[i].c_str());
1918
        }
1919
 
1920
        pos++;
1921
        com->data.srDeviceInfo.len = pos;
1922
        memcpy(com->data.srDeviceInfo.info, buf, pos);
1923
        com->hlen = 0x0016 - 3 + 31 + pos - 1;
1924
        comStack.push_back(*com);
1925
        sendCounter++;
1926
        com->count = sendCounter;
1927
    }
1928
 
1929
    return pos;
1930
}
1931
 
1932
void TAmxNet::start_write()
1933
{
1934
    DECL_TRACER("TAmxNet::start_write()");
1935
 
1936
    if (!isRunning())
1937
        return;
1938
 
1939
    if (write_busy)
1940
        return;
1941
 
1942
    write_busy = true;
1943
 
1944
    while (comStack.size() > 0)
1945
    {
1946
        if (!isRunning())
1947
        {
1948
            comStack.clear();
1949
            write_busy = false;
1950
            return;
1951
        }
1952
 
1953
        send = comStack.at(0);
1954
        comStack.erase(comStack.begin());   // delete oldest element
1955
        unsigned char *buf = makeBuffer(send);
1956
 
1957
        if (buf == 0)
1958
        {
1959
            MSG_ERROR("Error creating a buffer! Token number: " << send.MC);
1960
            continue;
1961
        }
1962
 
14 andreas 1963
        MSG_DEBUG("Wrote buffer with " << (send.hlen + 4) << " bytes.");
11 andreas 1964
        asio::async_write(socket_, asio::buffer(buf, send.hlen + 4), bind(&TAmxNet::handle_write, this, _1));
1965
        delete[] buf;
1966
    }
1967
 
14 andreas 1968
    mSendReady = false;
11 andreas 1969
    write_busy = false;
1970
}
1971
 
1972
void TAmxNet::handle_write(const error_code& error)
1973
{
1974
    DECL_TRACER("TAmxNet::handle_write(const error_code& error)");
1975
 
1976
    if (!isRunning())
1977
        return;
1978
 
1979
    if (!error)
1980
    {
1981
        while (comStack.size() == 0)
1982
            heartbeat_timer_.expires_after(chrono::microseconds(150));
1983
 
1984
        heartbeat_timer_.async_wait(bind(&TAmxNet::start_write, this));
1985
    }
1986
    else
1987
    {
1988
        MSG_TRACE("Error on heartbeat: " << error.message());
1989
        stop();
1990
    }
1991
}
1992
 
1993
void TAmxNet::check_deadline()
1994
{
1995
    DECL_TRACER("TAmxNet::check_deadline()");
1996
 
1997
    if (!isRunning())
1998
        return;
1999
 
2000
    // Check whether the deadline has passed. We compare the deadline against
2001
    // the current time since a new asynchronous operation may have moved the
2002
    // deadline before this actor had a chance to run.
2003
    if (deadline_.expiry() <= steady_timer::clock_type::now())
2004
    {
2005
        // The deadline has passed. The socket is closed so that any outstanding
2006
        // asynchronous operations are cancelled.
2007
        if (socket_.is_open())
2008
            socket_.close();
2009
 
2010
        // There is no longer an active deadline. The expiry is set to the
2011
        // maximum time point so that the actor takes no action until a new
2012
        // deadline is set.
2013
        deadline_.expires_at(steady_timer::time_point::max());
2014
    }
2015
 
2016
    // Put the actor back to sleep.
2017
    deadline_.async_wait(bind(&TAmxNet::check_deadline, this));
2018
}
2019
 
2020
uint16_t TAmxNet::swapWord(uint16_t w)
2021
{
2022
    uint16_t word = 0;
2023
    word = ((w << 8) & 0xff00) | ((w >> 8) & 0x00ff);
2024
    return word;
2025
}
2026
 
2027
uint32_t TAmxNet::swapDWord(uint32_t dw)
2028
{
2029
    uint32_t dword = 0;
2030
    dword = ((dw << 24) & 0xff000000) | ((dw << 8) & 0x00ff0000) | ((dw >> 8) & 0x0000ff00) | ((dw >> 24) & 0x000000ff);
2031
    return dword;
2032
}
2033
 
2034
unsigned char TAmxNet::calcChecksum(const unsigned char* buffer, size_t len)
2035
{
2036
    DECL_TRACER("TAmxNet::calcChecksum(const unsigned char* buffer, size_t len)");
2037
    unsigned long sum = 0;
2038
 
2039
    for (size_t i = 0; i < len; i++)
2040
        sum += (unsigned long)(*(buffer + i)) & 0x000000ff;
2041
 
2042
    sum &= 0x000000ff;
2043
    MSG_TRACE("Checksum=" << std::setw(2) << std::setfill('0') << std::hex << sum << ", #bytes=" << len << " bytes.");
2044
    return (unsigned char)sum;
2045
}
2046
 
2047
uint16_t TAmxNet::makeWord(unsigned char b1, unsigned char b2)
2048
{
2049
    return ((b1 << 8) & 0xff00) | b2;
2050
}
2051
 
2052
uint32_t TAmxNet::makeDWord(unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4)
2053
{
2054
    return ((b1 << 24) & 0xff000000) | ((b2 << 16) & 0x00ff0000) | ((b3  << 8) & 0x0000ff00) | b4;
2055
}
2056
 
2057
bool TAmxNet::isCommand(const string& cmd)
2058
{
2059
    DECL_TRACER("TAmxNet::isCommand(string& cmd)");
2060
 
2061
    int i = 0;
2062
 
2063
    while (cmdList[i][0] != 0)
2064
    {
2065
        if (cmd.find(cmdList[i]) == 0)
2066
            return true;
2067
 
2068
        i++;
2069
    }
2070
 
2071
    return false;
2072
}
2073
 
2074
unsigned char *TAmxNet::makeBuffer(const ANET_COMMAND& s)
2075
{
2076
    DECL_TRACER("TAmxNet::makeBuffer (const ANET_COMMAND& s)");
2077
 
2078
    int pos = 0;
2079
    int len;
2080
    bool valid = false;
2081
    unsigned char *buf;
2082
 
2083
    try
2084
    {
2085
        buf = new unsigned char[s.hlen + 5];
2086
        memset(buf, 0, s.hlen + 5);
2087
    }
2088
    catch (std::exception& e)
2089
    {
2090
        MSG_ERROR("Error allocating memory: " << e.what());
2091
        return nullptr;
2092
    }
2093
 
2094
    *buf = s.ID;
2095
    *(buf + 1) = s.hlen >> 8;
2096
    *(buf + 2) = s.hlen;
2097
    *(buf + 3) = s.sep1;
2098
    *(buf + 4) = s.type;
2099
    *(buf + 5) = s.unk1 >> 8;
2100
    *(buf + 6) = s.unk1;
2101
    *(buf + 7) = s.device1 >> 8;
2102
    *(buf + 8) = s.device1;
2103
    *(buf + 9) = s.port1 >> 8;
2104
    *(buf + 10) = s.port1;
2105
    *(buf + 11) = s.system >> 8;
2106
    *(buf + 12) = s.system;
2107
    *(buf + 13) = s.device2 >> 8;
2108
    *(buf + 14) = s.device2;
2109
    *(buf + 15) = s.port2 >> 8;
2110
    *(buf + 16) = s.port2;
2111
    *(buf + 17) = s.unk6;
2112
    *(buf + 18) = s.count >> 8;
2113
    *(buf + 19) = s.count;
2114
    *(buf + 20) = s.MC >> 8;
2115
    *(buf + 21) = s.MC;
2116
 
2117
    // Here the fixed block is complete. The data are following.
2118
    switch (s.MC)
2119
    {
2120
        case 0x0006:
2121
        case 0x0007:
2122
        case 0x0018:
2123
        case 0x0019:
2124
        case 0x0084:
2125
        case 0x0085:
2126
        case 0x0086:
2127
        case 0x0087:
2128
        case 0x0088:
2129
        case 0x0089:
2130
            *(buf + 22) = s.data.chan_state.device >> 8;
2131
            *(buf + 23) = s.data.chan_state.device;
2132
            *(buf + 24) = s.data.chan_state.port >> 8;
2133
            *(buf + 25) = s.data.chan_state.port;
2134
            *(buf + 26) = s.data.chan_state.system >> 8;
2135
            *(buf + 27) = s.data.chan_state.system;
2136
            *(buf + 28) = s.data.chan_state.channel >> 8;
2137
            *(buf + 29) = s.data.chan_state.channel;
2138
            *(buf + 30) = calcChecksum(buf, 30);
2139
            valid = true;
2140
            break;
2141
 
2142
        case 0x000a:
2143
        case 0x008a:
2144
            *(buf + 22) = s.data.message_value.device >> 8;
2145
            *(buf + 23) = s.data.message_value.device;
2146
            *(buf + 24) = s.data.message_value.port >> 8;
2147
            *(buf + 25) = s.data.message_value.port;
2148
            *(buf + 26) = s.data.message_value.system >> 8;
2149
            *(buf + 27) = s.data.message_value.system;
2150
            *(buf + 28) = s.data.message_value.value >> 8;
2151
            *(buf + 29) = s.data.message_value.value;
2152
            *(buf + 30) = s.data.message_value.type;
2153
            pos = 31;
2154
 
2155
            switch (s.data.message_value.type)
2156
            {
2157
                case 0x10: *(buf + pos) = s.data.message_value.content.byte; break;
2158
 
2159
                case 0x11: *(buf + pos) = s.data.message_value.content.ch; break;
2160
 
2161
                case 0x20:
2162
                    *(buf + pos) = s.data.message_value.content.integer >> 8;
2163
                    pos++;
2164
                    *(buf + pos) = s.data.message_value.content.integer;
2165
                    break;
2166
 
2167
                case 0x21:
2168
                    *(buf + pos) = s.data.message_value.content.sinteger >> 8;
2169
                    pos++;
2170
                    *(buf + pos) = s.data.message_value.content.sinteger;
2171
                    break;
2172
 
2173
                case 0x40:
2174
                    *(buf + pos) = s.data.message_value.content.dword >> 24;
2175
                    pos++;
2176
                    *(buf + pos) = s.data.message_value.content.dword >> 16;
2177
                    pos++;
2178
                    *(buf + pos) = s.data.message_value.content.dword >> 8;
2179
                    pos++;
2180
                    *(buf + pos) = s.data.message_value.content.dword;
2181
                    break;
2182
 
2183
                case 0x41:
2184
                    *(buf + pos) = s.data.message_value.content.sdword >> 24;
2185
                    pos++;
2186
                    *(buf + pos) = s.data.message_value.content.sdword >> 16;
2187
                    pos++;
2188
                    *(buf + pos) = s.data.message_value.content.sdword >> 8;
2189
                    pos++;
2190
                    *(buf + pos) = s.data.message_value.content.sdword;
2191
                    break;
2192
 
2193
                case 0x4f:
2194
                    memcpy(buf + pos, &s.data.message_value.content.fvalue, 4);
2195
                    pos += 3;
2196
                    break;
2197
 
2198
                case 0x8f:
2199
                    memcpy(buf + pos, &s.data.message_value.content.fvalue, 8);
2200
                    pos += 3;
2201
                    break;
2202
            }
2203
 
2204
            pos++;
2205
            *(buf + pos) = calcChecksum(buf, pos);
2206
            valid = true;
13 andreas 2207
        break;
11 andreas 2208
 
2209
        case 0x000b:
2210
        case 0x000c:
2211
        case 0x008b:
2212
        case 0x008c:
2213
            *(buf + 22) = s.data.message_string.device >> 8;
2214
            *(buf + 23) = s.data.message_string.device;
2215
            *(buf + 24) = s.data.message_string.port >> 8;
2216
            *(buf + 25) = s.data.message_string.port;
2217
            *(buf + 26) = s.data.message_string.system >> 8;
2218
            *(buf + 27) = s.data.message_string.system;
2219
            *(buf + 28) = s.data.message_string.type;
2220
            *(buf + 29) = s.data.message_string.length >> 8;
2221
            *(buf + 30) = s.data.message_string.length;
2222
            pos = 31;
2223
            memcpy(buf + pos, s.data.message_string.content, s.data.message_string.length);
2224
            pos += s.data.message_string.length;
2225
            *(buf + pos) = calcChecksum(buf, pos);
2226
            valid = true;
13 andreas 2227
        break;
11 andreas 2228
 
2229
        case 0x008d:    // Custom event
2230
            *(buf + 22) = s.data.customEvent.device >> 8;
2231
            *(buf + 23) = s.data.customEvent.device;
2232
            *(buf + 24) = s.data.customEvent.port >> 8;
2233
            *(buf + 25) = s.data.customEvent.port;
2234
            *(buf + 26) = s.data.customEvent.system >> 8;
2235
            *(buf + 27) = s.data.customEvent.system;
2236
            *(buf + 28) = s.data.customEvent.ID >> 8;
2237
            *(buf + 29) = s.data.customEvent.ID;
2238
            *(buf + 30) = s.data.customEvent.type >> 8;
2239
            *(buf + 31) = s.data.customEvent.type;
2240
            *(buf + 32) = s.data.customEvent.flag >> 8;
2241
            *(buf + 33) = s.data.customEvent.flag;
2242
            *(buf + 34) = s.data.customEvent.value1 >> 24;
2243
            *(buf + 35) = s.data.customEvent.value1 >> 16;
2244
            *(buf + 36) = s.data.customEvent.value1 >> 8;
2245
            *(buf + 37) = s.data.customEvent.value1;
2246
            *(buf + 38) = s.data.customEvent.value2 >> 24;
2247
            *(buf + 39) = s.data.customEvent.value2 >> 16;
2248
            *(buf + 40) = s.data.customEvent.value2 >> 8;
2249
            *(buf + 41) = s.data.customEvent.value2;
2250
            *(buf + 42) = s.data.customEvent.value3 >> 24;
2251
            *(buf + 43) = s.data.customEvent.value3 >> 16;
2252
            *(buf + 44) = s.data.customEvent.value3 >> 8;
2253
            *(buf + 45) = s.data.customEvent.value3;
2254
            *(buf + 46) = s.data.customEvent.dtype;
2255
            *(buf + 47) = s.data.customEvent.length >> 8;
2256
            *(buf + 48) = s.data.customEvent.length;
2257
            pos = 49;
2258
 
2259
            if (s.data.customEvent.length > 0)
2260
            {
2261
                memcpy(buf + pos, s.data.customEvent.data, s.data.customEvent.length);
2262
                pos += s.data.customEvent.length;
2263
            }
2264
 
2265
            *(buf + pos) = 0;
2266
            *(buf + pos + 1) = 0;
2267
            pos += 2;
2268
            *(buf + pos) = calcChecksum(buf, pos);
2269
            valid = true;
13 andreas 2270
        break;
11 andreas 2271
 
2272
        case 0x0090:
2273
            *(buf + 22) = s.data.sendPortNumber.device >> 8;
2274
            *(buf + 23) = s.data.sendPortNumber.device;
2275
            *(buf + 24) = s.data.sendPortNumber.system >> 8;
2276
            *(buf + 25) = s.data.sendPortNumber.system;
2277
            *(buf + 26) = s.data.sendPortNumber.pcount >> 8;
2278
            *(buf + 27) = s.data.sendPortNumber.pcount;
2279
            *(buf + 28) = calcChecksum(buf, 28);
2280
            valid = true;
13 andreas 2281
        break;
11 andreas 2282
 
2283
        case 0x0091:
2284
        case 0x0092:
2285
            *(buf + 22) = s.data.sendOutpChannels.device >> 8;
2286
            *(buf + 23) = s.data.sendOutpChannels.device;
2287
            *(buf + 24) = s.data.sendOutpChannels.port >> 8;
2288
            *(buf + 25) = s.data.sendOutpChannels.port;
2289
            *(buf + 26) = s.data.sendOutpChannels.system >> 8;
2290
            *(buf + 27) = s.data.sendOutpChannels.system;
2291
            *(buf + 28) = s.data.sendOutpChannels.count >> 8;
2292
            *(buf + 29) = s.data.sendOutpChannels.count;
2293
            *(buf + 30) = calcChecksum(buf, 30);
2294
            valid = true;
13 andreas 2295
        break;
11 andreas 2296
 
2297
        case 0x0093:
2298
        case 0x0094:
2299
            *(buf + 22) = s.data.sendSize.device >> 8;
2300
            *(buf + 23) = s.data.sendSize.device;
2301
            *(buf + 24) = s.data.sendSize.port >> 8;
2302
            *(buf + 25) = s.data.sendSize.port;
2303
            *(buf + 26) = s.data.sendSize.system >> 8;
2304
            *(buf + 27) = s.data.sendSize.system;
2305
            *(buf + 28) = s.data.sendSize.type;
2306
            *(buf + 29) = s.data.sendSize.length >> 8;
2307
            *(buf + 30) = s.data.sendSize.length;
2308
            *(buf + 31) = calcChecksum(buf, 31);
2309
            valid = true;
13 andreas 2310
        break;
11 andreas 2311
 
2312
        case 0x0095:
2313
            *(buf + 22) = s.data.sendLevSupport.device >> 8;
2314
            *(buf + 23) = s.data.sendLevSupport.device;
2315
            *(buf + 24) = s.data.sendLevSupport.port >> 8;
2316
            *(buf + 25) = s.data.sendLevSupport.port;
2317
            *(buf + 26) = s.data.sendLevSupport.system >> 8;
2318
            *(buf + 27) = s.data.sendLevSupport.system;
2319
            *(buf + 28) = s.data.sendLevSupport.level >> 8;
2320
            *(buf + 29) = s.data.sendLevSupport.level;
2321
            *(buf + 30) = s.data.sendLevSupport.num;
2322
            *(buf + 31) = s.data.sendLevSupport.types[0];
2323
            *(buf + 32) = s.data.sendLevSupport.types[1];
2324
            *(buf + 33) = s.data.sendLevSupport.types[2];
2325
            *(buf + 34) = s.data.sendLevSupport.types[3];
2326
            *(buf + 35) = s.data.sendLevSupport.types[4];
2327
            *(buf + 36) = s.data.sendLevSupport.types[5];
2328
            *(buf + 37) = calcChecksum(buf, 37);
2329
            valid = true;
13 andreas 2330
        break;
11 andreas 2331
 
2332
        case 0x0096:
2333
            *(buf + 22) = s.data.sendStatusCode.device >> 8;
2334
            *(buf + 23) = s.data.sendStatusCode.device;
2335
            *(buf + 24) = s.data.sendStatusCode.port >> 8;
2336
            *(buf + 25) = s.data.sendStatusCode.port;
2337
            *(buf + 26) = s.data.sendStatusCode.system >> 8;
2338
            *(buf + 27) = s.data.sendStatusCode.system;
2339
            *(buf + 28) = s.data.sendStatusCode.status >> 8;
2340
            *(buf + 29) = s.data.sendStatusCode.status;
2341
            *(buf + 30) = s.data.sendStatusCode.type;
2342
            *(buf + 31) = s.data.sendStatusCode.length >> 8;
2343
            *(buf + 32) = s.data.sendStatusCode.length;
2344
            pos = 33;
2345
            memset((void*)&s.data.sendStatusCode.str[0], 0, sizeof(s.data.sendStatusCode.str));
2346
            memcpy(buf + pos, s.data.sendStatusCode.str, s.data.sendStatusCode.length);
2347
            pos += s.data.sendStatusCode.length;
2348
            *(buf + pos) = calcChecksum(buf, pos);
2349
            valid = true;
13 andreas 2350
        break;
11 andreas 2351
 
2352
        case 0x0097:
2353
            *(buf + 22) = s.data.srDeviceInfo.device >> 8;
2354
            *(buf + 23) = s.data.srDeviceInfo.device;
2355
            *(buf + 24) = s.data.srDeviceInfo.system >> 8;
2356
            *(buf + 25) = s.data.srDeviceInfo.system;
2357
            *(buf + 26) = s.data.srDeviceInfo.flag >> 8;
2358
            *(buf + 27) = s.data.srDeviceInfo.flag;
2359
            *(buf + 28) = s.data.srDeviceInfo.objectID;
2360
            *(buf + 29) = s.data.srDeviceInfo.parentID;
2361
            *(buf + 30) = s.data.srDeviceInfo.herstID >> 8;
2362
            *(buf + 31) = s.data.srDeviceInfo.herstID;
2363
            *(buf + 32) = s.data.srDeviceInfo.deviceID >> 8;
2364
            *(buf + 33) = s.data.srDeviceInfo.deviceID;
2365
            pos = 34;
2366
            memcpy(buf + pos, s.data.srDeviceInfo.serial, 16);
2367
            pos += 16;
2368
            *(buf + pos) = s.data.srDeviceInfo.fwid >> 8;
2369
            pos++;
2370
            *(buf + pos) = s.data.srDeviceInfo.fwid;
2371
            pos++;
2372
            memcpy(buf + pos, s.data.srDeviceInfo.info, s.data.srDeviceInfo.len);
2373
            pos += s.data.srDeviceInfo.len;
2374
            *(buf + pos) = calcChecksum(buf, pos);
2375
            valid = true;
13 andreas 2376
        break;
11 andreas 2377
 
2378
        case 0x0098:
2379
            *(buf + 22) = s.data.reqPortCount.device >> 8;
2380
            *(buf + 23) = s.data.reqPortCount.device;
2381
            *(buf + 24) = s.data.reqPortCount.system >> 8;
2382
            *(buf + 25) = s.data.reqPortCount.system;
2383
            *(buf + 26) = calcChecksum(buf, 26);
2384
            valid = true;
13 andreas 2385
        break;
11 andreas 2386
 
2387
        case 0x0204:    // file transfer
2388
            *(buf + 22) = s.data.filetransfer.ftype >> 8;
2389
            *(buf + 23) = s.data.filetransfer.ftype;
2390
            *(buf + 24) = s.data.filetransfer.function >> 8;
2391
            *(buf + 25) = s.data.filetransfer.function;
2392
            pos = 26;
2393
 
2394
            switch (s.data.filetransfer.function)
2395
            {
2396
                case 0x0001:
2397
                    *(buf + 26) = s.data.filetransfer.unk;
2398
                    *(buf + 27) = s.data.filetransfer.unk1;
2399
                    pos = 28;
13 andreas 2400
                break;
11 andreas 2401
 
2402
                case 0x0003:
2403
                    *(buf + 26) = s.data.filetransfer.unk >> 8;
2404
                    *(buf + 27) = s.data.filetransfer.unk;
2405
                    pos = 28;
2406
 
2407
                    for (uint32_t i = 0; i < s.data.filetransfer.unk && pos < (s.hlen + 3); i++)
2408
                    {
2409
                        *(buf + pos) = s.data.filetransfer.data[i];
2410
                        pos++;
2411
                    }
13 andreas 2412
                break;
11 andreas 2413
 
2414
                case 0x0101:
2415
                    if (s.data.filetransfer.ftype == 0)
2416
                    {
2417
                        *(buf + 26) = s.data.filetransfer.unk >> 24;
2418
                        *(buf + 27) = s.data.filetransfer.unk >> 16;
2419
                        *(buf + 28) = s.data.filetransfer.unk >> 8;
2420
                        *(buf + 29) = s.data.filetransfer.unk;
2421
                        *(buf + 30) = s.data.filetransfer.unk1 >> 24;
2422
                        *(buf + 31) = s.data.filetransfer.unk1 >> 16;
2423
                        *(buf + 32) = s.data.filetransfer.unk1 >> 8;
2424
                        *(buf + 33) = s.data.filetransfer.unk1;
2425
                        *(buf + 34) = s.data.filetransfer.unk2 >> 24;
2426
                        *(buf + 35) = s.data.filetransfer.unk2 >> 16;
2427
                        *(buf + 36) = s.data.filetransfer.unk2 >> 8;
2428
                        *(buf + 37) = s.data.filetransfer.unk2;
2429
                        *(buf + 38) = 0x00;
2430
                        *(buf + 39) = 0x00;
2431
                        *(buf + 40) = 0x3e;
2432
                        *(buf + 41) = 0x75;
2433
                        pos = 42;
2434
                        len = 0;
2435
 
2436
                        while (s.data.filetransfer.data[len] != 0)
2437
                        {
2438
                            *(buf + pos) = s.data.filetransfer.data[len];
2439
                            len++;
2440
                            pos++;
2441
                        }
2442
 
2443
                        *(buf + pos) = 0;
2444
                        pos++;
2445
                    }
2446
                    else
2447
                    {
2448
                        *(buf + 26) = s.data.filetransfer.unk >> 24;
2449
                        *(buf + 27) = s.data.filetransfer.unk >> 16;
2450
                        *(buf + 28) = s.data.filetransfer.unk >> 8;
2451
                        *(buf + 29) = s.data.filetransfer.unk;
2452
                        *(buf + 30) = 0x00;
2453
                        *(buf + 31) = 0x00;
2454
                        *(buf + 32) = 0x00;
2455
                        *(buf + 33) = 0x00;
2456
                        pos = 34;
2457
                    }
2458
 
13 andreas 2459
                break;
11 andreas 2460
 
2461
                case 0x0102:
2462
                    *(buf + 26) = 0x00;
2463
                    *(buf + 27) = 0x00;
2464
                    *(buf + 28) = 0x00;
2465
                    *(buf + 29) = s.data.filetransfer.info1;        // dir flag
2466
                    *(buf + 30) = s.data.filetransfer.info2 >> 8;   // # entries
2467
                    *(buf + 31) = s.data.filetransfer.info2;
2468
                    *(buf + 32) = s.data.filetransfer.unk >> 8;     // counter
2469
                    *(buf + 33) = s.data.filetransfer.unk;
2470
                    *(buf + 34) = s.data.filetransfer.unk1 >> 24;   // file size
2471
                    *(buf + 35) = s.data.filetransfer.unk1 >> 16;
2472
                    *(buf + 36) = s.data.filetransfer.unk1 >> 8;
2473
                    *(buf + 37) = s.data.filetransfer.unk1;
2474
                    *(buf + 38) = (s.data.filetransfer.info1 == 1) ? 0x0c : 0x0b;
2475
                    *(buf + 39) = (s.data.filetransfer.info1 == 1) ? 0x0e : 0x13;
2476
                    *(buf + 40) = 0x07;
2477
                    *(buf + 41) = s.data.filetransfer.unk2 >> 24;   // Date
2478
                    *(buf + 42) = s.data.filetransfer.unk2 >> 16;
2479
                    *(buf + 43) = s.data.filetransfer.unk2 >> 8;
2480
                    *(buf + 44) = s.data.filetransfer.unk2;
2481
                    pos = 45;
2482
                    len = 0;
2483
 
2484
                    while (s.data.filetransfer.data[len] != 0)
2485
                    {
2486
                        *(buf + pos) = s.data.filetransfer.data[len];
2487
                        pos++;
2488
                        len++;
2489
                    }
2490
 
2491
                    *(buf + pos) = 0;
2492
                    pos++;
13 andreas 2493
                break;
11 andreas 2494
 
2495
                case 0x0103:
2496
                    *(buf + 26) = s.data.filetransfer.unk >> 8;
2497
                    *(buf + 27) = s.data.filetransfer.unk;
2498
                    *(buf + 28) = s.data.filetransfer.unk1 >> 24;
2499
                    *(buf + 29) = s.data.filetransfer.unk1 >> 16;
2500
                    *(buf + 30) = s.data.filetransfer.unk1 >> 8;
2501
                    *(buf + 31) = s.data.filetransfer.unk1;
2502
                    pos = 32;
13 andreas 2503
                break;
11 andreas 2504
 
2505
                case 0x105:
2506
                    *(buf + 26) = s.data.filetransfer.unk >> 24;
2507
                    *(buf + 27) = s.data.filetransfer.unk >> 16;
2508
                    *(buf + 28) = s.data.filetransfer.unk >> 8;
2509
                    *(buf + 29) = s.data.filetransfer.unk;
2510
                    *(buf + 30) = s.data.filetransfer.unk1 >> 24;
2511
                    *(buf + 31) = s.data.filetransfer.unk1 >> 16;
2512
                    *(buf + 32) = s.data.filetransfer.unk1 >> 8;
2513
                    *(buf + 33) = s.data.filetransfer.unk1;
2514
                    pos = 34;
13 andreas 2515
                break;
11 andreas 2516
            }
2517
 
2518
            *(buf + pos) = calcChecksum(buf, pos);
2519
            valid = true;
13 andreas 2520
        break;
11 andreas 2521
 
2522
        case 0x0581:    // Pong
2523
            *(buf + 22) = s.data.srDeviceInfo.device >> 8;
2524
            *(buf + 23) = s.data.srDeviceInfo.device;
2525
            *(buf + 24) = s.data.srDeviceInfo.system >> 8;
2526
            *(buf + 25) = s.data.srDeviceInfo.system;
2527
            *(buf + 26) = s.data.srDeviceInfo.herstID >> 8;
2528
            *(buf + 27) = s.data.srDeviceInfo.herstID;
2529
            *(buf + 28) = s.data.srDeviceInfo.deviceID >> 8;
2530
            *(buf + 29) = s.data.srDeviceInfo.deviceID;
2531
            *(buf + 30) = s.data.srDeviceInfo.info[0];
2532
            *(buf + 31) = s.data.srDeviceInfo.info[1];
2533
            *(buf + 32) = s.data.srDeviceInfo.info[2];
2534
            *(buf + 33) = s.data.srDeviceInfo.info[3];
2535
            *(buf + 34) = s.data.srDeviceInfo.info[4];
2536
            *(buf + 35) = s.data.srDeviceInfo.info[5];
2537
            *(buf + 36) = calcChecksum(buf, 36);
2538
            valid = true;
13 andreas 2539
        break;
11 andreas 2540
    }
2541
 
2542
    if (!valid)
2543
    {
2544
        delete[] buf;
2545
        return 0;
2546
    }
2547
 
13 andreas 2548
//    MSG_TRACE("Buffer:");
2549
//    TError::logHex((char *)buf, s.hlen + 4);
11 andreas 2550
    return buf;
2551
}
2552
 
2553
void TAmxNet::setSerialNum(const string& sn)
2554
{
2555
    DECL_TRACER("TAmxNet::setSerialNum(const string& sn)");
2556
 
2557
    serNum = sn;
2558
    size_t len = (sn.length() > 15) ? 15 : sn.length();
2559
 
2560
    for (size_t i = 0; i < devInfo.size(); i++)
2561
        memcpy(devInfo[i].serialNum, sn.c_str(), len);
2562
}
2563
 
2564
int TAmxNet::countFiles()
2565
{
2566
    DECL_TRACER("TAmxNet::countFiles()");
2567
 
2568
    int count = 0;
2569
    ifstream in;
2570
 
2571
    try
2572
    {
2573
        in.open(TConfig::getProjectPath() + "/manifest.xma", fstream::in);
2574
 
2575
        if (!in)
2576
            return 0;
2577
 
2578
        for (string line; getline(in, line);)
2579
            count++;
2580
 
2581
        in.close();
2582
    }
2583
    catch (exception& e)
2584
    {
2585
        MSG_ERROR("Error: " << e.what());
2586
        return 0;
2587
    }
2588
 
2589
    return count;
2590
}
15 andreas 2591
 
2592
void TAmxNet::sendAllFuncNetwork(int state)
2593
{
2594
    DECL_TRACER("TAmxNet::sendAllFuncNetwork(int state)");
2595
 
17 andreas 2596
    if (mFuncsNetwork.empty())
2597
        return;
2598
 
15 andreas 2599
    map<ulong, FUNC_NETWORK_t>::iterator iter;
2600
 
2601
    for (iter = mFuncsNetwork.begin(); iter != mFuncsNetwork.end(); iter++)
2602
        iter->second.func(state);
2603
}
2604
 
2605
void TAmxNet::sendAllFuncTimer(const ANET_BLINK& blink)
2606
{
2607
    DECL_TRACER("TAmxNet::sendAllFuncTimer(const ANET_BLINK& blink)");
2608
 
17 andreas 2609
    if (mFuncsTimer.empty())
2610
        return;
2611
 
15 andreas 2612
    map<ulong, FUNC_TIMER_t>::iterator iter;
2613
 
2614
    for (iter = mFuncsTimer.begin(); iter != mFuncsTimer.end(); iter++)
2615
        iter->second.func(blink);
2616
}