1 /*-
2 * Copyright (c) 1999 Thomas Runge (coto@core.de)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <netdb.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
37 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <X11/Intrinsic.h>
40
41 #include "lcd_net.h"
42 #include "radio.h"
43
44 static char buffer[MAXMSG];
45 extern XtAppContext app_con;
46 extern int sockfd;
47 extern int lcd_stereo;
48 extern int lcd_fieldstrength;
49 static XtIntervalId timerId;
50 static int width, height, cellw, cellh;
51
52 static int lcd_net_handle();
53 static void lcd_net_handler(XtPointer clientData, XtIntervalId *id);
54 static int lcd_net_read(char *buffer, int nbytes);
55 static int lcd_net_writen(const char *buffer, int nbytes);
56 static void lcd_net_update_values();
57 static void lcd_net_updateLCD(XtPointer, XtIntervalId*);
58
sig_pipe_handler()59 void sig_pipe_handler()
60 {
61 if(debug)
62 printf("got SIGPIPE!\n");
63 lcd_net_stop();
64 }
65
lcd_net_init(const char * host,u_short port,const char ** neterror)66 int lcd_net_init(const char *host, u_short port, const char **neterror)
67 {
68 int sock;
69 struct sockaddr_in serv_addr;
70 struct hostent *he;
71 unsigned long arg;
72
73 width = 20;
74 height = 4;
75 cellw = 5;
76 cellh = 8;
77
78 signal(SIGPIPE, (void*) sig_pipe_handler);
79
80 he = gethostbyname(host);
81 if(!he)
82 {
83 *neterror = hstrerror(h_errno);
84 return(-1);
85 }
86
87 bzero((char*) &serv_addr, sizeof(serv_addr));
88 serv_addr.sin_family = AF_INET;
89 serv_addr.sin_addr = *(struct in_addr *) he->h_addr_list[0];
90 serv_addr.sin_port = htons(port);
91
92 if(debug)
93 printf("lcd_net: socket\n");
94
95 if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
96 {
97 *neterror = hstrerror(h_errno);
98 return(-1);
99 }
100
101 if(debug)
102 printf("lcd_net: connect\n");
103
104 if(connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
105 {
106 *neterror = hstrerror(h_errno);
107 return(-1);
108 }
109
110 arg = 1;
111 if(ioctl(sock, FIONBIO, &arg) == -1)
112 fprintf(stderr,
113 "lcd_net error setting socket to non blocking mode: %s\n",
114 strerror(errno));
115
116 return(sock);
117 }
118
lcd_net_start()119 int lcd_net_start()
120 {
121 sprintf(buffer, "hello\n");
122 lcd_net_writen(buffer, strlen(buffer));
123
124 sprintf(buffer, "client_set name %s %s\n", APPNAME, APPVERSION);
125 lcd_net_writen(buffer, strlen(buffer));
126
127 sprintf(buffer, "screen_add %s\n", APPNAME);
128 lcd_net_writen(buffer, strlen(buffer));
129
130 sprintf(buffer, "screen_set %s name %s\n", APPNAME, APPNAME);
131 lcd_net_writen(buffer, strlen(buffer));
132
133 sprintf(buffer, "widget_add %s title title\n", APPNAME);
134 lcd_net_writen(buffer, strlen(buffer));
135
136 sprintf(buffer, "widget_set %s title %s-%s\n", APPNAME,
137 APPNAME, APPVERSION);
138 lcd_net_writen(buffer, strlen(buffer));
139
140 sprintf(buffer, "widget_add %s stationlabel string\n", APPNAME);
141 lcd_net_writen(buffer, strlen(buffer));
142
143 sprintf(buffer, "widget_add %s freqlabel string\n", APPNAME);
144 lcd_net_writen(buffer, strlen(buffer));
145
146 sprintf(buffer, "widget_add %s station string\n", APPNAME);
147 lcd_net_writen(buffer, strlen(buffer));
148
149 sprintf(buffer, "widget_add %s freq string\n", APPNAME);
150 lcd_net_writen(buffer, strlen(buffer));
151
152 /* check for display height before */
153 sprintf(buffer, "widget_add %s stereo string\n", APPNAME);
154 lcd_net_writen(buffer, strlen(buffer));
155
156 /* check for display height before */
157 sprintf(buffer, "widget_add %s fsindic string\n", APPNAME);
158 lcd_net_writen(buffer, strlen(buffer));
159
160 /* check for display height before */
161 sprintf(buffer, "widget_add %s fstrength hbar\n", APPNAME);
162 lcd_net_writen(buffer, strlen(buffer));
163
164 sprintf(buffer, "widget_set %s stationlabel 1 2 Station:\n", APPNAME);
165 lcd_net_writen(buffer, strlen(buffer));
166
167 sprintf(buffer, "widget_set %s freqlabel 1 3 {Freq :}\n", APPNAME);
168 lcd_net_writen(buffer, strlen(buffer));
169
170 sprintf(buffer, "widget_set %s fsindic 1 4 {Sig: }\n", APPNAME);
171 lcd_net_writen(buffer, strlen(buffer));
172
173 lcd_net_update_values();
174
175 XtAppAddTimeOut(app_con, 250, lcd_net_handler, (XtPointer)NULL);
176 timerId = XtAppAddTimeOut(app_con, 250, lcd_net_updateLCD, (XtPointer)NULL);
177
178 return(1);
179 }
180
lcd_net_stop()181 int lcd_net_stop()
182 {
183 int res = close(sockfd);
184
185 sockfd = 0;
186 sprintf(buffer, "lost connection to LCD server.");
187 lcdDisconnectCB(buffer);
188 return(res);
189 }
190
lcd_net_update_values()191 static void lcd_net_update_values()
192 {
193 if(!sockfd)
194 return;
195
196 sprintf(buffer, "widget_set %s station 10 2 {%s}\n",
197 APPNAME, global_station_name);
198 lcd_net_writen(buffer, strlen(buffer));
199
200 sprintf(buffer, "widget_set %s freq 10 3 {%3.2f MHz}\n", APPNAME,
201 frequency/100.);
202 lcd_net_writen(buffer, strlen(buffer));
203
204 /* check for display height before */
205 sprintf(buffer, "widget_set %s stereo 15 4 %s\n", APPNAME,
206 lcd_stereo ? "stereo" : "mono");
207 lcd_net_writen(buffer, strlen(buffer));
208
209 /* check for display height before */
210 sprintf(buffer, "widget_set %s fstrength 6 4 %d\n", APPNAME,
211 lcd_fieldstrength * cellw);
212 lcd_net_writen(buffer, strlen(buffer));
213 }
214
lcd_net_updateLCD(XtPointer clientData,XtIntervalId * id)215 static void lcd_net_updateLCD(XtPointer clientData, XtIntervalId *id)
216 {
217 static int old_freq = -1;
218 static int old_stereo = -1;
219 static int old_fieldstrength = -1;
220
221 if(!sockfd)
222 return;
223
224 if(old_freq != frequency ||
225 old_stereo != lcd_stereo ||
226 old_fieldstrength != lcd_fieldstrength)
227 {
228 lcd_net_update_values();
229
230 old_freq = frequency;
231 old_stereo = lcd_stereo;
232 old_fieldstrength = lcd_fieldstrength;
233 }
234
235 timerId = XtAppAddTimeOut(app_con, 250, lcd_net_updateLCD,
236 (XtPointer)NULL);
237 }
238
lcd_net_handler(XtPointer clientData,XtIntervalId * id)239 static void lcd_net_handler(XtPointer clientData, XtIntervalId *id)
240 {
241 if(sockfd)
242 {
243 lcd_net_handle();
244 XtAppAddTimeOut(app_con, 250, lcd_net_handler, (XtPointer)NULL);
245 }
246 }
247
lcd_net_handle()248 static int lcd_net_handle()
249 {
250 int res;
251
252 res = lcd_net_read(buffer, MAXMSG);
253 switch(res)
254 {
255 case -2: /* no data to read */
256 break;
257 case -1: /* socket related problem */
258 perror("socket");
259 lcd_net_stop();
260 return(False);
261 break;
262 case 0: /* server died or connection lost */
263 fprintf(stderr, "connection to LCD server down.\n");
264 lcd_net_stop();
265 return(False);
266 break;
267 default:
268 if(!strncmp(buffer, "huh", 3))
269 {
270 fprintf(stderr, "server replied an error: %s\n", buffer);
271 break;
272 }
273
274 if(!strncmp(buffer, "listen", 6))
275 {
276 timerId = XtAppAddTimeOut(app_con, 250, lcd_net_updateLCD,
277 (XtPointer)NULL);
278 break;
279 }
280
281 if(!strncmp(buffer, "ignore", 6))
282 {
283 if(timerId)
284 XtRemoveTimeOut(timerId);
285 break;
286 }
287
288 if(!strncmp(buffer, "connect", 7))
289 {
290 char *tmp;
291
292 tmp = strtok(buffer, " ");
293 while(tmp)
294 {
295 if(!strcmp(tmp, "wid"))
296 {
297 tmp = strtok(NULL, " ");
298 if(!tmp)
299 break;
300 width = atoi(tmp);
301 }
302 if(!strcmp(tmp, "hgt"))
303 {
304 tmp = strtok(NULL, " ");
305 if(!tmp)
306 break;
307 height = atoi(tmp);
308 }
309 if(!strcmp(tmp, "cellwid"))
310 {
311 tmp = strtok(NULL, " ");
312 if(!tmp)
313 break;
314 cellw = atoi(tmp);
315 }
316 if(!strcmp(tmp, "cellhgt"))
317 {
318 tmp = strtok(NULL, " ");
319 if(!tmp)
320 break;
321 cellh = atoi(tmp);
322 }
323 tmp = strtok(NULL, " ");
324 }
325 if(debug)
326 printf("got lcd. w: %d h: %d cw: %d ch: %d\n",
327 width, height, cellw, cellh);
328 break;
329 }
330
331 if(!strncmp(buffer, "bye", 3))
332 {
333 fprintf(stderr, "LCD server will go, quitting.\n");
334 lcd_net_stop();
335 break;
336 }
337
338 printf("unhandled message: %s\n", buffer);
339 }
340
341 return(True);
342 }
343
lcd_net_read(char * buf,int nbytes)344 static int lcd_net_read(char *buf, int nbytes)
345 {
346 int nread;
347
348 nread = read(sockfd, buf, nbytes);
349 if(nread == -1 && errno == EWOULDBLOCK) /* assume non blocking socket */
350 return(-2);
351
352 return(nread);
353 }
354
lcd_net_writen(const char * buf,int nbytes)355 static int lcd_net_writen(const char *buf, int nbytes)
356 {
357 int nleft, nwritten = 0;
358
359 nleft = nbytes;
360 while(nleft > 0)
361 {
362 nwritten = write(sockfd, buf, nleft);
363 if(nwritten <= 0)
364 return(nwritten);
365
366 nleft -= nwritten;
367 buf+= nwritten;
368 }
369 return(nbytes-nleft);
370 }
371
372