• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-minimal-raw-file
3  *
4  * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
9  * This demonstrates dealing with a serial port
10  */
11 
12 #include <libwebsockets.h>
13 #include <string.h>
14 #include <signal.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 
19 #include <termios.h>
20 #include <sys/ioctl.h>
21 
22 #if defined(__linux__)
23 #include <asm/ioctls.h>
24 #include <linux/serial.h>
25 #endif
26 
27 struct raw_vhd {
28 	lws_sorted_usec_list_t sul;
29 	struct lws *wsi;
30 	int filefd;
31 };
32 
33 static char filepath[256];
34 
35 static void
sul_cb(lws_sorted_usec_list_t * sul)36 sul_cb(lws_sorted_usec_list_t *sul)
37 {
38 	struct raw_vhd *v = lws_container_of(sul, struct raw_vhd, sul);
39 
40 	lws_callback_on_writable(v->wsi);
41 
42 	lws_sul_schedule(lws_get_context(v->wsi), 0, &v->sul, sul_cb,
43 			 2 * LWS_USEC_PER_SEC);
44 }
45 
46 static int
callback_raw_test(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)47 callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
48 			void *user, void *in, size_t len)
49 {
50 	struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
51 				     lws_get_vhost(wsi), lws_get_protocol(wsi));
52 #if defined(__linux__)
53 	struct serial_struct s_s;
54 #endif
55 	lws_sock_file_fd_type u;
56 	struct termios tio;
57 	uint8_t buf[1024];
58 	int n;
59 
60 	switch (reason) {
61 	case LWS_CALLBACK_PROTOCOL_INIT:
62 		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
63 				lws_get_protocol(wsi), sizeof(struct raw_vhd));
64 		vhd->filefd = lws_open(filepath, O_RDWR);
65 		if (vhd->filefd == -1) {
66 			lwsl_err("Unable to open %s\n", filepath);
67 
68 			return 1;
69 		}
70 
71 		tcflush(vhd->filefd, TCIOFLUSH);
72 
73 #if defined(__linux__)
74 		if (ioctl(vhd->filefd, TIOCGSERIAL, &s_s) == 0) {
75 			s_s.closing_wait = ASYNC_CLOSING_WAIT_NONE;
76 			ioctl(vhd->filefd, TIOCSSERIAL, &s_s);
77 		}
78 #endif
79 
80 		/* enforce suitable tty state */
81 
82 		memset(&tio, 0, sizeof tio);
83 		if (tcgetattr(vhd->filefd, &tio)) {
84 			close(vhd->filefd);
85 			vhd->filefd = -1;
86 			return -1;
87 		}
88 
89 		cfsetispeed(&tio, B115200);
90 		cfsetospeed(&tio, B115200);
91 
92 		tio.c_lflag &= (tcflag_t)~(ISIG | ICANON | IEXTEN | ECHO |
93 #if defined(__linux__)
94 				XCASE |
95 #endif
96 				 ECHOE | ECHOK | ECHONL | ECHOCTL | ECHOKE);
97 		tio.c_iflag &= (tcflag_t)~(INLCR | IGNBRK | IGNPAR | IGNCR | ICRNL |
98 				 IMAXBEL | IXON | IXOFF | IXANY
99 #if defined(__linux__)
100 				 | IUCLC
101 #endif
102 				| 0xff);
103 		tio.c_oflag = 0;
104 
105 		tio.c_cc[VMIN]  = 1;
106 		tio.c_cc[VTIME] = 0;
107 		tio.c_cc[VEOF] = 1;
108 		tio.c_cflag = tio.c_cflag & (unsigned long) ~(
109 #if defined(__linux__)
110 				CBAUD |
111 #endif
112 				CSIZE | CSTOPB | PARENB
113 #if !defined(__QNX__)
114 				| CRTSCTS
115 #endif
116 		);
117 		tio.c_cflag |= 0x1412 | CS8 | CREAD | CLOCAL;
118 
119 		tcsetattr(vhd->filefd, TCSANOW, &tio);
120 
121 		u.filefd = (lws_filefd_type)(long long)vhd->filefd;
122 		if (!lws_adopt_descriptor_vhost(lws_get_vhost(wsi),
123 						LWS_ADOPT_RAW_FILE_DESC, u,
124 						"raw-test", NULL)) {
125 			lwsl_err("Failed to adopt fifo descriptor\n");
126 			close(vhd->filefd);
127 			vhd->filefd = -1;
128 
129 			return 1;
130 		}
131 
132 		break;
133 
134 	case LWS_CALLBACK_PROTOCOL_DESTROY:
135 		if (vhd && vhd->filefd != -1)
136 			close(vhd->filefd);
137 		break;
138 
139 	/* callbacks related to raw file descriptor */
140 
141 	case LWS_CALLBACK_RAW_ADOPT_FILE:
142 		lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
143 		vhd->wsi = wsi;
144 		lws_sul_schedule(lws_get_context(wsi), 0, &vhd->sul, sul_cb, 1);
145 		break;
146 
147 	case LWS_CALLBACK_RAW_RX_FILE:
148 		lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
149 		n = (int)read(vhd->filefd, buf, sizeof(buf));
150 		if (n < 0) {
151 			lwsl_err("Reading from %s failed\n", filepath);
152 
153 			return 1;
154 		}
155 		lwsl_hexdump_level(LLL_NOTICE, buf, (unsigned int)n);
156 		break;
157 
158 	case LWS_CALLBACK_RAW_CLOSE_FILE:
159 		lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
160 		lws_sul_cancel(&vhd->sul);
161 		break;
162 
163 	case LWS_CALLBACK_RAW_WRITEABLE_FILE:
164 		lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
165 		if (lws_write(wsi, (uint8_t *)"hello-this-is-written-every-couple-of-seconds\r\n", 47, LWS_WRITE_RAW) != 47)
166 			return -1;
167 		break;
168 
169 	default:
170 		break;
171 	}
172 
173 	return 0;
174 }
175 
176 static struct lws_protocols protocols[] = {
177 	{ "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
178 	LWS_PROTOCOL_LIST_TERM
179 };
180 
181 static int interrupted;
182 
sigint_handler(int sig)183 void sigint_handler(int sig)
184 {
185 	interrupted = 1;
186 }
187 
main(int argc,const char ** argv)188 int main(int argc, const char **argv)
189 {
190 	struct lws_context_creation_info info;
191 	struct lws_context *context;
192 	const char *p;
193 	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
194 			/* for LLL_ verbosity above NOTICE to be built into lws,
195 			 * lws must have been configured and built with
196 			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
197 			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
198 			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
199 			/* | LLL_DEBUG */;
200 
201 	signal(SIGINT, sigint_handler);
202 
203 	if ((p = lws_cmdline_option(argc, argv, "-d")))
204 		logs = atoi(p);
205 
206 	lws_set_log_level(logs, NULL);
207 	lwsl_user("LWS minimal raw serial\n");
208 	if (argc < 2) {
209 		lwsl_user("Usage: %s <serial device>  "
210 			  " eg, /dev/ttyUSB0\n", argv[0]);
211 
212 		return 1;
213 	}
214 
215 	signal(SIGINT, sigint_handler);
216 
217 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
218 	info.port = CONTEXT_PORT_NO_LISTEN_SERVER; /* no listen socket for demo */
219 	info.protocols = protocols;
220 
221 	lws_strncpy(filepath, argv[1], sizeof(filepath));
222 
223 	context = lws_create_context(&info);
224 	if (!context) {
225 		lwsl_err("lws init failed\n");
226 		return 1;
227 	}
228 
229 	while (n >= 0 && !interrupted)
230 		n = lws_service(context, 0);
231 
232 	lws_context_destroy(context);
233 
234 	return 0;
235 }
236