530 lines
10 KiB
C
530 lines
10 KiB
C
|
/*
|
||
|
* Copyright (C) 2001 Dirk Jagdmann <doj@cubic.org>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License
|
||
|
* as published by the Free Software Foundation; either version 2
|
||
|
* of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Modified by Simon Newton (nomis52<AT>westnet.com.au)
|
||
|
* to use artnet
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#include <curses.h>
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <getopt.h>
|
||
|
#ifdef HAVE_MALLOC_H
|
||
|
#include <malloc.h>
|
||
|
#endif
|
||
|
#include <signal.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <termios.h>
|
||
|
#include <time.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/timeb.h>
|
||
|
|
||
|
#include <artnet/artnet.h>
|
||
|
|
||
|
/* color names used */
|
||
|
enum {
|
||
|
CHANNEL = 1,
|
||
|
ZERO,
|
||
|
NORM,
|
||
|
FULL,
|
||
|
HEADLINE,
|
||
|
HEADEMPH,
|
||
|
HEADERROR,
|
||
|
|
||
|
MAXCOLOR
|
||
|
};
|
||
|
|
||
|
/* display modes */
|
||
|
enum {
|
||
|
DISP_MODE_DMX = 0,
|
||
|
DISP_MODE_HEX,
|
||
|
DISP_MODE_DEC,
|
||
|
DISP_MODE_MAX,
|
||
|
};
|
||
|
|
||
|
int MAXCHANNELS=512;
|
||
|
|
||
|
typedef unsigned char dmx_t ;
|
||
|
|
||
|
static dmx_t *dmx;
|
||
|
|
||
|
static int display_mode = DISP_MODE_DMX;
|
||
|
static int current_channel = 0; /* channel cursor is positioned on */
|
||
|
static int first_channel = 0; /* channel in upper left corner */
|
||
|
static int channels_per_line=80/4;
|
||
|
static int channels_per_screen=80/4*24/2;
|
||
|
static int palette_number=0;
|
||
|
static int palette[MAXCOLOR];
|
||
|
static char *errorstr=NULL;
|
||
|
static int channels_offset=1;
|
||
|
|
||
|
WINDOW *w=NULL;
|
||
|
static artnet_node node ;
|
||
|
|
||
|
|
||
|
/* display the channels numbers */
|
||
|
void mask() {
|
||
|
int i=0,x,y,z=first_channel;
|
||
|
|
||
|
erase();
|
||
|
|
||
|
/* clear headline */
|
||
|
attrset(palette[HEADLINE]);
|
||
|
move(0,0);
|
||
|
for(x=0; x<COLS; x++)
|
||
|
addch(' ');
|
||
|
|
||
|
/* write channel numbers */
|
||
|
attrset(palette[CHANNEL]);
|
||
|
for(y=1; y<LINES && z<MAXCHANNELS && i<channels_per_screen; y+=2) {
|
||
|
move(y,0);
|
||
|
for(x=0; x<channels_per_line && z<MAXCHANNELS && i<channels_per_screen; x++, i++, z++)
|
||
|
switch(display_mode) {
|
||
|
case DISP_MODE_DMX:
|
||
|
case DISP_MODE_DEC:
|
||
|
default:
|
||
|
printw("%03d ",z+channels_offset); break;
|
||
|
|
||
|
case DISP_MODE_HEX:
|
||
|
printw("%03X ",z+channels_offset); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* update the screen */
|
||
|
void values() {
|
||
|
int i=0,x,y,z=first_channel;
|
||
|
|
||
|
/* headline */
|
||
|
if(COLS>24)
|
||
|
{
|
||
|
time_t t=time(NULL);
|
||
|
struct tm *tt=localtime(&t);
|
||
|
char *s=asctime(tt);
|
||
|
s[strlen(s)-1]=0; /* strip newline at end of string */
|
||
|
|
||
|
attrset(palette[HEADLINE]);
|
||
|
mvprintw(0,1,"%s", s);
|
||
|
}
|
||
|
|
||
|
/* values */
|
||
|
for(y=2; y<LINES && z<MAXCHANNELS && i<channels_per_screen; y+=2)
|
||
|
{
|
||
|
move(y,0);
|
||
|
for(x=0; x<channels_per_line && z<MAXCHANNELS && i<channels_per_screen; x++, z++, i++)
|
||
|
{
|
||
|
const int d=dmx[z];
|
||
|
switch(d)
|
||
|
{
|
||
|
case 0: attrset(palette[ZERO]); break;
|
||
|
case 255: attrset(palette[FULL]); break;
|
||
|
default: attrset(palette[NORM]);
|
||
|
}
|
||
|
if(z==current_channel)
|
||
|
attron(A_REVERSE);
|
||
|
switch(display_mode)
|
||
|
{
|
||
|
case DISP_MODE_HEX:
|
||
|
if(d==0)
|
||
|
addstr(" ");
|
||
|
else
|
||
|
printw(" %02x ", d);
|
||
|
break;
|
||
|
case DISP_MODE_DEC:
|
||
|
if(d==0)
|
||
|
addstr(" ");
|
||
|
else if(d<100)
|
||
|
printw(" %02d ", d);
|
||
|
else
|
||
|
printw("%03d ", d);
|
||
|
break;
|
||
|
case DISP_MODE_DMX:
|
||
|
default:
|
||
|
switch(d)
|
||
|
{
|
||
|
case 0: addstr(" "); break;
|
||
|
case 255: addstr(" FL "); break;
|
||
|
default: printw(" %02d ", (d*100)/255);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* change palette to "p". If p is invalid new palette is number "0". */
|
||
|
void changepalette(int p)
|
||
|
{
|
||
|
/* COLOR_BLACK
|
||
|
COLOR_RED
|
||
|
COLOR_GREEN
|
||
|
COLOR_YELLOW
|
||
|
COLOR_BLUE
|
||
|
COLOR_MAGENTA
|
||
|
COLOR_CYAN
|
||
|
COLOR_WHITE
|
||
|
|
||
|
A_NORMAL
|
||
|
A_ATTRIBUTES
|
||
|
A_CHARTEXT
|
||
|
A_COLOR
|
||
|
A_STANDOUT
|
||
|
A_UNDERLINE
|
||
|
A_REVERSE
|
||
|
A_BLINK
|
||
|
A_DIM
|
||
|
A_BOLD
|
||
|
A_ALTCHARSET
|
||
|
A_INVIS
|
||
|
*/
|
||
|
switch(p)
|
||
|
{
|
||
|
default:
|
||
|
palette_number=0;
|
||
|
case 0:
|
||
|
init_pair(CHANNEL, COLOR_BLACK, COLOR_CYAN);
|
||
|
init_pair(ZERO, COLOR_BLACK, COLOR_WHITE);
|
||
|
init_pair(NORM, COLOR_BLUE, COLOR_WHITE);
|
||
|
init_pair(FULL, COLOR_RED, COLOR_WHITE);
|
||
|
init_pair(HEADLINE, COLOR_WHITE, COLOR_BLUE);
|
||
|
init_pair(HEADEMPH, COLOR_YELLOW, COLOR_BLUE);
|
||
|
init_pair(HEADERROR, COLOR_RED, COLOR_BLUE);
|
||
|
goto color;
|
||
|
|
||
|
case 2:
|
||
|
init_pair(CHANNEL, COLOR_BLACK, COLOR_WHITE);
|
||
|
init_pair(ZERO, COLOR_BLUE, COLOR_BLACK);
|
||
|
init_pair(NORM, COLOR_GREEN, COLOR_BLACK);
|
||
|
init_pair(FULL, COLOR_RED, COLOR_BLACK);
|
||
|
init_pair(HEADLINE, COLOR_WHITE, COLOR_BLACK);
|
||
|
init_pair(HEADEMPH, COLOR_CYAN, COLOR_BLACK);
|
||
|
init_pair(HEADERROR, COLOR_RED, COLOR_BLACK);
|
||
|
goto color;
|
||
|
|
||
|
color:
|
||
|
palette[CHANNEL]=COLOR_PAIR(CHANNEL);
|
||
|
palette[ZERO]=COLOR_PAIR(ZERO);
|
||
|
palette[NORM]=COLOR_PAIR(NORM);
|
||
|
palette[FULL]=COLOR_PAIR(FULL);
|
||
|
palette[HEADLINE]=COLOR_PAIR(HEADLINE);
|
||
|
palette[HEADEMPH]=COLOR_PAIR(HEADEMPH);
|
||
|
palette[HEADERROR]=COLOR_PAIR(HEADERROR);
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
palette[CHANNEL]=A_REVERSE;
|
||
|
palette[ZERO]=A_NORMAL;
|
||
|
palette[NORM]=A_NORMAL;
|
||
|
palette[FULL]=A_BOLD;
|
||
|
palette[HEADLINE]=A_NORMAL;
|
||
|
palette[HEADEMPH]=A_NORMAL;
|
||
|
palette[HEADERROR]=A_BOLD;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
mask();
|
||
|
}
|
||
|
|
||
|
void CHECK(void *p)
|
||
|
{
|
||
|
if(p==NULL)
|
||
|
{
|
||
|
fprintf(stderr, "could not alloc\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* signal handler for crashes. Program is aborted */
|
||
|
void crash(int sig) {
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* calculate channels_per_line and channels_per_screen from LINES and COLS */
|
||
|
void calcscreengeometry() {
|
||
|
int c=LINES;
|
||
|
if(c<3) {
|
||
|
errorstr="screen to small, we need at least 3 lines";
|
||
|
exit(1);
|
||
|
}
|
||
|
c--; /* one line for headline */
|
||
|
if(c%2==1)
|
||
|
c--;
|
||
|
channels_per_line=COLS/4;
|
||
|
channels_per_screen=channels_per_line*c/2;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* signal handler for SIGWINCH */
|
||
|
void terminalresize(int sig) {
|
||
|
struct winsize size;
|
||
|
if(ioctl(0, TIOCGWINSZ, &size) < 0)
|
||
|
return;
|
||
|
|
||
|
resizeterm(size.ws_row, size.ws_col);
|
||
|
calcscreengeometry();
|
||
|
mask();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* cleanup handler for program exit. */
|
||
|
void cleanup() {
|
||
|
if(w) {
|
||
|
resetty();
|
||
|
endwin();
|
||
|
}
|
||
|
|
||
|
|
||
|
artnet_stop(node) ;
|
||
|
artnet_destroy(node) ;
|
||
|
|
||
|
}
|
||
|
|
||
|
int dmx_handler(artnet_node n, int prt , void *d ) {
|
||
|
int len ;
|
||
|
uint8_t *data ;
|
||
|
|
||
|
|
||
|
|
||
|
if( prt == 0 ) {
|
||
|
data = artnet_read_dmx(n, prt, &len) ;
|
||
|
memcpy(dmx, data,len) ;
|
||
|
values();
|
||
|
refresh();
|
||
|
}
|
||
|
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int main (int argc, char *argv[]) {
|
||
|
int c=0;
|
||
|
int optc , subnet_addr = 0 , port_addr = 0 ;
|
||
|
int artnet_sd ;
|
||
|
char *ip_addr = NULL ;
|
||
|
|
||
|
atexit(cleanup);
|
||
|
|
||
|
dmx = malloc(MAXCHANNELS) ;
|
||
|
|
||
|
if(!dmx) {
|
||
|
printf("malloc failed\n") ;
|
||
|
return 1 ;
|
||
|
}
|
||
|
|
||
|
memset(dmx, 0x00, MAXCHANNELS) ;
|
||
|
|
||
|
// parse options
|
||
|
while ((optc = getopt (argc, argv, "s:p:a:")) != EOF) {
|
||
|
switch (optc) {
|
||
|
case 'a':
|
||
|
ip_addr = (char *) strdup(optarg) ;
|
||
|
break;
|
||
|
case 's':
|
||
|
subnet_addr = atoi(optarg) ;
|
||
|
|
||
|
if(subnet_addr < 0 && subnet_addr > 15) {
|
||
|
printf("Subnet address must be between 0 and 15\n") ;
|
||
|
exit(1) ;
|
||
|
}
|
||
|
break ;
|
||
|
case 'p':
|
||
|
port_addr = atoi(optarg) ;
|
||
|
|
||
|
if(port_addr < 0 && port_addr > 15) {
|
||
|
printf("Port address must be between 0 and 15\n") ;
|
||
|
exit(1) ;
|
||
|
}
|
||
|
break ;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* set up artnet connection */
|
||
|
node = artnet_new(ip_addr, 0 ) ; ;
|
||
|
|
||
|
if(node == NULL) {
|
||
|
printf("Unable to connect\n") ;
|
||
|
return 1 ;
|
||
|
}
|
||
|
|
||
|
if(artnet_set_dmx_handler(node, dmx_handler, NULL) ) {
|
||
|
printf("Failed to install handler\n") ;
|
||
|
return 1 ;
|
||
|
}
|
||
|
|
||
|
artnet_set_subnet_addr(node, subnet_addr) ;
|
||
|
|
||
|
artnet_set_port_type(node, 0, ARTNET_ENABLE_OUTPUT, ARTNET_PORT_DMX) ;
|
||
|
artnet_set_port_addr(node, 0, ARTNET_OUTPUT_PORT, port_addr);
|
||
|
|
||
|
artnet_start(node) ;
|
||
|
|
||
|
// store the sds
|
||
|
artnet_sd = artnet_get_sd(node) ;
|
||
|
|
||
|
/* init curses */
|
||
|
w = initscr();
|
||
|
if (!w) {
|
||
|
printf ("unable to open main-screen\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
savetty();
|
||
|
start_color();
|
||
|
noecho();
|
||
|
raw();
|
||
|
keypad(w, TRUE);
|
||
|
|
||
|
calcscreengeometry();
|
||
|
changepalette(palette_number);
|
||
|
|
||
|
/* main loop */
|
||
|
c=0;
|
||
|
while (c!='q') {
|
||
|
int n, max;
|
||
|
fd_set rd_fds;
|
||
|
struct timeval tv;
|
||
|
|
||
|
FD_ZERO(&rd_fds);
|
||
|
FD_SET(0, &rd_fds);
|
||
|
FD_SET(artnet_sd, &rd_fds) ;
|
||
|
|
||
|
max = artnet_sd ;
|
||
|
|
||
|
tv.tv_sec = 1;
|
||
|
tv.tv_usec = 0;
|
||
|
|
||
|
n = select(max+1, &rd_fds, NULL, NULL, &tv);
|
||
|
if(n>0) {
|
||
|
if(FD_ISSET(0, &rd_fds)) {
|
||
|
c=wgetch(w);
|
||
|
switch (c) {
|
||
|
case KEY_HOME:
|
||
|
current_channel=0;
|
||
|
first_channel=0;
|
||
|
mask();
|
||
|
break;
|
||
|
case KEY_RIGHT:
|
||
|
if(current_channel < MAXCHANNELS-1) {
|
||
|
current_channel++;
|
||
|
if(current_channel >= first_channel+channels_per_screen) {
|
||
|
first_channel+=channels_per_line;
|
||
|
mask();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case KEY_LEFT:
|
||
|
if(current_channel > 0) {
|
||
|
current_channel--;
|
||
|
if(current_channel < first_channel) {
|
||
|
first_channel-=channels_per_line;
|
||
|
if(first_channel<0)
|
||
|
first_channel=0;
|
||
|
mask();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case KEY_DOWN:
|
||
|
current_channel+=channels_per_line;
|
||
|
if(current_channel>=MAXCHANNELS)
|
||
|
current_channel=MAXCHANNELS-1;
|
||
|
if(current_channel >= first_channel+channels_per_screen)
|
||
|
{
|
||
|
first_channel+=channels_per_line;
|
||
|
mask();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case KEY_UP:
|
||
|
current_channel-=channels_per_line;
|
||
|
if(current_channel<0)
|
||
|
current_channel=0;
|
||
|
if(current_channel < first_channel)
|
||
|
{
|
||
|
first_channel-=channels_per_line;
|
||
|
if(first_channel<0)
|
||
|
first_channel=0;
|
||
|
mask();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case KEY_IC:
|
||
|
for(n=MAXCHANNELS-1; n>current_channel && n>0; n--)
|
||
|
dmx[n]=dmx[n-1];
|
||
|
break;
|
||
|
|
||
|
case KEY_DC:
|
||
|
for(n=current_channel; n<MAXCHANNELS-1; n++)
|
||
|
dmx[n]=dmx[n+1];
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 'M':
|
||
|
case 'm':
|
||
|
if(++display_mode>=DISP_MODE_MAX)
|
||
|
display_mode=0;
|
||
|
mask();
|
||
|
break;
|
||
|
|
||
|
case 'N':
|
||
|
case 'n':
|
||
|
if(++channels_offset>1)
|
||
|
channels_offset=0;
|
||
|
mask();
|
||
|
break;
|
||
|
|
||
|
case 'P':
|
||
|
case 'p':
|
||
|
changepalette(++palette_number);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FD_ISSET(artnet_sd , &rd_fds) )
|
||
|
artnet_read(node,0);
|
||
|
}
|
||
|
|
||
|
values();
|
||
|
refresh();
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|