Subversion Repositories tpanel

Rev

Rev 482 | Details | Compare with Previous | Last modification | View Log | RSS feed

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