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