mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00

Added a new C/C++ formatter profile called "Unmanaged profile 'CDT'" (name stolen from the Java formatter) that is basically K&R with the tweak of maxium line width set to 120 (same width as for .java files). Added enforcement of the formatter during build. libspawner.so/jnilib have differences because the re-formatting changes line numbers and therefore the __LINE__ macro expands to a different value. Change-Id: Id3a0619cb31640c7817dc684c72139f90cab0fc6 Signed-off-by: Torbjörn Svensson <azoff@svenskalinuxforeningen.se>
568 lines
13 KiB
C
568 lines
13 KiB
C
/*******************************************************************************
|
|
* Copyright (c) 2015 QNX Software Systems and others.
|
|
*
|
|
* This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License 2.0
|
|
* which accompanies this distribution, and is available at
|
|
* https://www.eclipse.org/legal/epl-2.0/
|
|
*
|
|
* SPDX-License-Identifier: EPL-2.0
|
|
*
|
|
* Contributors:
|
|
* QNX Software Systems - initial API and implementation
|
|
* STMicroelectronics
|
|
*******************************************************************************/
|
|
#ifdef __APPLE__
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/uio.h>
|
|
#endif
|
|
#ifndef __MINGW32__
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <termios.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
#ifndef __APPLE__
|
|
#include <linux/serial.h>
|
|
#endif
|
|
#else
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define UNICODE
|
|
#include <windows.h>
|
|
#endif
|
|
#include <jni.h>
|
|
#include <org_eclipse_cdt_serial_SerialPort.h>
|
|
|
|
#define FUNC(x) Java_org_eclipse_cdt_serial_SerialPort_ ## x
|
|
|
|
/**
|
|
* Use this method to throw an exception when open fails after the OS open
|
|
* stage. This method obtains the last error from OS to include in the
|
|
* IOException
|
|
*/
|
|
#ifndef __MINGW32__
|
|
static void closeAndthrowIOException(int fd, JNIEnv *env, const char *msg)
|
|
#else
|
|
static void closeAndthrowIOException(HANDLE handle, JNIEnv *env, const char *msg)
|
|
#endif
|
|
{
|
|
char buff[256];
|
|
#ifndef __MINGW32__
|
|
sprintf(buff, "%s: %s", msg, strerror(errno));
|
|
close(fd);
|
|
#else
|
|
sprintf_s(buff, sizeof(buff), "%s (%d)", msg, GetLastError());
|
|
CloseHandle(handle);
|
|
#endif
|
|
jclass cls = (*env)->FindClass(env, "java/io/IOException");
|
|
(*env)->ThrowNew(env, cls, buff);
|
|
}
|
|
|
|
static void throwIOException(JNIEnv *env, const char *msg) {
|
|
char buff[256];
|
|
#ifndef __MINGW32__
|
|
sprintf(buff, "%s: %s", msg, strerror(errno));
|
|
#else
|
|
sprintf_s(buff, sizeof(buff), "%s (%d)", msg, GetLastError());
|
|
#endif
|
|
jclass cls = (*env)->FindClass(env, "java/io/IOException");
|
|
(*env)->ThrowNew(env, cls, buff);
|
|
}
|
|
|
|
JNIEXPORT jlong JNICALL FUNC(open0)(JNIEnv *env, jobject jobj, jstring portName, jint baudRate, jint byteSize,
|
|
jint parity, jint stopBits) {
|
|
#ifndef __MINGW32__
|
|
const char *cportName = (*env)->GetStringUTFChars(env, portName, NULL);
|
|
int fd = open(cportName, O_RDWR | O_NOCTTY | O_NDELAY);
|
|
if (fd < 0) {
|
|
char msg[256];
|
|
sprintf(msg, "Error opening %s", cportName);
|
|
(*env)->ReleaseStringUTFChars(env, portName, cportName);
|
|
throwIOException(env, msg);
|
|
return fd;
|
|
}
|
|
(*env)->ReleaseStringUTFChars(env, portName, cportName);
|
|
|
|
// Turn off all flags
|
|
fcntl(fd, F_SETFL, 0);
|
|
|
|
struct termios options;
|
|
tcgetattr(fd, &options);
|
|
options.c_cflag |= (CLOCAL | CREAD);
|
|
|
|
#ifndef __APPLE__
|
|
speed_t baud;
|
|
switch (baudRate) {
|
|
case 110:
|
|
baud = B110;
|
|
break;
|
|
case 300:
|
|
baud = B300;
|
|
break;
|
|
case 600:
|
|
baud = B600;
|
|
break;
|
|
case 1200:
|
|
baud = B1200;
|
|
break;
|
|
case 2400:
|
|
baud = B2400;
|
|
break;
|
|
case 4800:
|
|
baud = B4800;
|
|
break;
|
|
case 9600:
|
|
baud = B9600;
|
|
break;
|
|
case 19200:
|
|
baud = B19200;
|
|
break;
|
|
case 38400:
|
|
baud = B38400;
|
|
break;
|
|
case 57600:
|
|
baud = B57600;
|
|
break;
|
|
case 115200:
|
|
baud = B115200;
|
|
break;
|
|
case 230400:
|
|
baud = B230400;
|
|
break;
|
|
case 460800:
|
|
baud = B460800;
|
|
break;
|
|
case 500000:
|
|
baud = B500000;
|
|
break;
|
|
case 576000:
|
|
baud = B576000;
|
|
break;
|
|
case 921600:
|
|
baud = B921600;
|
|
break;
|
|
case 1000000:
|
|
baud = B1000000;
|
|
break;
|
|
case 1152000:
|
|
baud = B1152000;
|
|
break;
|
|
case 1500000:
|
|
baud = B1500000;
|
|
break;
|
|
case 2000000:
|
|
baud = B2000000;
|
|
break;
|
|
case 2500000:
|
|
baud = B2500000;
|
|
break;
|
|
case 3000000:
|
|
baud = B3000000;
|
|
break;
|
|
case 3500000:
|
|
baud = B3500000;
|
|
break;
|
|
case 4000000:
|
|
baud = B4000000;
|
|
break;
|
|
default:
|
|
baud = B0;
|
|
break;
|
|
}
|
|
|
|
if (baud == B0) {
|
|
// Use custom linux baud rates if possible: https://bugs.eclipse.org/bugs/show_bug.cgi?id=543122#c8
|
|
struct serial_struct serial_options;
|
|
options.c_cflag |= B38400;
|
|
|
|
if (ioctl(fd, TIOCGSERIAL, &serial_options) != 0) {
|
|
closeAndthrowIOException(fd, env, "Failed to use custom baud rate. Error using TIOCGSERIAL");
|
|
return -1;
|
|
}
|
|
serial_options.custom_divisor = serial_options.baud_base / baudRate;
|
|
if (serial_options.custom_divisor == 0) {
|
|
serial_options.custom_divisor = 1;
|
|
}
|
|
|
|
serial_options.flags &= ~ASYNC_SPD_MASK;
|
|
serial_options.flags |= ASYNC_SPD_CUST;
|
|
|
|
if (ioctl(fd, TIOCSSERIAL, &serial_options) != 0) {
|
|
closeAndthrowIOException(fd, env, "Failed to use custom baud rate. Error using TIOCSSERIAL");
|
|
return -1;
|
|
}
|
|
} else {
|
|
// Set baud rate
|
|
cfsetispeed(&options, baud);
|
|
cfsetospeed(&options, baud);
|
|
}
|
|
|
|
#else
|
|
// On OSX speed_t is simply the baud rate: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/cfsetispeed.3.html
|
|
cfsetispeed(&options, baudRate);
|
|
cfsetospeed(&options, baudRate);
|
|
#endif
|
|
|
|
// set data size
|
|
options.c_cflag &= ~CSIZE;
|
|
switch (byteSize) {
|
|
case 5:
|
|
options.c_cflag |= CS5;
|
|
break;
|
|
case 6:
|
|
options.c_cflag |= CS6;
|
|
break;
|
|
case 7:
|
|
options.c_cflag |= CS7;
|
|
break;
|
|
case 8:
|
|
options.c_cflag |= CS8;
|
|
break;
|
|
|
|
}
|
|
|
|
// set parity
|
|
switch (parity) {
|
|
case 0: // None
|
|
options.c_cflag &= ~PARENB;
|
|
break;
|
|
case 1: // Even
|
|
options.c_cflag |= PARENB;
|
|
options.c_cflag &= ~PARODD;
|
|
break;
|
|
case 2: // Odd
|
|
options.c_cflag |= (PARENB | PARODD);
|
|
break;
|
|
}
|
|
|
|
switch (stopBits) {
|
|
case 0: // 1
|
|
options.c_cflag &= ~CSTOPB;
|
|
break;
|
|
case 1: // 2
|
|
options.c_cflag |= CSTOPB;
|
|
break;
|
|
}
|
|
|
|
// raw input
|
|
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
|
|
|
// ignore parity
|
|
options.c_iflag |= IGNPAR;
|
|
|
|
// turn off those bits in the input flag that fiddle with CR and NL
|
|
options.c_iflag &= ~(ICRNL | INLCR | IGNCR);
|
|
|
|
options.c_cc[VMIN] = 0; // min chars to read
|
|
options.c_cc[VTIME] = 2; // 10ths second timeout
|
|
|
|
tcflush(fd, TCIFLUSH);
|
|
tcsetattr(fd, TCSANOW, &options);
|
|
|
|
return fd;
|
|
#else // __MINGW32__
|
|
const wchar_t * cportName = (const wchar_t *)(*env)->GetStringChars(env, portName, NULL);
|
|
HANDLE handle = CreateFile(cportName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
(*env)->ReleaseStringChars(env, portName, cportName);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
char msg[256];
|
|
const char * name = (*env)->GetStringUTFChars(env, portName, NULL);
|
|
sprintf_s(msg, sizeof(msg), "Error opening %s", name);
|
|
(*env)->ReleaseStringUTFChars(env, portName, name);
|
|
throwIOException(env, msg);
|
|
return -1;
|
|
}
|
|
|
|
DCB dcb = { 0 };
|
|
|
|
if (!GetCommState(handle, &dcb)) {
|
|
closeAndthrowIOException(handle, env, "Error getting DCB");
|
|
return -1;
|
|
}
|
|
|
|
dcb.BaudRate = baudRate;
|
|
dcb.ByteSize = (BYTE)byteSize;
|
|
|
|
switch (parity) {
|
|
case 0: // None
|
|
dcb.fParity = FALSE;
|
|
dcb.Parity = NOPARITY;
|
|
break;
|
|
case 1: // Even
|
|
dcb.fParity = TRUE;
|
|
dcb.Parity = EVENPARITY;
|
|
break;
|
|
case 2: // Odd
|
|
dcb.fParity = TRUE;
|
|
dcb.Parity = ODDPARITY;
|
|
break;
|
|
}
|
|
|
|
switch (stopBits) {
|
|
case 0:
|
|
dcb.StopBits = ONESTOPBIT;
|
|
break;
|
|
case 1:
|
|
dcb.StopBits = TWOSTOPBITS;
|
|
break;
|
|
}
|
|
|
|
if (!SetCommState(handle, &dcb)) {
|
|
closeAndthrowIOException(handle, env, "Error setting DCB");
|
|
return -1;
|
|
}
|
|
|
|
COMMTIMEOUTS timeouts = { 0 };
|
|
timeouts.ReadIntervalTimeout = MAXDWORD;
|
|
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
|
|
timeouts.ReadTotalTimeoutConstant = 200;
|
|
if (!SetCommTimeouts(handle, &timeouts)) {
|
|
closeAndthrowIOException(handle, env, "Error setting timeouts");
|
|
return -1;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
return (jlong)handle;
|
|
#else
|
|
return (jlong)(unsigned)handle;
|
|
#endif
|
|
#endif // __MINGW32__
|
|
}
|
|
|
|
JNIEXPORT void JNICALL FUNC(close0)
|
|
(JNIEnv *env, jobject jobj, jlong handle)
|
|
{
|
|
#ifndef __MINGW32__
|
|
close(handle);
|
|
#else
|
|
#ifdef _WIN64
|
|
CloseHandle((HANDLE)handle);
|
|
#else
|
|
CloseHandle((HANDLE)(unsigned)handle);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL FUNC(available0)(JNIEnv *env, jobject jobj, jlong jhandle) {
|
|
#ifndef __MINGW32__
|
|
int result = 0;
|
|
if (ioctl(jhandle, FIONREAD, &result) < 0) {
|
|
throwIOException(env, "Error calling ioctl");
|
|
return 0;
|
|
}
|
|
return result;
|
|
#else
|
|
COMSTAT stat;
|
|
DWORD errCode;
|
|
#ifdef _WIN64
|
|
HANDLE handle = (HANDLE)jhandle;
|
|
#else
|
|
HANDLE handle = (HANDLE)(unsigned)jhandle;
|
|
#endif
|
|
|
|
if (ClearCommError(handle, &errCode, &stat) == 0) {
|
|
throwIOException(env, "Error calling ClearCommError");
|
|
return -1;
|
|
}
|
|
return (int)stat.cbInQue;
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL FUNC(read1)(JNIEnv *env, jobject jobj, jlong jhandle, jbyteArray bytes, jint offset, jint size) {
|
|
#ifndef __MINGW32__
|
|
jbyte buff[256];
|
|
int n = size < sizeof(buff) ? size : sizeof(buff);
|
|
n = read(jhandle, buff, n);
|
|
if (n > 0) {
|
|
(*env)->SetByteArrayRegion(env, bytes, offset, n, buff);
|
|
}
|
|
return n;
|
|
#else
|
|
OVERLAPPED olp = { 0 };
|
|
|
|
olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (olp.hEvent == NULL) {
|
|
throwIOException(env, "Error creating event");
|
|
return -1;
|
|
}
|
|
|
|
char buff[256];
|
|
DWORD nread = sizeof(buff) < size ? sizeof(buff) : size;
|
|
#ifdef _WIN64
|
|
HANDLE handle = (HANDLE)jhandle;
|
|
#else
|
|
HANDLE handle = (HANDLE)(unsigned)jhandle;
|
|
#endif
|
|
|
|
if (!ReadFile(handle, buff, sizeof(buff), &nread, &olp)) {
|
|
if (GetLastError() != ERROR_IO_PENDING) {
|
|
throwIOException(env, "Error reading from port");
|
|
CloseHandle(olp.hEvent);
|
|
return -1;
|
|
} else {
|
|
switch (WaitForSingleObject(olp.hEvent, INFINITE)) {
|
|
case WAIT_OBJECT_0:
|
|
if (!GetOverlappedResult(handle, &olp, &nread, FALSE)) {
|
|
if (GetLastError() != ERROR_OPERATION_ABORTED) {
|
|
throwIOException(env, "Error waiting for read");
|
|
}
|
|
CloseHandle(olp.hEvent);
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nread > 0) {
|
|
(*env)->SetByteArrayRegion(env, bytes, offset, nread, (jbyte *)buff);
|
|
}
|
|
CloseHandle(olp.hEvent);
|
|
return nread;
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL FUNC(write0)
|
|
(JNIEnv *env, jobject jobj, jlong jhandle, jint b)
|
|
{
|
|
#ifndef __MINGW32__
|
|
char buff = b;
|
|
write(jhandle, &buff, 1);
|
|
#else
|
|
OVERLAPPED olp = { 0 };
|
|
|
|
olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (olp.hEvent == NULL) {
|
|
throwIOException(env, "Error creating event");
|
|
return;
|
|
}
|
|
|
|
char buff = (char)b;
|
|
DWORD nwritten;
|
|
#ifdef _WIN64
|
|
HANDLE handle = (HANDLE)jhandle;
|
|
#else
|
|
HANDLE handle = (HANDLE)(unsigned)jhandle;
|
|
#endif
|
|
|
|
if (!WriteFile(handle, &buff, sizeof(buff), &nwritten, &olp)) {
|
|
if (GetLastError() != ERROR_IO_PENDING) {
|
|
throwIOException(env, "Error writing to port");
|
|
}
|
|
else {
|
|
switch (WaitForSingleObject(olp.hEvent, INFINITE)) {
|
|
case WAIT_OBJECT_0:
|
|
if (!GetOverlappedResult(handle, &olp, &nwritten, FALSE)) {
|
|
throwIOException(env, "Error waiting for write");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseHandle(olp.hEvent);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL FUNC(write1)(JNIEnv *env, jobject jobj, jlong jhandle, jbyteArray bytes, jint offset, jint size)
|
|
{
|
|
#ifndef __MINGW32__
|
|
while (size > 0) {
|
|
jbyte buff[256];
|
|
int n = size < sizeof(buff) ? size : sizeof(buff);
|
|
(*env)->GetByteArrayRegion(env, bytes, offset, n, buff);
|
|
n = write(jhandle, buff, n);
|
|
if (n < 0) {
|
|
return;
|
|
}
|
|
size -= n;
|
|
offset += n;
|
|
}
|
|
#else
|
|
OVERLAPPED olp = { 0 };
|
|
|
|
olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (olp.hEvent == NULL) {
|
|
throwIOException(env, "Error creating event");
|
|
return;
|
|
}
|
|
|
|
while (size > 0) {
|
|
char buff[256];
|
|
DWORD nwritten = sizeof(buff) < size ? sizeof(buff) : size;
|
|
(*env)->GetByteArrayRegion(env, bytes, offset, nwritten, (jbyte *)buff);
|
|
#ifdef _WIN64
|
|
HANDLE handle = (HANDLE)jhandle;
|
|
#else
|
|
HANDLE handle = (HANDLE)(unsigned)jhandle;
|
|
#endif
|
|
|
|
if (!WriteFile(handle, buff, nwritten, &nwritten, &olp)) {
|
|
if (GetLastError() != ERROR_IO_PENDING) {
|
|
throwIOException(env, "Error writing to port");
|
|
return;
|
|
}
|
|
else {
|
|
switch (WaitForSingleObject(olp.hEvent, INFINITE)) {
|
|
case WAIT_OBJECT_0:
|
|
if (!GetOverlappedResult(handle, &olp, &nwritten, FALSE)) {
|
|
throwIOException(env, "Error waiting for write");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
size -= nwritten;
|
|
offset += nwritten;
|
|
}
|
|
|
|
CloseHandle(olp.hEvent);
|
|
#endif
|
|
}
|
|
|
|
#ifdef __MINGW32__
|
|
JNIEXPORT jstring FUNC(getPortName)(JNIEnv *env, jclass cls, jint i)
|
|
{
|
|
HKEY key;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &key) != ERROR_SUCCESS) {
|
|
// There are none
|
|
return NULL;
|
|
}
|
|
|
|
wchar_t name[256];
|
|
DWORD len = sizeof(name);
|
|
LONG rc = RegEnumValue(key, (DWORD)i, name, &len, NULL, NULL, NULL, NULL);
|
|
if (rc != ERROR_SUCCESS) {
|
|
if (rc != ERROR_NO_MORE_ITEMS) {
|
|
throwIOException(env, "Can not enum value");
|
|
}
|
|
RegCloseKey(key);
|
|
return NULL;
|
|
}
|
|
|
|
wchar_t value[256];
|
|
DWORD type;
|
|
len = sizeof(value);
|
|
if (RegQueryValueEx(key, name, NULL, &type, (BYTE *)value, &len) != ERROR_SUCCESS) {
|
|
throwIOException(env, "Can not query value");
|
|
RegCloseKey(key);
|
|
return NULL;
|
|
}
|
|
|
|
jstring result = (*env)->NewString(env, (jchar *)value, (jsize) wcslen(value));
|
|
RegCloseKey(key);
|
|
return result;
|
|
}
|
|
#endif
|