add lcdvc client: virtal console on LCD
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
SUBDIRS = examples headlines lcdexec lcdproc metar
|
||||
SUBDIRS = examples headlines lcdexec lcdproc lcdvc metar
|
||||
|
||||
## EOF
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
lcdvc
|
||||
@@ -0,0 +1,23 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
sysconf_DATA = lcdvc.conf
|
||||
|
||||
bin_PROGRAMS = lcdvc
|
||||
|
||||
lcdvc_SOURCES = lcdvc.c lcdvc.h lcd_link.c lcd_link.h vc_link.c vc_link.h
|
||||
|
||||
lcdvc_LDADD = @ldap_libs@ ../../shared/libLCDstuff.a
|
||||
|
||||
if DARWIN
|
||||
AM_LDFLAGS = -framework CoreFoundation -framework IOKit
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
|
||||
#AM_CFLAGS = -g -O0
|
||||
#AM_LDFLAGS = -g
|
||||
|
||||
|
||||
EXTRA_DIST = $(sysconf_DATA)
|
||||
|
||||
## EOF
|
||||
@@ -0,0 +1,316 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lcd_link.h"
|
||||
#include "vc_link.h"
|
||||
#include "lcdvc.h"
|
||||
#include "shared/report.h"
|
||||
#include "shared/str.h"
|
||||
#include "shared/sockets.h"
|
||||
|
||||
char * address = UNSET_STR;
|
||||
int port = UNSET_INT;
|
||||
short autoscroll = 1;
|
||||
|
||||
int sock;
|
||||
short listening = 0;
|
||||
short scroll_x = 0, scroll_y = 0;
|
||||
short lcd_cursor_x, lcd_cursor_y;
|
||||
short lcd_width = 0, lcd_height = 0;
|
||||
char * lcd_buf = NULL;
|
||||
|
||||
short last_vc_cursor_y = 0;
|
||||
short last_vc_cursor_x = 0;
|
||||
short last_lcd_cursor_x = 0;
|
||||
short last_lcd_cursor_y = 0;
|
||||
|
||||
int read_connect_string();
|
||||
|
||||
int connect_and_setup()
|
||||
{
|
||||
char buf[200];
|
||||
int i;
|
||||
int e = 0;
|
||||
short line;
|
||||
|
||||
report(RPT_INFO, "Connecting to %s:%d", address, port);
|
||||
|
||||
sock = sock_connect(address, port);
|
||||
if (sock <= 0) {
|
||||
report(RPT_ERR, "Connecting to %s:%d failed", address, port);
|
||||
return -1;
|
||||
}
|
||||
/* Create our menu */
|
||||
sock_send_string(sock, "hello\n");
|
||||
if (read_connect_string() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf)-1, "client_set -name \"%s\"\n", progname);
|
||||
sock_send_string(sock, buf);
|
||||
|
||||
/* Create screen */
|
||||
CHAIN(e, sock_send_string(sock, "screen_add console\n"));
|
||||
for (line = 0; line < lcd_height; line++) {
|
||||
snprintf(buf, sizeof(buf)-1, "widget_add console line%d string\n", line);
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
CHAIN(e, sock_send_string(sock, buf));
|
||||
}
|
||||
/* Add menu items */
|
||||
CHAIN(e, sock_send_string(sock, "menu_add_item \"\" autoscroll checkbox \"Auto scroll\"\n"));
|
||||
CHAIN(e, sock_send_string(sock, "menu_set_item \"\" autoscroll -value on\n"));
|
||||
|
||||
/* Reserve keys */
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
snprintf(buf, sizeof(buf)-1, "client_add_key \"%s\"\n", keys[i]);
|
||||
CHAIN(e, sock_send_string(sock, buf));
|
||||
}
|
||||
|
||||
if (e < 0) {
|
||||
report(RPT_ERR, "Could not send to to LCDd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_connect_string()
|
||||
{
|
||||
char buf[8192];
|
||||
int len = 0;
|
||||
int a;
|
||||
char * argv[20];
|
||||
int argc;
|
||||
short received = 0;
|
||||
short timeout = 50; /* Give the server 5 secs to respond */
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
while (!received && timeout > 0) {
|
||||
len = sock_recv_string(sock, buf, sizeof(buf));
|
||||
if (len == 0) {
|
||||
usleep(100000);
|
||||
timeout --;
|
||||
} else {
|
||||
received = 1;
|
||||
}
|
||||
}
|
||||
report(RPT_INFO, "Received: %s", buf);
|
||||
|
||||
if (len <= 0) {
|
||||
report(RPT_ERR, "Did not receive LCDd connect response.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
argc = split(buf, ' ', argv, 20);
|
||||
for (a = 1; a < argc; a++) {
|
||||
if (0 == strcmp (argv[a], "wid"))
|
||||
lcd_width = atoi (argv[++a]);
|
||||
else if (0 == strcmp (argv[a], "hgt"))
|
||||
lcd_height = atoi (argv[++a]);
|
||||
}
|
||||
if (argc <= 0 || strcmp(argv[0], "connect") != 0
|
||||
|| lcd_width == 0 || lcd_width == 0) {
|
||||
report(RPT_ERR, "Received invalid LCDd connect response.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int read_response(char * buf, int maxsize)
|
||||
{
|
||||
return sock_recv_string(sock, buf, maxsize);
|
||||
}
|
||||
|
||||
int process_response(char * str)
|
||||
{
|
||||
char *argv[10];
|
||||
int argc;
|
||||
//int i;
|
||||
//char * p;
|
||||
char * str2 = strdup(str); /* get_args modifies str2 */
|
||||
|
||||
report(RPT_DEBUG, "Server said: \"%s\"", str);
|
||||
|
||||
/* Check what the server just said to us... */
|
||||
argc = get_args(argv, str2, 10);
|
||||
if (argc < 1) {
|
||||
free(str2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "listen") == 0) {
|
||||
listening = 1;
|
||||
}
|
||||
else if (strcmp(argv[0], "ignore") == 0) {
|
||||
listening = 0;
|
||||
}
|
||||
else if (strcmp(argv[0], "menuevent") == 0) {
|
||||
/* Ah, this is what we were waiting for ! */
|
||||
if (argc < 2) {
|
||||
report(RPT_WARNING, "Server gave invalid response");
|
||||
free(str2);
|
||||
return -1;
|
||||
}
|
||||
else if (strcmp(argv[1], "update") == 0) {
|
||||
if (argc < 4) {
|
||||
report(RPT_WARNING, "Server gave invalid response");
|
||||
free(str2);
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(argv[2], "autoscroll") == 0) {
|
||||
if (strcmp(argv[3], "on") == 0) {
|
||||
autoscroll = 1;
|
||||
} else if (strcmp(argv[3], "off") == 0) {
|
||||
autoscroll = 0;
|
||||
}
|
||||
report(RPT_INFO, "Autoscroll set to %d", autoscroll);
|
||||
}
|
||||
}
|
||||
else {
|
||||
; /* Ignore other menuevents */
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[0], "key") == 0) {
|
||||
if (argc < 2) {
|
||||
report(RPT_WARNING, "Server gave invalid response");
|
||||
free(str2);
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(argv[1], keys[0]) == 0) {
|
||||
if (scroll_y > 0) scroll_y --;
|
||||
} else if (strcmp(argv[1], keys[1]) == 0) {
|
||||
if (scroll_y + lcd_height < vc_height) scroll_y ++;
|
||||
} else if (strcmp(argv[1], keys[2]) == 0) {
|
||||
if (scroll_x > 0) scroll_x --;
|
||||
} else if (strcmp(argv[1], keys[3]) == 0) {
|
||||
if (scroll_x + lcd_width < vc_width) scroll_x ++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[0], "huh?") == 0) {
|
||||
/* Report errors */
|
||||
report(RPT_WARNING, "Server said: \"%s\"", str);
|
||||
}
|
||||
else {
|
||||
; /* Ignore all other responses */
|
||||
}
|
||||
free(str2);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int update_display()
|
||||
{
|
||||
//int bytes_read;
|
||||
short line;
|
||||
int e = 0;
|
||||
char buf[80];
|
||||
char * str_buf;
|
||||
short num_lines;
|
||||
num_lines = min(lcd_height, vc_height);
|
||||
|
||||
if (!listening)
|
||||
return 0;
|
||||
|
||||
if (!lcd_buf) {
|
||||
/* Not yet allocated */
|
||||
lcd_buf = malloc(lcd_width * lcd_height);
|
||||
memset(lcd_buf, ' ', lcd_width * lcd_height);
|
||||
}
|
||||
|
||||
if (autoscroll
|
||||
&& (last_vc_cursor_x != vc_cursor_x || last_vc_cursor_y != vc_cursor_y)) {
|
||||
last_vc_cursor_x = vc_cursor_x;
|
||||
last_vc_cursor_y = vc_cursor_y;
|
||||
|
||||
/* Adjust scroll position */
|
||||
if (scroll_x > vc_cursor_x)
|
||||
scroll_x = vc_cursor_x;
|
||||
if (scroll_x < vc_cursor_x - lcd_width + 1)
|
||||
scroll_x = vc_cursor_x - lcd_width + 1;
|
||||
if (scroll_y > vc_cursor_y)
|
||||
scroll_y = vc_cursor_y;
|
||||
if (scroll_y < vc_cursor_y - lcd_height + 1)
|
||||
scroll_y = vc_cursor_y - lcd_height + 1;
|
||||
}
|
||||
lcd_cursor_x = vc_cursor_x - scroll_x + 1;
|
||||
lcd_cursor_y = vc_cursor_y - scroll_y + 1;
|
||||
if (lcd_cursor_x != last_lcd_cursor_x || lcd_cursor_y != last_lcd_cursor_y) {
|
||||
last_lcd_cursor_x = lcd_cursor_x;
|
||||
last_lcd_cursor_y = lcd_cursor_y;
|
||||
|
||||
/* New scroll positions, send the cursor command */
|
||||
if (lcd_cursor_x < 1 || lcd_cursor_x > lcd_width
|
||||
|| lcd_cursor_y < 1 || lcd_cursor_y > lcd_height) {
|
||||
snprintf(buf, sizeof(buf)-1, "screen_set console -cursor off\n");
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf)-1, "screen_set console -cursor on -cursor_x %d -cursor_y %d\n",
|
||||
lcd_cursor_x, lcd_cursor_y);
|
||||
}
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
CHAIN(e, sock_send_string(sock, buf));
|
||||
}
|
||||
|
||||
/* Send all (changed) lines */
|
||||
str_buf = malloc(80 + 2 * lcd_width);
|
||||
for (line = 0; line < num_lines; line++) {
|
||||
|
||||
char * vc_p;
|
||||
char * lcd_p;
|
||||
short line_width;
|
||||
|
||||
line_width = min(lcd_width, vc_width);
|
||||
|
||||
/* Where does the data for this line come from ? */
|
||||
vc_p = vc_buf + vc_width * (scroll_y + line) + scroll_x;
|
||||
lcd_p = lcd_buf + lcd_width * line;
|
||||
|
||||
/* Has the line data changed ? */
|
||||
if (memcmp(vc_p, lcd_p, line_width) != 0) {
|
||||
/* Yes, so send it */
|
||||
char * a;
|
||||
short pos;
|
||||
|
||||
/* Format/escape the data */
|
||||
snprintf(str_buf, 80, "widget_set console line%d 1 %d \"", line, line+1);
|
||||
|
||||
a = str_buf + strlen(str_buf); /* start just after the " */
|
||||
for (pos = 0; pos < line_width; pos++) {
|
||||
if (vc_p[pos] == '\\' || vc_p[pos] == '\"') {
|
||||
*a++ = '\\'; /* add escape char */
|
||||
}
|
||||
if ((signed char) vc_p[pos] >= 32) {
|
||||
*a++ = vc_p[pos]; /* add char */
|
||||
} else {
|
||||
*a++ = '?';
|
||||
}
|
||||
}
|
||||
*a++ = '\"'; /* end string */
|
||||
*a++ = '\n'; /* newline */
|
||||
*a = 0; /* terminate */
|
||||
CHAIN(e, sock_send_string(sock, str_buf));
|
||||
|
||||
/* And store the new data */
|
||||
memcpy(lcd_p, vc_p, line_width);
|
||||
|
||||
}
|
||||
}
|
||||
free(str_buf);
|
||||
|
||||
if (e < 0) {
|
||||
report(RPT_ERR, "Error while sending data to LCDd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_nop()
|
||||
{
|
||||
return sock_send_string(sock, "\n");
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef LCD_LINK_H
|
||||
#define LCD_LINK_H
|
||||
|
||||
extern char * address;
|
||||
extern int port;
|
||||
|
||||
int connect_and_setup();
|
||||
int read_response( char * str, int maxsize );
|
||||
int process_response( char * str );
|
||||
int update_display();
|
||||
int send_nop();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* lcdvc.c
|
||||
* This file is part of lcdvc, an LCDproc client.
|
||||
*
|
||||
* This file is released under the GNU General Public License. Refer to the
|
||||
* COPYING file distributed with this package.
|
||||
*
|
||||
* Copyright (c) 2002, Joris Robijn
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
extern char *optarg;
|
||||
extern int optind, optopt, opterr;
|
||||
|
||||
#include "shared/str.h"
|
||||
#include "shared/report.h"
|
||||
#include "shared/configfile.h"
|
||||
#include "shared/sockets.h"
|
||||
#include "lcd_link.h"
|
||||
#include "vc_link.h"
|
||||
#include "lcdvc.h"
|
||||
|
||||
#define DEFAULT_CONFIGFILE SYSCONFDIR "/lcdvc.conf"
|
||||
|
||||
char * help_text =
|
||||
"lcdvc - LCDproc virtual console displayer.\n"
|
||||
"Copyright (c) 2002, Joris Robijn\n"
|
||||
"This file is released under the GNU General Public License. Refer to the\n"
|
||||
"COPYING file distributed with this package.\n"
|
||||
"Options:\n"
|
||||
" -c <file>\tSpecify a configfile to load ["DEFAULT_CONFIGFILE"]\n"
|
||||
" -a <address>\tDNS name or IP address of the LCDd server [localhost]\n"
|
||||
" -p <port>\tPort of the LCDd server [13666]\n"
|
||||
" -f <0|1>\tRun in 1=foreground or 0=background\n"
|
||||
" -r <level>\tSet reporting level (0-5) [2: errors and warnings]\n"
|
||||
" -s <0|1>\tReport to 1=syslog or 0=stderr\n"
|
||||
" -h\t\tShow this help\n";
|
||||
|
||||
char *progname = "lcdvc";
|
||||
char *configfile = UNSET_STR;
|
||||
|
||||
/* Variables set by config */
|
||||
int foreground_mode = UNSET_INT;
|
||||
static int report_level = UNSET_INT;
|
||||
static int report_dest = UNSET_INT;
|
||||
char *vcsa_device = UNSET_STR;
|
||||
char *vcs_device = UNSET_STR;
|
||||
char *keys[4];
|
||||
|
||||
/* Function prototypes */
|
||||
int process_command_line(int argc, char ** argv);
|
||||
int process_configfile(char * configfile);
|
||||
int connect_and_setup();
|
||||
int update_display();
|
||||
int process_response(char * str);
|
||||
int main_loop();
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
int e = 0;
|
||||
|
||||
CHAIN( e, process_command_line( argc, argv ));
|
||||
if (strcmp( configfile, UNSET_STR ) == 0) {
|
||||
configfile = DEFAULT_CONFIGFILE;
|
||||
}
|
||||
CHAIN( e, process_configfile( configfile ));
|
||||
if (report_dest == UNSET_INT || report_level == UNSET_INT) {
|
||||
report_dest = RPT_DEST_STDERR;
|
||||
report_level = RPT_ERR;
|
||||
}
|
||||
set_reporting( progname, report_level, report_dest );
|
||||
|
||||
CHAIN( e, open_vcs() );
|
||||
CHAIN( e, connect_and_setup() );
|
||||
CHAIN_END( e );
|
||||
|
||||
if (!foreground_mode) {
|
||||
if (daemon(1,1) != 0) {
|
||||
report(RPT_ERR, "Error: daemonize failed");
|
||||
}
|
||||
}
|
||||
|
||||
main_loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_command_line( int argc, char ** argv )
|
||||
{
|
||||
char c;
|
||||
char * p;
|
||||
int temp_int;
|
||||
int error = 0;
|
||||
|
||||
/* No error output from getopt */
|
||||
opterr = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "hc:a:p:f:r:s:")) > 0) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
fprintf(stderr, "%s", help_text);
|
||||
exit( 0 );
|
||||
case 'c':
|
||||
configfile = strdup(optarg);
|
||||
break;
|
||||
case 'a':
|
||||
address = strdup(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
temp_int = strtol(optarg, &p, 0);
|
||||
if ( *optarg != 0 && *p == 0) {
|
||||
port = temp_int;
|
||||
} else {
|
||||
report(RPT_ERR, "Could not interpret value for -%c", c);
|
||||
error = -1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
temp_int = strtol(optarg, &p, 0);
|
||||
if (*optarg != 0 && *p == 0) {
|
||||
foreground_mode = temp_int;
|
||||
} else {
|
||||
report(RPT_ERR, "Could not interpret value for -%c", c);
|
||||
error = -1;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
temp_int = strtol(optarg, &p, 0);
|
||||
if (*optarg != 0 && *p == 0 ) {
|
||||
report_level = temp_int;
|
||||
} else {
|
||||
report(RPT_ERR, "Could not interpret value for -%c", c);
|
||||
error = -1;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
temp_int = strtol( optarg, &p, 0 );
|
||||
if (*optarg != 0 && *p == 0 ) {
|
||||
report_dest = (temp_int?RPT_DEST_SYSLOG:RPT_DEST_STDERR);
|
||||
} else {
|
||||
report(RPT_ERR, "Could not interpret value for -%c", c);
|
||||
error = -1;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
report(RPT_ERR, "Missing option argument for %c", optopt);
|
||||
error = -1;
|
||||
break;
|
||||
case '?':
|
||||
report(RPT_ERR, "Unknown option: %c", optopt);
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int process_configfile( char * configfile )
|
||||
{
|
||||
if (strcmp(configfile, UNSET_STR) == 0) {
|
||||
configfile = DEFAULT_CONFIGFILE;
|
||||
}
|
||||
if (config_read_file( configfile ) < 0) {
|
||||
report( RPT_WARNING, "Could not read config file: %s", configfile);
|
||||
}
|
||||
|
||||
if (strcmp(address, UNSET_STR ) == 0) {
|
||||
address = strdup(config_get_string( progname, "Address", 0, "localhost"));
|
||||
}
|
||||
if (port == UNSET_INT) {
|
||||
port = config_get_int(progname, "Port", 0, 13666);
|
||||
}
|
||||
if (report_level == UNSET_INT ) {
|
||||
report_level = config_get_int(progname, "ReportLevel", 0, RPT_WARNING);
|
||||
}
|
||||
if (report_dest == UNSET_INT) {
|
||||
if (config_get_bool(progname, "ReportToSyslog", 0, 0)) {
|
||||
report_dest = RPT_DEST_SYSLOG;
|
||||
} else {
|
||||
report_dest = RPT_DEST_STDERR;
|
||||
}
|
||||
}
|
||||
if (foreground_mode == UNSET_INT) {
|
||||
foreground_mode = config_get_bool(progname, "Foreground", 0, 1);
|
||||
}
|
||||
vcs_device = strdup(config_get_string(progname, "vcsDevice", 0, "/dev/vcs"));
|
||||
vcsa_device = strdup(config_get_string(progname, "vcsaDevice", 0, "/dev/vcsa"));
|
||||
|
||||
keys[0] = strdup( config_get_string( progname, "UpKey", 0, "Up" ));
|
||||
keys[1] = strdup( config_get_string( progname, "DownKey", 0, "Down" ));
|
||||
keys[2] = strdup( config_get_string( progname, "LeftKey", 0, "Left" ));
|
||||
keys[3] = strdup( config_get_string( progname, "RightKey", 0, "Right" ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int split( char * str, char delim, char * parts[], int maxparts )
|
||||
/* Splits a string into parts, to which pointers will be returned in &parts.
|
||||
* The return value is the number of parts.
|
||||
* maxparts is the maximum number of parts returned. If more parts exist
|
||||
* they are (unsplit) in the last part.
|
||||
* The parts are split at the character delim.
|
||||
* No new space will be allocated, the string str will be mutated !
|
||||
*/
|
||||
{
|
||||
char * p1 = str;
|
||||
char * p2;
|
||||
int part_nr = 0;
|
||||
|
||||
/* Find the delim char to end the current part */
|
||||
while (part_nr < maxparts - 1 && (p2 = strchr(p1, delim))) {
|
||||
|
||||
/* subsequent parts... */
|
||||
*p2 = 0;
|
||||
parts[part_nr] = p1;
|
||||
|
||||
p1 = p2 + 1; /* Just after the delim char */
|
||||
part_nr ++;
|
||||
}
|
||||
/* and the last part... */
|
||||
parts[part_nr] = p1;
|
||||
part_nr ++;
|
||||
|
||||
return part_nr;
|
||||
}
|
||||
|
||||
int main_loop()
|
||||
{
|
||||
int num_bytes;
|
||||
char buf[80];
|
||||
short w;
|
||||
|
||||
/* Continuously check if we get a menu event... */
|
||||
|
||||
while ((num_bytes = read_response(buf, sizeof(buf)-1)) >= 0) {
|
||||
if (num_bytes != 0) {
|
||||
process_response(buf);
|
||||
}
|
||||
else {
|
||||
read_vcdata();
|
||||
update_display();
|
||||
|
||||
/* Send an empty line every 3 seconds to make sure the server still exists */
|
||||
if (w++ >= 60) {
|
||||
w = 0;
|
||||
if (send_nop() < 0) {
|
||||
break; /* Out of while loop */
|
||||
}
|
||||
}
|
||||
usleep(50000);
|
||||
}
|
||||
}
|
||||
|
||||
report(RPT_WARNING, "Server disconnected %d", num_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# lcdvc client configuration file
|
||||
|
||||
## general options ##
|
||||
[lcdvc]
|
||||
|
||||
# Address of the LCDd server
|
||||
#Address=127.0.0.1
|
||||
|
||||
# Port to attach to LCDd server
|
||||
#Port=13666
|
||||
|
||||
#If false, report to stderr. If true, to syslog.
|
||||
#ReportToSyslog=true
|
||||
|
||||
# Same as with LCDd.
|
||||
#ReportLevel=4
|
||||
|
||||
# If false, it forks to the background.
|
||||
#Foreground=false
|
||||
|
||||
# Keys to move the visible area around the screen.
|
||||
#UpKey=Up
|
||||
#DownKey=Down
|
||||
#LeftKey=Left
|
||||
#RightKey=Right
|
||||
|
||||
# VC devices to use [default: /dev/vcs, /dev/vcsa]
|
||||
vcsDevice=/dev/vcs
|
||||
vcsaDevice=/dev/vcsa
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef LCDVC_H
|
||||
#define LCDVC_H
|
||||
|
||||
#define CHAIN(e,f) { if( e>=0 ) { e=(f); }}
|
||||
#define CHAIN_END(e) { if( e<0 ) { report( RPT_CRIT,"Critical error, abort"); exit(e); }}
|
||||
|
||||
#define min(a,b) ((a)<(b))?(a):(b)
|
||||
|
||||
#define UNSET_INT -1
|
||||
#define UNSET_STR "\01"
|
||||
|
||||
extern char *vcs_device;
|
||||
extern char *vcsa_device;
|
||||
|
||||
extern char *keys[4];
|
||||
|
||||
extern char *progname;
|
||||
|
||||
int split(char * str, char delim, char * parts[], int maxparts);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lcdvc.h"
|
||||
#include "vc_link.h"
|
||||
#include "shared/report.h"
|
||||
#include "shared/sockets.h"
|
||||
|
||||
int vcs0, vcsa;
|
||||
unsigned short vc_width = 0, vc_height = 0;
|
||||
unsigned short vc_cursor_x = 0, vc_cursor_y = 0;
|
||||
char * vc_buf = NULL;
|
||||
|
||||
int open_vcs()
|
||||
{
|
||||
/* Open the /dev/vcsX and /dev/vcsaX devices */
|
||||
vcs0 = open(vcs_device, O_RDONLY);
|
||||
if (vcs0 < 0) {
|
||||
report(RPT_ERR, "Could not open %s: %s", vcs_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
vcsa = open(vcsa_device, O_RDONLY);
|
||||
if (vcsa < 0) {
|
||||
report(RPT_ERR, "Could not open %s: %s", vcsa_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_vcdata()
|
||||
{
|
||||
unsigned short new_vc_height;
|
||||
unsigned short new_vc_width;
|
||||
|
||||
int bytes_read;
|
||||
unsigned char buf[20];
|
||||
|
||||
/* Read size and cursor position from /dev/vcsa */
|
||||
lseek(vcsa, 0, SEEK_SET);
|
||||
bytes_read = read(vcsa, buf, 4);
|
||||
if (bytes_read != 4) {
|
||||
report(RPT_ERR, "Could not read from %s", vcsa_device);
|
||||
return -1;
|
||||
}
|
||||
new_vc_height = buf[0];
|
||||
new_vc_width = buf[1];
|
||||
vc_cursor_x = buf[2];
|
||||
vc_cursor_y = buf[3];
|
||||
|
||||
/* Screen resize or initial buffer allocation ? */
|
||||
if (new_vc_width != vc_width || new_vc_height != vc_height) {
|
||||
vc_width = new_vc_width;
|
||||
vc_height = new_vc_height;
|
||||
if (vc_buf)
|
||||
free(vc_buf);
|
||||
vc_buf = malloc(vc_width * vc_height);
|
||||
memset(vc_buf, ' ', vc_width * vc_height);
|
||||
}
|
||||
|
||||
/* Read characters from /dev/cvs0 */
|
||||
lseek(vcs0, 0, SEEK_SET);
|
||||
bytes_read = read(vcs0, vc_buf, vc_width * vc_height);
|
||||
if (bytes_read != vc_width * vc_height) {
|
||||
report(RPT_ERR, "Could not read from %s", vcs_device);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef VC_LINK_H
|
||||
#define VC_LINK_H
|
||||
|
||||
extern unsigned short vc_width, vc_height;
|
||||
extern unsigned short vc_cursor_x, vc_cursor_y;
|
||||
extern char * vc_buf;
|
||||
|
||||
int open_vcs();
|
||||
int read_vcdata();
|
||||
|
||||
#endif
|
||||
@@ -554,6 +554,7 @@ AC_CONFIG_FILES([Makefile
|
||||
clients/Makefile
|
||||
clients/lcdproc/Makefile
|
||||
clients/lcdexec/Makefile
|
||||
clients/lcdvc/Makefile
|
||||
clients/examples/Makefile
|
||||
clients/headlines/Makefile
|
||||
clients/metar/Makefile
|
||||
|
||||
Reference in New Issue
Block a user