37 | #include "WindowsHelperFunctions.h"
38 |
39 | // Common storage functionality
40 | serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location, const wchar_t* serialNumber, const wchar_t* manufacturer, int vid, int pid)
41 | {
42 | // Allocate memory for the new SerialPort storage structure
43 | unsigned char containsSlashes = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\'));
44 | if (vector->capacity == vector->length)
45 | {
46 | serialPort** newArray = (serialPort**)realloc(vector->ports, ++vector->capacity * sizeof(serialPort*));
47 | if (newArray)
48 | vector->ports = newArray;
49 | else
50 | {
51 | vector->capacity--;
52 | return NULL;
53 | }
54 | }
55 | serialPort* port = (serialPort*)malloc(sizeof(serialPort));
56 | if (port)
57 | vector->ports[vector->length++] = port;
58 | else
59 | return NULL;
60 |
61 | // Initialize the storage structure
62 | memset(port, 0, sizeof(serialPort));
63 | port->handle = (void*)-1;
64 | port->enumerated = 1;
65 | port->vendorID = vid;
66 | port->productID = pid;
67 | port->portPath = (wchar_t*)malloc((wcslen(key)+(containsSlashes ? 1 : 5))*sizeof(wchar_t));
68 | port->portLocation = (wchar_t*)malloc((wcslen(location)+1)*sizeof(wchar_t));
69 | port->friendlyName = (wchar_t*)malloc((wcslen(friendlyName)+1)*sizeof(wchar_t));
70 | port->serialNumber = (wchar_t*)malloc((wcslen(serialNumber)+1)*sizeof(wchar_t));
71 | port->manufacturer = (wchar_t*)malloc((wcslen(manufacturer)+1)*sizeof(wchar_t));
72 | port->portDescription = (wchar_t*)malloc((wcslen(description)+1)*sizeof(wchar_t));
73 | if (!port->portPath || !port->portLocation || !port->friendlyName || !port->serialNumber || !port->manufacturer || !port->portDescription)
74 | {
75 | // Clean up memory associated with the port
76 | vector->length--;
77 | if (port->portPath)
78 | free(port->portPath);
79 | if (port->portLocation)
80 | free(port->portLocation);
81 | if (port->friendlyName)
82 | free(port->friendlyName);
83 | if (port->serialNumber)
84 | free(port->serialNumber);
85 | if (port->manufacturer)
86 | free(port->manufacturer);
87 | if (port->portDescription)
88 | free(port->portDescription);
89 | free(port);
90 | return NULL;
91 | }
92 |
93 | // Store port strings
94 | if (containsSlashes)
95 | wcscpy_s(port->portPath, wcslen(key)+1, key);
96 | else
97 | {
98 | wcscpy_s(port->portPath, wcslen(key)+5, L"\\\\.\\");
99 | wcscat_s(port->portPath, wcslen(key)+5, key);
100 | }
101 | wcscpy_s(port->portLocation, wcslen(location)+1, location);
102 | wcscpy_s(port->friendlyName, wcslen(friendlyName)+1, friendlyName);
103 | wcscpy_s(port->portDescription, wcslen(description)+1, description);
104 | wcscpy_s(port->serialNumber, wcslen(serialNumber)+1, serialNumber);
105 | wcscpy_s(port->manufacturer, wcslen(manufacturer)+1, manufacturer);
106 |
107 | // Return the newly created serial port structure
108 | return port;
109 | }
110 |
111 | serialPort* fetchPort(serialPortVector* vector, const wchar_t* key)
112 | {
113 | // Retrieve the serial port specified by the passed-in key
114 | int keyOffset = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\')) ? 0 : 4;
115 | for (int i = 0; i < vector->length; ++i)
116 | if (wcscmp(key, vector->ports[i]->portPath + keyOffset) == 0)
117 | return vector->ports[i];
118 | return NULL;
119 | }
120 |
121 | void removePort(serialPortVector* vector, serialPort* port)
122 | {
123 | // Clean up memory associated with the port
124 | free(port->portPath);
125 | free(port->portLocation);
126 | free(port->friendlyName);
127 | free(port->serialNumber);
128 | free(port->manufacturer);
129 | free(port->portDescription);
130 |
131 | // Move up all remaining ports in the serial port listing
132 | for (int i = 0; i < vector->length; ++i)
133 | if (vector->ports[i] == port)
134 | {
135 | for (int j = i; j < (vector->length - 1); ++j)
136 | vector->ports[j] = vector->ports[j+1];
137 | vector->length--;
138 | break;
139 | }
140 |
141 | // Free the serial port structure memory
142 | free(port);
143 | }
144 |
145 | void cleanUpVector(serialPortVector* vector)
146 | {
147 | while (vector->length)
148 | removePort(vector, vector->ports[0]);
149 | if (vector->ports)
150 | free(vector->ports);
151 | vector->ports = NULL;
152 | vector->length = vector->capacity = 0;
153 | }
154 |
155 | // Windows-specific functionality
156 | void reduceLatencyToMinimum(const wchar_t* portName, unsigned char requestElevatedPermissions)
157 | {
158 | // Search for this port in all FTDI enumerated ports
159 | HKEY key, paramKey;
160 | DWORD maxSubkeySize, maxPortNameSize = 8;
161 | if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS) &&
162 | (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, &maxSubkeySize, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
163 | {
164 | maxSubkeySize += 32;
165 | DWORD index = 0, subkeySize = maxSubkeySize;
166 | wchar_t *subkey = (wchar_t*)malloc(maxSubkeySize * sizeof(wchar_t)), *portPath = (wchar_t*)malloc(maxPortNameSize * sizeof(wchar_t));
167 | while (subkey && portPath && (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
168 | {
169 | // Retrieve the current port latency value
170 | size_t convertedSize;
171 | char *subkeyString = NULL;
172 | subkeySize = maxSubkeySize;
173 | DWORD desiredLatency = 2, oldLatency = 2;
174 | if ((wcstombs_s(&convertedSize, NULL, 0, subkey, 0) == 0) && (convertedSize < 255))
175 | {
176 | subkeyString = (char*)malloc(convertedSize);
177 | if (subkeyString && (wcstombs_s(NULL, subkeyString, convertedSize, subkey, convertedSize - 1) == 0) &&
178 | (wcscat_s(subkey, maxSubkeySize, L"\\0000\\Device Parameters") == 0))
179 | {
180 | if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
181 | {
182 | DWORD oldLatencySize = sizeof(DWORD), portNameSize = maxPortNameSize * sizeof(wchar_t);
183 | if ((RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)portPath, &portNameSize) == ERROR_SUCCESS) && (wcscmp(portName, portPath) == 0))
184 | RegQueryValueExW(paramKey, L"LatencyTimer", NULL, NULL, (LPBYTE)&oldLatency, &oldLatencySize);
185 | RegCloseKey(paramKey);
186 | }
187 | }
188 | }
189 |
190 | // Update the port latency value if it is too high
191 | if (oldLatency > desiredLatency)
192 | {
193 | if (RegOpenKeyExW(key, subkey, 0, KEY_SET_VALUE, ¶mKey) == ERROR_SUCCESS)
194 | {
195 | RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&desiredLatency, sizeof(desiredLatency));
196 | RegCloseKey(paramKey);
197 | }
198 | else if (requestElevatedPermissions)
199 | {
200 | // Create registry update file
201 | char *workingDirectory = _getcwd(NULL, 0);
202 | wchar_t *workingDirectoryWide = _wgetcwd(NULL, 0);
203 | int workingDirectoryLength = strlen(workingDirectory) + 1;
204 | char *registryFileName = (char*)malloc(workingDirectoryLength + 8);
205 | wchar_t *paramsString = (wchar_t*)malloc((workingDirectoryLength + 11) * sizeof(wchar_t));
206 | sprintf(registryFileName, "%s\\del.reg", workingDirectory);
207 | swprintf(paramsString, workingDirectoryLength + 11, L"/s %s\\del.reg", workingDirectoryWide);
208 | FILE *registryFile = fopen(registryFileName, "wb");
209 | if (registryFile)
210 | {
211 | fprintf(registryFile, "Windows Registry Editor Version 5.00\n\n");
212 | fprintf(registryFile, "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS\\%s\\0000\\Device Parameters]\n", subkeyString);
213 | fprintf(registryFile, "\"LatencyTimer\"=dword:00000002\n\n");
214 | fclose(registryFile);
215 | }
216 |
217 | // Launch a new administrative process to update the registry value
218 | SHELLEXECUTEINFOW shExInfo = { 0 };
219 | shExInfo.cbSize = sizeof(shExInfo);
220 | shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
221 | shExInfo.hwnd = NULL;
222 | shExInfo.lpVerb = L"runas";
223 | shExInfo.lpFile = L"C:\\Windows\\regedit.exe";
224 | shExInfo.lpParameters = paramsString;
225 | shExInfo.lpDirectory = NULL;
226 | shExInfo.nShow = SW_SHOW;
227 | shExInfo.hInstApp = 0;
228 | if (ShellExecuteExW(&shExInfo))
229 | {
230 | WaitForSingleObject(shExInfo.hProcess, INFINITE);
231 | CloseHandle(shExInfo.hProcess);
232 | }
233 |
234 | // Delete the registry update file
235 | remove(registryFileName);
236 | free(workingDirectoryWide);
237 | free(workingDirectory);
238 | free(registryFileName);
239 | free(paramsString);
240 | }
241 | }
242 |
243 | // Clean up memory
244 | if (subkeyString)
245 | free(subkeyString);
246 | }
247 | RegCloseKey(key);
248 | free(portPath);
249 | free(subkey);
250 | }
251 | }
252 |
253 | int getPortPathFromSerial(wchar_t* portPath, int portPathLength, const char* ftdiSerialNumber)
254 | {
255 | // Search for this port in all FTDI enumerated ports
256 | int found = 0;
257 | HKEY key, paramKey;
258 | DWORD maxSubkeySize;
259 | if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS) &&
260 | (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, &maxSubkeySize, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
261 | {
262 | maxSubkeySize += 32;
263 | DWORD index = 0, subkeySize = maxSubkeySize;
264 | wchar_t *subkey = (wchar_t*)malloc(maxSubkeySize * sizeof(wchar_t));
265 | while (subkey && (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
266 | {
267 | // Convert this string from wchar* to char*
268 | size_t convertedSize;
269 | subkeySize = maxSubkeySize;
270 | if ((wcstombs_s(&convertedSize, NULL, 0, subkey, 0) == 0) && (convertedSize < 255))
271 | {
272 | char *subkeyString = (char*)malloc(convertedSize);
273 | if (subkeyString && (wcstombs_s(NULL, subkeyString, convertedSize, subkey, convertedSize - 1) == 0))
274 | {
275 | // Determine if this device matches the specified serial number
276 | if (ftdiSerialNumber && strstr(subkeyString, ftdiSerialNumber) && (wcscat_s(subkey, maxSubkeySize, L"\\0000\\Device Parameters") == 0))
277 | {
278 | DWORD portNameSize = portPathLength;
279 | if ((RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS) &&
280 | (RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)portPath, &portNameSize) == ERROR_SUCCESS))
281 | {
282 | found = 1;
283 | RegCloseKey(paramKey);
284 | }
285 | }
286 | }
287 | if (subkeyString)
288 | free(subkeyString);
289 | }
290 | }
291 | RegCloseKey(key);
292 | if (subkey)
293 | free(subkey);
294 | }
295 | return found;
296 | }
297 |
298 | #endif
299 |
--------------------------------------------------------------------------------
/src/main/c/Windows/WindowsHelperFunctions.h:
--------------------------------------------------------------------------------
1 | /*
2 | * WindowsHelperFunctions.h
3 | *
4 | * Created on: May 05, 2015
5 | * Last Updated on: Apr 10, 2024
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2024 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
27 | #define __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
28 |
29 | // Serial port JNI header file
30 | #include "../com_fazecast_jSerialComm_SerialPort.h"
31 |
32 | // Serial port data structure
33 | typedef struct serialPort
34 | {
35 | void *handle;
36 | wchar_t *portPath, *friendlyName, *portDescription, *portLocation, *serialNumber, *manufacturer;
37 | int errorLineNumber, errorNumber, vendorID, productID;
38 | volatile char enumerated, eventListenerRunning;
39 | char ftdiSerialNumber[16];
40 | } serialPort;
41 |
42 | // Common storage functionality
43 | typedef struct serialPortVector
44 | {
45 | serialPort **ports;
46 | int length, capacity;
47 | } serialPortVector;
48 | serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location, const wchar_t* serialNumber, const wchar_t* manufacturer, int vid, int pid);
49 | serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
50 | void removePort(serialPortVector* vector, serialPort* port);
51 | void cleanUpVector(serialPortVector* vector);
52 |
53 | // Windows-specific functionality
54 | void reduceLatencyToMinimum(const wchar_t* portName, unsigned char requestElevatedPermissions);
55 | int getPortPathFromSerial(wchar_t* portPath, int portPathLength, const char* ftdiSerialNumber);
56 |
57 | #endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
58 |
--------------------------------------------------------------------------------
/src/main/c/Windows/win32/jni_md.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | *
24 | */
25 |
26 | #ifndef _JAVASOFT_JNI_MD_H_
27 | #define _JAVASOFT_JNI_MD_H_
28 |
29 | #define JNIEXPORT __declspec(dllexport)
30 | #define JNIIMPORT __declspec(dllimport)
31 | #define JNICALL __stdcall
32 |
33 | // 'long' is always 32 bit on windows so this matches what jdk expects
34 | typedef long jint;
35 | typedef __int64 jlong;
36 | typedef signed char jbyte;
37 |
38 | #endif /* !_JAVASOFT_JNI_MD_H_ */
39 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortDataListener.java
3 | *
4 | * Created on: Feb 25, 2015
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | import java.util.EventListener;
29 |
30 | /**
31 | * This interface must be implemented to enable simple event-based serial port I/O.
32 | *
33 | * @see java.util.EventListener
34 | */
35 | public interface SerialPortDataListener extends EventListener
36 | {
37 | /**
38 | * Must be overridden to return one or more desired event constants for which the {@link #serialEvent(SerialPortEvent)} callback should be triggered.
39 | *
40 | * Valid event constants are:
41 | *
42 | * {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
43 | * {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
44 | * {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
45 | * {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
46 | * {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
47 | * {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
48 | * {@link SerialPort#LISTENING_EVENT_CTS}
49 | * {@link SerialPort#LISTENING_EVENT_DSR}
50 | * {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
51 | * {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
52 | * {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
53 | * {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
54 | * {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
55 | *
56 | * Two or more events may be OR'd together to listen for multiple events; however, if {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE} is OR'd with {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}, the {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED} flag will take precedence.
57 | *
58 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
59 | * event will never be called on a non-Windows system.
60 | *
61 | * It is recommended to only use the {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}, {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED},
62 | * {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}, and/or {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED} listening events in production or cross-platform code
63 | * since underlying differences and lack of support for the control line status and error events among the various operating systems and device drivers make it
64 | * unlikely that code listening for these events will behave similarly across different serial devices or OS's, if it works at all.
65 | *
66 | * @return The event constants that should trigger the {@link #serialEvent(SerialPortEvent)} callback.
67 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE
68 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED
69 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN
70 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED
71 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT
72 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT
73 | * @see SerialPort#LISTENING_EVENT_CTS
74 | * @see SerialPort#LISTENING_EVENT_DSR
75 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR
76 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR
77 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR
78 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR
79 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR
80 | */
81 | int getListeningEvents();
82 |
83 | /**
84 | * Called whenever one or more of the serial port events specified by the {@link #getListeningEvents()} method occurs.
85 | *
86 | * Note that your implementation of this function should always perform as little data processing as possible, as the speed at which this callback will fire is at the mercy of the underlying operating system. If you need to collect a large amount of data, application-level buffering should be implemented and data processing should occur on a separate thread.
87 | *
88 | * @param event A {@link SerialPortEvent} object containing information and/or data about the serial events that occurred.
89 | * @see SerialPortEvent
90 | */
91 | void serialEvent(SerialPortEvent event);
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortDataListenerWithExceptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortDataListenerWithExceptions.java
3 | *
4 | * Created on: Jul 11, 2019
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | /**
29 | * This interface must be implemented to enable simple event-based serial port I/O with a custom Exception callback.
30 | *
31 | * @see com.fazecast.jSerialComm.SerialPortDataListener
32 | * @see java.util.EventListener
33 | */
34 | public interface SerialPortDataListenerWithExceptions extends SerialPortDataListener
35 | {
36 | /**
37 | * Must be overridden to handle any Java exceptions that occur asynchronously in this data listener.
38 | *
39 | * @param e An {@link Exception} object containing information about the exception that occurred.
40 | */
41 | void catchException(Exception e);
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortEvent.java
3 | *
4 | * Created on: Feb 25, 2015
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | import java.util.EventObject;
29 |
30 | /**
31 | * This class describes an asynchronous serial port event.
32 | *
33 | * @see java.util.EventObject
34 | */
35 | public class SerialPortEvent extends EventObject
36 | {
37 | private static final long serialVersionUID = 3060830619653354150L;
38 | private final int eventType;
39 | private final byte[] serialData;
40 |
41 | /**
42 | * Constructs a {@link SerialPortEvent} object corresponding to the specified serial event type.
43 | *
44 | * This constructor should only be used when the {@link SerialPortEvent} does not contain any data bytes.
45 | *
46 | * Valid serial event types are:
47 | *
48 | * {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
49 | * {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
50 | * {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
51 | * {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
52 | * {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
53 | * {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
54 | * {@link SerialPort#LISTENING_EVENT_CTS}
55 | * {@link SerialPort#LISTENING_EVENT_DSR}
56 | * {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
57 | * {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
58 | * {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
59 | * {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
60 | * {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
61 | *
62 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
63 | * event will never be called on a non-Windows system.
64 | *
65 | * Also, most control line status and error events from {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT} to {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
66 | * are unlikely to function the same across different operating systems or serial devices on the same operating system, if they work properly at all.
67 | *
68 | * @param comPort The {@link SerialPort} about which this object is being created.
69 | * @param serialEventType The type of serial port event that this object describes.
70 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE
71 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED
72 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN
73 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED
74 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT
75 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT
76 | * @see SerialPort#LISTENING_EVENT_CTS
77 | * @see SerialPort#LISTENING_EVENT_DSR
78 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR
79 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR
80 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR
81 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR
82 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR
83 | */
84 | public SerialPortEvent(SerialPort comPort, int serialEventType)
85 | {
86 | super(comPort);
87 | eventType = serialEventType;
88 | serialData = null;
89 | }
90 |
91 | /**
92 | * Constructs a {@link SerialPortEvent} object corresponding to the specified serial event type and containing the passed-in data bytes.
93 | *
94 | * Valid serial event types are:
95 | *
96 | * {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
97 | * {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
98 | * {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
99 | * {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
100 | * {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
101 | * {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
102 | * {@link SerialPort#LISTENING_EVENT_CTS}
103 | * {@link SerialPort#LISTENING_EVENT_DSR}
104 | * {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
105 | * {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
106 | * {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
107 | * {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
108 | * {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
109 | *
110 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
111 | * event will never be called on a non-Windows system.
112 | *
113 | * Also, most control line status and error events from {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT} to {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
114 | * are unlikely to function the same across different operating systems or serial devices on the same operating system, if they work properly at all.
115 | *
116 | * @param comPort The {@link SerialPort} about which this object is being created.
117 | * @param serialEventType The type of serial port event that this object describes.
118 | * @param data The raw data bytes corresponding to this serial port event.
119 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE
120 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED
121 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN
122 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED
123 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT
124 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT
125 | * @see SerialPort#LISTENING_EVENT_CTS
126 | * @see SerialPort#LISTENING_EVENT_DSR
127 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR
128 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR
129 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR
130 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR
131 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR
132 | */
133 | public SerialPortEvent(SerialPort comPort, int serialEventType, byte[] data)
134 | {
135 | super(comPort);
136 | eventType = serialEventType;
137 | serialData = data;
138 | }
139 |
140 | /**
141 | * Returns a string representation of the type of event represented by this object.
142 | *
143 | * @return A string representation of the type of event represented by this object.
144 | */
145 | @Override
146 | public final String toString() {
147 | switch(eventType) {
148 | case SerialPort.LISTENING_EVENT_DATA_AVAILABLE: return "LISTENING_EVENT_DATA_AVAILABLE";
149 | case SerialPort.LISTENING_EVENT_DATA_RECEIVED: return "LISTENING_EVENT_DATA_RECEIVED";
150 | case SerialPort.LISTENING_EVENT_DATA_WRITTEN: return "LISTENING_EVENT_DATA_WRITTEN";
151 | case SerialPort.LISTENING_EVENT_PORT_DISCONNECTED: return "LISTENING_EVENT_PORT_DISCONNECTED";
152 | case SerialPort.LISTENING_EVENT_BREAK_INTERRUPT: return "LISTENING_EVENT_BREAK_INTERRUPT";
153 | case SerialPort.LISTENING_EVENT_CARRIER_DETECT: return "LISTENING_EVENT_CARRIER_DETECT";
154 | case SerialPort.LISTENING_EVENT_CTS: return "LISTENING_EVENT_CTS";
155 | case SerialPort.LISTENING_EVENT_DSR: return "LISTENING_EVENT_DSR";
156 | case SerialPort.LISTENING_EVENT_RING_INDICATOR: return "LISTENING_EVENT_RING_INDICATOR";
157 | case SerialPort.LISTENING_EVENT_FRAMING_ERROR: return "LISTENING_EVENT_FRAMING_ERROR";
158 | case SerialPort.LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR: return "LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR";
159 | case SerialPort.LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR: return "LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR";
160 | case SerialPort.LISTENING_EVENT_PARITY_ERROR: return "LISTENING_EVENT_PARITY_ERROR";
161 | default: return "LISTENING_EVENT_UNKNOWN_TYPE";
162 | }
163 | }
164 |
165 | /**
166 | * Returns the {@link SerialPort} that triggered this event.
167 | *
168 | * @return The {@link SerialPort} that triggered this event.
169 | */
170 | public final SerialPort getSerialPort() { return (SerialPort)source; }
171 |
172 | /**
173 | * Returns the type of serial port events that caused this object to be created.
174 | *
175 | * Return value will be a bitmask containing one or more of the following items OR'd together:
176 | *
177 | * {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
178 | * {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
179 | * {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
180 | * {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
181 | * {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
182 | * {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
183 | * {@link SerialPort#LISTENING_EVENT_CTS}
184 | * {@link SerialPort#LISTENING_EVENT_DSR}
185 | * {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
186 | * {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
187 | * {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
188 | * {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
189 | * {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
190 | *
191 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
192 | * event will never be called on a non-Windows system.
193 | *
194 | * Also, most control line status and error events from {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT} to {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
195 | * are unlikely to function the same across different operating systems or serial devices on the same operating system, if they work properly at all.
196 | *
197 | * @return The serial port event that this object describes.
198 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE
199 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED
200 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN
201 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED
202 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT
203 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT
204 | * @see SerialPort#LISTENING_EVENT_CTS
205 | * @see SerialPort#LISTENING_EVENT_DSR
206 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR
207 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR
208 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR
209 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR
210 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR
211 | */
212 | public final int getEventType() { return eventType; }
213 |
214 | /**
215 | * Returns any raw data bytes associated with this serial port event.
216 | *
217 | * @return Any data bytes associated with this serial port event or null if none exist.
218 | */
219 | public final byte[] getReceivedData() { return serialData; }
220 | }
221 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortIOException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortIOException.java
3 | *
4 | * Created on: Aug 08, 2018
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | import java.io.IOException;
29 |
30 | /**
31 | * This class describes a serial port IO exception.
32 | *
33 | * @see java.io.IOException
34 | */
35 | public final class SerialPortIOException extends IOException
36 | {
37 | private static final long serialVersionUID = 3353684802475494674L;
38 |
39 | /**
40 | * Constructs a {@link SerialPortIOException} with the specified detail message.
41 | *
42 | * @param message The detail message (which is saved for later retrieval by the {@link SerialPortIOException#getMessage()} method).
43 | */
44 | public SerialPortIOException(String message)
45 | {
46 | super(message);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortInvalidPortException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortInvalidPortException.java
3 | *
4 | * Created on: Apr 15, 2019
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | /**
29 | * This class describes a serial port invalid port exception.
30 | *
31 | * @see java.lang.RuntimeException
32 | */
33 | public final class SerialPortInvalidPortException extends RuntimeException
34 | {
35 | private static final long serialVersionUID = 3420177672598538224L;
36 |
37 | /**
38 | * Constructs a {@link SerialPortInvalidPortException} with the specified detail message and cause.
39 | *
40 | * Note that the detail message associated with cause is not automatically incorporated into this exception's detail message.
41 | *
42 | * @param message message The detail message (which is saved for later retrieval by the {@link SerialPortInvalidPortException#getMessage()} method).
43 | * @param cause The cause (which is saved for later retrieval by the {@link SerialPortInvalidPortException#getCause()} method). (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
44 | */
45 | public SerialPortInvalidPortException(String message, Throwable cause)
46 | {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortMessageListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortMessageListener.java
3 | *
4 | * Created on: Mar 14, 2019
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2020 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | /**
29 | * This interface must be implemented to enable delimited message reads using event-based serial port I/O.
30 | *
31 | * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context.
32 | *
33 | * @see com.fazecast.jSerialComm.SerialPortDataListener
34 | * @see java.util.EventListener
35 | */
36 | public interface SerialPortMessageListener extends SerialPortDataListener
37 | {
38 | /**
39 | * Must be overridden to return the expected message delimiter bytes that must be encountered before the {@link #serialEvent(SerialPortEvent)} callback is triggered.
40 | *
41 | * @return A byte array containing the expected message delimiters that must be encountered before the {@link #serialEvent(SerialPortEvent)} callback is triggered.
42 | */
43 | byte[] getMessageDelimiter();
44 |
45 | /**
46 | * Must be overridden to return whether the message delimiter indicates the end or the beginning of a message.
47 | *
48 | * @return A boolean indicating whether the message delimiter indicates the end or the beginning of a message.
49 | */
50 | boolean delimiterIndicatesEndOfMessage();
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortMessageListenerWithExceptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortMessageListenerWithExceptions.java
3 | *
4 | * Created on: Jan 03, 2020
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | /**
29 | * This interface must be implemented to enable delimited message reads using event-based serial port I/O with a custom Exception callback.
30 | *
31 | * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context.
32 | *
33 | * @see com.fazecast.jSerialComm.SerialPortMessageListener
34 | * @see com.fazecast.jSerialComm.SerialPortDataListener
35 | * @see java.util.EventListener
36 | */
37 | public interface SerialPortMessageListenerWithExceptions extends SerialPortMessageListener
38 | {
39 | /**
40 | * Must be overridden to handle any Java exceptions that occur asynchronously in this data listener.
41 | *
42 | * @param e An {@link Exception} object containing information about the exception that occurred.
43 | */
44 | void catchException(Exception e);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortPacketListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortPacketListener.java
3 | *
4 | * Created on: Feb 25, 2015
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | /**
29 | * This interface must be implemented to enable full packet reads using event-based serial port I/O.
30 | *
31 | * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context.
32 | *
33 | * @see com.fazecast.jSerialComm.SerialPortDataListener
34 | * @see java.util.EventListener
35 | */
36 | public interface SerialPortPacketListener extends SerialPortDataListener
37 | {
38 | /**
39 | * Must be overridden to return the desired number of bytes that must be read before the {@link #serialEvent(SerialPortEvent)} callback is triggered.
40 | *
41 | * @return The number of bytes that must be read before the {@link #serialEvent(SerialPortEvent)} callback is triggered.
42 | */
43 | int getPacketSize();
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortThreadFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortThreadFactory.java
3 | *
4 | * Created on: May 31, 2022
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | import java.util.concurrent.ThreadFactory;
29 |
30 | /**
31 | * This class is used to create internal jSerialComm threads.
32 | *
33 | * A user can call the {@link #set(ThreadFactory)} method to override the way in which threads are created.
34 | *
35 | * @see java.util.concurrent.ThreadFactory
36 | */
37 | public class SerialPortThreadFactory
38 | {
39 | // Default ThreadFactory instance
40 | private static ThreadFactory instance = new ThreadFactory()
41 | {
42 | @Override
43 | public Thread newThread(Runnable r) { return new Thread(r); }
44 | };
45 |
46 | /**
47 | * Returns the current {@link java.util.concurrent.ThreadFactory} instance associated with this library.
48 | *
49 | * @return The current {@link java.util.concurrent.ThreadFactory} instance.
50 | * @see java.util.concurrent.ThreadFactory
51 | */
52 | public static ThreadFactory get() { return instance; }
53 |
54 | /**
55 | * Allows a user to define a custom thread factory to be used by this library for creating new threads.
56 | *
57 | * Such a custom factory method may be used, for example, to set all new threads to run as daemons.
58 | *
59 | * @param threadFactory A user-defined custom thread factory instance.
60 | * @see java.util.concurrent.ThreadFactory
61 | */
62 | public static void set(ThreadFactory threadFactory)
63 | {
64 | instance = threadFactory;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/SerialPortTimeoutException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortTimeoutException.java
3 | *
4 | * Created on: Aug 08, 2018
5 | * Last Updated on: Jun 08, 2022
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2022 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | import java.io.InterruptedIOException;
29 |
30 | /**
31 | * This class describes a serial port timeout exception.
32 | *
33 | * @see java.io.InterruptedIOException
34 | */
35 | public final class SerialPortTimeoutException extends InterruptedIOException
36 | {
37 | private static final long serialVersionUID = 3209035213903386044L;
38 |
39 | /**
40 | * Constructs a {@link SerialPortTimeoutException} with the specified detail message.
41 | *
42 | * @param message The detail message (which is saved for later retrieval by the {@link SerialPortTimeoutException#getMessage()} method).
43 | */
44 | public SerialPortTimeoutException(String message)
45 | {
46 | super(message);
47 | bytesTransferred = 0;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java:
--------------------------------------------------------------------------------
1 | /*
2 | * AndroidPort.java
3 | *
4 | * Created on: Feb 15, 2022
5 | * Last Updated on: Jul 27, 2023
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2022-2023 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm.android;
27 |
28 | import com.fazecast.jSerialComm.SerialPort;
29 |
30 | import android.app.Application;
31 | import android.app.PendingIntent;
32 | import android.content.BroadcastReceiver;
33 | import android.content.Context;
34 | import android.content.Intent;
35 | import android.content.IntentFilter;
36 | import android.content.pm.PackageManager;
37 | import android.hardware.usb.UsbDevice;
38 | import android.hardware.usb.UsbDeviceConnection;
39 | import android.hardware.usb.UsbEndpoint;
40 | import android.hardware.usb.UsbInterface;
41 | import android.hardware.usb.UsbManager;
42 | import android.util.Log;
43 |
44 | import java.lang.reflect.Constructor;
45 | import java.lang.reflect.Field;
46 | import java.util.HashMap;
47 |
48 | public abstract class AndroidPort
49 | {
50 | // USB request and recipient types
51 | protected static final int USB_REQUEST_TYPE_STANDARD = 0;
52 | protected static final int USB_REQUEST_TYPE_CLASS = 0x01 << 5;
53 | protected static final int USB_REQUEST_TYPE_VENDOR = 0x02 << 5;
54 | protected static final int USB_REQUEST_TYPE_RESERVED = 0x03 << 5;
55 | protected static final int USB_ENDPOINT_IN = 0x80;
56 | protected static final int USB_ENDPOINT_OUT = 0x00;
57 | protected static final int USB_RECIPIENT_DEVICE = 0x00;
58 | protected static final int USB_RECIPIENT_INTERFACE = 0x01;
59 | protected static final int USB_RECIPIENT_ENDPOINT = 0x02;
60 | protected static final int USB_RECIPIENT_OTHER = 0x03;
61 |
62 | // Static shared port parameters
63 | protected static Application context = null;
64 | protected static UsbManager usbManager = null;
65 |
66 | // Static private port parameters
67 | private static final String ACTION_USB_PERMISSION = "com.fazecast.jSerialComm.USB_PERMISSION";
68 | private static volatile boolean userPermissionGranted = false, awaitingUserPermission = false;
69 | private static PendingIntent permissionIntent = null;
70 |
71 | // Shared serial port parameters
72 | protected final UsbDevice usbDevice;
73 | protected UsbInterface usbInterface = null;
74 | protected UsbDeviceConnection usbConnection = null;
75 | protected UsbEndpoint usbDeviceIn = null, usbDeviceOut = null;
76 | protected volatile int writeBufferIndex = 0, writeBufferLength = 1024;
77 | protected volatile int readBufferIndex = 0, readBufferOffset = 0, readBufferLength = 1024;
78 | protected final byte[] readBuffer = new byte[readBufferLength], writeBuffer = new byte[writeBufferLength];
79 |
80 | // Private constructor so that class can only be created by the enumeration method
81 | protected AndroidPort(UsbDevice device) { usbDevice = device; }
82 |
83 | // Method to set the Android application context
84 | public static void setAndroidContext(Object androidContext) { context = Application.class.cast(androidContext); }
85 |
86 | // USB event handler
87 | private static final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
88 | public void onReceive(Context context, Intent intent) {
89 | if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
90 | synchronized (AndroidPort.class) {
91 | userPermissionGranted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
92 | awaitingUserPermission = false;
93 | AndroidPort.class.notifyAll();
94 | }
95 | } else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
96 | UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
97 | if (device != null)
98 | Log.i("jSerialComm", "Port was disconnected. Need TODO something");
99 | // TODO: Alert event waiting thread, close port, set to null
100 | }
101 | }
102 | };
103 |
104 | // Port enumeration method
105 | public static SerialPort[] getCommPortsNative()
106 | {
107 | // Ensure that the Android application context has been specified
108 | if (context == null)
109 | throw new RuntimeException("The Android application context must be specified using 'setAndroidContext()' before making any jSerialComm library calls.");
110 |
111 | // Ensure that the device has a USB Manager
112 | if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST))
113 | return new SerialPort[0];
114 |
115 | // Register a listener to handle permission request responses
116 | if (permissionIntent == null) {
117 | permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
118 | IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
119 | filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
120 | context.registerReceiver(usbReceiver, filter);
121 | }
122 |
123 | // Enumerate all serial ports on the device
124 | usbManager = (UsbManager)context.getApplicationContext().getSystemService(Context.USB_SERVICE);
125 | HashMap deviceList = usbManager.getDeviceList();
126 | SerialPort[] portsList = new SerialPort[deviceList.size()];
127 |
128 | // Create and return the SerialPort port listing
129 | int i = 0;
130 | for (UsbDevice device : deviceList.values()) {
131 | // TODO: Determine the type of port
132 | AndroidPort androidPort = null;
133 |
134 | // Create a new serial port object and add it to the port listing
135 | SerialPort serialPort = null;
136 | try {
137 | Constructor serialPortConstructor = SerialPort.class.getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, int.class, int.class);
138 | serialPortConstructor.setAccessible(true);
139 | serialPort = serialPortConstructor.newInstance("COM" + (i+1), device.getDeviceName(), device.getProductName(), device.getSerialNumber(), device.getSerialNumber(), device.getVendorId(), device.getProductId());
140 | Field privateAndroidPort = SerialPort.class.getDeclaredField("androidPort");
141 | privateAndroidPort.setAccessible(true);
142 | privateAndroidPort.set(serialPort, androidPort);
143 | portsList[i++] = serialPort;
144 | } catch (Exception e) {
145 | e.printStackTrace();
146 | continue;
147 | }
148 |
149 | Log.i("jSerialComm", "System Port Name: " + serialPort.getSystemPortName());
150 | Log.i("jSerialComm", "System Port Path: " + serialPort.getSystemPortPath());
151 | Log.i("jSerialComm", "Descriptive Port Name: " + serialPort.getDescriptivePortName());
152 | Log.i("jSerialComm", "Port Description: " + serialPort.getPortDescription());
153 | Log.i("jSerialComm", "Serial Number: " + serialPort.getSerialNumber());
154 | Log.i("jSerialComm", "Location: " + serialPort.getPortLocation());
155 | Log.i("jSerialComm", "Vendor ID: " + serialPort.getVendorID());
156 | Log.i("jSerialComm", "Product ID: " + serialPort.getProductID());
157 | }
158 | return portsList;
159 | }
160 |
161 | // Native port opening method
162 | public long openPortNative(SerialPort serialPort)
163 | {
164 | // Obtain user permission to open the port
165 | if (!usbManager.hasPermission(usbDevice)) {
166 | synchronized (AndroidPort.class) {
167 | awaitingUserPermission = true;
168 | while (awaitingUserPermission) {
169 | usbManager.requestPermission(usbDevice, permissionIntent);
170 | try { AndroidPort.class.wait(); } catch (InterruptedException ignored) { }
171 | }
172 | if (!userPermissionGranted)
173 | return 0L;
174 | }
175 | }
176 |
177 | // Open and configure the port using chip-specific methods
178 | usbConnection = usbManager.openDevice(usbDevice);
179 | if ((usbConnection == null) || !openPort() || !configPort(serialPort))
180 | closePortNative();
181 |
182 | // Return whether the port was successfully opened
183 | return (usbConnection != null) ? 1L: 0L;
184 | }
185 |
186 | // Native port closing method
187 | public long closePortNative()
188 | {
189 | // Close the port using chip-specific methods
190 | if ((usbConnection != null) && closePort()) {
191 | usbConnection.close();
192 | usbConnection = null;
193 | usbInterface = null;
194 | usbDeviceOut = null;
195 | usbDeviceIn = null;
196 | }
197 |
198 | // Return whether the port was successfully closed
199 | return (usbConnection == null) ? 0L : 1L;
200 | }
201 |
202 | // Shared VID/PID-to-long creation method
203 | protected static long makeVidPid(int vid, int pid) { return (((long)vid << 16) & 0xFFFF0000) | ((long)pid & 0x0000FFFF); }
204 |
205 | // Android Port required interface
206 | public abstract boolean openPort();
207 | public abstract boolean closePort();
208 | public abstract boolean configPort(SerialPort serialPort);
209 | public abstract boolean flushRxTxBuffers();
210 | public abstract int waitForEvent();
211 | public abstract int bytesAvailable();
212 | public abstract int bytesAwaitingWrite();
213 | public abstract int readBytes(byte[] buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout);
214 | public abstract int writeBytes(byte[] buffer, long bytesToWrite, long offset, int timeoutMode);
215 | public abstract void setEventListeningStatus(boolean eventListenerRunning);
216 | public abstract boolean setBreak();
217 | public abstract boolean clearBreak();
218 | public abstract boolean setRTS();
219 | public abstract boolean clearRTS();
220 | public abstract boolean setDTR();
221 | public abstract boolean clearDTR();
222 | public abstract boolean getCTS();
223 | public abstract boolean getDSR();
224 | public abstract boolean getDCD();
225 | public abstract boolean getDTR();
226 | public abstract boolean getRTS();
227 | public abstract boolean getRI();
228 | public abstract int getLastErrorLocation();
229 | public abstract int getLastErrorCode();
230 | }
231 |
--------------------------------------------------------------------------------
/src/main/java/com/fazecast/jSerialComm/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * package-info.java
3 | *
4 | * Created on: Jun 08, 2022
5 | * Last Updated on: Jun 29, 2023
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2023 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | /**
27 | * This package contains all of the classes and interfaces that make up the
28 | * Java serial communications library.
29 | *
30 | * @author Will Hedgecock <will.hedgecock@fazecast.com>
31 | * @version 2.11.1
32 | */
33 | package com.fazecast.jSerialComm;
34 |
--------------------------------------------------------------------------------
/src/main/resources/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/main/resources/Android/arm64-v8a/libjSerialComm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/arm64-v8a/libjSerialComm.so
--------------------------------------------------------------------------------
/src/main/resources/Android/armeabi-v7a/libjSerialComm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/armeabi-v7a/libjSerialComm.so
--------------------------------------------------------------------------------
/src/main/resources/Android/x86/libjSerialComm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/x86/libjSerialComm.so
--------------------------------------------------------------------------------
/src/main/resources/Android/x86_64/libjSerialComm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/x86_64/libjSerialComm.so
--------------------------------------------------------------------------------
/src/moduleInfo/java/module-info.java:
--------------------------------------------------------------------------------
1 | module com.fazecast.jSerialComm {
2 | exports com.fazecast.jSerialComm;
3 | }
--------------------------------------------------------------------------------
/src/test/c/Makefile:
--------------------------------------------------------------------------------
1 | # Compiler tools, commands, and flags
2 | COMPILE = gcc
3 | COMPILE_WIN = cl
4 | LINK = gcc
5 | LINK_WIN = link
6 | BUILD_DIR = build
7 | JDK_HOME = $(shell if [ "`uname`" = "Darwin" ]; then echo "`/usr/libexec/java_home`"; else echo "$$JDK_HOME"; fi)
8 | INCLUDES = -I"../../main/c/Posix" -I"../../main/c/Windows" -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/win32" -I"$(JDK_HOME)/include/linux" -I"$(JDK_HOME)/include/darwin" -I"$(JDK_HOME)/include/solaris"
9 | CFLAGS = -fPIC -O0 -g -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 $(shell if [ "`uname`" != "Darwin" ]; then echo "-static-libgcc"; fi)
10 | CFLAGS_WIN = /c /O2 /GF /GL /MT /EHsc /fp:precise /J /nologo /TC /Zi
11 | LDFLAGS = -O0 -g $(shell if [ "`uname`" != "Darwin" ]; then echo "-static-libgcc"; fi)
12 | LDFLAGS_WIN = /LTCG /NOLOGO /INCREMENTAL:NO /DEBUG /OPT:REF,ICF,LBR
13 | LIBRARIES = $(shell if [ "`uname`" = "Darwin" ]; then echo "-framework Cocoa -framework IOKit"; else echo "-pthread"; fi)
14 | LIBRARIES_WIN = Advapi32.lib SetupAPI.lib Shell32.lib
15 | DELETE = @rm
16 | MKDIR = @mkdir -p
17 | COPY = @cp
18 | MOVE = @mv
19 | PRINT = @echo
20 |
21 | # Define phony and suffix rules
22 | .PHONY: all clean
23 | .SUFFIXES:
24 | .SUFFIXES: .cpp .c .o .h
25 | vpath %.c ../../main/c/Posix ../../main/c/Windows
26 |
27 | # Default build target does nothing
28 | all :
29 | $(PRINT) You must specify a specify test to make!
30 | clean :
31 | $(DELETE) -rf "$(BUILD_DIR)"
32 | $(DELETE) -rf *.pdb *.exe
33 |
34 | # Rule to create build directories
35 | $(BUILD_DIR) :
36 | $(MKDIR) -p $@
37 |
38 | # Build rules for all tests
39 | testOpenClose : $(BUILD_DIR)/testOpenClose.o $(BUILD_DIR)/PosixHelperFunctions.o
40 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^
41 | testRS485 : $(BUILD_DIR)/testRS485.o
42 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^
43 | testEnumeratePosix : $(BUILD_DIR)/testEnumeratePosix.o $(BUILD_DIR)/PosixHelperFunctions.o
44 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^
45 | testEnumerateWindows : $(BUILD_DIR)/testEnumerateWindows.obj $(BUILD_DIR)/WindowsHelperFunctions.obj
46 | $(LINK_WIN) $(LDFLAGS_WIN) /OUT:$@.exe $^ $(LIBRARIES_WIN)
47 | testEventsWindows : $(BUILD_DIR)/testEventsWindows.obj $(BUILD_DIR)/WindowsHelperFunctions.obj
48 | $(LINK_WIN) $(LDFLAGS_WIN) /OUT:$@.exe $^ $(LIBRARIES_WIN)
49 | testPollPosix : $(BUILD_DIR)/testPollPosix.o $(BUILD_DIR)/PosixHelperFunctions.o
50 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^
51 |
52 | # Suffix rules to get from *.c -> *.o
53 | $(BUILD_DIR)/testEnumerateWindows.obj : testEnumerateWindows.c
54 | $(MKDIR) $(BUILD_DIR)
55 | $(COPY) ../../main/c/Posix/*.h ../../main/c/
56 | $(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -Fo$@
57 | $(DELETE) ../../main/c/*.h
58 | $(BUILD_DIR)/testEventsWindows.obj : testEventsWindows.c
59 | $(MKDIR) $(BUILD_DIR)
60 | $(COPY) ../../main/c/Posix/*.h ../../main/c/
61 | $(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -Fo$@
62 | $(DELETE) ../../main/c/*.h
63 | $(BUILD_DIR)/WindowsHelperFunctions.obj : WindowsHelperFunctions.c
64 | $(MKDIR) $(BUILD_DIR)
65 | $(COPY) ../../main/c/Posix/*.h ../../main/c/
66 | $(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -Fo$@
67 | $(DELETE) ../../main/c/*.h
68 | $(BUILD_DIR)/%.o : %.c
69 | $(MKDIR) $(BUILD_DIR)
70 | $(COMPILE) $(INCLUDES) $(CFLAGS) -c $< -o $@
71 |
--------------------------------------------------------------------------------
/src/test/c/testEnumeratePosix.c:
--------------------------------------------------------------------------------
1 | #include "PosixHelperFunctions.h"
2 |
3 | static serialPortVector comPorts = { NULL, 0, 0 };
4 |
5 | int main(void)
6 | {
7 | // Enumerate all serial ports
8 | searchForComPorts(&comPorts);
9 |
10 | // Output all enumerated ports
11 | printf("Initial enumeration:\n\n");
12 | for (int i = 0; i < comPorts.length; ++i)
13 | {
14 | serialPort *port = comPorts.ports[i];
15 | printf("\t%s: Friendly Name = %s, Description = %s, Location = %s, VID/PID = %04X/%04X, Serial = %s\n", port->portPath, port->friendlyName, port->portDescription, port->portLocation, port->vendorID, port->productID, port->serialNumber);
16 | }
17 |
18 | // Reset the enumerated flag on all non-open serial ports
19 | for (int i = 0; i < comPorts.length; ++i)
20 | comPorts.ports[i]->enumerated = (comPorts.ports[i]->handle > 0);
21 |
22 | // Re-enumerate all serial ports
23 | searchForComPorts(&comPorts);
24 |
25 | // Remove all non-enumerated ports from the serial port listing
26 | for (int i = 0; i < comPorts.length; ++i)
27 | if (!comPorts.ports[i]->enumerated)
28 | {
29 | removePort(&comPorts, comPorts.ports[i]);
30 | i--;
31 | }
32 |
33 | // Output all enumerated ports once again
34 | printf("\nSecond enumeration:\n\n");
35 | for (int i = 0; i < comPorts.length; ++i)
36 | {
37 | serialPort *port = comPorts.ports[i];
38 | printf("\t%s: Friendly Name = %s, Description = %s, Location = %s, VID/PID = %04X/%04X, Serial = %s\n", port->portPath, port->friendlyName, port->portDescription, port->portLocation, port->vendorID, port->productID, port->serialNumber);
39 | }
40 |
41 | // Clean up all memory and return
42 | cleanUpVector(&comPorts);
43 | return 0;
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/c/testEventsWindows.c:
--------------------------------------------------------------------------------
1 | #define WINVER _WIN32_WINNT_VISTA
2 | #define _WIN32_WINNT _WIN32_WINNT_VISTA
3 | #define NTDDI_VERSION NTDDI_VISTA
4 | #define WIN32_LEAN_AND_MEAN
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include "../../main/c/Windows/ftdi/ftd2xx.h"
17 | #include "WindowsHelperFunctions.h"
18 |
19 | static const int eventsToMonitor = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED | com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED;
20 | static const int timeoutMode = com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING;
21 | static const DWORD readTimeout = 0, writeTimeout = 0;
22 |
23 | BOOL configPort(void *portHandle)
24 | {
25 | // Retrieve existing port configuration
26 | DCB dcbSerialParams;
27 | memset(&dcbSerialParams, 0, sizeof(DCB));
28 | dcbSerialParams.DCBlength = sizeof(DCB);
29 | DWORD receiveDeviceQueueSize = 4096, sendDeviceQueueSize = 4096;
30 | if (!SetupComm(portHandle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(portHandle, &dcbSerialParams))
31 | {
32 | printf("Error Line = %d, Code = %d\n", __LINE__ - 2, GetLastError());
33 | return FALSE;
34 | }
35 |
36 | // Set updated port parameters
37 | dcbSerialParams.BaudRate = 9600;
38 | dcbSerialParams.ByteSize = 8;
39 | dcbSerialParams.StopBits = ONESTOPBIT;
40 | dcbSerialParams.Parity = NOPARITY;
41 | dcbSerialParams.fParity = FALSE;
42 | dcbSerialParams.fBinary = TRUE;
43 | dcbSerialParams.fAbortOnError = FALSE;
44 | dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
45 | dcbSerialParams.fOutxCtsFlow = FALSE;
46 | dcbSerialParams.fOutxDsrFlow = FALSE;
47 | dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
48 | dcbSerialParams.fDsrSensitivity = FALSE;
49 | dcbSerialParams.fOutX = FALSE;
50 | dcbSerialParams.fInX = FALSE;
51 | dcbSerialParams.fTXContinueOnXoff = TRUE;
52 | dcbSerialParams.fErrorChar = FALSE;
53 | dcbSerialParams.fNull = FALSE;
54 | dcbSerialParams.XonLim = 2048;
55 | dcbSerialParams.XoffLim = 512;
56 | dcbSerialParams.XonChar = 17;
57 | dcbSerialParams.XoffChar = 19;
58 |
59 | // Apply changes
60 | if (!SetCommState(portHandle, &dcbSerialParams))
61 | {
62 | printf("Error Line = %d, Code = %d\n", __LINE__ - 2, GetLastError());
63 | return FALSE;
64 | }
65 |
66 | // Get event flags from the Java class
67 | int eventFlags = EV_ERR;
68 | if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) || (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED))
69 | eventFlags |= EV_RXCHAR;
70 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN)
71 | eventFlags |= EV_TXEMPTY;
72 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT)
73 | eventFlags |= EV_BREAK;
74 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS)
75 | eventFlags |= EV_CTS;
76 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR)
77 | eventFlags |= EV_DSR;
78 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR)
79 | eventFlags |= EV_RING;
80 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT)
81 | eventFlags |= EV_RLSD;
82 |
83 | // Set updated port timeouts
84 | COMMTIMEOUTS timeouts;
85 | memset(&timeouts, 0, sizeof(COMMTIMEOUTS));
86 | timeouts.WriteTotalTimeoutMultiplier = 0;
87 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED)
88 | {
89 | // Force specific read timeouts if we are monitoring data received
90 | timeouts.ReadIntervalTimeout = MAXDWORD;
91 | timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
92 | timeouts.ReadTotalTimeoutConstant = 1000;
93 | timeouts.WriteTotalTimeoutConstant = 0;
94 | }
95 | else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER)
96 | {
97 | timeouts.ReadIntervalTimeout = MAXDWORD;
98 | timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
99 | timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF;
100 | timeouts.WriteTotalTimeoutConstant = writeTimeout;
101 | }
102 | else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING)
103 | {
104 | timeouts.ReadIntervalTimeout = MAXDWORD;
105 | timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
106 | timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF;
107 | timeouts.WriteTotalTimeoutConstant = writeTimeout;
108 | }
109 | else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING)
110 | {
111 | timeouts.ReadIntervalTimeout = 0;
112 | timeouts.ReadTotalTimeoutMultiplier = 0;
113 | timeouts.ReadTotalTimeoutConstant = readTimeout;
114 | timeouts.WriteTotalTimeoutConstant = writeTimeout;
115 | }
116 | else // Non-blocking
117 | {
118 | timeouts.ReadIntervalTimeout = MAXDWORD;
119 | timeouts.ReadTotalTimeoutMultiplier = 0;
120 | timeouts.ReadTotalTimeoutConstant = 0;
121 | timeouts.WriteTotalTimeoutConstant = writeTimeout;
122 | }
123 |
124 | // Apply changes
125 | if (!SetCommTimeouts(portHandle, &timeouts) || !SetCommMask(portHandle, eventFlags))
126 | {
127 | printf("Error Line = %d, Code = %d\n", __LINE__ - 2, GetLastError());
128 | return FALSE;
129 | }
130 | return TRUE;
131 | }
132 |
133 | void* openPortNative(const char *portName)
134 | {
135 | // Try to open the serial port with read/write access
136 | void *portHandle = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL);
137 | if (portHandle != INVALID_HANDLE_VALUE)
138 | {
139 | // Configure the port parameters and timeouts
140 | if (!configPort(portHandle))
141 | {
142 | // Close the port if there was a problem setting the parameters
143 | PurgeComm(portHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
144 | if (CancelIoEx)
145 | CancelIoEx(portHandle, NULL);
146 | SetCommMask(portHandle, 0);
147 | CloseHandle(portHandle);
148 | portHandle = INVALID_HANDLE_VALUE;
149 | }
150 | }
151 | return portHandle;
152 | }
153 |
154 | void closePortNative(void *portHandle)
155 | {
156 | // Force the port to enter non-blocking mode to ensure that any current reads return
157 | COMMTIMEOUTS timeouts;
158 | memset(&timeouts, 0, sizeof(COMMTIMEOUTS));
159 | timeouts.WriteTotalTimeoutMultiplier = 0;
160 | timeouts.ReadIntervalTimeout = MAXDWORD;
161 | timeouts.ReadTotalTimeoutMultiplier = 0;
162 | timeouts.ReadTotalTimeoutConstant = 0;
163 | timeouts.WriteTotalTimeoutConstant = 0;
164 | SetCommTimeouts(portHandle, &timeouts);
165 |
166 | // Purge any outstanding port operations
167 | PurgeComm(portHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
168 | if (CancelIoEx)
169 | CancelIoEx(portHandle, NULL);
170 | SetCommMask(portHandle, 0);
171 |
172 | // Close the port
173 | if (!CloseHandle(portHandle))
174 | printf("Error Line = %d, Code = %d\n", __LINE__ - 1, GetLastError());
175 | }
176 |
177 | int waitForEvent(void *portHandle)
178 | {
179 | // Create an asynchronous event structure
180 | OVERLAPPED overlappedStruct;
181 | memset(&overlappedStruct, 0, sizeof(OVERLAPPED));
182 | overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
183 | int event = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT;
184 | if (!overlappedStruct.hEvent)
185 | {
186 | printf("Error Line = %d, Code = %d\n", __LINE__ - 3, GetLastError());
187 | return event;
188 | }
189 |
190 | // Wait for a serial port event
191 | DWORD eventMask = 0, errorMask = 0, waitValue, numBytesTransferred;
192 | if (!WaitCommEvent(portHandle, &eventMask, &overlappedStruct))
193 | {
194 | if ((GetLastError() == ERROR_IO_PENDING) || (GetLastError() == ERROR_INVALID_PARAMETER))
195 | {
196 | do { waitValue = WaitForSingleObject(overlappedStruct.hEvent, 500); }
197 | while (waitValue == WAIT_TIMEOUT);
198 | if ((waitValue != WAIT_OBJECT_0) || !GetOverlappedResult(portHandle, &overlappedStruct, &numBytesTransferred, FALSE))
199 | {
200 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED;
201 | printf("Error Line = %d, Code = %d, Wait Value = %d\n", __LINE__ - 3, GetLastError(), waitValue);
202 | CloseHandle(overlappedStruct.hEvent);
203 | return event;
204 | }
205 | }
206 | else // Problem occurred
207 | {
208 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED;
209 | printf("Error Line = %d, Code = %d\n", __LINE__ - 17, GetLastError());
210 | CloseHandle(overlappedStruct.hEvent);
211 | return event;
212 | }
213 | }
214 |
215 | // Retrieve and clear any serial port errors
216 | COMSTAT commInfo;
217 | if (ClearCommError(portHandle, &errorMask, &commInfo))
218 | {
219 | if (errorMask & CE_BREAK)
220 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT;
221 | if (errorMask & CE_FRAME)
222 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FRAMING_ERROR;
223 | if (errorMask & CE_OVERRUN)
224 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR;
225 | if (errorMask & CE_RXOVER)
226 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR;
227 | if (errorMask & CE_RXPARITY)
228 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PARITY_ERROR;
229 | }
230 |
231 | // Parse any received serial port events
232 | if (eventMask & EV_BREAK)
233 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT;
234 | if (eventMask & EV_TXEMPTY)
235 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN;
236 | if ((eventMask & EV_RXCHAR) && (commInfo.cbInQue > 0))
237 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE;
238 | if (eventMask & EV_CTS)
239 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS;
240 | if (eventMask & EV_DSR)
241 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR;
242 | if (eventMask & EV_RING)
243 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR;
244 | if (eventMask & EV_RLSD)
245 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT;
246 |
247 | // Return the serial event type
248 | CloseHandle(overlappedStruct.hEvent);
249 | return event;
250 | }
251 |
252 | int main(int argc, char *argv[])
253 | {
254 | // Check for correct input parameters
255 | if (argc != 2)
256 | {
257 | printf("USAGE: ./testEventsWindows [PORT_FILE_NAME]\n");
258 | return -1;
259 | }
260 |
261 | // Open the serial port
262 | void *portHandle = INVALID_HANDLE_VALUE;
263 | if ((portHandle = openPortNative(argv[1])) == INVALID_HANDLE_VALUE)
264 | {
265 | printf("ERROR: Could not open port: %s\n", argv[1]);
266 | return -2;
267 | }
268 | printf("Port opened\n");
269 |
270 | // Wait forever for incoming events
271 | int events = 0;
272 | while ((events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED) == 0)
273 | {
274 | events = waitForEvent(portHandle);
275 | printf("Received Events: %d\n", events);
276 | if (events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED)
277 | printf(" Including LISTENING_EVENT_PORT_DISCONNECTED\n");
278 | if (events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE)
279 | printf(" Including LISTENING_EVENT_DATA_AVAILABLE\n");
280 | if (events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN)
281 | printf(" Including LISTENING_EVENT_DATA_WRITTEN\n");
282 | }
283 |
284 | // Close the serial port
285 | closePortNative(portHandle);
286 | return 0;
287 | }
288 |
--------------------------------------------------------------------------------
/src/test/c/testOpenClose.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #if defined(__linux__)
13 | #include
14 | #define termios asmtermios
15 | #define termio asmtermio
16 | #define winsize asmwinsize
17 | #include
18 | #include
19 | #undef termio
20 | #undef termios
21 | #undef winsize
22 | #ifndef SER_RS485_TERMINATE_BUS
23 | #define SER_RS485_TERMINATE_BUS (1 << 5)
24 | #endif
25 | #elif defined(__APPLE__)
26 | #include
27 | #include
28 | #include
29 | #include
30 | #endif
31 | #include
32 | #include
33 | #include "PosixHelperFunctions.h"
34 |
35 |
36 | // Global static variables
37 | static volatile long portHandle = -1, readBufferLength = 0;
38 | static char *comPort = NULL, *readBuffer = NULL;
39 |
40 |
41 | // JNI functionality
42 | bool configTimeouts(long serialPortFD, int timeoutMode, int readTimeout, int writeTimeout, int eventsToMonitor)
43 | {
44 | // Get port timeouts from Java class
45 | int flags = 0;
46 | struct termios options = { 0 };
47 | baud_rate baudRate = 9600;
48 | tcgetattr(serialPortFD, &options);
49 |
50 | // Set updated port timeouts
51 | if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout
52 | {
53 | options.c_cc[VMIN] = 0;
54 | options.c_cc[VTIME] = readTimeout / 100;
55 | }
56 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) // Read Semi-blocking without timeout
57 | {
58 | options.c_cc[VMIN] = 1;
59 | options.c_cc[VTIME] = 0;
60 | }
61 | else if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout > 0)) // Read Blocking with timeout
62 | {
63 | options.c_cc[VMIN] = 0;
64 | options.c_cc[VTIME] = readTimeout / 100;
65 | }
66 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Read Blocking without timeout
67 | {
68 | options.c_cc[VMIN] = 1;
69 | options.c_cc[VTIME] = 0;
70 | }
71 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER) > 0) // Scanner Mode
72 | {
73 | options.c_cc[VMIN] = 1;
74 | options.c_cc[VTIME] = 1;
75 | }
76 | else // Non-blocking
77 | {
78 | flags = O_NONBLOCK;
79 | options.c_cc[VMIN] = 0;
80 | options.c_cc[VTIME] = 0;
81 | }
82 |
83 | // Apply changes
84 | if (fcntl(serialPortFD, F_SETFL, flags))
85 | return false;
86 | if (tcsetattr(serialPortFD, TCSANOW, &options) || tcsetattr(serialPortFD, TCSANOW, &options))
87 | return false;
88 | if (!getBaudRateCode(baudRate) && setBaudRateCustom(serialPortFD, baudRate))
89 | return false;
90 | return true;
91 | }
92 |
93 | bool configPort(long serialPortFD)
94 | {
95 | // Get port parameters from Java class
96 | baud_rate baudRate = 9600;
97 | int byteSizeInt = 8;
98 | int stopBitsInt = 1;
99 | int parityInt = 0;
100 | int flowControl = 0;
101 | int sendDeviceQueueSize = 4096;
102 | int receiveDeviceQueueSize = 4096;
103 | int rs485DelayBefore = 0;
104 | int rs485DelayAfter = 0;
105 | int timeoutMode = 0;
106 | int readTimeout = 0;
107 | int writeTimeout = 0;
108 | int eventsToMonitor = 0;
109 | unsigned char rs485ModeEnabled = false;
110 | unsigned char rs485ActiveHigh = true;
111 | unsigned char rs485EnableTermination = false;
112 | unsigned char rs485RxDuringTx = false;
113 | unsigned char isDtrEnabled = true;
114 | unsigned char isRtsEnabled = true;
115 | char xonStartChar = 17;
116 | char xoffStopChar = 19;
117 |
118 | // Clear any serial port flags and set up raw non-canonical port parameters
119 | struct termios options = { 0 };
120 | tcgetattr(serialPortFD, &options);
121 | options.c_cc[VSTART] = (unsigned char)xonStartChar;
122 | options.c_cc[VSTOP] = (unsigned char)xoffStopChar;
123 | options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | INPCK | IGNPAR | IGNCR | ICRNL | IXON | IXOFF);
124 | options.c_oflag &= ~OPOST;
125 | options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
126 | options.c_cflag &= ~(CSIZE | PARENB | CMSPAR | PARODD | CSTOPB | CRTSCTS);
127 |
128 | // Update the user-specified port parameters
129 | tcflag_t byteSize = (byteSizeInt == 5) ? CS5 : (byteSizeInt == 6) ? CS6 : (byteSizeInt == 7) ? CS7 : CS8;
130 | tcflag_t parity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? 0 : (parityInt == com_fazecast_jSerialComm_SerialPort_ODD_PARITY) ? (PARENB | PARODD) : (parityInt == com_fazecast_jSerialComm_SerialPort_EVEN_PARITY) ? PARENB : (parityInt == com_fazecast_jSerialComm_SerialPort_MARK_PARITY) ? (PARENB | CMSPAR | PARODD) : (PARENB | CMSPAR);
131 | options.c_cflag |= (byteSize | parity | CLOCAL | CREAD);
132 | if (!isDtrEnabled || !isRtsEnabled)
133 | options.c_cflag &= ~HUPCL;
134 | if (!rs485ModeEnabled)
135 | options.c_iflag |= BRKINT;
136 | if (stopBitsInt == com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS)
137 | options.c_cflag |= CSTOPB;
138 | if (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED) > 0) || ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0))
139 | options.c_cflag |= CRTSCTS;
140 | if (byteSizeInt < 8)
141 | options.c_iflag |= ISTRIP;
142 | if (parityInt != 0)
143 | options.c_iflag |= (INPCK | IGNPAR);
144 | if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED) > 0)
145 | options.c_iflag |= IXOFF;
146 | if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0)
147 | options.c_iflag |= IXON;
148 |
149 | // Set baud rate and apply changes
150 | baud_rate baudRateCode = getBaudRateCode(baudRate);
151 | if (!baudRateCode)
152 | baudRateCode = B38400;
153 | cfsetispeed(&options, baudRateCode);
154 | cfsetospeed(&options, baudRateCode);
155 | if (tcsetattr(serialPortFD, TCSANOW, &options) || tcsetattr(serialPortFD, TCSANOW, &options))
156 | return false;
157 |
158 | // Attempt to set the transmit buffer size and any necessary custom baud rates
159 | #if defined(__linux__)
160 |
161 | struct serial_struct serInfo = { 0 };
162 | if (!ioctl(serialPortFD, TIOCGSERIAL, &serInfo))
163 | {
164 | serInfo.xmit_fifo_size = sendDeviceQueueSize;
165 | serInfo.flags |= ASYNC_LOW_LATENCY;
166 | ioctl(serialPortFD, TIOCSSERIAL, &serInfo);
167 | }
168 |
169 | // Attempt to set the requested RS-485 mode
170 | struct serial_rs485 rs485Conf = { 0 };
171 | if (!ioctl(serialPortFD, TIOCGRS485, &rs485Conf))
172 | {
173 | if (rs485ModeEnabled)
174 | rs485Conf.flags |= SER_RS485_ENABLED;
175 | else
176 | rs485Conf.flags &= ~SER_RS485_ENABLED;
177 | if (rs485ActiveHigh)
178 | {
179 | rs485Conf.flags |= SER_RS485_RTS_ON_SEND;
180 | rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
181 | }
182 | else
183 | {
184 | rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND);
185 | rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND;
186 | }
187 | if (rs485RxDuringTx)
188 | rs485Conf.flags |= SER_RS485_RX_DURING_TX;
189 | else
190 | rs485Conf.flags &= ~(SER_RS485_RX_DURING_TX);
191 | if (rs485EnableTermination)
192 | rs485Conf.flags |= SER_RS485_TERMINATE_BUS;
193 | else
194 | rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS);
195 | rs485Conf.delay_rts_before_send = rs485DelayBefore / 1000;
196 | rs485Conf.delay_rts_after_send = rs485DelayAfter / 1000;
197 | if (ioctl(serialPortFD, TIOCSRS485, &rs485Conf))
198 | return false;
199 | }
200 | #endif
201 |
202 | // Configure the serial port read and write timeouts
203 | return configTimeouts(serialPortFD, timeoutMode, readTimeout, writeTimeout, eventsToMonitor);
204 | }
205 |
206 | long openPortNative(void)
207 | {
208 | const char *portName = comPort;
209 | unsigned char disableExclusiveLock = false;
210 | unsigned char disableAutoConfig = false;
211 |
212 | // Try to open existing serial port with read/write access
213 | int serialPortFD = -1;
214 | if ((serialPortFD = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC)) > 0)
215 | {
216 | // Ensure that multiple root users cannot access the device simultaneously
217 | if (!disableExclusiveLock && flock(serialPortFD, LOCK_EX | LOCK_NB))
218 | {
219 | while (close(serialPortFD) && (errno == EINTR))
220 | errno = 0;
221 | serialPortFD = -1;
222 | }
223 | else if (!disableAutoConfig && !configPort(serialPortFD))
224 | {
225 | // Close the port if there was a problem setting the parameters
226 | fcntl(serialPortFD, F_SETFL, O_NONBLOCK);
227 | while ((close(serialPortFD) == -1) && (errno == EINTR))
228 | errno = 0;
229 | serialPortFD = -1;
230 | }
231 | }
232 |
233 | return serialPortFD;
234 | }
235 |
236 | long closePortNative(long serialPortFD)
237 | {
238 | // Force the port to enter non-blocking mode to ensure that any current reads return
239 | struct termios options = { 0 };
240 | tcgetattr(serialPortFD, &options);
241 | options.c_cc[VMIN] = 0;
242 | options.c_cc[VTIME] = 0;
243 | fcntl(serialPortFD, F_SETFL, O_NONBLOCK);
244 | tcsetattr(serialPortFD, TCSANOW, &options);
245 | tcsetattr(serialPortFD, TCSANOW, &options);
246 |
247 | // Unblock, unlock, and close the port
248 | fsync(serialPortFD);
249 | tcdrain(serialPortFD);
250 | tcflush(serialPortFD, TCIOFLUSH);
251 | flock(serialPortFD, LOCK_UN | LOCK_NB);
252 | while (close(serialPortFD) && (errno == EINTR))
253 | errno = 0;
254 | serialPortFD = -1;
255 | return -1;
256 | }
257 |
258 | int readBytes(long serialPortFD, char* buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout)
259 | {
260 | // Ensure that the allocated read buffer is large enough
261 | int numBytesRead, numBytesReadTotal = 0, bytesRemaining = bytesToRead, ioctlResult = 0;
262 | if (bytesToRead > readBufferLength)
263 | {
264 | char *newMemory = (char*)realloc(readBuffer, bytesToRead);
265 | if (!newMemory)
266 | return -1;
267 | readBuffer = newMemory;
268 | readBufferLength = bytesToRead;
269 | }
270 |
271 | // Infinite blocking mode specified, don't return until we have completely finished the read
272 | if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout == 0))
273 | {
274 | // While there are more bytes we are supposed to read
275 | while (bytesRemaining > 0)
276 | {
277 | // Attempt to read some number of bytes from the serial port
278 | do { errno = 0; numBytesRead = read(serialPortFD, readBuffer + numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR));
279 | if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1)))
280 | break;
281 |
282 | // Fix index variables
283 | numBytesReadTotal += numBytesRead;
284 | bytesRemaining -= numBytesRead;
285 | }
286 | }
287 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Blocking mode, but not indefinitely
288 | {
289 | // Get current system time
290 | struct timeval expireTime = { 0 }, currTime = { 0 };
291 | gettimeofday(&expireTime, NULL);
292 | expireTime.tv_usec += (readTimeout * 1000);
293 | if (expireTime.tv_usec > 1000000)
294 | {
295 | expireTime.tv_sec += (expireTime.tv_usec * 0.000001);
296 | expireTime.tv_usec = (expireTime.tv_usec % 1000000);
297 | }
298 |
299 | // While there are more bytes we are supposed to read and the timeout has not elapsed
300 | do
301 | {
302 | do { errno = 0; numBytesRead = read(serialPortFD, readBuffer + numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR));
303 | if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1)))
304 | break;
305 |
306 | // Fix index variables
307 | numBytesReadTotal += numBytesRead;
308 | bytesRemaining -= numBytesRead;
309 |
310 | // Get current system time
311 | gettimeofday(&currTime, NULL);
312 | } while ((bytesRemaining > 0) && ((expireTime.tv_sec > currTime.tv_sec) || ((expireTime.tv_sec == currTime.tv_sec) && (expireTime.tv_usec > currTime.tv_usec))));
313 | }
314 | else // Semi- or non-blocking specified
315 | {
316 | // Read from the port
317 | do { errno = 0; numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR));
318 | if (numBytesRead > 0)
319 | numBytesReadTotal = numBytesRead;
320 | }
321 |
322 | // Return number of bytes read if successful
323 | memcpy(buffer, readBuffer, numBytesReadTotal);
324 | return (numBytesRead == -1) ? -1 : numBytesReadTotal;
325 | }
326 |
327 | void* readingThread(void *arg)
328 | {
329 | // Read forever in a loop while the port is open
330 | char readBuffer[2048];
331 | while (portHandle > 0)
332 | {
333 | printf("\nBeginning blocking read...\n");
334 | int numBytesRead = readBytes(portHandle, readBuffer, sizeof(readBuffer), 0, com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING, 0);
335 | printf("Read %d bytes\n", numBytesRead);
336 | }
337 | return NULL;
338 | }
339 | int testCloseSeparateThread(void)
340 | {
341 | // Open the serial port
342 | if ((portHandle = openPortNative()) <= 0)
343 | {
344 | printf("ERROR: Could not open port: %s\n", comPort);
345 | return -1;
346 | }
347 | printf("Port opened: %s\n", comPort);
348 |
349 | // Configure the serial port for indefinitely blocking reads
350 | if (!configTimeouts(portHandle, com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING, 0, 0, 0))
351 | {
352 | printf("ERROR: Could not configure port timeouts\n");
353 | return -2;
354 | }
355 | printf("Blocking read timeouts successfully configured\n");
356 |
357 | // Start a new thread to continuously read from the serial port for 5 seconds
358 | pthread_t pid;
359 | if (pthread_create(&pid, NULL, &readingThread, NULL))
360 | {
361 | printf("ERROR: Could not create a reading thread\n");
362 | return -3;
363 | }
364 | sleep(5);
365 |
366 | // Close the serial port
367 | printf("\nAttempting to close serial port from a separate thread...\n");
368 | if ((portHandle = closePortNative(portHandle)) > 0)
369 | {
370 | printf("ERROR: Could not close port: %s\n", comPort);
371 | return -4;
372 | }
373 | printf("Port closed\n");
374 |
375 | // Wait for the reading thread to return
376 | pthread_join(pid, NULL);
377 | printf("Reading thread successfully returned\n");
378 | return 0;
379 | }
380 |
381 | int testSimpleOpenClose(void)
382 | {
383 | // Open the serial port
384 | if ((portHandle = openPortNative()) <= 0)
385 | {
386 | printf("ERROR: Could not open port: %s\n", comPort);
387 | return -2;
388 | }
389 | printf("Port opened\n");
390 |
391 | // Close the serial port
392 | if ((portHandle = closePortNative(portHandle)) > 0)
393 | {
394 | printf("ERROR: Could not close port: %s\n", comPort);
395 | return -3;
396 | }
397 | printf("Port closed\n");
398 | return 0;
399 | }
400 |
401 | int main(int argc, char *argv[])
402 | {
403 | // Check for correct input parameters
404 | if (argc != 2)
405 | {
406 | printf("USAGE: ./testOpenClose [PORT_FILE_NAME]\n");
407 | return -1;
408 | }
409 | comPort = argv[1];
410 |
411 | // Perform one of the above open/close tests
412 | return testCloseSeparateThread();
413 | //return testSimpleOpenClose();
414 | }
415 |
--------------------------------------------------------------------------------
/src/test/c/testPollPosix.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "PosixHelperFunctions.h"
15 |
16 | static serialPortVector serialPorts = { NULL, 0, 0 };
17 | static serialPort *currentPort = NULL;
18 |
19 | #define PERR 0b001000000000
20 | #define PHUP 0b000100000000
21 | #define PIN 0b000010000000
22 | #define PNVAL 0b000001000000
23 | #define POUT 0b000000100000
24 | #define PPRI 0b000000010000
25 | #define PRDBAND 0b000000001000
26 | #define PRDNORM 0b000000000100
27 | #define PWRBAND 0b000000000010
28 | #define PWRNORM 0b000000000001
29 |
30 | unsigned short convertEventCodes(short revents)
31 | {
32 | unsigned short eventBits = 0;
33 | if (revents & POLLERR)
34 | eventBits |= PERR;
35 | if (revents & POLLHUP)
36 | eventBits |= PHUP;
37 | if (revents & POLLIN)
38 | eventBits |= PIN;
39 | if (revents & POLLNVAL)
40 | eventBits |= PNVAL;
41 | if (revents & POLLOUT)
42 | eventBits |= POUT;
43 | if (revents & POLLPRI)
44 | eventBits |= PPRI;
45 | if (revents & POLLRDBAND)
46 | eventBits |= PRDBAND;
47 | if (revents & POLLRDNORM)
48 | eventBits |= PRDNORM;
49 | if (revents & POLLWRBAND)
50 | eventBits |= PWRBAND;
51 | if (revents & POLLWRNORM)
52 | eventBits |= PWRNORM;
53 | return eventBits;
54 | }
55 |
56 | void ctrlCHandler(int dummy)
57 | {
58 | if (currentPort)
59 | currentPort->eventListenerRunning = 0;
60 | else
61 | {
62 | printf("\n");
63 | exit(0);
64 | }
65 | }
66 |
67 | int configPort(serialPort *port)
68 | {
69 | // Clear any serial port flags and set up raw non-canonical port parameters
70 | struct termios options = { 0 };
71 | tcgetattr(port->handle, &options);
72 | options.c_cc[VSTART] = (unsigned char)17;
73 | options.c_cc[VSTOP] = (unsigned char)19;
74 | options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | INPCK | IGNPAR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
75 | options.c_oflag &= ~OPOST;
76 | options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
77 | options.c_cflag &= ~(CSIZE | PARENB | CMSPAR | PARODD | CSTOPB | CRTSCTS);
78 |
79 | // Update the user-specified port parameters
80 | int baudRate = 115200;
81 | tcflag_t byteSize = CS8;
82 | tcflag_t parity = 0;
83 | options.c_cflag |= (byteSize | parity | CLOCAL | CREAD);
84 | options.c_cflag &= ~HUPCL;
85 |
86 | // Configure the serial port read and write timeouts
87 | int flags = 0;
88 | port->eventsMask = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED;// | com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE;
89 | options.c_cc[VMIN] = 0;
90 | options.c_cc[VTIME] = 10;
91 |
92 | // Apply changes
93 | if (fcntl(port->handle, F_SETFL, flags))
94 | return 0;
95 | if (setConfigOptions(port->handle, baudRate, &options))
96 | return 0;
97 | return 1;
98 | }
99 |
100 | int waitForEvent(serialPort *port)
101 | {
102 | // Initialize local variables
103 | int pollResult;
104 | short pollEventsMask = ((port->eventsMask & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) || (port->eventsMask & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED)) ? (POLLIN | POLLERR) : (POLLHUP | POLLERR);
105 | jint event = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT;
106 | struct pollfd waitingSet = { port->handle, pollEventsMask, 0 };
107 |
108 | // Wait for a serial port event
109 | do
110 | {
111 | waitingSet.revents = 0;
112 | pollResult = poll(&waitingSet, 1, 1000);
113 | printf("Poll Result: %d, Revents: %hu, Codes: %hu\n", pollResult, waitingSet.revents, convertEventCodes(waitingSet.revents));
114 | }
115 | while ((pollResult == 0) && port->eventListenerRunning);
116 |
117 | // Return the detected port events
118 | if (waitingSet.revents & (POLLHUP | POLLNVAL))
119 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED;
120 | else if (waitingSet.revents & POLLIN)
121 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE;
122 | return event;
123 | }
124 |
125 | int main(void)
126 | {
127 | // Enumerate all serial ports
128 | signal(SIGINT, ctrlCHandler);
129 | searchForComPorts(&serialPorts);
130 |
131 | // Prompt user which port to open
132 | int userSelection = -1;
133 | while ((userSelection < 0) || (userSelection >= serialPorts.length))
134 | {
135 | printf("Select the index of the serial device to connect to:\n\n");
136 | for (int i = 0; i < serialPorts.length; ++i)
137 | {
138 | serialPort *port = serialPorts.ports[i];
139 | printf("\t[%d]: %s (Description = %s)\n", i, port->portPath, port->portDescription);
140 | }
141 | printf("\nTarget device index: ");
142 | scanf("%d", &userSelection);
143 | }
144 | serialPort *port = serialPorts.ports[userSelection];
145 |
146 | // Try to open the serial port with read/write access
147 | int portHandle = open(port->portPath, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
148 | if (portHandle > 0)
149 | {
150 | // Set the newly opened port handle in the serial port structure
151 | port->handle = portHandle;
152 |
153 | // Quickly set the desired RTS/DTR line status immediately upon opening
154 | int modemBits = TIOCM_DTR;
155 | ioctl(port->handle, TIOCMBIS, &modemBits);
156 | modemBits = TIOCM_RTS;
157 | ioctl(port->handle, TIOCMBIS, &modemBits);
158 |
159 | // Ensure that multiple root users cannot access the device simultaneously
160 | if (flock(port->handle, LOCK_EX | LOCK_NB))
161 | {
162 | while (close(port->handle) && (errno == EINTR))
163 | errno = 0;
164 | port->handle = -1;
165 | }
166 | else if (!configPort(port))
167 | {
168 | // Close the port if there was a problem setting the parameters
169 | fcntl(port->handle, F_SETFL, O_NONBLOCK);
170 | while (close(port->handle) && (errno == EINTR))
171 | errno = 0;
172 | port->handle = -1;
173 | }
174 |
175 | // Start listening for events
176 | currentPort = port;
177 | port->eventListenerRunning = 1;
178 | while (port->eventListenerRunning)
179 | {
180 | int event = waitForEvent(port);
181 | if (event != com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT)
182 | printf("Received event: %s\n", event == com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED ? "Disconnected" : "Available");
183 | if (event == com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED)
184 | port->eventListenerRunning = 0;
185 | else if (event == com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE)
186 | tcflush(port->handle, TCIOFLUSH);
187 | }
188 |
189 | // Close the port
190 | struct termios options = { 0 };
191 | tcgetattr(port->handle, &options);
192 | options.c_cc[VMIN] = 0;
193 | options.c_cc[VTIME] = 0;
194 | fcntl(port->handle, F_SETFL, O_NONBLOCK);
195 | tcsetattr(port->handle, TCSANOW, &options);
196 | fdatasync(port->handle);
197 | tcflush(port->handle, TCIOFLUSH);
198 | flock(port->handle, LOCK_UN | LOCK_NB);
199 | while (close(port->handle) && (errno == EINTR))
200 | errno = 0;
201 | port->handle = -1;
202 | }
203 |
204 | // Clean up all memory and return
205 | cleanUpVector(&serialPorts);
206 | return 0;
207 | }
208 |
--------------------------------------------------------------------------------
/src/test/c/testRS485.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #define termios asmtermios
11 | #define termio asmtermio
12 | #define winsize asmwinsize
13 | #include
14 | #include
15 | #undef termio
16 | #undef termios
17 | #undef winsize
18 |
19 | int main(int argc, char *argv[])
20 | {
21 | // Ensure that port handle was passed in
22 | if (argc != 2)
23 | {
24 | printf("Usage: ./testRS485 /dev/port/path\n");
25 | return 0;
26 | }
27 | const char *portName = argv[1];
28 |
29 | // Open serial port
30 | int portHandle = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
31 | if (portHandle > 0)
32 | {
33 | // Ensure that multiple root users cannot access the device simultaneously
34 | if (flock(portHandle, LOCK_EX | LOCK_NB))
35 | {
36 | while (close(portHandle) && (errno == EINTR))
37 | errno = 0;
38 | portHandle = -1;
39 | }
40 | }
41 | if (portHandle <= 0)
42 | {
43 | printf("Error opening port at %s\n", portName);
44 | return -1;
45 | }
46 |
47 | // Attempt to retrieve RS485 configuration from connected device
48 | struct serial_rs485 rs485Conf = { 0 };
49 | int retVal = ioctl(portHandle, TIOCGRS485, &rs485Conf);
50 | if (retVal)
51 | {
52 | printf("Error retrieving RS485 configuration, Code = %d, Errno = %d\n", retVal, errno);
53 | return -2;
54 | }
55 |
56 | // Attempt to enable RS485 configuration
57 | rs485Conf.flags |= SER_RS485_ENABLED;
58 | rs485Conf.flags |= SER_RS485_RTS_ON_SEND;
59 | rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
60 | rs485Conf.flags &= ~(SER_RS485_RX_DURING_TX);
61 | rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS);
62 | rs485Conf.delay_rts_before_send = 1;
63 | rs485Conf.delay_rts_after_send = 1;
64 | retVal = ioctl(portHandle, TIOCSRS485, &rs485Conf);
65 | if (retVal)
66 | {
67 | printf("Error enabling RS485 configuration, Code = %d, Errno = %d\n", retVal, errno);
68 | return -3;
69 | }
70 |
71 | // Attempt to disable RS485 configuration
72 | rs485Conf.flags &= ~SER_RS485_ENABLED;
73 | rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND);
74 | rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND;
75 | rs485Conf.flags |= SER_RS485_RX_DURING_TX;
76 | rs485Conf.flags |= SER_RS485_TERMINATE_BUS;
77 | retVal = ioctl(portHandle, TIOCSRS485, &rs485Conf);
78 | if (retVal)
79 | {
80 | printf("Error disabling RS485 configuration, Code = %d, Errno = %d\n", retVal, errno);
81 | return -4;
82 | }
83 |
84 | // Unblock, unlock, and close the port
85 | fsync(portHandle);
86 | tcdrain(portHandle);
87 | tcflush(portHandle, TCIOFLUSH);
88 | flock(portHandle, LOCK_UN | LOCK_NB);
89 | while (close(portHandle) && (errno == EINTR))
90 | errno = 0;
91 | portHandle = -1;
92 | return 0;
93 | }
94 |
--------------------------------------------------------------------------------
/src/test/java/com/fazecast/jSerialComm/SerialPortTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SerialPortTest.java
3 | *
4 | * Created on: Feb 27, 2015
5 | * Last Updated on: Apr 11, 2024
6 | * Author: Will Hedgecock
7 | *
8 | * Copyright (C) 2012-2024 Fazecast, Inc.
9 | *
10 | * This file is part of jSerialComm.
11 | *
12 | * jSerialComm is free software: you can redistribute it and/or modify
13 | * it under the terms of either the Apache Software License, version 2, or
14 | * the GNU Lesser General Public License as published by the Free Software
15 | * Foundation, version 3 or above.
16 | *
17 | * jSerialComm is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 | *
21 | * You should have received a copy of both the GNU Lesser General Public
22 | * License and the Apache Software License along with jSerialComm. If not,
23 | * see and .
24 | */
25 |
26 | package com.fazecast.jSerialComm;
27 |
28 | import java.io.InputStream;
29 | import java.util.Scanner;
30 |
31 | /**
32 | * This class provides a test case for the jSerialComm library.
33 | *
34 | * @see java.io.InputStream
35 | * @see java.io.OutputStream
36 | */
37 | public class SerialPortTest
38 | {
39 | private static final class PacketListener implements SerialPortPacketListener
40 | {
41 | @Override
42 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }
43 | @Override
44 | public void serialEvent(SerialPortEvent event)
45 | {
46 | byte[] newData = event.getReceivedData();
47 | System.out.println("Received data of size: " + newData.length);
48 | for (int i = 0; i < newData.length; ++i)
49 | System.out.print((char)newData[i]);
50 | System.out.println("\n");
51 | }
52 | @Override
53 | public int getPacketSize() { return 100; }
54 | }
55 |
56 | private static final class MessageListener implements SerialPortMessageListener
57 | {
58 | public String byteToHex(byte num)
59 | {
60 | char[] hexDigits = new char[2];
61 | hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
62 | hexDigits[1] = Character.forDigit((num & 0xF), 16);
63 | return new String(hexDigits);
64 | }
65 | @Override
66 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }
67 | @Override
68 | public void serialEvent(SerialPortEvent event)
69 | {
70 | byte[] byteArray = event.getReceivedData();
71 | StringBuffer hexStringBuffer = new StringBuffer();
72 | for (int i = 0; i < byteArray.length; i++)
73 | hexStringBuffer.append(byteToHex(byteArray[i]));
74 | System.out.println("Received the following message: " + hexStringBuffer.toString());
75 | }
76 | @Override
77 | public byte[] getMessageDelimiter() { return new byte[]{ (byte)0xB5, (byte)0x62 }; }
78 | @Override
79 | public boolean delimiterIndicatesEndOfMessage() { return false; }
80 | }
81 |
82 | static public void main(String[] args)
83 | {
84 | System.out.println("\nUsing Library Version v" + SerialPort.getVersion());
85 | SerialPort.allowPortOpenForEnumeration();
86 | SerialPort.autoCleanupAtShutdown();
87 | SerialPort.addShutdownHook(new Thread() { public void run() { System.out.println("\nRunning shutdown hook"); } });
88 | SerialPort[] ports = SerialPort.getCommPorts();
89 | System.out.println("\nAvailable Ports:\n");
90 | for (int i = 0; i < ports.length; ++i)
91 | System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + " (" + ports[i].getSystemPortPath() + "): " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation() + " (VID = " + ports[i].getVendorID() + ", PID = " + ports[i].getProductID() + ", Serial = " + ports[i].getSerialNumber() + ", Manufacturer = " + ports[i].getManufacturer() + ")");
92 | System.out.println("\nRe-enumerating ports again in 2 seconds...\n");
93 | try { Thread.sleep(2000); } catch (Exception e) {}
94 | ports = SerialPort.getCommPorts();
95 | System.out.println("Available Ports:\n");
96 | for (int i = 0; i < ports.length; ++i)
97 | System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + " (" + ports[i].getSystemPortPath() + "): " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation() + " (VID = " + ports[i].getVendorID() + ", PID = " + ports[i].getProductID() + ", Serial = " + ports[i].getSerialNumber() + ", Manufacturer = " + ports[i].getManufacturer() + ")");
98 | SerialPort ubxPort;
99 | System.out.print("\nChoose your desired serial port or enter -1 to specify a port directly: ");
100 | int serialPortChoice = -2;
101 | Scanner inputScanner = new Scanner(System.in);
102 | try {
103 | serialPortChoice = inputScanner.nextInt();
104 | } catch (Exception e) {}
105 | if (serialPortChoice == -2)
106 | {
107 | inputScanner.close();
108 | return;
109 | }
110 | else if (serialPortChoice == -1)
111 | {
112 | String serialPortDescriptor = "";
113 | System.out.print("\nSpecify your desired serial port descriptor: ");
114 | try {
115 | while (serialPortDescriptor.isEmpty())
116 | serialPortDescriptor = inputScanner.nextLine();
117 | } catch (Exception e) { e.printStackTrace(); }
118 | ubxPort = SerialPort.getCommPort(serialPortDescriptor);
119 | }
120 | else
121 | ubxPort = ports[serialPortChoice];
122 | ubxPort.allowElevatedPermissionsRequest();
123 | byte[] readBuffer = new byte[2048];
124 | System.out.println("\nPre-setting RTS: " + (ubxPort.setRTS() ? "Success" : "Failure"));
125 | boolean openedSuccessfully = ubxPort.openPort(0);
126 | System.out.println("\nOpening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + " - " + ubxPort.getPortDescription() + ": " + openedSuccessfully);
127 | if (!openedSuccessfully)
128 | {
129 | System.out.println("Error code was " + ubxPort.getLastErrorCode() + " at Line " + ubxPort.getLastErrorLocation());
130 | inputScanner.close();
131 | return;
132 | }
133 | System.out.println("Setting read timeout mode to non-blocking");
134 | ubxPort.setBaudRate(115200);
135 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 1000, 0);
136 | try
137 | {
138 | for (int i = 0; i < 3; ++i)
139 | {
140 | System.out.println("\nReading #" + i);
141 | System.out.println("Available: " + ubxPort.bytesAvailable());
142 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length);
143 | System.out.println("Read " + numRead + " bytes.");
144 | }
145 | } catch (Exception e) { e.printStackTrace(); }
146 | System.out.println("\nSetting read timeout mode to semi-blocking with a timeout of 200ms");
147 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 200, 0);
148 | try
149 | {
150 | for (int i = 0; i < 3; ++i)
151 | {
152 | System.out.println("\nReading #" + i);
153 | System.out.println("Available: " + ubxPort.bytesAvailable());
154 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length);
155 | System.out.println("Read " + numRead + " bytes.");
156 | }
157 | } catch (Exception e) { e.printStackTrace(); }
158 | System.out.println("\nSetting read timeout mode to semi-blocking with no timeout");
159 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
160 | System.out.println("\nWaiting for available bytes to read...");
161 | while (ubxPort.bytesAvailable() == 0);
162 | System.out.println("Available: " + ubxPort.bytesAvailable());
163 | System.out.println("Flushing read buffers: " + ubxPort.flushIOBuffers());
164 | try
165 | {
166 | for (int i = 0; i < 3; ++i)
167 | {
168 | System.out.println("\nReading #" + i);
169 | System.out.println("Available: " + ubxPort.bytesAvailable());
170 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length);
171 | System.out.println("Read " + numRead + " bytes.");
172 | }
173 | } catch (Exception e) { e.printStackTrace(); }
174 | System.out.println("\nSetting read timeout mode to blocking with a timeout of 100ms");
175 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 100, 0);
176 | try
177 | {
178 | for (int i = 0; i < 3; ++i)
179 | {
180 | System.out.println("\nReading #" + i);
181 | System.out.println("Available: " + ubxPort.bytesAvailable());
182 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length);
183 | System.out.println("Read " + numRead + " bytes.");
184 | }
185 | } catch (Exception e) { e.printStackTrace(); }
186 | System.out.println("\nSetting read timeout mode to blocking with no timeout");
187 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0);
188 | try
189 | {
190 | for (int i = 0; i < 3; ++i)
191 | {
192 | System.out.println("\nReading #" + i);
193 | System.out.println("Available: " + ubxPort.bytesAvailable());
194 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length);
195 | System.out.println("Read " + numRead + " bytes.");
196 | }
197 | } catch (Exception e) { e.printStackTrace(); }
198 | System.out.println("\nSwitching over to event-based reading");
199 | System.out.println("\nListening for any amount of data available\n");
200 | ubxPort.addDataListener(new SerialPortDataListener() {
201 | @Override
202 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; }
203 | @Override
204 | public void serialEvent(SerialPortEvent event)
205 | {
206 | SerialPort comPort = event.getSerialPort();
207 | System.out.println("Available: " + comPort.bytesAvailable() + " bytes.");
208 | byte[] newData = new byte[comPort.bytesAvailable()];
209 | int numRead = comPort.readBytes(newData, newData.length);
210 | System.out.println("Read " + numRead + " bytes.");
211 | }
212 | });
213 | try { Thread.sleep(5000); } catch (Exception e) {}
214 | ubxPort.removeDataListener();
215 | System.out.println("\nNow listening for full 100-byte data packets\n");
216 | PacketListener listener = new PacketListener();
217 | ubxPort.addDataListener(listener);
218 | try { Thread.sleep(5000); } catch (Exception e) {}
219 | ubxPort.removeDataListener();
220 | System.out.println("\nNow listening for byte-delimited binary messages\n");
221 | MessageListener messageListener = new MessageListener();
222 | ubxPort.addDataListener(messageListener);
223 | try { Thread.sleep(5000); } catch (Exception e) {}
224 | ubxPort.removeDataListener();
225 | System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
226 | try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); }
227 | System.out.println("Reopening " + ubxPort.getDescriptivePortName() + ": " + ubxPort.openPort() + "\n");
228 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);
229 | InputStream in = ubxPort.getInputStream();
230 | try
231 | {
232 | for (int j = 0; j < 1000; ++j)
233 | System.out.print((char)in.read());
234 | in.close();
235 | } catch (Exception e) { e.printStackTrace(); }
236 | System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
237 | openedSuccessfully = ubxPort.openPort(0);
238 | System.out.println("Reopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully);
239 | if (!openedSuccessfully)
240 | {
241 | inputScanner.close();
242 | return;
243 | }
244 | System.out.println("\n\nReading for 5 seconds then closing from a separate thread...");
245 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0);
246 | final SerialPort finalPort = ubxPort;
247 | Thread thread = new Thread(new Runnable()
248 | {
249 | @Override
250 | public void run()
251 | {
252 | byte[] buffer = new byte[2048];
253 | while (finalPort.isOpen())
254 | {
255 | System.out.println("\nStarting blocking read...");
256 | int numRead = finalPort.readBytes(buffer, buffer.length);
257 | System.out.println("Read " + numRead + " bytes");
258 | }
259 | System.out.println("\nPort was successfully closed from a separate thread");
260 | }
261 | });
262 | thread.start();
263 | try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); }
264 | System.out.println("\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
265 | try { thread.join(); } catch (Exception e) { e.printStackTrace(); }
266 | openedSuccessfully = ubxPort.openPort(0);
267 | System.out.println("\nReopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully);
268 | if (!openedSuccessfully)
269 | {
270 | inputScanner.close();
271 | return;
272 | }
273 | System.out.println("\n\nNow waiting asynchronously for all possible listening events...");
274 | ubxPort.addDataListener(new SerialPortDataListener() {
275 | @Override
276 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_PARITY_ERROR | SerialPort.LISTENING_EVENT_DATA_WRITTEN | SerialPort.LISTENING_EVENT_BREAK_INTERRUPT |
277 | SerialPort.LISTENING_EVENT_CARRIER_DETECT | SerialPort.LISTENING_EVENT_CTS | SerialPort.LISTENING_EVENT_DSR | SerialPort.LISTENING_EVENT_RING_INDICATOR | SerialPort.LISTENING_EVENT_PORT_DISCONNECTED |
278 | SerialPort.LISTENING_EVENT_FRAMING_ERROR | SerialPort.LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR | SerialPort.LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR | SerialPort.LISTENING_EVENT_DATA_AVAILABLE; }
279 | @Override
280 | public void serialEvent(SerialPortEvent event)
281 | {
282 | System.out.println("Received event type: " + event.toString());
283 | if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE)
284 | {
285 | byte[] buffer = new byte[event.getSerialPort().bytesAvailable()];
286 | event.getSerialPort().readBytes(buffer, buffer.length);
287 | System.out.println(" Reading " + buffer.length + " bytes");
288 | }
289 | }
290 | });
291 | try { Thread.sleep(5000); } catch (Exception e) {}
292 | ubxPort.removeDataListener();
293 | ubxPort.closePort();
294 | openedSuccessfully = ubxPort.openPort(0);
295 | System.out.println("\nReopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully);
296 | if (!openedSuccessfully)
297 | {
298 | inputScanner.close();
299 | return;
300 | }
301 | System.out.println("\n\nUnplug the device sometime in the next 10 seconds to ensure that it closes properly...\n");
302 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0);
303 | ubxPort.addDataListener(new SerialPortDataListener() {
304 | @Override
305 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; }
306 | @Override
307 | public void serialEvent(SerialPortEvent event)
308 | {
309 | SerialPort comPort = event.getSerialPort();
310 | System.out.println("Available: " + comPort.bytesAvailable() + " bytes.");
311 | byte[] newData = new byte[comPort.bytesAvailable()];
312 | int numRead = comPort.readBytes(newData, newData.length);
313 | System.out.println("Read " + numRead + " bytes.");
314 | }
315 | });
316 | try { Thread.sleep(10000); } catch (Exception e) {}
317 | ubxPort.removeDataListener();
318 | System.out.println("\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
319 |
320 | /*System.out.println("\n\nAttempting to read from two serial ports simultaneously\n");
321 | System.out.println("\nAvailable Ports:\n");
322 | for (int i = 0; i < ports.length; ++i)
323 | System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription());
324 | SerialPort ubxPort2;
325 | System.out.print("\nChoose your second desired serial port, or enter -1 to skip this test: ");
326 | serialPortChoice = 0;
327 | try {
328 | Scanner inputScanner = new Scanner(System.in);
329 | serialPortChoice = inputScanner.nextInt();
330 | inputScanner.close();
331 | } catch (Exception e) {}
332 | if (serialPortChoice != -1)
333 | {
334 | ubxPort2 = ports[serialPortChoice];
335 | ubxPort2.openPort();
336 | try
337 | {
338 | System.out.print("\nReading from first serial port...\n\n");
339 | in = ubxPort.getInputStream();
340 | InputStream in2 = ubxPort2.getInputStream();
341 | for (int j = 0; j < 1000; ++j)
342 | System.out.print((char)in.read());
343 | System.out.print("\nReading from second serial port...\n\n");
344 | for (int j = 0; j < 100; ++j)
345 | System.out.print((char)in2.read());
346 | System.out.print("\nReading from first serial port again...\n\n");
347 | for (int j = 0; j < 1000; ++j)
348 | System.out.print((char)in.read());
349 | in.close();
350 | in2.close();
351 | }
352 | catch (SerialPortIOException e) { e.printStackTrace(); }
353 | catch (Exception e) { e.printStackTrace(); }
354 | }
355 | System.out.println("\n\nEntering Java-based InputStream in Scanner mode and reading 200 lines\n");
356 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
357 | Scanner scanner = new Scanner(ubxPort.getInputStream());
358 | for (int i = 1; i < 201; ++i)
359 | if (scanner.hasNextLine())
360 | System.out.println("Full Line #" + i + ": " + scanner.nextLine());
361 | scanner.close();
362 | System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());*/
363 | inputScanner.close();
364 | }
365 | }
366 |
--------------------------------------------------------------------------------