• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenLightingProject / ola / 16900099157

12 Aug 2025 05:43AM UTC coverage: 45.72% (-0.02%) from 45.742%
16900099157

Pull #2016

github

web-flow
Merge c368ef6ae into eaf937e80
Pull Request #2016: Bump actions/checkout from 4 to 5

7586 of 17462 branches covered (43.44%)

22424 of 49046 relevant lines covered (45.72%)

51.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/examples/ola-dmxconsole.cpp
1
/*
2
 * Copyright (C) 2001 Dirk Jagdmann <doj@cubic.org>
3
 *
4
 * This program is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU General Public License
6
 * as published by the Free Software Foundation; either version 2
7
 * of the License, or (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
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
 *
18
 * Modified by Simon Newton (nomis52<AT>gmail.com) to use ola
19
 *
20
 * The (void) before attrset is due to a bug in curses. See
21
 * http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg682294.html
22
 */
23

24
#ifdef HAVE_CONFIG_H
25
#include <config.h>
26
#endif  // HAVE_CONFIG_H
27

28
#ifdef HAVE_CURSES_H
29
#include <curses.h>
30
#elif defined(HAVE_NCURSES_CURSES_H)
31
#include <ncurses/curses.h>
32
#endif  // HAVE_CURSES_H
33

34
#include <errno.h>
35
#include <getopt.h>
36
#include <signal.h>
37
#include <stdint.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <sys/ioctl.h>
42
#include <sys/time.h>
43
#ifdef HAVE_FTIME
44
#include <sys/timeb.h>
45
#endif  // HAVE_FTIME
46
#include <termios.h>
47
#include <time.h>
48
#include <math.h>
49

50
#include <ola/Callback.h>
51
#include <ola/Constants.h>
52
#include <ola/DmxBuffer.h>
53
#include <ola/base/Init.h>
54
#include <ola/base/SysExits.h>
55
#include <ola/client/ClientWrapper.h>
56
#include <ola/client/OlaClient.h>
57
#include <ola/io/SelectServer.h>
58

59
#include <iostream>
60
#include <string>
61

62
using ola::client::OlaClient;
63
using ola::client::OlaClientWrapper;
64
using ola::io::SelectServer;
65
using std::string;
66

67
static const unsigned int DEFAULT_UNIVERSE = 0;
68
static const unsigned char CHANNEL_NUDGE_VALUE = 0x10;
69
static const unsigned char CHANNEL_DISPLAY_WIDTH = 4;
70
static const unsigned char ROWS_PER_CHANNEL_ROW = 2;
71

72
/* color names used */
73
enum {
74
  CHANNEL = 1,
75
  ZERO,
76
  NORM,
77
  FULL,
78
  HEADLINE,
79
  HEADEMPH,
80
  HEADERROR,
81
  MAXCOLOR
82
};
83

84
/* display modes */
85
enum {
86
  DISP_MODE_DMX = 0,
87
  DISP_MODE_HEX,
88
  DISP_MODE_DEC,
89
  DISP_MODE_MAX,
90
};
91

92
typedef struct {
93
  unsigned int universe;
94
  bool help;        // help
95
} options;
96

97
unsigned int MAXFKEY = 12;
98

99
unsigned int universe = 0;
100

101
typedef unsigned char dmx_t;
102

103
static dmx_t *dmx;
104
static dmx_t *dmxsave;
105
static dmx_t *dmxundo;
106

107
static int display_mode = DISP_MODE_DMX;
108
static int current_channel = 0;  // channel cursor is positioned on
109
static int first_channel = 0;  // channel in upper left corner
110
static int channels_per_line = 80 / CHANNEL_DISPLAY_WIDTH;
111
// Default chans/screen is 80x24, less a row for the header,
112
// and one at the bottom to get an even number of rows
113
static int channels_per_screen =
114
    (80 / CHANNEL_DISPLAY_WIDTH) * ((24 - 2) / ROWS_PER_CHANNEL_ROW);
115
static int undo_possible = 0;
116
static int current_cue = 0;  // select with F keys
117
static float fadetime = 1.0f;
118
static int fading = 0;  // percentage counter of fade process
119
static int palette_number = 0;
120
static int palette[MAXCOLOR];
121
static bool screen_to_small = false;
122
static int channels_offset = 1;
123

124
OlaClient *client;
125
SelectServer *ss;
126

127

128
void DMXsleep(int usec) {
×
129
  struct timeval tv;
×
130
  tv.tv_sec = usec / 1000000;
×
131
  tv.tv_usec = usec % 1000000;
×
132
  if (select(1, NULL, NULL, NULL, &tv) < 0)
×
133
    perror("could not select");
×
134
}
×
135

136
// returns the time in milliseconds
137
uint64_t timeGetTime() {
×
138
#ifdef HAVE_GETTIMEOFDAY
139
  struct timeval tv;
×
140
  gettimeofday(&tv, NULL);
×
141
  return (static_cast<uint64_t>(tv.tv_sec) * 1000UL +
×
142
          static_cast<uint64_t>(tv.tv_usec / 1000));
×
143

144
#else
145
# ifdef HAVE_FTIME
146
  struct timeb t;
147
  ftime(&t);
148
  return (static_cast<uint64_t>(t.time) * 1000UL +
149
          static_cast<uint64_t>(t.millitm);
150
# else
151

152
# endif  // HAVE_FTIME
153
#endif  // HAVE_GETTIMEOFDAY
154
}
155

156

157

158
/* set all DMX channels */
159
void setall() {
×
160
  ola::DmxBuffer buffer(dmx, ola::DMX_UNIVERSE_SIZE);
×
161
  client->SendDMX(universe, buffer, ola::client::SendDMXArgs());
×
162
}
×
163

164
/* set current DMX channel */
165
void set() {
×
166
  setall();
×
167
}
×
168

169

170
/* display the channels numbers */
171
void mask() {
×
172
  int i = 0;
×
173
  int x, y;
×
174
  int z = first_channel;
×
175

176
  erase();
×
177

178
  /* clear headline */
179
  (void) attrset(palette[HEADLINE]);
×
180
  move(0, 0);  // NOLINT(build/include_what_you_use) This is ncurses.h's move
×
181
  for (x = 0; x < COLS; x++)
×
182
    addch(' ');
×
183

184
  /* write channel numbers */
185
  (void) attrset(palette[CHANNEL]);
×
186
  for (y = 1;
×
187
       y < LINES && z < ola::DMX_UNIVERSE_SIZE && i < channels_per_screen;
×
188
       y += ROWS_PER_CHANNEL_ROW) {
×
189
    move(y, 0);  // NOLINT(build/include_what_you_use) This is ncurses.h's move
×
190
    for (x = 0;
×
191
         x < channels_per_line &&
×
192
         z < ola::DMX_UNIVERSE_SIZE &&
×
193
         i < channels_per_screen;
×
194
         x++, i++, z++) {
×
195
      switch (display_mode) {
×
196
        case DISP_MODE_DMX:
×
197
        case DISP_MODE_DEC:
×
198
        default:
×
199
          printw("%03d ", z + channels_offset);
×
200
          break;
×
201
        case DISP_MODE_HEX:
×
202
          printw("%03X ", z + channels_offset);
×
203
          break;
×
204
        }
205
    }
206
  }
207
}
×
208

209
/* update the screen */
210
void values() {
×
211
  int i = 0;
×
212
  int x, y;
×
213
  int z = first_channel;
×
214
  int universe_length = 0;
×
215
  int width_total = 0;
×
216

217
  if (universe > 0) {
×
218
    universe_length = floor(log10(universe)) + 1;
×
219
  } else {
220
    universe_length = 1;
221
  }
222

223
  /* headline */
224
  width_total += 25;
×
225
  if (COLS >= width_total) {
×
226
    time_t t = time(NULL);
×
227
    struct tm tt;
×
228
    localtime_r(&t, &tt);
×
229
    char s[32];
×
230
    asctime_r(&tt, s);
×
231
    s[strlen(s) - 1] = 0; /* strip newline at end of string */
×
232

233
    attrset(palette[HEADLINE]);
×
234
    mvprintw(0, 1, "%s", s);
×
235
  }
236
  width_total += (5 + universe_length);
×
237
  if (COLS >= width_total) {
×
238
    /* Max universe 4294967295 - see MAX_UNIVERSE in include/ola/Constants.h */
239
    attrset(palette[HEADLINE]);
×
240
    printw(" uni:");
×
241
    attrset(palette[HEADEMPH]);
×
242
    printw("%u", universe);
×
243
  }
244
  width_total += (5 + 2);
×
245
  if (COLS >= width_total) {
×
246
    attrset(palette[HEADLINE]);
×
247
    printw(" cue:");
×
248
    attrset(palette[HEADEMPH]);
×
249
    printw("%02i", current_cue + 1);
×
250
  }
251
  width_total += (10 + 3);
×
252
  if (COLS >= width_total) {
×
253
    attrset(palette[HEADLINE]);
×
254
    printw(" fadetime:");
×
255
    attrset(palette[HEADEMPH]);
×
256
    printw("%1.1f", fadetime);
×
257
  }
258
  width_total += (8 + 3);
×
259
  if (COLS >= width_total) {
×
260
    if (fading) {
×
261
      attrset(palette[HEADLINE]);
×
262
      printw(" fading:");
×
263
      attrset(palette[HEADEMPH]);
×
264
      printw("%02i%%", (fading < 100) ? fading: 99);
×
265
    } else {
266
      attrset(palette[HEADLINE]);
×
267
      printw("           ");
×
268
    }
269
  }
270
  /* Use 10 as error string length, rather than error_str.length(),
271
     as a safety feature to ensure it's shown */
272
  width_total += (6 + 10);
×
273
  if (COLS >= width_total && screen_to_small) {
×
274
    attrset(palette[HEADERROR]);
×
275
    printw("ERROR: screen too small, we need at least 3 lines");
×
276
  }
277

278
  /* values */
279
  for (y = ROWS_PER_CHANNEL_ROW;
×
280
       y < LINES && z < ola::DMX_UNIVERSE_SIZE && i < channels_per_screen;
×
281
       y += ROWS_PER_CHANNEL_ROW) {
×
282
    move(y, 0);  // NOLINT(build/include_what_you_use) This is ncurses.h's move
×
283
    for (x = 0;
×
284
         x < channels_per_line &&
×
285
         z < ola::DMX_UNIVERSE_SIZE &&
×
286
         i < channels_per_screen;
×
287
         x++, z++, i++) {
×
288
      const int d = dmx[z];
×
289
      switch (d) {
×
290
        case ola::DMX_MIN_SLOT_VALUE:
×
291
          attrset(palette[ZERO]);
×
292
          break;
×
293
        case ola::DMX_MAX_SLOT_VALUE:
×
294
          attrset(palette[FULL]);
×
295
          break;
×
296
        default:
×
297
          attrset(palette[NORM]);
×
298
      }
299
      if (z == current_channel)
×
300
        attron(A_REVERSE);
×
301
      switch (display_mode) {
×
302
        case DISP_MODE_HEX:
×
303
          if (d == 0)
×
304
            addstr("    ");
×
305
          else
306
            printw(" %02x ", d);
×
307
          break;
308
        case DISP_MODE_DEC:
×
309
          if (d == 0)
×
310
            addstr("    ");
×
311
          else if (d < 100)
×
312
            printw(" %02d ", d);
×
313
          else
314
            printw("%03d ", d);
×
315
          break;
316
        case DISP_MODE_DMX:
×
317
        default:
×
318
          switch (d) {
×
319
            case ola::DMX_MIN_SLOT_VALUE:
×
320
              addstr("    ");
×
321
              break;
×
322
            case ola::DMX_MAX_SLOT_VALUE:
×
323
              addstr(" FL ");
×
324
              break;
×
325
            default:
×
326
              printw(" %02d ", (d * 100) / ola::DMX_MAX_SLOT_VALUE);
×
327
          }
328
      }
329
    }
330
  }
331
}
×
332

333
/* save current cue into cuebuffer */
334
void savecue() {
×
335
  memcpy(&dmxsave[current_cue * ola::DMX_UNIVERSE_SIZE],
×
336
         dmx,
337
         ola::DMX_UNIVERSE_SIZE);
338
}
×
339

340
/* get new cue from cuebuffer */
341
void loadcue() {
×
342
  memcpy(dmx,
×
343
         &dmxsave[current_cue * ola::DMX_UNIVERSE_SIZE],
×
344
         ola::DMX_UNIVERSE_SIZE);
345
}
×
346

347
/* fade cue "new_cue" into current cue */
348
void crossfade(unsigned int new_cue) {
×
349
  dmx_t *dmxold;
×
350
  dmx_t *dmxnew;
×
351
  int i;
×
352
  int max = ola::DMX_UNIVERSE_SIZE;
×
353

354
  /* check parameter */
355
  if (new_cue > MAXFKEY)
×
356
    return;
357

358
  undo_possible = 0;
×
359

360
  /* don't crossfade for small fadetimes */
361
  if (fadetime < 0.1f) {
×
362
    savecue();
×
363
    current_cue = new_cue;
×
364
    loadcue();
×
365
    setall();
×
366
    return;
×
367
  }
368

369
  savecue();
×
370
  dmxold = &dmxsave[current_cue * ola::DMX_UNIVERSE_SIZE];
×
371
  dmxnew = &dmxsave[new_cue * ola::DMX_UNIVERSE_SIZE];
×
372

373
  /* try to find the last channel value > 0, so we don't have to
374
     crossfade large blocks of 0s */
375
  for (i = ola::DMX_UNIVERSE_SIZE - 1; i >= 0; max = i, i--)
×
376
    if (dmxold[i] || dmxnew[i])
×
377
      break;
378

379
  {
×
380
    const uint64_t tstart = timeGetTime();
×
381
    const uint64_t tend = tstart + static_cast<int>(fadetime * 1000.0);
×
382
    uint64_t t = tstart;
×
383
    while (t <= tend) {
×
384
    /* calculate new cue */
385
    t = timeGetTime();
×
386
    {
×
387
      const float p = static_cast<float>(t - tstart) / 1000.0f / fadetime;
×
388
      const float q = 1.0f - p;
×
389
      for (i = 0; i < max; i++)
×
390
        if (dmxold[i] || dmxnew[i]) /* avoid calculating with only 0 */
×
391
          dmx[i] = static_cast<int>(static_cast<float>(dmxold[i]) * q +
×
392
                                    static_cast<float>(dmxnew[i]) * p);
×
393
      setall();
×
394

395
      /* update screen */
396
      fading = static_cast<int>(p * 100.0f);
×
397
      values();
×
398
      refresh();
×
399
      DMXsleep(100000);
×
400

401
      // get current time, because the last time is too old (due to the sleep)
402
      t = timeGetTime();
×
403
    }
404
      }
405
    fading = 0;
×
406

407
    /* set the new cue */
408
    current_cue = new_cue;
×
409
    loadcue();
×
410
    setall();
×
411
  }
412
}
413

414

415
void undo() {
×
416
  if (undo_possible) {
×
417
    memcpy(dmx, dmxundo, ola::DMX_UNIVERSE_SIZE);
×
418
    undo_possible = 0;
×
419
  }
420
}
×
421

422
void undoprep() {
×
423
  memcpy(dmxundo, dmx, ola::DMX_UNIVERSE_SIZE);
×
424
  undo_possible = 1;
×
425
}
×
426

427
/* change palette to "p". If p is invalid new palette is number "0". */
428
void changepalette(int p) {
×
429
  /* COLOR_BLACK
430
     COLOR_RED
431
     COLOR_GREEN
432
     COLOR_YELLOW
433
     COLOR_BLUE
434
     COLOR_MAGENTA
435
     COLOR_CYAN
436
     COLOR_WHITE
437

438
     A_NORMAL
439
     A_ATTRIBUTES
440
     A_CHARTEXT
441
     A_COLOR
442
     A_STANDOUT
443
     A_UNDERLINE
444
     A_REVERSE
445
     A_BLINK
446
     A_DIM
447
     A_BOLD
448
     A_ALTCHARSET
449
     A_INVIS
450
  */
451
  switch (p) {
×
452
    default:
×
453
      palette_number = 0;
×
454
      // fall through, use 0 as default palette
455
      OLA_FALLTHROUGH
×
456
    case 0:
×
457
      init_pair(CHANNEL, COLOR_BLACK, COLOR_CYAN);
×
458
      init_pair(ZERO, COLOR_BLACK, COLOR_WHITE);
×
459
      init_pair(NORM, COLOR_BLUE, COLOR_WHITE);
×
460
      init_pair(FULL, COLOR_RED, COLOR_WHITE);
×
461
      init_pair(HEADLINE, COLOR_WHITE, COLOR_BLUE);
×
462
      init_pair(HEADEMPH, COLOR_YELLOW, COLOR_BLUE);
×
463
      init_pair(HEADERROR, COLOR_RED, COLOR_BLUE);
×
464
      break;
×
465
    case 2:
×
466
      init_pair(CHANNEL, COLOR_BLACK, COLOR_WHITE);
×
467
      init_pair(ZERO, COLOR_BLUE, COLOR_BLACK);
×
468
      init_pair(NORM, COLOR_GREEN, COLOR_BLACK);
×
469
      init_pair(FULL, COLOR_RED, COLOR_BLACK);
×
470
      init_pair(HEADLINE, COLOR_WHITE, COLOR_BLACK);
×
471
      init_pair(HEADEMPH, COLOR_CYAN, COLOR_BLACK);
×
472
      init_pair(HEADERROR, COLOR_RED, COLOR_BLACK);
×
473
      break;
×
474
    case 1:
×
475
      palette[CHANNEL] = A_REVERSE;
×
476
      palette[ZERO] = A_NORMAL;
×
477
      palette[NORM] = A_NORMAL;
×
478
      palette[FULL] = A_BOLD;
×
479
      palette[HEADLINE] = A_NORMAL;
×
480
      palette[HEADEMPH] = A_NORMAL;
×
481
      palette[HEADERROR] = A_BOLD;
×
482
      break;
×
483
  }
484

485
  if (p == 0 || p == 2) {
×
486
    palette[CHANNEL] = COLOR_PAIR(CHANNEL);
×
487
    palette[ZERO] = COLOR_PAIR(ZERO);
×
488
    palette[NORM] = COLOR_PAIR(NORM);
×
489
    palette[FULL] = COLOR_PAIR(FULL);
×
490
    palette[HEADLINE] = COLOR_PAIR(HEADLINE);
×
491
    palette[HEADEMPH] = COLOR_PAIR(HEADEMPH);
×
492
    palette[HEADERROR] = COLOR_PAIR(HEADERROR);
×
493
  }
494

495
  mask();
×
496
}
×
497

498
void CHECK(void *p) {
×
499
  if (p == NULL) {
×
500
    fprintf(stderr, "could not alloc\n");
×
501
    exit(1);
×
502
  }
503
}
×
504

505

506
/* calculate channels_per_line and channels_per_screen from LINES and COLS */
507
void calcscreengeometry() {
×
508
  int c = LINES;
×
509
  if (c < 3) {
×
510
    screen_to_small = true;
×
511
    exit(1);
×
512
  }
513
  c--;  // One line for headline
×
514
  if (c % ROWS_PER_CHANNEL_ROW == 1)
×
515
    c--;  // Need an even number of lines for data
×
516
  channels_per_line = COLS / CHANNEL_DISPLAY_WIDTH;
×
517
  channels_per_screen = channels_per_line * (c / ROWS_PER_CHANNEL_ROW);
×
518
}
×
519

520
/* signal handler for SIGWINCH */
521
void terminalresize(int sig) {
×
522
  struct winsize size;
×
523
  if (ioctl(0, TIOCGWINSZ, &size) < 0)
×
524
    return;
×
525

526
  resizeterm(size.ws_row, size.ws_col);
×
527
  calcscreengeometry();
×
528
  mask();
×
529
  (void) sig;
×
530
}
531

532
WINDOW *w = NULL;
533

534
/* cleanup handler for program exit. */
535
void cleanup() {
×
536
  if (w) {
×
537
    resetty();
×
538
    endwin();
×
539
  }
540

541
  if (screen_to_small)
×
542
    puts("screen too small, we need at least 3 lines");
×
543
}
×
544

545
void stdin_ready() {
×
546
  int n;
×
547
  int c = wgetch(w);
×
548
  switch (c) {
×
549
    case KEY_PPAGE:
×
550
      undoprep();
×
551
      if (dmx[current_channel] < ola::DMX_MAX_SLOT_VALUE - CHANNEL_NUDGE_VALUE)
×
552
        dmx[current_channel] += CHANNEL_NUDGE_VALUE;
×
553
      else
554
        dmx[current_channel] = ola::DMX_MAX_SLOT_VALUE;
×
555
      set();
×
556
      break;
×
557

558
    case '+':
×
559
      if (dmx[current_channel] < ola::DMX_MAX_SLOT_VALUE) {
×
560
        undoprep();
×
561
        dmx[current_channel]++;
×
562
      }
563
      set();
×
564
      break;
×
565

566
    case KEY_NPAGE:
×
567
      undoprep();
×
568
      if (dmx[current_channel] == ola::DMX_MAX_SLOT_VALUE) {
×
569
        // Smooth out the fade down
570
        dmx[current_channel] = (ola::DMX_MAX_SLOT_VALUE + 1) -
×
571
            CHANNEL_NUDGE_VALUE;
572
      } else if (dmx[current_channel] > CHANNEL_NUDGE_VALUE) {
×
573
        dmx[current_channel] -= CHANNEL_NUDGE_VALUE;
×
574
      } else {
575
        dmx[current_channel] = ola::DMX_MIN_SLOT_VALUE;
×
576
      }
577
      set();
×
578
      break;
×
579

580
    case '-':
×
581
      if (dmx[current_channel] > ola::DMX_MIN_SLOT_VALUE) {
×
582
        undoprep();
×
583
        dmx[current_channel]--;
×
584
      }
585
      set();
×
586
      break;
×
587

588
    case ' ':
×
589
      undoprep();
×
590
      if (dmx[current_channel] < ((ola::DMX_MAX_SLOT_VALUE + 1) / 2))
×
591
        dmx[current_channel] = ola::DMX_MAX_SLOT_VALUE;
×
592
      else
593
        dmx[current_channel] = ola::DMX_MIN_SLOT_VALUE;
×
594
      set();
×
595
      break;
×
596

597
    case '0' ... '9':
×
598
      fadetime = c -'0';
×
599
      break;
×
600

601
    case KEY_HOME:
×
602
      current_channel = 0;
×
603
      first_channel = 0;
×
604
      mask();
×
605
      break;
×
606

607
    case KEY_END:
×
608
      current_channel = ola::DMX_UNIVERSE_SIZE - 1;
×
609
      if (channels_per_screen >= ola::DMX_UNIVERSE_SIZE) {
×
610
        first_channel = 0;
×
611
      } else {
612
        first_channel = current_channel - (channels_per_screen - 1);
×
613
      }
614
      mask();
×
615
      break;
×
616

617
    case KEY_RIGHT:
×
618
      if (current_channel < ola::DMX_UNIVERSE_SIZE - 1) {
×
619
        current_channel++;
×
620
        if (current_channel >= first_channel + channels_per_screen) {
×
621
          first_channel += channels_per_line;
×
622
          mask();
×
623
        }
624
      }
625
      break;
626

627
    case KEY_LEFT:
×
628
      if (current_channel > 0) {
×
629
        current_channel--;
×
630
        if (current_channel < first_channel) {
×
631
          first_channel -= channels_per_line;
×
632
          if (first_channel < 0)
×
633
            first_channel = 0;
×
634
          mask();
×
635
        }
636
      }
637
      break;
638

639
    case KEY_DOWN:
×
640
      current_channel += channels_per_line;
×
641
      if (current_channel >= ola::DMX_UNIVERSE_SIZE)
×
642
        current_channel = ola::DMX_UNIVERSE_SIZE - 1;
×
643
      if (current_channel >= first_channel + channels_per_screen) {
×
644
        first_channel += channels_per_line;
×
645
        mask();
×
646
      }
647
      break;
648

649
    case KEY_UP:
×
650
      current_channel -= channels_per_line;
×
651
      if (current_channel < 0)
×
652
        current_channel = 0;
×
653
      if (current_channel < first_channel) {
×
654
        first_channel -= channels_per_line;
×
655
        if (first_channel < 0)
×
656
          first_channel = 0;
×
657
        mask();
×
658
      }
659
      break;
660

661
    case KEY_IC:
×
662
      undoprep();
×
663
      for (n = ola::DMX_UNIVERSE_SIZE - 1; n > current_channel && n > 0; n--)
×
664
        dmx[n] = dmx[n - 1];
×
665
      setall();
×
666
      break;
×
667

668
    case KEY_DC:
×
669
      undoprep();
×
670
      for (n = current_channel; n < ola::DMX_UNIVERSE_SIZE - 1; n++)
×
671
        dmx[n] = dmx[n + 1];
×
672
      setall();
×
673
      break;
×
674

675
    case 'B':
×
676
    case 'b':
×
677
      undoprep();
×
678
      memset(dmx, ola::DMX_MIN_SLOT_VALUE, ola::DMX_UNIVERSE_SIZE);
×
679
      setall();
×
680
      break;
×
681

682
    case 'F':
×
683
    case 'f':
×
684
      undoprep();
×
685
      memset(dmx, ola::DMX_MAX_SLOT_VALUE, ola::DMX_UNIVERSE_SIZE);
×
686
      setall();
×
687
      break;
×
688

689
    case 'M':
×
690
    case 'm':
×
691
      if (++display_mode >= DISP_MODE_MAX)
×
692
        display_mode = 0;
×
693
      mask();
×
694
      break;
×
695

696
    case 'N':
×
697
    case 'n':
×
698
      if (++channels_offset > 1)
×
699
        channels_offset = 0;
×
700
      mask();
×
701
      break;
×
702

703
    case 'P':
×
704
    case 'p':
×
705
      changepalette(++palette_number);
×
706
      break;
×
707

708
    case 'U':
×
709
    case 'u':
×
710
      undo();
×
711
      break;
×
712

713
    case 'Q':
×
714
    case 'q':
×
715
      ss->Terminate();
×
716
      break;
×
717

718
    default:
×
719
      if (c >= static_cast<int>(KEY_F(1)) &&
×
720
          c <= static_cast<int>(KEY_F(MAXFKEY)))
×
721
        crossfade(c - KEY_F(1));
×
722
      break;
723
  }
724
  values();
×
725
  refresh();
×
726
}
×
727

728
/*
729
 * parse our cmd line options
730
 */
731
void ParseOptions(int argc, char *argv[], options *opts) {
×
732
  static struct option long_options[] = {
×
733
      {"help", no_argument, 0, 'h'},
734
      {"universe", required_argument, 0, 'u'},
735
      {0, 0, 0, 0}
736
    };
737

738
  opts->universe = DEFAULT_UNIVERSE;
×
739
  opts->help = false;
×
740

741
  int c;
×
742
  int option_index = 0;
×
743

744
  while (1) {
×
745
    c = getopt_long(argc, argv, "hu:", long_options, &option_index);
×
746

747
    if (c == -1)
×
748
      break;
749

750
    switch (c) {
×
751
      case 0:
752
        break;
753
      case 'h':
×
754
        opts->help = true;
×
755
        break;
×
756
      case 'u':
×
757
        opts->universe = strtoul(optarg, NULL, 0);
×
758
        break;
×
759
      case '?':
760
        break;
761
      default:
762
        break;
763
    }
764
  }
765
}
×
766

767

768
/*
769
 * Display the help message
770
 */
771
void DisplayHelpAndExit(char arg[]) {
×
772
  std::cout << "Usage: " << arg << " [--universe <universe_id>]\n"
×
773
  "\n"
774
  "Send data to a DMX512 universe.\n"
775
  "\n"
776
  "  -h, --help                   Display this help message and exit.\n"
777
  "  -u, --universe <universe_id> Id of universe to control (defaults to "
×
778
  << DEFAULT_UNIVERSE << ").\n"
×
779
  << std::endl;
×
780
  exit(ola::EXIT_OK);
×
781
}
782

783
int main(int argc, char *argv[]) {
×
784
  signal(SIGWINCH, terminalresize);
×
785
  atexit(cleanup);
×
786

787
  if (!ola::NetworkInit()) {
×
788
    std::cerr << "Network initialization failed." << std::endl;
×
789
    exit(ola::EXIT_UNAVAILABLE);
×
790
  }
791

792
  // 10 bytes security, for file IO routines, will be optimized and checked
793
  // later
794
  dmx = reinterpret_cast<dmx_t*>(calloc(ola::DMX_UNIVERSE_SIZE + 10,
×
795
                                 sizeof(dmx_t)));
796
  CHECK(dmx);
×
797

798
  dmxsave = reinterpret_cast<dmx_t*>(
×
799
      calloc(ola::DMX_UNIVERSE_SIZE * MAXFKEY, sizeof(dmx_t)));
×
800
  CHECK(dmxsave);
×
801

802
  dmxundo = reinterpret_cast<dmx_t*>(
×
803
      calloc(ola::DMX_UNIVERSE_SIZE, sizeof(dmx_t)));
×
804
  CHECK(dmxundo);
×
805

806
  options opts;
×
807

808
  ParseOptions(argc, argv, &opts);
×
809

810
  if (opts.help) {
×
811
    DisplayHelpAndExit(argv[0]);
×
812
  }
813

814
  universe = opts.universe;
×
815

816
  /* set up ola connection */
817
  OlaClientWrapper ola_client;
×
818
  ola::io::UnmanagedFileDescriptor stdin_descriptor(0);
×
819
  stdin_descriptor.SetOnData(ola::NewCallback(&stdin_ready));
×
820

821
  if (!ola_client.Setup()) {
×
822
    printf("error: %s", strerror(errno));
×
823
    exit(1);
×
824
  }
825

826
  client = ola_client.GetClient();
×
827
  ss = ola_client.GetSelectServer();
×
828
  ss->AddReadDescriptor(&stdin_descriptor);
×
829

830
  /* init curses */
831
  w = initscr();
×
832
  if (!w) {
×
833
    printf("unable to open main-screen\n");
×
834
    return 1;
835
  }
836

837
  savetty();
×
838
  start_color();
×
839
  noecho();
×
840
  raw();
×
841
  keypad(w, TRUE);
×
842

843
  calcscreengeometry();
×
844
  changepalette(palette_number);
×
845

846
  values();
×
847
  refresh();
×
848
  ss->Run();
×
849
  return 0;
850
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc