Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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