1 | // This file is part of SmallBASIC |
2 | // |
3 | // serial I/O, driver |
4 | // |
5 | // This program is distributed under the terms of the GPL v2.0 or later |
6 | // Download the GNU Public License (GPL) from www.gnu.org |
7 | // |
8 | // Copyright(C) 2000 Nicholas Christopoulos |
9 | |
10 | #include "common/sys.h" |
11 | #include "common/device.h" |
12 | #include "common/pproc.h" |
13 | #include "common/fs_stream.h" |
14 | #include "common/fs_serial.h" |
15 | |
16 | #if USE_TERM_IO |
17 | #include <sys/time.h> |
18 | #include <termios.h> |
19 | #include <unistd.h> |
20 | #include <sys/select.h> |
21 | #include <errno.h> |
22 | |
23 | int serial_open(dev_file_t *f) { |
24 | sprintf(f->name, "/dev/ttyS%d" , f->port); |
25 | |
26 | f->handle = open(f->name, O_RDWR | O_NOCTTY); |
27 | if (f->handle < 0) { |
28 | err_file((f->last_error = errno)); |
29 | } |
30 | // save current port settings |
31 | tcgetattr(f->handle, &f->oldtio); |
32 | bzero(&f->newtio, sizeof(f->newtio)); |
33 | f->newtio.c_cflag = f->devspeed | CRTSCTS | CS8 | CLOCAL | CREAD; |
34 | f->newtio.c_iflag = IGNPAR; |
35 | f->newtio.c_oflag = 0; |
36 | |
37 | // set input mode (non-canonical, no echo,...) |
38 | f->newtio.c_lflag = 0; |
39 | f->newtio.c_cc[VTIME] = 0; // inter-character timer unused |
40 | f->newtio.c_cc[VMIN] = 1; // blocking read until 1 char received |
41 | tcflush(f->handle, TCIFLUSH); |
42 | tcsetattr(f->handle, TCSANOW, &f->newtio); |
43 | return (f->handle >= 0); |
44 | } |
45 | |
46 | int serial_close(dev_file_t *f) { |
47 | tcsetattr(f->handle, TCSANOW, &f->oldtio); |
48 | close(f->handle); |
49 | f->handle = -1; |
50 | return 1; |
51 | } |
52 | |
53 | int serial_write(dev_file_t *f, byte *data, uint32_t size) { |
54 | return stream_write(f, data, size); |
55 | } |
56 | |
57 | int serial_read(dev_file_t *f, byte *data, uint32_t size) { |
58 | return stream_read(f, data, size); |
59 | } |
60 | |
61 | // Returns the number of the available data on serial port |
62 | uint32_t serial_length(dev_file_t *f) { |
63 | fd_set readfs; |
64 | struct timeval tv; |
65 | |
66 | FD_ZERO(&readfs); |
67 | FD_SET(f->handle, &readfs); |
68 | |
69 | tv.tv_usec = 250; // milliseconds |
70 | tv.tv_sec = 0; // seconds |
71 | |
72 | select(f->handle + 1, &readfs, NULL, NULL, &tv); |
73 | if (FD_ISSET(f->handle, &readfs)) { |
74 | return 1; |
75 | } |
76 | return 0; |
77 | } |
78 | |
79 | #elif defined(_Win32) |
80 | |
81 | int serial_open(dev_file_t *f) { |
82 | DCB dcb; |
83 | HANDLE hCom; |
84 | DWORD dwer; |
85 | |
86 | sprintf(f->name, "COM%d" , f->port); |
87 | |
88 | hCom = CreateFile(f->name, GENERIC_READ | GENERIC_WRITE, |
89 | 0, NULL, OPEN_EXISTING, 0, NULL); |
90 | |
91 | if (hCom == INVALID_HANDLE_VALUE) { |
92 | dwer = GetLastError(); |
93 | if (dwer != 5) { |
94 | rt_raise("SERIALFS: CreateFile() failed (%d)" , dwer); |
95 | } else { |
96 | rt_raise("SERIALFS: ACCESS DENIED" ); |
97 | } |
98 | return 0; |
99 | } |
100 | |
101 | if (!GetCommState(hCom, &dcb)) { |
102 | rt_raise("SERIALFS: GetCommState() failed (%d)" , GetLastError()); |
103 | return 0; |
104 | } |
105 | |
106 | dcb.BaudRate = f->devspeed; |
107 | dcb.ByteSize = 8; |
108 | dcb.Parity = NOPARITY; |
109 | dcb.StopBits = ONESTOPBIT; |
110 | |
111 | if (!SetCommState(hCom, &dcb)) { |
112 | rt_raise("SERIALFS: SetCommState() failed (%d)" , GetLastError()); |
113 | return 0; |
114 | } |
115 | |
116 | f->handle = (intptr_t)hCom; |
117 | return 1; |
118 | } |
119 | |
120 | int serial_close(dev_file_t *f) { |
121 | CloseHandle((HANDLE) (intptr_t)f->handle); |
122 | f->handle = -1; |
123 | return 1; |
124 | } |
125 | |
126 | int serial_write(dev_file_t *f, byte *data, uint32_t size) { |
127 | DWORD bytes; |
128 | f->last_error = !WriteFile((HANDLE)(intptr_t)f->handle, data, size, &bytes, NULL); |
129 | return bytes; |
130 | } |
131 | |
132 | int serial_read(dev_file_t *f, byte *data, uint32_t size) { |
133 | DWORD bytes; |
134 | f->last_error = !ReadFile((HANDLE)(intptr_t)f->handle, data, size, &bytes, NULL); |
135 | return bytes; |
136 | } |
137 | |
138 | uint32_t serial_length(dev_file_t *f) { |
139 | COMSTAT cs; |
140 | DWORD de = CE_BREAK; |
141 | ClearCommError((HANDLE)(intptr_t)f->handle, &de, &cs); |
142 | return cs.cbInQue; |
143 | } |
144 | |
145 | #else |
146 | |
147 | int serial_open(dev_file_t *f) { |
148 | err_unsup(); |
149 | return 0; |
150 | } |
151 | |
152 | int serial_close(dev_file_t *f) { |
153 | return 0; |
154 | } |
155 | |
156 | int serial_write(dev_file_t *f, byte *data, uint32_t size) { |
157 | return 0; |
158 | } |
159 | |
160 | int serial_read(dev_file_t *f, byte *data, uint32_t size) { |
161 | return 0; |
162 | } |
163 | |
164 | uint32_t serial_length(dev_file_t *f) { |
165 | return 0; |
166 | } |
167 | |
168 | #endif |
169 | |
170 | /* |
171 | * Returns true (EOF) if the connection is broken |
172 | */ |
173 | uint32_t serial_eof(dev_file_t *f) { |
174 | return f->last_error; |
175 | } |
176 | |