Remove Android-specific code and move to Posix codebase
This commit is contained in:
parent
4e7e2711ff
commit
80cbf0362f
|
@ -1,13 +0,0 @@
|
||||||
LOCAL_PATH := $(call my-dir)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
LOCAL_MODULE := jSerialComm
|
|
||||||
LOCAL_SRC_FILES := SerialPort_Android.c AndroidHelperFunctions.c
|
|
||||||
LOCAL_LDLIBS := -llog
|
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
|
||||||
|
|
||||||
all:
|
|
||||||
cp -rf libs/* ../../resources/Android
|
|
||||||
rm -rf libs/* libs obj
|
|
|
@ -1,322 +0,0 @@
|
||||||
/*
|
|
||||||
* AndroidHelperFunctions.c
|
|
||||||
*
|
|
||||||
* Created on: Mar 10, 2015
|
|
||||||
* Last Updated on: Mar 25, 2016
|
|
||||||
* Author: Will Hedgecock
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012-2018 Fazecast, Inc.
|
|
||||||
*
|
|
||||||
* This file is part of jSerialComm.
|
|
||||||
*
|
|
||||||
* jSerialComm is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of either the Apache Software License, version 2, or
|
|
||||||
* the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation, version 3 or above.
|
|
||||||
*
|
|
||||||
* jSerialComm is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of both the GNU Lesser General Public
|
|
||||||
* License and the Apache Software License along with jSerialComm. If not,
|
|
||||||
* see <http://www.gnu.org/licenses/> and <http://www.apache.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <asm/termios.h>
|
|
||||||
#include <asm/ioctls.h>
|
|
||||||
#include <linux/usbdevice_fs.h>
|
|
||||||
#include <asm/byteorder.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#ifndef BOTHER
|
|
||||||
#include <termios.h>
|
|
||||||
#endif
|
|
||||||
#include "AndroidHelperFunctions.h"
|
|
||||||
|
|
||||||
void push_back(struct charTupleVector* vector, const char* firstString, const char* secondString, const char* thirdString)
|
|
||||||
{
|
|
||||||
// Allocate memory for new string storage
|
|
||||||
vector->length++;
|
|
||||||
char** newMemory = (char**)realloc(vector->first, vector->length*sizeof(char*));
|
|
||||||
if (newMemory)
|
|
||||||
vector->first = newMemory;
|
|
||||||
newMemory = (char**)realloc(vector->second, vector->length*sizeof(char*));
|
|
||||||
if (newMemory)
|
|
||||||
vector->second = newMemory;
|
|
||||||
newMemory = (char**)realloc(vector->third, vector->length*sizeof(char*));
|
|
||||||
if (newMemory)
|
|
||||||
vector->third = newMemory;
|
|
||||||
|
|
||||||
// Store new strings
|
|
||||||
vector->first[vector->length-1] = (char*)malloc(strlen(firstString)+1);
|
|
||||||
vector->second[vector->length-1] = (char*)malloc(strlen(secondString)+1);
|
|
||||||
vector->third[vector->length-1] = (char*)malloc(strlen(thirdString)+1);
|
|
||||||
strcpy(vector->first[vector->length-1], firstString);
|
|
||||||
strcpy(vector->second[vector->length-1], secondString);
|
|
||||||
strcpy(vector->third[vector->length-1], thirdString);
|
|
||||||
}
|
|
||||||
|
|
||||||
char keyExists(struct charTupleVector* vector, const char* key)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < vector->length; ++i)
|
|
||||||
if (strcmp(key, vector->first[i]) == 0)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getFriendlyName(const char* productFile, char* friendlyName)
|
|
||||||
{
|
|
||||||
int friendlyNameLength = 0;
|
|
||||||
friendlyName[0] = '\0';
|
|
||||||
|
|
||||||
FILE *input = fopen(productFile, "rb");
|
|
||||||
if (input)
|
|
||||||
{
|
|
||||||
char ch = getc(input);
|
|
||||||
while ((ch != '\n') && ((int)ch != EOF))
|
|
||||||
{
|
|
||||||
friendlyName[friendlyNameLength++] = ch;
|
|
||||||
ch = getc(input);
|
|
||||||
}
|
|
||||||
friendlyName[friendlyNameLength] = '\0';
|
|
||||||
fclose(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void getDriverName(const char* directoryToSearch, char* friendlyName)
|
|
||||||
{
|
|
||||||
friendlyName[0] = '\0';
|
|
||||||
|
|
||||||
// Open the directory
|
|
||||||
DIR *directoryIterator = opendir(directoryToSearch);
|
|
||||||
if (!directoryIterator)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Read all sub-directories in the current directory
|
|
||||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
|
||||||
while (directoryEntry)
|
|
||||||
{
|
|
||||||
// Check if entry is a valid sub-directory
|
|
||||||
if (directoryEntry->d_name[0] != '.')
|
|
||||||
{
|
|
||||||
// Get the readable part of the driver name
|
|
||||||
strcpy(friendlyName, "USB-to-Serial Port (");
|
|
||||||
char *startingPoint = strchr(directoryEntry->d_name, ':');
|
|
||||||
if (startingPoint != NULL)
|
|
||||||
strcat(friendlyName, startingPoint+1);
|
|
||||||
else
|
|
||||||
strcat(friendlyName, directoryEntry->d_name);
|
|
||||||
strcat(friendlyName, ")");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
directoryEntry = readdir(directoryIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the directory
|
|
||||||
closedir(directoryIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
void recursiveSearchForComPorts(charTupleVector* comPorts, const char* fullPathToSearch)
|
|
||||||
{
|
|
||||||
// Open the directory
|
|
||||||
DIR *directoryIterator = opendir(fullPathToSearch);
|
|
||||||
if (!directoryIterator)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Read all sub-directories in the current directory
|
|
||||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
|
||||||
while (directoryEntry)
|
|
||||||
{
|
|
||||||
// Check if entry is a sub-directory
|
|
||||||
if (directoryEntry->d_type == DT_DIR)
|
|
||||||
{
|
|
||||||
// Only process non-dot, non-virtual directories
|
|
||||||
if ((directoryEntry->d_name[0] != '.') && (strcmp(directoryEntry->d_name, "virtual") != 0))
|
|
||||||
{
|
|
||||||
// See if the directory names a potential serial port
|
|
||||||
if ((strlen(directoryEntry->d_name) > 3) && (directoryEntry->d_name[0] == 't') && (directoryEntry->d_name[1] == 't') && (directoryEntry->d_name[2] == 'y'))
|
|
||||||
{
|
|
||||||
// Determine system name of port
|
|
||||||
char* systemName = (char*)malloc(256);
|
|
||||||
strcpy(systemName, "/dev/");
|
|
||||||
strcat(systemName, directoryEntry->d_name);
|
|
||||||
|
|
||||||
// See if device has a registered friendly name
|
|
||||||
char* friendlyName = (char*)malloc(256);
|
|
||||||
char* productFile = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 30);
|
|
||||||
strcpy(productFile, fullPathToSearch);
|
|
||||||
strcat(productFile, directoryEntry->d_name);
|
|
||||||
strcat(productFile, "/device/../product");
|
|
||||||
getFriendlyName(productFile, friendlyName);
|
|
||||||
if (friendlyName[0] == '\0')
|
|
||||||
{
|
|
||||||
// Get friendly name based on the driver loaded
|
|
||||||
strcpy(productFile, fullPathToSearch);
|
|
||||||
strcat(productFile, directoryEntry->d_name);
|
|
||||||
strcat(productFile, "/driver/module/drivers");
|
|
||||||
getDriverName(productFile, friendlyName);
|
|
||||||
if (friendlyName[0] != '\0')
|
|
||||||
push_back(comPorts, systemName, friendlyName, friendlyName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
push_back(comPorts, systemName, friendlyName, friendlyName);
|
|
||||||
|
|
||||||
// Clean up memory
|
|
||||||
free(productFile);
|
|
||||||
free(systemName);
|
|
||||||
free(friendlyName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Search for more serial ports within the directory
|
|
||||||
charTupleVector newComPorts = { (char**)malloc(1), (char**)malloc(1), (char**)malloc(1), 0 };
|
|
||||||
char* nextDirectory = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 5);
|
|
||||||
strcpy(nextDirectory, fullPathToSearch);
|
|
||||||
strcat(nextDirectory, directoryEntry->d_name);
|
|
||||||
strcat(nextDirectory, "/");
|
|
||||||
recursiveSearchForComPorts(&newComPorts, nextDirectory);
|
|
||||||
free(nextDirectory);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < newComPorts.length; ++i)
|
|
||||||
{
|
|
||||||
push_back(comPorts, newComPorts.first[i], newComPorts.second[i], newComPorts.third[i]);
|
|
||||||
free(newComPorts.first[i]);
|
|
||||||
free(newComPorts.second[i]);
|
|
||||||
free(newComPorts.third[i]);
|
|
||||||
}
|
|
||||||
free(newComPorts.first);
|
|
||||||
free(newComPorts.second);
|
|
||||||
free(newComPorts.third);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
directoryEntry = readdir(directoryIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the directory
|
|
||||||
closedir(directoryIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int getBaudRateCode(int baudRate)
|
|
||||||
{
|
|
||||||
switch (baudRate)
|
|
||||||
{
|
|
||||||
case 50:
|
|
||||||
return B50;
|
|
||||||
case 75:
|
|
||||||
return B75;
|
|
||||||
case 110:
|
|
||||||
return B110;
|
|
||||||
case 134:
|
|
||||||
return B134;
|
|
||||||
case 150:
|
|
||||||
return B150;
|
|
||||||
case 200:
|
|
||||||
return B200;
|
|
||||||
case 300:
|
|
||||||
return B300;
|
|
||||||
case 600:
|
|
||||||
return B600;
|
|
||||||
case 1200:
|
|
||||||
return B1200;
|
|
||||||
case 1800:
|
|
||||||
return B1800;
|
|
||||||
case 2400:
|
|
||||||
return B2400;
|
|
||||||
case 4800:
|
|
||||||
return B4800;
|
|
||||||
case 9600:
|
|
||||||
return B9600;
|
|
||||||
case 19200:
|
|
||||||
return B19200;
|
|
||||||
case 38400:
|
|
||||||
return B38400;
|
|
||||||
case 57600:
|
|
||||||
return B57600;
|
|
||||||
case 115200:
|
|
||||||
return B115200;
|
|
||||||
case 230400:
|
|
||||||
return B230400;
|
|
||||||
case 460800:
|
|
||||||
return B460800;
|
|
||||||
case 500000:
|
|
||||||
return B500000;
|
|
||||||
case 576000:
|
|
||||||
return B576000;
|
|
||||||
case 921600:
|
|
||||||
return B921600;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBaudRate(int portFD, int baudRate)
|
|
||||||
{
|
|
||||||
#ifdef BOTHER
|
|
||||||
struct termios2 options = { 0 };
|
|
||||||
|
|
||||||
if (isatty(portFD))
|
|
||||||
ioctl(portFD, TCGETS2, &options);
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
// {
|
|
||||||
// struct usbdevfs_ioctl requestWrapper;
|
|
||||||
// requestWrapper.ifno = 1;// TODO
|
|
||||||
// requestWrapper.ioctl_code = TCGETS2;
|
|
||||||
// requestWrapper.data = &options;
|
|
||||||
// ioctl(portFD, USBDEVFS_IOCTL, &requestWrapper);
|
|
||||||
// }
|
|
||||||
options.c_cflag &= ~CBAUD;
|
|
||||||
options.c_cflag |= BOTHER;
|
|
||||||
options.c_ispeed = baudRate;
|
|
||||||
options.c_ospeed = baudRate;
|
|
||||||
if (isatty(portFD))
|
|
||||||
ioctl(portFD, TCSETS2, &options);
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
// {
|
|
||||||
// struct usbdevfs_ioctl requestWrapper;
|
|
||||||
// requestWrapper.ifno = 1;// TODO
|
|
||||||
// requestWrapper.ioctl_code = TCSETS2;
|
|
||||||
// requestWrapper.data = &options;
|
|
||||||
// ioctl(portFD, USBDEVFS_IOCTL, &requestWrapper);
|
|
||||||
// }
|
|
||||||
#else
|
|
||||||
struct termios options = { 0 };
|
|
||||||
if (isatty(portFD))
|
|
||||||
ioctl(portFD, TCGETS, &options);
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
// {
|
|
||||||
// struct usbdevfs_ioctl requestWrapper;
|
|
||||||
// requestWrapper.ifno = 1;// TODO
|
|
||||||
// requestWrapper.ioctl_code = TCGETS;
|
|
||||||
// requestWrapper.data = &options;
|
|
||||||
// ioctl(portFD, USBDEVFS_IOCTL, &requestWrapper);
|
|
||||||
// }
|
|
||||||
options.c_cflag = (options.c_cflag & ~CBAUD) | (B38400 & CBAUD);
|
|
||||||
if (isatty(portFD))
|
|
||||||
ioctl(portFD, TCSETS, &options);
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
// {
|
|
||||||
// struct usbdevfs_ioctl requestWrapper;
|
|
||||||
// requestWrapper.ifno = 1;// TODO
|
|
||||||
// requestWrapper.ioctl_code = TCSETS;
|
|
||||||
// requestWrapper.data = &options;
|
|
||||||
// ioctl(portFD, USBDEVFS_IOCTL, &requestWrapper);
|
|
||||||
// }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* AndroidHelperFunctions.h
|
|
||||||
*
|
|
||||||
* Created on: Mar 10, 2015
|
|
||||||
* Last Updated on: Mar 25, 2016
|
|
||||||
* Author: Will Hedgecock
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012-2018 Fazecast, Inc.
|
|
||||||
*
|
|
||||||
* This file is part of jSerialComm.
|
|
||||||
*
|
|
||||||
* jSerialComm is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of either the Apache Software License, version 2, or
|
|
||||||
* the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation, version 3 or above.
|
|
||||||
*
|
|
||||||
* jSerialComm is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of both the GNU Lesser General Public
|
|
||||||
* License and the Apache Software License along with jSerialComm. If not,
|
|
||||||
* see <http://www.gnu.org/licenses/> and <http://www.apache.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ANDROID_HELPER_FUNCTIONS_HEADER_H__
|
|
||||||
#define __ANDROID_HELPER_FUNCTIONS_HEADER_H__
|
|
||||||
|
|
||||||
typedef struct charTupleVector
|
|
||||||
{
|
|
||||||
char **first, **second, **third;
|
|
||||||
size_t length;
|
|
||||||
} charTupleVector;
|
|
||||||
void push_back(struct charTupleVector* vector, const char* firstString, const char* secondString, const char* thirdString);
|
|
||||||
char keyExists(struct charTupleVector* vector, const char* key);
|
|
||||||
|
|
||||||
void getDriverName(const char* directoryToSearch, char* friendlyName);
|
|
||||||
void recursiveSearchForComPorts(charTupleVector* comPorts, const char* fullPathToSearch);
|
|
||||||
void getFriendlyName(const char* productFile, char* friendlyName);
|
|
||||||
unsigned int getBaudRateCode(int baudRate);
|
|
||||||
void setBaudRate(int portFD, int baudRate);
|
|
||||||
|
|
||||||
extern int ioctl(int __fd, int __request, ...);
|
|
||||||
|
|
||||||
#endif // #ifndef __ANDROID_HELPER_FUNCTIONS_HEADER_H__
|
|
|
@ -1,741 +0,0 @@
|
||||||
/*
|
|
||||||
* SerialPort_Android.c
|
|
||||||
*
|
|
||||||
* Created on: Mar 13, 2015
|
|
||||||
* Last Updated on: Feb 18, 2020
|
|
||||||
* Author: Will Hedgecock
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012-2020 Fazecast, Inc.
|
|
||||||
*
|
|
||||||
* This file is part of jSerialComm.
|
|
||||||
*
|
|
||||||
* jSerialComm is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of either the Apache Software License, version 2, or
|
|
||||||
* the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation, version 3 or above.
|
|
||||||
*
|
|
||||||
* jSerialComm is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of both the GNU Lesser General Public
|
|
||||||
* License and the Apache Software License along with jSerialComm. If not,
|
|
||||||
* see <http://www.gnu.org/licenses/> and <http://www.apache.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#ifndef CMSPAR
|
|
||||||
#define CMSPAR 010000000000
|
|
||||||
#endif
|
|
||||||
#include <android/log.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <linux/usbdevice_fs.h>
|
|
||||||
#include <linux/serial.h>
|
|
||||||
#include <asm/byteorder.h>
|
|
||||||
#include "com_fazecast_jSerialComm_SerialPort.h"
|
|
||||||
#include "AndroidHelperFunctions.h"
|
|
||||||
|
|
||||||
// Logging defines
|
|
||||||
#define LOG_TAG "com.fazecast.jSerialComm"
|
|
||||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
|
||||||
|
|
||||||
// Cached class, method, and field IDs
|
|
||||||
jclass serialCommClass;
|
|
||||||
jmethodID serialCommConstructor;
|
|
||||||
jfieldID serialPortFdField;
|
|
||||||
jfieldID comPortField;
|
|
||||||
jfieldID friendlyNameField;
|
|
||||||
jfieldID portDescriptionField;
|
|
||||||
jfieldID eventListenerRunningField;
|
|
||||||
jfieldID disableConfigField;
|
|
||||||
jfieldID isDtrEnabledField;
|
|
||||||
jfieldID isRtsEnabledField;
|
|
||||||
jfieldID baudRateField;
|
|
||||||
jfieldID dataBitsField;
|
|
||||||
jfieldID stopBitsField;
|
|
||||||
jfieldID parityField;
|
|
||||||
jfieldID flowControlField;
|
|
||||||
jfieldID sendDeviceQueueSizeField;
|
|
||||||
jfieldID receiveDeviceQueueSizeField;
|
|
||||||
jfieldID rs485ModeField;
|
|
||||||
jfieldID rs485ActiveHighField;
|
|
||||||
jfieldID rs485DelayBeforeField;
|
|
||||||
jfieldID rs485DelayAfterField;
|
|
||||||
jfieldID timeoutModeField;
|
|
||||||
jfieldID readTimeoutField;
|
|
||||||
jfieldID writeTimeoutField;
|
|
||||||
jfieldID eventFlagsField;
|
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
|
|
||||||
{
|
|
||||||
// Enumerate serial ports on machine
|
|
||||||
charTupleVector serialPorts = { (char**)malloc(1), (char**)malloc(1), (char**)malloc(1), 0 };
|
|
||||||
recursiveSearchForComPorts(&serialPorts, "/sys/devices/");
|
|
||||||
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < serialPorts.length; ++i)
|
|
||||||
{
|
|
||||||
// Create new SerialComm object containing the enumerated values
|
|
||||||
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
|
||||||
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewStringUTF(env, serialPorts.third[i]));
|
|
||||||
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewStringUTF(env, serialPorts.second[i]));
|
|
||||||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewStringUTF(env, serialPorts.first[i]));
|
|
||||||
free(serialPorts.first[i]);
|
|
||||||
free(serialPorts.second[i]);
|
|
||||||
free(serialPorts.third[i]);
|
|
||||||
|
|
||||||
// Add new SerialComm object to array
|
|
||||||
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
|
||||||
}
|
|
||||||
free(serialPorts.first);
|
|
||||||
free(serialPorts.second);
|
|
||||||
free(serialPorts.third);
|
|
||||||
|
|
||||||
return arrayObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrary(JNIEnv *env, jclass serialComm)
|
|
||||||
{
|
|
||||||
// Cache class and method ID as global references
|
|
||||||
serialCommClass = (jclass)(*env)->NewGlobalRef(env, serialComm);
|
|
||||||
serialCommConstructor = (*env)->GetMethodID(env, serialCommClass, "<init>", "()V");
|
|
||||||
|
|
||||||
// Cache
|
|
||||||
serialPortFdField = (*env)->GetFieldID(env, serialCommClass, "portHandle", "J");
|
|
||||||
comPortField = (*env)->GetFieldID(env, serialCommClass, "comPort", "Ljava/lang/String;");
|
|
||||||
friendlyNameField = (*env)->GetFieldID(env, serialCommClass, "friendlyName", "Ljava/lang/String;");
|
|
||||||
portDescriptionField = (*env)->GetFieldID(env, serialCommClass, "portDescription", "Ljava/lang/String;");
|
|
||||||
eventListenerRunningField = (*env)->GetFieldID(env, serialCommClass, "eventListenerRunning", "Z");
|
|
||||||
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
|
|
||||||
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
|
|
||||||
isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z");
|
|
||||||
baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I");
|
|
||||||
dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I");
|
|
||||||
stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I");
|
|
||||||
parityField = (*env)->GetFieldID(env, serialCommClass, "parity", "I");
|
|
||||||
flowControlField = (*env)->GetFieldID(env, serialCommClass, "flowControl", "I");
|
|
||||||
sendDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "sendDeviceQueueSize", "I");
|
|
||||||
receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I");
|
|
||||||
rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "Z");
|
|
||||||
rs485ActiveHighField = (*env)->GetFieldID(env, serialCommClass, "rs485ActiveHigh", "Z");
|
|
||||||
rs485DelayBeforeField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayBefore", "I");
|
|
||||||
rs485DelayAfterField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayAfter", "I");
|
|
||||||
timeoutModeField = (*env)->GetFieldID(env, serialCommClass, "timeoutMode", "I");
|
|
||||||
readTimeoutField = (*env)->GetFieldID(env, serialCommClass, "readTimeout", "I");
|
|
||||||
writeTimeoutField = (*env)->GetFieldID(env, serialCommClass, "writeTimeout", "I");
|
|
||||||
eventFlagsField = (*env)->GetFieldID(env, serialCommClass, "eventFlags", "I");
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm)
|
|
||||||
{
|
|
||||||
// Delete the cached global reference
|
|
||||||
(*env)->DeleteGlobalRef(env, serialCommClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(JNIEnv *env, jobject obj)
|
|
||||||
{
|
|
||||||
// TODO: SET A FLAG SAYING THAT WE ARE NOT USING USBFS
|
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
|
||||||
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
|
|
||||||
unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
|
|
||||||
unsigned char isRtsEnabled = (*env)->GetBooleanField(env, obj, isRtsEnabledField);
|
|
||||||
|
|
||||||
// Try to open existing serial port with read/write access
|
|
||||||
int serialPortFD = -1;
|
|
||||||
if ((serialPortFD = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK)) > 0)
|
|
||||||
{
|
|
||||||
// Clear any serial port flags and set up raw, non-canonical port parameters
|
|
||||||
if (isatty(serialPortFD))
|
|
||||||
{
|
|
||||||
struct termios options = {0};
|
|
||||||
fcntl(serialPortFD, F_SETFL, 0);
|
|
||||||
ioctl(serialPortFD, TCGETS, &options);
|
|
||||||
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
|
||||||
options.c_oflag &= ~OPOST;
|
|
||||||
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
|
||||||
options.c_cflag &= ~(CSIZE | PARENB);
|
|
||||||
options.c_cflag |= CS8;
|
|
||||||
if (!isDtrEnabled || !isRtsEnabled)
|
|
||||||
options.c_cflag &= ~HUPCL;
|
|
||||||
options.c_iflag |= BRKINT;
|
|
||||||
ioctl(serialPortFD, TCSETS, &options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the port parameters and timeouts
|
|
||||||
if (Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, serialPortFD))
|
|
||||||
(*env)->SetLongField(env, obj, serialPortHandleField, serialPortFD);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Close the port if there was a problem setting the parameters
|
|
||||||
tcdrain(serialPortFD);
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
serialPortFD = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
|
||||||
return serialPortFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
struct serial_struct serInfo = {0};
|
|
||||||
struct termios options = {0};
|
|
||||||
|
|
||||||
// Get port parameters from Java class
|
|
||||||
int baudRate = (*env)->GetIntField(env, obj, baudRateField);
|
|
||||||
int byteSizeInt = (*env)->GetIntField(env, obj, dataBitsField);
|
|
||||||
int stopBitsInt = (*env)->GetIntField(env, obj, stopBitsField);
|
|
||||||
int parityInt = (*env)->GetIntField(env, obj, parityField);
|
|
||||||
int flowControl = (*env)->GetIntField(env, obj, flowControlField);
|
|
||||||
int sendDeviceQueueSize = (*env)->GetIntField(env, obj, sendDeviceQueueSizeField);
|
|
||||||
int receiveDeviceQueueSize = (*env)->GetIntField(env, obj, receiveDeviceQueueSizeField);
|
|
||||||
int rs485DelayBefore = (*env)->GetIntField(env, obj, rs485DelayBeforeField);
|
|
||||||
int rs485DelayAfter = (*env)->GetIntField(env, obj, rs485DelayAfterField);
|
|
||||||
unsigned char configDisabled = (*env)->GetBooleanField(env, obj, disableConfigField);
|
|
||||||
unsigned char rs485ModeEnabled = (*env)->GetBooleanField(env, obj, rs485ModeField);
|
|
||||||
unsigned char rs485ActiveHigh = (*env)->GetBooleanField(env, obj, rs485ActiveHighField);
|
|
||||||
unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
|
|
||||||
unsigned char isRtsEnabled = (*env)->GetBooleanField(env, obj, isRtsEnabledField);
|
|
||||||
tcflag_t byteSize = (byteSizeInt == 5) ? CS5 : (byteSizeInt == 6) ? CS6 : (byteSizeInt == 7) ? CS7 : CS8;
|
|
||||||
tcflag_t stopBits = ((stopBitsInt == com_fazecast_jSerialComm_SerialPort_ONE_STOP_BIT) || (stopBitsInt == com_fazecast_jSerialComm_SerialPort_ONE_POINT_FIVE_STOP_BITS)) ? 0 : CSTOPB;
|
|
||||||
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);
|
|
||||||
tcflag_t CTSRTSEnabled = (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED) > 0) ||
|
|
||||||
((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0)) ? CRTSCTS : 0;
|
|
||||||
tcflag_t XonXoffInEnabled = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED) > 0) ? IXOFF : 0;
|
|
||||||
tcflag_t XonXoffOutEnabled = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0) ? IXON : 0;
|
|
||||||
|
|
||||||
// Set updated port parameters
|
|
||||||
if (isatty(serialPortFD))
|
|
||||||
{
|
|
||||||
ioctl(serialPortFD, TCGETS, &options);
|
|
||||||
options.c_cflag = (byteSize | stopBits | parity | CLOCAL | CREAD | CTSRTSEnabled);
|
|
||||||
if (parityInt == com_fazecast_jSerialComm_SerialPort_SPACE_PARITY)
|
|
||||||
options.c_cflag &= ~PARODD;
|
|
||||||
if (!isDtrEnabled || !isRtsEnabled)
|
|
||||||
options.c_cflag &= ~HUPCL;
|
|
||||||
options.c_iflag &= ~(INPCK | IGNPAR | PARMRK | ISTRIP);
|
|
||||||
if (byteSizeInt < 8)
|
|
||||||
options.c_iflag |= ISTRIP;
|
|
||||||
if (parityInt != 0)
|
|
||||||
options.c_iflag |= (INPCK | IGNPAR);
|
|
||||||
options.c_iflag |= (XonXoffInEnabled | XonXoffOutEnabled);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return JNI_FALSE;/*
|
|
||||||
{
|
|
||||||
struct usbdevfs_ioctl requestWrapper;
|
|
||||||
requestWrapper.ifno = 1;// TODO
|
|
||||||
requestWrapper.ioctl_code = TCGETS;
|
|
||||||
requestWrapper.data = &options;
|
|
||||||
ioctl(serialPortFD, USBDEVFS_IOCTL, &requestWrapper);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Set baud rate
|
|
||||||
unsigned int baudRateCode = getBaudRateCode(baudRate);
|
|
||||||
if (baudRateCode != 0)
|
|
||||||
options.c_cflag = (options.c_cflag & ~CBAUD) | (baudRateCode & CBAUD);
|
|
||||||
|
|
||||||
// Apply changes
|
|
||||||
int retVal = -1;
|
|
||||||
if (isatty(serialPortFD))
|
|
||||||
retVal = configDisabled ? 0 : ioctl(serialPortFD, TCSETS, &options);
|
|
||||||
else
|
|
||||||
return JNI_FALSE;/*
|
|
||||||
{
|
|
||||||
struct usbdevfs_ioctl requestWrapper;
|
|
||||||
requestWrapper.ifno = 1;// TODO
|
|
||||||
requestWrapper.ioctl_code = TCSETS;
|
|
||||||
requestWrapper.data = &options;
|
|
||||||
retVal = ioctl(serialPortFD, USBDEVFS_IOCTL, &requestWrapper);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Attempt to set the transmit buffer size and any necessary custom baud rates
|
|
||||||
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
|
|
||||||
ioctl(serialPortFD, TIOCGSERIAL, &serInfo);
|
|
||||||
serInfo.xmit_fifo_size = sendDeviceQueueSize;
|
|
||||||
ioctl(serialPortFD, TIOCSSERIAL, &serInfo);
|
|
||||||
if (baudRateCode == 0)
|
|
||||||
setBaudRate(serialPortFD, baudRate);
|
|
||||||
|
|
||||||
// Attempt to set the requested RS-485 mode
|
|
||||||
struct serial_rs485 rs485Conf = {0};
|
|
||||||
if (ioctl(serialPortFD, TIOCGRS485, &rs485Conf) == 0)
|
|
||||||
{
|
|
||||||
if (rs485ModeEnabled)
|
|
||||||
rs485Conf.flags |= SER_RS485_ENABLED;
|
|
||||||
else
|
|
||||||
rs485Conf.flags &= ~SER_RS485_ENABLED;
|
|
||||||
if (rs485ActiveHigh)
|
|
||||||
{
|
|
||||||
rs485Conf.flags |= SER_RS485_RTS_ON_SEND;
|
|
||||||
rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND);
|
|
||||||
rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND;
|
|
||||||
}
|
|
||||||
rs485Conf.delay_rts_before_send = rs485DelayBefore;
|
|
||||||
rs485Conf.delay_rts_after_send = rs485DelayAfter;
|
|
||||||
ioctl(serialPortFD, TIOCSRS485, &rs485Conf);
|
|
||||||
}
|
|
||||||
return ((retVal == 0) && Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj, serialPortFD) ? JNI_TRUE : JNI_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
// Get port timeouts from Java class
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int baudRate = (*env)->GetIntField(env, obj, baudRateField);
|
|
||||||
unsigned int baudRateCode = getBaudRateCode(baudRate);
|
|
||||||
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
|
|
||||||
int readTimeout = (*env)->GetIntField(env, obj, readTimeoutField);
|
|
||||||
|
|
||||||
// Retrieve existing port configuration
|
|
||||||
struct termios options = {0};
|
|
||||||
if (isatty(serialPortFD))
|
|
||||||
ioctl(serialPortFD, TCGETS, &options);
|
|
||||||
else
|
|
||||||
return JNI_FALSE;/*
|
|
||||||
{
|
|
||||||
struct usbdevfs_ioctl requestWrapper;
|
|
||||||
requestWrapper.ifno = 1;// TODO
|
|
||||||
requestWrapper.ioctl_code = TCGETS;
|
|
||||||
requestWrapper.data = &options;
|
|
||||||
if (ioctl(serialPortFD, USBDEVFS_IOCTL, &requestWrapper) < 0)
|
|
||||||
LOGD("ERROR GETTING tcgetattr PORT SETTINGS = %d\n", errno);
|
|
||||||
}*/
|
|
||||||
int flags = fcntl(serialPortFD, F_GETFL);
|
|
||||||
if (flags == -1)
|
|
||||||
return JNI_FALSE;
|
|
||||||
|
|
||||||
// Set updated port timeouts
|
|
||||||
if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout
|
|
||||||
{
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 0;
|
|
||||||
options.c_cc[VTIME] = readTimeout / 100;
|
|
||||||
}
|
|
||||||
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) // Read Semi-blocking without timeout
|
|
||||||
{
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 1;
|
|
||||||
options.c_cc[VTIME] = 0;
|
|
||||||
}
|
|
||||||
else if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout > 0)) // Read Blocking with timeout
|
|
||||||
{
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 0;
|
|
||||||
options.c_cc[VTIME] = readTimeout / 100;
|
|
||||||
}
|
|
||||||
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Read Blocking without timeout
|
|
||||||
{
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 1;
|
|
||||||
options.c_cc[VTIME] = 0;
|
|
||||||
}
|
|
||||||
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER) > 0) // Scanner Mode
|
|
||||||
{
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 1;
|
|
||||||
options.c_cc[VTIME] = 1;
|
|
||||||
}
|
|
||||||
else // Non-blocking
|
|
||||||
{
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 0;
|
|
||||||
options.c_cc[VTIME] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply changes
|
|
||||||
int retVal = fcntl(serialPortFD, F_SETFL, flags);
|
|
||||||
if (retVal != -1)
|
|
||||||
{
|
|
||||||
if (isatty(serialPortFD))
|
|
||||||
retVal = ioctl(serialPortFD, TCSETS, &options);
|
|
||||||
else
|
|
||||||
return JNI_FALSE;/*
|
|
||||||
{
|
|
||||||
struct usbdevfs_ioctl requestWrapper;
|
|
||||||
requestWrapper.ifno = 1;// TODO
|
|
||||||
requestWrapper.ioctl_code = TCSETS;
|
|
||||||
requestWrapper.data = &options;
|
|
||||||
if (ioctl(serialPortFD, USBDEVFS_IOCTL, &requestWrapper) < 0)
|
|
||||||
LOGD("ERROR SETTING ioctl PORT SETTINGS = %d\n", errno);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
if (baudRateCode == 0) // Set custom baud rate
|
|
||||||
setBaudRate(serialPortFD, baudRate);
|
|
||||||
return ((retVal == 0) ? JNI_TRUE : JNI_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
|
|
||||||
// Get event flags from Java class
|
|
||||||
int baudRate = (*env)->GetIntField(env, obj, baudRateField);
|
|
||||||
unsigned int baudRateCode = getBaudRateCode(baudRate);
|
|
||||||
int eventsToMonitor = (*env)->GetIntField(env, obj, eventFlagsField);
|
|
||||||
|
|
||||||
// Change read timeouts if we are monitoring data received
|
|
||||||
jboolean retVal;
|
|
||||||
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0)
|
|
||||||
{
|
|
||||||
struct termios options = {0};
|
|
||||||
ioctl(serialPortFD, TCGETS, &options);
|
|
||||||
int flags = fcntl(serialPortFD, F_GETFL);
|
|
||||||
if (flags == -1)
|
|
||||||
return JNI_FALSE;
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 0;
|
|
||||||
options.c_cc[VTIME] = 10;
|
|
||||||
retVal = ((fcntl(serialPortFD, F_SETFL, flags) == -1) || (ioctl(serialPortFD, TCSETS, &options) == -1)) ?
|
|
||||||
JNI_FALSE : JNI_TRUE;
|
|
||||||
if (baudRateCode == 0) // Set custom baud rate
|
|
||||||
setBaudRate(serialPortFD, baudRate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
retVal = Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD);
|
|
||||||
|
|
||||||
// Apply changes
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
// Initialize the waiting set
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return 0;
|
|
||||||
struct pollfd waitingSet = { serialPortFD, POLLIN, 0 };
|
|
||||||
|
|
||||||
// Wait for a serial port event
|
|
||||||
if (poll(&waitingSet, 1, 1000) <= 0)
|
|
||||||
return 0;
|
|
||||||
return (waitingSet.revents & POLLIN) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
// Ensure that the port is open
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_TRUE;
|
|
||||||
|
|
||||||
// Force the port to enter non-blocking mode to ensure that any current reads return
|
|
||||||
struct termios options = {0};
|
|
||||||
ioctl(serialPortFD, TCGETS, &options);
|
|
||||||
int flags = fcntl(serialPortFD, F_GETFL);
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
options.c_cc[VMIN] = 0;
|
|
||||||
options.c_cc[VTIME] = 0;
|
|
||||||
int retVal = fcntl(serialPortFD, F_SETFL, flags);
|
|
||||||
ioctl(serialPortFD, TCSETS, &options);
|
|
||||||
|
|
||||||
// Close the port
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
|
||||||
return JNI_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
int numBytesAvailable = -1;
|
|
||||||
if ((serialPortFD > 0) && (ioctl(serialPortFD, FIONREAD, &numBytesAvailable) == -1))
|
|
||||||
{
|
|
||||||
// Problem detected, close the port
|
|
||||||
tcdrain(serialPortFD);
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
|
||||||
}
|
|
||||||
|
|
||||||
return numBytesAvailable;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAwaitingWrite(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
int numBytesToWrite = -1;
|
|
||||||
if (serialPortFD > 0)
|
|
||||||
ioctl(serialPortFD, TIOCOUTQ, &numBytesToWrite);
|
|
||||||
|
|
||||||
return numBytesToWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv *env, jobject obj, jlong serialPortFD, jbyteArray buffer, jlong bytesToRead, jlong offset)
|
|
||||||
{
|
|
||||||
// Get port handle and read timeout from Java class
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return -1;
|
|
||||||
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
|
|
||||||
int readTimeout = (*env)->GetIntField(env, obj, readTimeoutField);
|
|
||||||
int numBytesRead, numBytesReadTotal = 0, bytesRemaining = bytesToRead, ioctlResult = 0;
|
|
||||||
char* readBuffer = (char*)malloc(bytesToRead);
|
|
||||||
|
|
||||||
// Infinite blocking mode specified, don't return until we have completely finished the read
|
|
||||||
if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout == 0))
|
|
||||||
{
|
|
||||||
// While there are more bytes we are supposed to read
|
|
||||||
while (bytesRemaining > 0)
|
|
||||||
{
|
|
||||||
do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR));
|
|
||||||
if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1)))
|
|
||||||
{
|
|
||||||
// Problem reading, close port
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
serialPortFD = -1;
|
|
||||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix index variables
|
|
||||||
numBytesReadTotal += numBytesRead;
|
|
||||||
bytesRemaining -= numBytesRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Blocking mode, but not indefinitely
|
|
||||||
{
|
|
||||||
// Get current system time
|
|
||||||
struct timeval expireTime = {0}, currTime = {0};
|
|
||||||
gettimeofday(&expireTime, NULL);
|
|
||||||
expireTime.tv_usec += (readTimeout * 1000);
|
|
||||||
if (expireTime.tv_usec > 1000000)
|
|
||||||
{
|
|
||||||
expireTime.tv_sec += (expireTime.tv_usec * 0.000001);
|
|
||||||
expireTime.tv_usec = (expireTime.tv_usec % 1000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// While there are more bytes we are supposed to read and the timeout has not elapsed
|
|
||||||
do
|
|
||||||
{
|
|
||||||
do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR));
|
|
||||||
if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1)))
|
|
||||||
{
|
|
||||||
// Problem reading, close port
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
serialPortFD = -1;
|
|
||||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix index variables
|
|
||||||
numBytesReadTotal += numBytesRead;
|
|
||||||
bytesRemaining -= numBytesRead;
|
|
||||||
|
|
||||||
// Get current system time
|
|
||||||
gettimeofday(&currTime, NULL);
|
|
||||||
} while ((bytesRemaining > 0) && ((expireTime.tv_sec > currTime.tv_sec) ||
|
|
||||||
((expireTime.tv_sec == currTime.tv_sec) && (expireTime.tv_usec > currTime.tv_usec))));
|
|
||||||
}
|
|
||||||
else // Semi- or non-blocking specified
|
|
||||||
{
|
|
||||||
// Read from port
|
|
||||||
do { numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR));
|
|
||||||
if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1)))
|
|
||||||
{
|
|
||||||
// Problem reading, close port
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
serialPortFD = -1;
|
|
||||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
numBytesReadTotal = numBytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return number of bytes read if successful
|
|
||||||
(*env)->SetByteArrayRegion(env, buffer, offset, numBytesReadTotal, (jbyte*)readBuffer);
|
|
||||||
free(readBuffer);
|
|
||||||
return (numBytesRead == -1) || (serialPortFD == -1) ? -1 : numBytesReadTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEnv *env, jobject obj, jlong serialPortFD, jbyteArray buffer, jlong bytesToWrite, jlong offset)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return -1;
|
|
||||||
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
|
|
||||||
jbyte *writeBuffer = (*env)->GetByteArrayElements(env, buffer, 0);
|
|
||||||
int numBytesWritten, ioctlResult = 0;
|
|
||||||
|
|
||||||
// Write to port
|
|
||||||
do { numBytesWritten = write(serialPortFD, writeBuffer+offset, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR));
|
|
||||||
if ((numBytesWritten == -1) || ((numBytesWritten == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1)))
|
|
||||||
{
|
|
||||||
// Problem writing, close the port
|
|
||||||
ioctl(serialPortFD, TCSBRK, 1);
|
|
||||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
|
||||||
serialPortFD = -1;
|
|
||||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until all bytes were written in write-blocking mode
|
|
||||||
if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0) && (serialPortFD > 0))
|
|
||||||
ioctl(serialPortFD, TCSBRK, 1);
|
|
||||||
|
|
||||||
// Return number of bytes written if successful
|
|
||||||
(*env)->ReleaseByteArrayElements(env, buffer, writeBuffer, JNI_ABORT);
|
|
||||||
return numBytesWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setBreak(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
return (ioctl(serialPortFD, TIOCSBRK) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearBreak(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
return (ioctl(serialPortFD, TIOCCBRK) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setRTS(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = TIOCM_RTS;
|
|
||||||
return (ioctl(serialPortFD, TIOCMBIS, &modemBits) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearRTS(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = TIOCM_RTS;
|
|
||||||
return (ioctl(serialPortFD, TIOCMBIC, &modemBits) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetRTS(JNIEnv *env, jobject obj)
|
|
||||||
{
|
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
|
||||||
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
|
|
||||||
|
|
||||||
// Send a system command to preset the RTS mode of the serial port
|
|
||||||
char commandString[128];
|
|
||||||
sprintf(commandString, "stty -F %s hupcl >>/dev/null 2>&1", portName);
|
|
||||||
int result = system(commandString);
|
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
|
||||||
return (result == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearRTS(JNIEnv *env, jobject obj)
|
|
||||||
{
|
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
|
||||||
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
|
|
||||||
|
|
||||||
// Send a system command to preset the RTS mode of the serial port
|
|
||||||
char commandString[128];
|
|
||||||
sprintf(commandString, "stty -F %s -hupcl >>/dev/null 2>&1", portName);
|
|
||||||
int result = system(commandString);
|
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
|
||||||
return (result == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setDTR(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = TIOCM_DTR;
|
|
||||||
return (ioctl(serialPortFD, TIOCMBIS, &modemBits) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearDTR(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = TIOCM_DTR;
|
|
||||||
return (ioctl(serialPortFD, TIOCMBIC, &modemBits) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetDTR(JNIEnv *env, jobject obj)
|
|
||||||
{
|
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
|
||||||
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
|
|
||||||
|
|
||||||
// Send a system command to preset the DTR mode of the serial port
|
|
||||||
char commandString[128];
|
|
||||||
sprintf(commandString, "stty -F %s hupcl >>/dev/null 2>&1", portName);
|
|
||||||
int result = system(commandString);
|
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
|
||||||
return (result == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearDTR(JNIEnv *env, jobject obj)
|
|
||||||
{
|
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
|
||||||
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
|
|
||||||
|
|
||||||
// Send a system command to preset the DTR mode of the serial port
|
|
||||||
char commandString[128];
|
|
||||||
sprintf(commandString, "stty -F %s -hupcl >>/dev/null 2>&1", portName);
|
|
||||||
int result = system(commandString);
|
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
|
||||||
return (result == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCTS(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = 0;
|
|
||||||
return (ioctl(serialPortFD, TIOCMGET, &modemBits) == 0) && (modemBits & TIOCM_CTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDSR(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = 0;
|
|
||||||
return (ioctl(serialPortFD, TIOCMGET, &modemBits) == 0) && (modemBits & TIOCM_DSR);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDCD(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = 0;
|
|
||||||
return (ioctl(serialPortFD, TIOCMGET, &modemBits) == 0) && (modemBits & TIOCM_CAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDTR(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = 0;
|
|
||||||
return (ioctl(serialPortFD, TIOCMGET, &modemBits) == 0) && (modemBits & TIOCM_DTR);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRTS(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = 0;
|
|
||||||
return (ioctl(serialPortFD, TIOCMGET, &modemBits) == 0) && (modemBits & TIOCM_RTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRI(JNIEnv *env, jobject obj, jlong serialPortFD)
|
|
||||||
{
|
|
||||||
if (serialPortFD <= 0)
|
|
||||||
return JNI_FALSE;
|
|
||||||
int modemBits = 0;
|
|
||||||
return (ioctl(serialPortFD, TIOCMGET, &modemBits) == 0) && (modemBits & TIOCM_RI);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,7 +2,7 @@
|
||||||
* PosixHelperFunctions.c
|
* PosixHelperFunctions.c
|
||||||
*
|
*
|
||||||
* Created on: Mar 10, 2015
|
* Created on: Mar 10, 2015
|
||||||
* Last Updated on: Mar 07, 2019
|
* Last Updated on: Feb 25, 2020
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2020 Fazecast, Inc.
|
* Copyright (C) 2012-2020 Fazecast, Inc.
|
||||||
|
|
|
@ -43,7 +43,11 @@ char keyExists(struct charTupleVector* vector, const char* key);
|
||||||
// Linux-specific functionality
|
// Linux-specific functionality
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
typedef int baud_rate;
|
typedef int baud_rate;
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
extern int ioctl(int __fd, int __request, ...);
|
||||||
|
#else
|
||||||
extern int ioctl(int __fd, unsigned long int __request, ...);
|
extern int ioctl(int __fd, unsigned long int __request, ...);
|
||||||
|
#endif
|
||||||
void getDriverName(const char* directoryToSearch, char* friendlyName);
|
void getDriverName(const char* directoryToSearch, char* friendlyName);
|
||||||
void getFriendlyName(const char* productFile, char* friendlyName);
|
void getFriendlyName(const char* productFile, char* friendlyName);
|
||||||
void getInterfaceDescription(const char* interfaceFile, char* interfaceDescription);
|
void getInterfaceDescription(const char* interfaceFile, char* interfaceDescription);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort_Posix.c
|
* SerialPort_Posix.c
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Feb 19, 2020
|
* Last Updated on: Feb 25, 2020
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2020 Fazecast, Inc.
|
* Copyright (C) 2012-2020 Fazecast, Inc.
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE := jSerialComm
|
||||||
|
TARGET_OUT := ../../resources/Android/$(TARGET_ARCH_ABI)
|
||||||
|
LOCAL_SRC_FILES := ../SerialPort_Posix.c ../PosixHelperFunctions.c
|
||||||
|
LOCAL_LDLIBS := -llog
|
||||||
|
LOCAL_CFLAGS := -fsigned-char
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
|
all:
|
||||||
|
rmdir /Q /S libs obj
|
Loading…
Reference in New Issue