Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
11 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
11 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include "tamxcommands.h"
20
#include "terror.h"
21
#include "tresources.h"
14 andreas 22
#include "tconfig.h"
11 andreas 23
 
24
using std::string;
25
using std::vector;
26
 
27
typedef struct CMD_DEFINATIONS
28
{
29
    string cmd;
30
    bool hasChannels{false};
31
    bool hasPars{false};
14 andreas 32
    char separator{0};
11 andreas 33
}CMD_DEFINATIONS;
34
 
35
CMD_DEFINATIONS cmdDefinations[] = {
14 andreas 36
    { "@WLD", false, true, ',' },
37
    { "@AFP", false, true, ',' },
38
    { "@GCE", false, true, ',' },
39
    { "@APG", false, true, ';' },
40
    { "@CPG", false, true, ',' },
41
    { "@DPG", false, true, ';' },
42
    { "@PDR", false, true, ';' },
43
    { "@PHE", false, true, ';' },
44
    { "@PHP", false, true, ';' },
45
    { "@PHT", false, true, ';' },
46
    { "@PPA", false, true, ',' },
47
    { "@PPF", false, true, ';' },
48
    { "@PPG", false, true, ';' },
49
    { "@PPK", false, true, ',' },
50
    { "@PPM", false, true, ';' },
51
    { "@PPN", false, true, ';' },
52
    { "@PPT", false, true, ';' },
53
    { "@PPX", false, false, '\0' },
54
    { "@PSE", false, true, ';' },
55
    { "@PSP", false, true, ';' },
56
    { "@PST", false, true, ';' },
57
    { "PAGE", false, true, ',' },
58
    { "PPOF", false, true, ';' },
59
    { "PPOG", false, true, ';' },
60
    { "PPON", false, true, ';' },
61
    { "^ANI", true, true, ',' },
62
    { "^APF", true, true, ',' },
63
    { "^BAT", true, true, ',' },
64
    { "^BAU", true, true, ',' },
65
    { "^BCB", true, true, ',' },
66
    { "?BCB", true, true, ',' },
67
    { "^BCF", true, true, ',' },
68
    { "?BCF", true, true, ',' },
69
    { "^BCT", true, true, ',' },
70
    { "?BCT", true, true, ',' },
71
    { "^BDO", true, true, ',' },
72
    { "^BFB", true, true, ',' },
73
    { "^BIM", true, true, ',' },
74
    { "^BLN", true, true, ',' },
75
    { "^BMC", true, true, ',' },
76
    { "^BMF", true, true, ',' },
77
    { "^BMI", true, true, ',' },
78
    { "^BML", true, true, ',' },
79
    { "^BMP", true, true, ',' },
80
    { "?BMP", true, true, ',' },
81
    { "^BNC", true, true, ',' },
82
    { "^BNN", true, true, ',' },
83
    { "^BNT", true, true, ',' },
84
    { "^BOP", true, true, ',' },
85
    { "?BOP", true, true, ',' },
86
    { "^BOR", true, true, ',' },
87
    { "^BOS", true, true, ',' },
88
    { "^BPP", true, true, ',' },
89
    { "^BRD", true, true, ',' },
90
    { "?BRD", true, true, ',' },
91
    { "^BSF", true, true, ',' },
92
    { "^BSP", true, true, ',' },
93
    { "^BSM", true, false, ',' },
94
    { "^BSO", true, true, ',' },
95
    { "^BVL", true, true, ',' },
96
    { "^BVN", false, true, ',' },
97
    { "^BVP", true, true, ',' },
98
    { "^BVT", true, true, ',' },
99
    { "^BWW", true, true, ',' },
100
    { "?BWW", true, true, ',' },
101
    { "^CPF", true, false, ',' },
102
    { "^DLD", false, false, ',' },
103
    { "^DPF", true, true, ',' },
104
    { "^ENA", true, true, ',' },
105
    { "^FON", true, true, ',' },
106
    { "?FON", true, true, ',' },
107
    { "^GDI", true, true, ',' },
108
    { "^GIV", true, true, ',' },
109
    { "^GLH", true, true, ',' },
110
    { "^GLL", true, true, ',' },
111
    { "^GRD", true, true, ',' },
112
    { "^GRU", true, true, ',' },
113
    { "^GSC", true, true, ',' },
114
    { "^GSN", true, true, ',' },
115
    { "^ICO", true, true, ',' },
116
    { "?ICO", true, true, ',' },
117
    { "^IRM", false, true, ',' },
118
    { "^JSB", true, true, ',' },
119
    { "?JSB", true, true, ',' },
120
    { "^JSI", true, true, ',' },
121
    { "?JSI", true, true, ',' },
122
    { "^JST", true, true, ',' },
123
    { "?JST", true, true, ',' },
124
    { "^MBT", false, false, ',' },
125
    { "^MDC", false, false, ',' },
126
    { "^SHO", true, true, ',' },
127
    { "^TEC", true, true, ',' },
128
    { "?TEC", true, true, ',' },
129
    { "^TEF", true, true, ',' },
130
    { "?TEF", true, true, ',' },
131
    { "^TOP", false, true, ',' },
132
    { "^TXT", true, true, ',' },
133
    { "?TXT", true, true, ',' },
134
    { "^UNI", true, true, ',' },
135
    { "^LPC", false, true, ',' },
136
    { "^LPR", false, true, ',' },
137
    { "^LPS", false, true, ',' },
138
    { "ABEEP", false, false, ',' },
139
    { "ADBEEP", false, false, ',' },
140
    { "@AKB", false, true, ';' },
141
    { "AKEYB", false, true, ',' },
142
    { "AKEYP", false, true, ',' },
143
    { "AKEYR", false, true, ',' },
144
    { "@AKP", false, true, ';' },
145
    { "@AKR", false, false, ',' },
146
    { "BEEP", false, false, ',' },
147
    { "BRIT", false, true, ',' },
148
    { "@BRT", false, true, ',' },
149
    { "DBEEP", false, false, ',' },
150
    { "@EKP", false, true, ';' },
151
    { "PKEYP", false, true, ',' },
152
    { "@PKP", false, true, ';' },
153
    { "SETUP", false, false, ',' },
154
    { "SHUTDOWN", false, false, ',' },
155
    { "SLEEP", false, false, ',' },
156
    { "@SOU", false, true, ',' },
157
    { "@TKP", false, true, ';' },
158
    { "TPAGEON", false, false, ',' },
159
    { "TPAGEOFF", false, false, ',' },
160
    { "@VKB", false, false, ',' },
161
    { "WAKE", false, false, ',' },
162
    { "^CAL", false, false, ',' },
163
    { "^KPS", false, true, ',' },
164
    { "^VKS", false, true, ',' },
165
    { "@PWD", false, true, ',' },
166
    { "^PWD", false, true, ',' },
167
    { "^BBR", true, true, ',' },
168
    { "^RAF", false, true, ',' },
169
    { "^RFR", false, true, ',' },
170
    { "^RMF", false, true, ',' },
171
    { "^RSR", false, true, ',' },
172
    { "^MODEL?", false, false, ',' },
173
    { "^ICS", false, true, ',' },
174
    { "^ICE", false, false, ',' },
175
    { "^ICM", false, true, ',' },
176
    { "^PHN", false, true, ',' },
177
    { "?PHN", false, true, ',' },
178
    { "LEVON", false, false, ',' },
179
    { "RXON", false, false, ',' },
180
    { "ON", false, true, ',' },
181
    { "OFF", false, true, ',' },
15 andreas 182
    { "LEVEL", false, true, ',' },
183
    { "BLINK", false, true, ',' },
14 andreas 184
    { "", false, false, '\0' }
11 andreas 185
};
186
 
187
CMD_DEFINATIONS& findCmdDefines(const string& cmd)
188
{
189
    DECL_TRACER("findCmdDefines(const string& cmd)");
190
 
191
    int i = 0;
192
 
193
    while (cmdDefinations[i].cmd.length() > 0)
194
    {
195
        if (cmdDefinations[i].cmd.compare(cmd) == 0)
196
            return cmdDefinations[i];
197
 
198
        i++;
199
    }
200
 
201
    return cmdDefinations[i];
202
}
203
 
204
TAmxCommands::TAmxCommands()
205
{
206
    DECL_TRACER("TAmxCommands::TAmxCommands()");
14 andreas 207
    readMap();
11 andreas 208
}
209
 
210
TAmxCommands::~TAmxCommands()
211
{
212
    DECL_TRACER("TAmxCommands::~TAmxCommands()");
213
}
214
 
14 andreas 215
bool TAmxCommands::readMap()
216
{
217
    DECL_TRACER("TAmxCommands::readMap()");
218
 
219
    makeFileName(TConfig::getProjectPath(), "map.xma");
220
    string path;
221
    vector<string> elements = { "cm", "am", "lm", "bm", "sm", "strm", "pm" };
222
 
223
    if (isValidFile())
224
        path = getFileName();
225
 
226
    TReadXML reader(path);
227
 
228
    if (TError::isError())
229
        return false;
230
 
231
    vector<string>::iterator mapIter;
232
 
233
    for (mapIter = elements.begin(); mapIter != elements.end(); mapIter++)
234
    {
235
        reader.findElement(*mapIter);
236
 
237
        if (!reader.success())
238
        {
239
            MSG_ERROR("Element \"" << *mapIter << "\" was not found!");
240
            TError::setError();
241
            return false;
242
        }
243
 
244
        MAP_T map;
245
        MAP_BM_T mapBm;
246
        MAP_PM_T mapPm;
247
        mxml_node_t *node = reader.getFirstChild();
248
 
249
        while (node)
250
        {
251
            string el = reader.getElementName(node);
252
 
253
            if (el.compare("me") == 0)
254
            {
255
                mxml_node_t *n = reader.getFirstChild(node);
256
 
257
                while (n)
258
                {
259
                    string e = reader.getElementName(n);
260
 
261
                    if (mapIter->compare("cm") == 0 || mapIter->compare("am") == 0 ||
262
                        mapIter->compare("lm") == 0 || mapIter->compare("strm") == 0)
263
                    {
264
                        if (e.compare("p") == 0)
265
                            map.p = reader.getIntFromNode(n);
266
                        else if (e.compare("c") == 0)
267
                            map.c = reader.getIntFromNode(n);
268
                        else if (e.compare("ax") == 0)
269
                            map.ax = reader.getIntFromNode(n);
270
                        else if (e.compare("pg") == 0)
271
                            map.pg = reader.getIntFromNode(n);
272
                        else if (e.compare("bt") == 0)
273
                            map.bt = reader.getIntFromNode(n);
274
                        else if (e.compare("pn") == 0)
275
                            map.pn = reader.getTextFromNode(n);
276
                        else if (e.compare("bn") == 0)
277
                            map.bn = reader.getTextFromNode(n);
278
                    }
279
                    else if (mapIter->compare("bm") == 0)
280
                    {
281
                        mxml_node_t *no = reader.getFirstChild(n);
282
 
283
                        while (no)
284
                        {
285
                            string im = reader.getElementName(no);
286
 
287
                            if (im.compare("i") == 0)
288
                                mapBm.i = reader.getTextFromNode(no);
289
                            else if (im.compare("id") == 0)
290
                                mapBm.id = reader.getIntFromNode(no);
291
                            else if (im.compare("rt") == 0)
292
                                mapBm.rt = reader.getIntFromNode(no);
293
                            else if (im.compare("pg") == 0)
294
                                mapBm.pg = reader.getIntFromNode(no);
295
                            else if (im.compare("bt") == 0)
296
                                mapBm.bt = reader.getIntFromNode(no);
297
                            else if (im.compare("st") == 0)
298
                                mapBm.st = reader.getIntFromNode(no);
299
                            else if (im.compare("sl") == 0)
300
                                mapBm.sl = reader.getIntFromNode(no);
301
                            else if (im.compare("pn") == 0)
302
                                mapBm.pn = reader.getTextFromNode(no);
303
                            else if (im.compare("bn") == 0)
304
                                mapBm.bn = reader.getTextFromNode(no);
305
 
306
                            no = reader.getNextChild(no);
307
                        }
308
 
309
                        mMap.map_bm.push_back(mapBm);
310
                    }
311
                    else if (mapIter->compare("sm") == 0)
312
                    {
313
                        if (e.compare("i") == 0)
314
                            mMap.map_sm.push_back(reader.getTextFromNode(n));
315
                    }
316
                    else if (mapIter->compare("pm") == 0)
317
                    {
318
                        if (e.compare("a") == 0)
319
                            mapPm.a = reader.getIntFromNode(n);
320
                        else if (e.compare("t") == 0)
321
                            mapPm.t = reader.getTextFromNode(n);
322
                        else if (e.compare("pg") == 0)
323
                            mapPm.pg = reader.getIntFromNode(n);
324
                        else if (e.compare("bt") == 0)
325
                            mapPm.bt = reader.getIntFromNode(n);
326
                        else if (e.compare("pn") == 0)
327
                            mapPm.pn = reader.getTextFromNode(n);
328
                        else if (e.compare("bn") == 0)
329
                            mapPm.bn = reader.getTextFromNode(n);
330
                    }
331
 
332
                    n = reader.getNextChild(n);
333
                }
334
 
335
                if (mapIter->compare("cm") == 0)
336
                    mMap.map_cm.push_back(map);
337
                else if (mapIter->compare("am") == 0)
338
                    mMap.map_am.push_back(map);
339
                else if (mapIter->compare("lm") == 0)
340
                    mMap.map_lm.push_back(map);
341
                else if (mapIter->compare("strm") == 0)
342
                    mMap.map_strm.push_back(map);
343
                else if (mapIter->compare("pm") == 0)
344
                    mMap.map_pm.push_back(mapPm);
345
            }
346
 
347
            node = reader.getNextChild();
348
        }
349
    }
350
 
351
    return true;
352
}
353
 
354
vector<string> TAmxCommands::getFields(string& msg, char sep)
355
{
356
    DECL_TRACER("TAmxCommands::getFields(string& msg, char sep)");
357
 
358
    vector<string> flds;
359
    bool bStr = false;
360
    string part;
361
 
16 andreas 362
    for (size_t i = 0; i < msg.length(); i++)
14 andreas 363
    {
16 andreas 364
        if (msg.at(i) == sep && !bStr)
14 andreas 365
        {
366
            flds.push_back(part);
367
            part.clear();
368
            continue;
369
        }
16 andreas 370
        else if (msg.at(i) == '\'' && !bStr)
14 andreas 371
            bStr = true;
16 andreas 372
        else if (msg.at(i) == '\'' && bStr)
14 andreas 373
            bStr = false;
374
        else
16 andreas 375
            part.append(msg.substr(i, 1));
14 andreas 376
    }
377
 
378
    if (!part.empty())
379
        flds.push_back(part);
380
 
381
    if (TStreamError::checkFilter(LOG_DEBUG))
382
    {
383
        MSG_DEBUG("Found fields:");
384
        vector<string>::iterator iter;
385
        int i = 1;
386
 
387
        for (iter = flds.begin(); iter != flds.end(); iter++)
388
        {
389
            MSG_DEBUG("    " << i << ": " << *iter);
390
            i++;
391
        }
392
    }
393
 
394
    return flds;
395
}
396
 
19 andreas 397
vector<MAP_T> TAmxCommands::findButtons(int port, vector<int>& channels, MAP_TYPE mt)
14 andreas 398
{
19 andreas 399
    DECL_TRACER("TAmxCommands::findButtons(int port, vector<int>& channels, MAP_TYPE mt)");
14 andreas 400
 
401
    vector<MAP_T> map;
402
    vector<int>::iterator iter;
403
 
19 andreas 404
    if (channels.empty())
405
    {
406
        MSG_WARNING("Got empty channel list!");
407
        return map;
408
    }
409
 
410
    vector<MAP_T> localMap;
411
 
412
    switch (mt)
413
    {
414
        case TYPE_AM:   localMap = mMap.map_am; break;
415
        case TYPE_CM:   localMap = mMap.map_cm; break;
416
        case TYPE_LM:   localMap = mMap.map_lm; break;
417
    }
418
 
419
    if (localMap.empty())
420
    {
421
        MSG_WARNING("The internal list of elements is empty!")
422
        return map;
423
    }
424
 
14 andreas 425
    for (iter = channels.begin(); iter != channels.end(); iter++)
426
    {
427
        vector<MAP_T>::iterator mapIter;
428
 
19 andreas 429
        for (mapIter = localMap.begin(); mapIter != localMap.end(); mapIter++)
14 andreas 430
        {
431
            if (mapIter->p == port && mapIter->c == *iter)
432
                map.push_back(*mapIter);
433
        }
434
    }
435
 
436
    MSG_DEBUG("Found " << map.size() << " buttons.");
437
    return map;
438
}
439
 
15 andreas 440
vector<MAP_T> TAmxCommands::findBargraphs(int port, vector<int>& channels)
441
{
442
    DECL_TRACER("TAmxCommands::findBargraphs(int port, vector<int>& channels)");
443
 
444
    vector<MAP_T> map;
445
    vector<int>::iterator iter;
446
 
447
    for (iter = channels.begin(); iter != channels.end(); iter++)
448
    {
449
        vector<MAP_T>::iterator mapIter;
450
 
451
        for (mapIter = mMap.map_lm.begin(); mapIter != mMap.map_lm.end(); mapIter++)
452
        {
453
            if (mapIter->p == port && mapIter->c == *iter)
454
                map.push_back(*mapIter);
455
        }
456
    }
457
 
458
    MSG_DEBUG("Found " << map.size() << " buttons.");
459
    return map;
460
}
461
 
11 andreas 462
bool TAmxCommands::parseCommand(int device, int port, const string& cmd)
463
{
464
    DECL_TRACER("TAmxCommands::parseCommand(int device, int port, const string& cmd)");
465
 
14 andreas 466
    if (device != TConfig::getChannel())    // This should never happens!
467
    {
468
        MSG_WARNING("Command is for device " << device << ", but this device is " << TConfig::getChannel());
469
    }
470
 
11 andreas 471
    vector<CMD_TABLE>::iterator iter;
16 andreas 472
    size_t pos = cmd.find_first_of("-");
11 andreas 473
 
16 andreas 474
    if (pos != string::npos)
475
    {
476
        MSG_TRACE("Parsing for device <" << device << ":" << port << ":" << TConfig::getSystem() << "> the command: " << cmd.substr(0, pos));
477
    }
478
    else
479
    {
480
        MSG_TRACE("Parsing for device <" << device << ":" << port << ":" << TConfig::getSystem() << "> the command: " << cmd);
481
    }
13 andreas 482
 
11 andreas 483
    if (pos != string::npos)    // Command with parameters
484
    {
485
        string bef = cmd.substr(0, pos);
486
        string rest = cmd.substr(pos + 1);
487
 
488
        for (iter = mCmdTable.begin(); iter != mCmdTable.end(); iter++)
489
        {
13 andreas 490
            iter->channels.clear();
491
            iter->pars.clear();
492
 
11 andreas 493
            if (iter->cmd.compare(bef) == 0 && iter->command)
494
            {
495
                CMD_DEFINATIONS cdef = findCmdDefines(bef);
496
 
497
                if (cdef.cmd.empty())
498
                {
499
                    MSG_WARNING("Command \"" << bef << "\" not found in command table! Ignoring it.");
500
                    continue;
501
                }
502
 
503
                if (cdef.hasChannels || cdef.hasPars)
504
                {
14 andreas 505
                    vector<string> parts = getFields(rest, cdef.separator);
11 andreas 506
 
507
                    if (cdef.hasChannels)
13 andreas 508
                        extractChannels(parts[0], &iter->channels);
11 andreas 509
 
510
                    if (cdef.hasPars)
511
                    {
13 andreas 512
                        MSG_DEBUG("Command may have parameters. Found " << parts.size() << " parameters.");
11 andreas 513
 
13 andreas 514
                        if (parts.size() > 0)
11 andreas 515
                        {
13 andreas 516
                            vector<string>::iterator piter;
517
                            int cnt = 0;
518
 
519
                            for (piter = parts.begin(); piter != parts.end(); piter++)
11 andreas 520
                            {
13 andreas 521
                                if (cdef.hasChannels && !cnt)
522
                                {
523
                                    cnt++;
524
                                    continue;
525
                                }
526
 
527
                                iter->pars.push_back(*piter);
11 andreas 528
                                cnt++;
529
                            }
530
                        }
13 andreas 531
                        else
532
                            iter->pars.push_back(rest);
11 andreas 533
                    }
534
                }
535
 
536
                iter->command(port, iter->channels, iter->pars);
537
                return true;
538
            }
539
        }
540
    }
541
    else        // Command without parameter
542
    {
543
        for (iter = mCmdTable.begin(); iter != mCmdTable.end(); iter++)
544
        {
545
            if (iter->cmd.compare(cmd) == 0 && iter->command)
546
            {
547
                iter->command(port, iter->channels, iter->pars);
548
                return true;
549
            }
550
        }
551
    }
552
 
553
    MSG_WARNING("Command \"" << cmd << "\" currently not supported!");
554
    return false;
555
}
556
 
557
bool TAmxCommands::extractChannels(const string& schan, vector<int>* ch)
558
{
559
    DECL_TRACER("TAmxCommands::extractChannels(const string& schan, vector<int>* ch)");
560
 
561
    if (!ch || schan.empty())
562
        return false;
563
 
16 andreas 564
    if (schan.find("&") == string::npos && schan.find(".") == string::npos)
11 andreas 565
    {
566
        int c = atoi(schan.c_str());
567
        ch->push_back(c);
568
        return true;
569
    }
570
 
571
    if (schan.find("&") != string::npos)
572
    {
573
        vector<string> parts = StrSplit(schan, "&");
574
        vector<string>::iterator iter;
575
 
576
        for (iter = parts.begin(); iter != parts.end(); iter++)
577
        {
578
            if (iter->find(".") != string::npos)
579
            {
580
                vector<string> p2 = StrSplit(*iter, ".");
581
                vector<string>::iterator piter;
582
 
583
                for (piter = p2.begin(); piter != p2.end(); piter++)
584
                    ch->push_back(atoi(piter->c_str()));
585
            }
586
            else
587
                ch->push_back(atoi(iter->c_str()));
588
        }
589
    }
590
    else
591
    {
592
        vector<string> parts = StrSplit(schan, ".");
593
        vector<string>::iterator iter;
594
 
595
        for (iter = parts.begin(); iter != parts.end(); iter++)
596
            ch->push_back(atoi(iter->c_str()));
597
    }
598
 
599
    return true;
600
}
601
 
602
void TAmxCommands::registerCommand(std::function<void (int port, vector<int>& channels, vector<string>& pars)> command, const string& name)
603
{
604
    DECL_TRACER("TAmxCommands::registerCommand(std::function<void (vector<int>& channels, vector<string>& pars)> command, const string& name)");
605
 
606
    vector<CMD_TABLE>::iterator iter;
607
 
608
    for (iter = mCmdTable.begin(); iter != mCmdTable.end(); iter++)
609
    {
610
        if (iter->cmd.compare(name) == 0)
611
        {
612
            iter->command = command;
613
            iter->channels.clear();
614
            iter->pars.clear();
615
            return;
616
        }
617
    }
618
 
619
    CMD_TABLE ctbl;
620
    ctbl.cmd = name;
621
    ctbl.command = command;
622
    mCmdTable.push_back(ctbl);
623
}