#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;
static int read_connect_string(void);
static int split(char *str, char delim, char *parts[], int maxparts);
int connect_and_setup(void)
{
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;
}
static int read_connect_string(void)
{
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;
}
return 0;
}
static 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 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(void)
{
//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(void)
{
return sock_send_string(sock, "\n");
}
syntax highlighted by Code2HTML, v. 0.9.1