1 /*
2  * example.c - example program for cwdaemon
3  * Copyright (C) 2003, 2006 Joop Stakenborg <pg4i@amsat.org>
4  * Copyright (C) 2012 - 2015 Kamil Ignacak <acerion@wp.pl>
5  *
6  * Some of this code is taken from netkeyer.c, which is part of the tlf source,
7  * here is the copyright:
8  * Tlf - contest logging program for amateur radio operators
9  * Copyright (C) 2001-2002-2003 Rein Couperus <pa0rct@amsat.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24  * 02110-1301, USA.
25  */
26 
27 /*
28  * Compile this program with "gcc -o example example.c"
29  * Usage: 'example' or 'example <portname>'
30  */
31 
32 #define _POSIX_SOURCE /* getaddrinfo() and friends. */
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #include <errno.h>
44 #include <signal.h>
45 
46 #define K_MESSAGE 1
47 
48 #define K_RESET 0
49 #define K_SPEED 2
50 #define K_TONE 3
51 #define K_ABORT 4
52 #define K_STOP 5
53 #define K_WORDMODE 6
54 #define K_WEIGHT 7
55 #define K_DEVICE 8
56 #define K_TOD 9         // set txdelay (turn on delay)
57 #define K_ADDRESS 10    // set port address of device (obsolete)
58 #define K_SET14 11      // set pin 14 on lpt
59 #define K_TUNE 12       // tune
60 #define K_PTT 13        // PTT on/off
61 #define K_SWITCH 14     // set band switch output pins 2,7,8,9 on lpt
62 #define K_SDEVICE 15	// set sound device
63 #define K_VOLUME 16     // volume for soundcard
64 
65 static char netkeyer_port[] = "6789";
66 static char netkeyer_hostaddress[16] = "127.0.0.1";
67 static int socket_descriptor;
68 static struct addrinfo *addrinfo_list;
69 static struct addrinfo *selected_addrinfo;
70 
71 int netkeyer_init(void);
72 int netkeyer_close(void);
73 int netkeyer(int cw_op, const char *cwmessage);
74 void catchint(int signal);
75 
76 
77 
78 
79 
netkeyer_init(void)80 int netkeyer_init(void)
81 {
82 	/* Code in this function has been copied from
83 	   getaddrinfo() man page. */
84 
85 	struct addrinfo hints;
86 
87 	memset(&hints, 0, sizeof(struct addrinfo));
88 	hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
89 	hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
90 	hints.ai_flags = 0;
91 	hints.ai_protocol = IPPROTO_UDP;
92 
93 	int rv = getaddrinfo(netkeyer_hostaddress,
94 			     netkeyer_port,
95 			     &hints, &addrinfo_list);
96 	if (rv) {
97 		fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(rv));
98 		return -1;
99 	}
100 
101 	/* getaddrinfo() returns a list of address structures.
102 	   Try each address until we successfully connect(2).
103 	   If socket(2) (or connect(2)) fails, we (close the socket
104 	   and) try the next address. */
105 
106 	for (selected_addrinfo = addrinfo_list;
107 	     selected_addrinfo;
108 	     selected_addrinfo = selected_addrinfo->ai_next) {
109 
110 		socket_descriptor = socket(selected_addrinfo->ai_family,
111 					   selected_addrinfo->ai_socktype,
112 					   selected_addrinfo->ai_protocol);
113 		if (socket_descriptor == -1) {
114 			continue;
115 		}
116 
117 		if (connect(socket_descriptor,
118 			    selected_addrinfo->ai_addr,
119 			    selected_addrinfo->ai_addrlen) != -1) {
120 			break;
121 		}
122 
123 		close(socket_descriptor);
124 	}
125 
126 	if (!selected_addrinfo) {
127 		fprintf(stderr, "Could not connect\n");
128 		return -1;
129 	} else {
130 		return 0;
131 	}
132 }
133 
134 
135 
136 
137 
netkeyer_close(void)138 int netkeyer_close(void)
139 {
140 	if (close(socket_descriptor) == -1) {
141 		perror("close call failed");
142 		return -1;
143 	}
144 
145 	freeaddrinfo(addrinfo_list);           /* No longer needed */
146 
147 	return 0;
148 }
149 
150 
151 
152 
153 
netkeyer(int cw_op,const char * cwmessage)154 int netkeyer(int cw_op, const char *cwmessage)
155 {
156 	char buf[80];
157 
158 	switch (cw_op) {
159 		case K_RESET :
160   			buf[0] = 27;
161 			sprintf(buf + 1, "0");
162  			break;
163 		case K_MESSAGE :
164 			sprintf(buf, "%s", cwmessage);
165  			break;
166 		case K_SPEED :
167   			buf[0] = 27;
168 			sprintf(buf + 1, "2");
169 			sprintf(buf + 2, "%s", cwmessage);
170  			break;
171 		case K_TONE :
172   			buf[0] = 27;
173 			sprintf(buf + 1, "3");
174 			sprintf(buf + 2, "%s", cwmessage);
175  			break;
176 		case K_ABORT :
177   			buf[0] = 27;
178 			sprintf(buf + 1, "4");
179  			break;
180 		case K_STOP :
181   			buf[0] = 27;
182 			sprintf(buf + 1, "5");
183  			break;
184 		case K_WORDMODE :
185   			buf[0] = 27;
186 			sprintf(buf + 1, "6");
187  			break;
188 		case K_WEIGHT :
189   			buf[0] = 27;
190 			sprintf(buf + 1, "7");
191 			sprintf(buf + 2, "%s", cwmessage);
192  			break;
193 		case K_DEVICE :
194   			buf[0] = 27;
195 			sprintf(buf + 1, "8");
196 			sprintf(buf + 2, "%s", cwmessage);
197  			break;
198 		case K_PTT :
199   			buf[0] = 27;
200 			sprintf(buf + 1, "a");
201 			sprintf(buf + 2, "%s", cwmessage);
202  			break;
203 		case K_TUNE :
204   			buf[0] = 27;
205 			sprintf(buf + 1, "c");
206 			sprintf(buf + 2, "%s", cwmessage);
207  			break;
208 		case K_TOD :
209   			buf[0] = 27;
210 			sprintf(buf + 1, "d");
211 			sprintf(buf + 2, "%s", cwmessage);
212  			break;
213 		case K_SDEVICE :
214   			buf[0] = 27;
215 			sprintf(buf + 1, "f");
216 			sprintf(buf + 2, "%s", cwmessage);
217  			break;
218 		case K_VOLUME :
219   			buf[0] = 27;
220 			sprintf(buf + 1, "g");
221 			sprintf(buf + 2, "%s", cwmessage);
222  			break;
223 		default :
224 			buf[0] = '\0';
225 	}
226 
227 	ssize_t sendto_rc = 0;
228 	if (buf[0] != '\0') {
229 		sendto_rc = sendto(socket_descriptor,
230 				   buf, sizeof (buf),
231 				   0,
232 				   selected_addrinfo->ai_addr,
233 				   sizeof (struct addrinfo));
234 	}
235 
236 	buf[0] = '\0';
237 	cw_op = K_RESET;
238 
239 	if (sendto_rc == -1) {
240      	 	printf("Keyer send failed (%s)!\n", strerror(errno));
241 		return -1;
242      	} else {
243 		return 0;
244 	}
245 }
246 
247 
248 
249 
250 
catchint(int signal)251 void catchint(__attribute__((unused)) int signal)
252 {
253 	__attribute__((unused)) int result = netkeyer(K_ABORT, "");
254 	exit(EXIT_SUCCESS);
255 }
256 
257 
258 
259 
260 
main(int argc,char ** argv)261 int main(int argc, char **argv)
262 {
263 	if (netkeyer_init() == -1) {
264 		exit(EXIT_FAILURE);
265 	}
266 
267 	/* tests start here, no error handling */
268 	int result;
269 	if (argc > 1) {
270 		result = netkeyer(K_DEVICE, argv[1]);
271 		printf("opening port %s\n", argv[1]);
272 	}
273 
274 	printf("first message at initial speed\n");
275 	result = netkeyer(K_MESSAGE, "paris");
276 	sleep(3);
277 
278 	printf("speed 40\n");
279 	result = netkeyer(K_SPEED, "40");
280 	result = netkeyer(K_MESSAGE, "paris");
281 	sleep(2);
282 
283 	printf("tone 1000, speed 40\n");
284 	result = netkeyer(K_TONE, "1000");
285 	result = netkeyer(K_SPEED, "40");
286 	result = netkeyer(K_MESSAGE, "paris");
287 	sleep(2);
288 
289 	printf("tone 800, weight +20\n");
290 	result = netkeyer(K_TONE, "800");
291 	result = netkeyer(K_WEIGHT, "20");
292 	result = netkeyer(K_MESSAGE, "paris");
293 	sleep(2);
294 
295 	printf("weight -20\n");
296 	result = netkeyer(K_WEIGHT, "-20");
297 	result = netkeyer(K_MESSAGE, "paris");
298 	sleep(2);
299 
300 	printf("weight 0\n");
301 	result = netkeyer(K_WEIGHT, "0");
302 	printf("speed increase / decrease\n");
303 	result = netkeyer(K_MESSAGE, "p++++++++++aris----------");
304 	sleep(2);
305 
306 	printf("half gap\n");
307 	result = netkeyer(K_MESSAGE, "p~ari~s");
308 	sleep(2);
309 
310 	printf("tune 3 seconds\n");
311 	result = netkeyer(K_TUNE, "3");
312 	sleep(4);
313 
314 	printf("test message abort\n");
315 	result = netkeyer(K_MESSAGE, "paris paris");
316 	sleep(1);
317 	result = netkeyer(K_ABORT, "");
318 	sleep(1);
319 
320 	printf("switch to soundcard\n");
321 	result = netkeyer(K_SDEVICE, "s");
322 	result = netkeyer(K_MESSAGE, "paris");
323 	sleep(2);
324 
325 	printf("volume 30\n");
326 	result = netkeyer(K_VOLUME, "30");
327 	result = netkeyer(K_MESSAGE, "paris");
328 	sleep(2);
329 
330 	printf("prosigns: SK BK SN AS AR\n");
331 	result = netkeyer(K_MESSAGE, "< > ! & *");
332 	sleep(4);
333 
334 	printf("set volume back to 70\n");
335 	result = netkeyer(K_VOLUME, "70");
336 	result = netkeyer(K_MESSAGE, "paris");
337 	sleep(2);
338 
339 	printf("back to console\n");
340 	result = netkeyer(K_SDEVICE, "c");
341 	result = netkeyer(K_MESSAGE, "paris");
342 	sleep(2);
343 
344 	printf("message with PTT on\n");
345 	result = netkeyer(K_PTT, "1");
346 	result = netkeyer(K_MESSAGE, "paris");
347 	sleep(2);
348 	result = netkeyer(K_PTT, "0");
349 
350 	printf("same with different TOD\n");
351 	result = netkeyer(K_TOD, "20");
352 	result = netkeyer(K_PTT, "1");
353 	result = netkeyer(K_MESSAGE, "paris");
354 	sleep(2);
355 	result = netkeyer(K_PTT, "0");
356 	result = netkeyer(K_TOD, "0");
357 
358 	/* almost done, reset keyer */
359 	printf("almost done, reset\n");
360 	result = netkeyer(K_RESET, "");
361 
362 
363 	printf("test message abort with SIGALRM\n");
364 	signal(SIGALRM, catchint);
365 	result = netkeyer(K_MESSAGE, "paris paris");
366 	alarm(2);
367 	while (1) {}
368 
369 	printf("done");
370 
371 	/* end tests */
372 	if (netkeyer_close() == -1) {
373 		exit(EXIT_FAILURE);
374 	} else {
375 		exit(EXIT_SUCCESS);
376 	}
377 }
378