aboutsummaryrefslogtreecommitdiff
path: root/flow-native
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2016-05-16 15:28:59 -0700
committerJakob Odersky <jakob@odersky.com>2016-06-09 03:30:35 -0700
commit92c4b3d41e06ad4b89004212c85248e9e6cd61d7 (patch)
tree69470f7c4ed48edaebea91964d7d552e7eaacf0d /flow-native
parentf6f26c2c9e3ec9bdd45fb384483b3450bef5984a (diff)
downloadakka-serial-92c4b3d41e06ad4b89004212c85248e9e6cd61d7.tar.gz
akka-serial-92c4b3d41e06ad4b89004212c85248e9e6cd61d7.tar.bz2
akka-serial-92c4b3d41e06ad4b89004212c85248e9e6cd61d7.zip
Move project to `ch.jodersky` and upgrade sbt-jni
Diffstat (limited to 'flow-native')
-rw-r--r--flow-native/build.sbt5
-rw-r--r--flow-native/src/.gitignore8
-rw-r--r--flow-native/src/CMakeLists.txt56
-rw-r--r--flow-native/src/flow_jni.c243
-rw-r--r--flow-native/src/include/ch_jodersky_flow_UnsafeSerial.h45
-rw-r--r--flow-native/src/include/ch_jodersky_flow_UnsafeSerial__.h29
-rw-r--r--flow-native/src/include/com_github_jodersky_flow_internal_NativeSerial.h83
-rw-r--r--flow-native/src/include/flow.h79
-rw-r--r--flow-native/src/platform/posix/flow.c394
9 files changed, 472 insertions, 470 deletions
diff --git a/flow-native/build.sbt b/flow-native/build.sbt
index b6b39a0..1f5720e 100644
--- a/flow-native/build.sbt
+++ b/flow-native/build.sbt
@@ -4,6 +4,7 @@ FlowBuild.commonSettings
enablePlugins(JniNative)
-sourceDirectory in nativeCompile in Compile := sourceDirectory.value
+sourceDirectory in nativeCompile := sourceDirectory.value
-nativeLibraryPath in Compile := "com/github/jodersky/flow"
+// uncomment below to use library in lib_native instead
+//enableNativeCompilation in Compile := false
diff --git a/flow-native/src/.gitignore b/flow-native/src/.gitignore
index e259f31..1785c46 100644
--- a/flow-native/src/.gitignore
+++ b/flow-native/src/.gitignore
@@ -1,8 +1,8 @@
# CMake
-CMakeFiles/
-CMakeCache.txt
-cmake_install.cmake
-Makefile
+/CMakeFiles/
+/CMakeCache.txt
+/cmake_install.cmake
+/Makefile
# Binary files
*.o
diff --git a/flow-native/src/CMakeLists.txt b/flow-native/src/CMakeLists.txt
index 7f6cbd7..8be2fab 100644
--- a/flow-native/src/CMakeLists.txt
+++ b/flow-native/src/CMakeLists.txt
@@ -1,23 +1,24 @@
-cmake_minimum_required(VERSION 2.6)
+################################################################
+# A minimal CMake file that is compatible with sbt-jni #
+# #
+# All settings required by sbt-jni have been marked so, please #
+# add/modify/remove settings to build your specific library. #
+################################################################
+
+cmake_minimum_required(VERSION 2.8.0)
# Define project and related variables
+# (required by sbt-jni) please use semantic versioning
#
project (flow)
+set(PROJECT_VERSION_MAJOR 4)
+set(PROJECT_VERSION_MINOR 0)
+set(PROJECT_VERSION_PATCH 0)
-# Set versions and library name
-# Note: major version will be appended to library name
-#
-set (VERSION_MAJOR 3)
-set (VERSION_MINOR 0)
-set (VERSION_PATCH 1)
-set (LIB_NAME flow${VERSION_MAJOR})
-
-# Command-line options
-#
-# required by sbt-jni to install binaries to correct places
-set (LIB_INSTALL_DIR lib CACHE PATH "Path in which to install libraries (Autoconf equivalent to --libdir).")
-# required by sbt-jni to disable versioned libraries
-set (ENABLE_VERSIONED_LIB ON CACHE BOOLEAN "Generate versioned library files and symlinks.")
+set(CMAKE_C_FLAGS "-std=c99")
+add_definitions(-Wall)
+add_definitions(-Wextra)
+add_definitions(-pedantic)
# Setup JNI
find_package(JNI REQUIRED)
@@ -26,20 +27,19 @@ if (JNI_FOUND)
endif()
# Include directories
+include_directories(.)
include_directories(include)
include_directories(${JNI_INCLUDE_DIRS})
-# Setup main shared library
-# Note: major version is appended to library name
-add_library(${LIB_NAME} SHARED flow_jni.c platform/posix/flow.c)
-if (ENABLE_VERSIONED_LIB)
- set_target_properties(
- ${LIB_NAME}
- PROPERTIES
- VERSION 0.${VERSION_MINOR}.${VERSION_PATCH} # major version always 0, it is included in name
- SOVERSION 0
- )
-endif()
+# Sources
+file(GLOB LIB_SRC
+ "*.c"
+ "platform/posix/*.c"
+)
-# Installation targets
-install(TARGETS ${LIB_NAME} LIBRARY DESTINATION ${LIB_INSTALL_DIR})
+# Setup installation targets
+# (required by sbt-jni) major version should always be appended to library name
+#
+set (LIB_NAME ${PROJECT_NAME}${PROJECT_VERSION_MAJOR})
+add_library(${LIB_NAME} SHARED ${LIB_SRC})
+install(TARGETS ${LIB_NAME} LIBRARY DESTINATION .)
diff --git a/flow-native/src/flow_jni.c b/flow-native/src/flow_jni.c
index 8ec2aed..75bffff 100644
--- a/flow-native/src/flow_jni.c
+++ b/flow-native/src/flow_jni.c
@@ -1,169 +1,150 @@
+#include <stdint.h>
+
#include "flow.h"
-#include "com_github_jodersky_flow_internal_NativeSerial.h"
+#include "ch_jodersky_flow_UnsafeSerial.h"
+#include "ch_jodersky_flow_UnsafeSerial__.h"
-static inline void throwException(JNIEnv* env, const char* const exception, const char * const message) {
- (*env)->ThrowNew(env, (*env)->FindClass(env, exception), message);
-}
+// suppress unused parameter warnings
+#define UNUSED_ARG(x) (void)(x)
-static inline void check(JNIEnv* env, int id) {
- switch (id) {
- case E_IO: throwException(env, "java/io/IOException", ""); break;
- case E_BUSY: throwException(env, "com/github/jodersky/flow/PortInUseException", ""); break;
- case E_ACCESS_DENIED: throwException(env, "com/github/jodersky/flow/AccessDeniedException", ""); break;
- case E_INVALID_SETTINGS: throwException(env, "com/github/jodersky/flow/InvalidSettingsException", ""); break;
- case E_INTERRUPT: throwException(env, "com/github/jodersky/flow/PortInterruptedException", ""); break;
- case E_NO_PORT: throwException(env, "com/github/jodersky/flow/NoSuchPortException", ""); break;
- default: return;
- }
+static inline void throwException(JNIEnv* env, const char* const exception, const char * const message)
+{
+ (*env)->ThrowNew(env, (*env)->FindClass(env, exception), message);
}
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: open
- * Signature: (Ljava/lang/String;IIZI)J
- */
-JNIEXPORT jlong JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_open
- (JNIEnv *env, jclass clazz, jstring port_name, jint baud, jint char_size, jboolean two_stop_bits, jint parity) {
-
- const char *dev = (*env)->GetStringUTFChars(env, port_name, 0);
- struct serial_config* config;
- int r = serial_open(dev, baud, char_size, two_stop_bits, parity, &config);
- (*env)->ReleaseStringUTFChars(env, port_name, dev);
-
-
- if (r < 0) {
- check(env, r);
- return 0;
- }
-
- long jpointer = (long) config;
- return jpointer;
+/** Check return code and throw exception in case it is non-zero. */
+static void check(JNIEnv* env, int ret)
+{
+ switch (ret) {
+ case -E_IO: throwException(env, "java/io/IOException", ""); break;
+ case -E_BUSY: throwException(env, "ch/jodersky/flow/PortInUseException", ""); break;
+ case -E_ACCESS_DENIED: throwException(env, "ch/jodersky/flow/AccessDeniedException", ""); break;
+ case -E_INVALID_SETTINGS: throwException(env, "ch/jodersky/flow/InvalidSettingsException", ""); break;
+ case -E_INTERRUPT: throwException(env, "ch/jodersky/flow/PortInterruptedException", ""); break;
+ case -E_NO_PORT: throwException(env, "ch/jodersky/flow/NoSuchPortException", ""); break;
+ default: return;
+ }
+}
+/** Get pointer to serial config associated to an UnsafeSerial instance. */
+static struct serial_config* get_config(JNIEnv* env, jobject unsafe_serial)
+{
+ jclass clazz = (*env)->FindClass(env, "ch/jodersky/flow/UnsafeSerial");
+ jfieldID field = (*env)->GetFieldID(env, clazz, "serialAddr", "J");
+ jlong addr = (*env)->GetLongField(env, unsafe_serial, field);
+ return (struct serial_config*) (intptr_t) addr;
}
/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: readDirect
- * Signature: (JLjava/nio/ByteBuffer;)I
+ * Class: ch_jodersky_flow_UnsafeSerial__
+ * Method: open
+ * Signature: (Ljava/lang/String;IIZI)J
*/
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_readDirect
- (JNIEnv *env, jclass clazz, jlong config, jobject buffer) {
-
- char* local_buffer = (char*) (*env)->GetDirectBufferAddress(env, buffer);
- if (local_buffer == NULL) {
- throwException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
- return -1;
- }
- jlong size = (*env)->GetDirectBufferCapacity(env, buffer);
-
- int r = serial_read((struct serial_config*) config, local_buffer, (size_t) size);
- if (r < 0) {
- check(env, r);
- return -1;
- }
- return r;
-
+JNIEXPORT jlong JNICALL Java_ch_jodersky_flow_UnsafeSerial_00024_open
+(JNIEnv *env, jobject instance, jstring port_name, jint baud, jint char_size, jboolean two_stop_bits, jint parity)
+{
+ UNUSED_ARG(instance);
+
+ const char *dev = (*env)->GetStringUTFChars(env, port_name, 0);
+ struct serial_config* config;
+ int r = serial_open(dev, baud, char_size, two_stop_bits, parity, &config);
+ (*env)->ReleaseStringUTFChars(env, port_name, dev);
+
+ if (r < 0) {
+ check(env, r);
+ return -E_IO;
+ }
+
+ long jpointer = (long) config;
+ return (jlong) jpointer;
}
/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
+ * Class: ch_jodersky_flow_UnsafeSerial
* Method: read
- * Signature: (J[B)I
+ * Signature: (Ljava/nio/ByteBuffer;)I
*/
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_read
- (JNIEnv *env, jclass clazz, jlong config, jbyteArray buffer) {
-
- jsize size = (*env)->GetArrayLength(env, buffer);
- char local_buffer[size];
- int r = serial_read((struct serial_config*) config, local_buffer, size);
- if (r < 0) {
- check(env, r);
- return -1;
- }
-
- (*env)->SetByteArrayRegion(env, buffer, 0, r, (signed char *) local_buffer);
- return r;
+JNIEXPORT jint JNICALL Java_ch_jodersky_flow_UnsafeSerial_read
+(JNIEnv *env, jobject instance, jobject buffer)
+{
+ char* local_buffer = (char*) (*env)->GetDirectBufferAddress(env, buffer);
+ if (local_buffer == NULL) {
+ throwException(env, "java/lang/IllegalArgumentException", "buffer is not direct");
+ return -E_IO;
+ }
+ size_t size = (size_t) (*env)->GetDirectBufferCapacity(env, buffer);
+ struct serial_config* config = get_config(env, instance);
+
+ int r = serial_read(config, local_buffer, size);
+ if (r < 0) {
+ check(env, r);
+ }
+ return r;
}
/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
+ * Class: ch_jodersky_flow_UnsafeSerial
* Method: cancelRead
- * Signature: (J)V
+ * Signature: ()V
*/
-JNIEXPORT void JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_cancelRead
- (JNIEnv *env, jclass clazz, jlong config) {
-
- int r = serial_cancel_read((struct serial_config*) config);
- if (r < 0) {
- check(env, r);
- }
-
+JNIEXPORT void JNICALL Java_ch_jodersky_flow_UnsafeSerial_cancelRead
+(JNIEnv *env, jobject instance)
+{
+ int r = serial_cancel_read(get_config(env, instance));
+ if (r < 0) {
+ check(env, r);
+ }
}
/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: writeDirect
- * Signature: (JLjava/nio/ByteBuffer;I)I
- */
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_writeDirect
- (JNIEnv *env, jclass clazz, jlong config, jobject buffer, jint size) {
-
- char* local_buffer = (char *) (*env)->GetDirectBufferAddress(env, buffer);
- if (local_buffer == NULL) {
- throwException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
- return -1;
- }
-
- int r = serial_write((struct serial_config*) config, local_buffer, (size_t) size);
- if (r < 0) {
- check(env, r);
- return -1;
- }
- return r;
-
-}
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
+ * Class: ch_jodersky_flow_UnsafeSerial
* Method: write
- * Signature: (J[BI)I
+ * Signature: (Ljava/nio/ByteBuffer;I)I
*/
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_write
- (JNIEnv *env, jclass clazz, jlong config, jbyteArray buffer, jint size) {
-
- char* local_buffer = (char*) (*env)->GetByteArrayElements(env, buffer, NULL);
- int r = serial_write((struct serial_config*) config, local_buffer, size);
- (*env)->ReleaseByteArrayElements(env, buffer, (signed char*) local_buffer, JNI_ABORT);
- if (r < 0) {
- check(env, r);
- return -1;
- }
- return r;
-
+JNIEXPORT jint JNICALL Java_ch_jodersky_flow_UnsafeSerial_write
+(JNIEnv *env, jobject instance, jobject buffer, jint size)
+{
+
+ char* local_buffer = (char *) (*env)->GetDirectBufferAddress(env, buffer);
+ if (local_buffer == NULL) {
+ throwException(env, "java/lang/IllegalArgumentException", "buffer is not direct");
+ return -E_IO;
+ }
+
+ int r = serial_write(get_config(env, instance), local_buffer, (size_t) size);
+ if (r < 0) {
+ check(env, r);
+ return -E_IO;
+ }
+ return r;
}
/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
+ * Class: ch_jodersky_flow_UnsafeSerial
* Method: close
- * Signature: (J)V
+ * Signature: ()V
*/
-JNIEXPORT void JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_close
- (JNIEnv *env, jclass clazz, jlong config) {
- int r = serial_close((struct serial_config*) config);
- if (r < 0) {
- check(env, r);
- }
+JNIEXPORT void JNICALL Java_ch_jodersky_flow_UnsafeSerial_close
+(JNIEnv *env, jobject instance)
+{
+ int r = serial_close(get_config(env, instance));
+ if (r < 0) {
+ check(env, r);
+ }
}
/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
+ * Class: ch_jodersky_flow_UnsafeSerial__
* Method: debug
* Signature: (Z)V
*/
-JNIEXPORT void JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_debug
- (JNIEnv *env, jclass clazz, jboolean value) {
- serial_debug((bool) value);
-} \ No newline at end of file
+JNIEXPORT void JNICALL Java_ch_jodersky_flow_UnsafeSerial_00024_debug
+(JNIEnv *env, jobject instance, jboolean value)
+{
+ UNUSED_ARG(env);
+ UNUSED_ARG(instance);
+
+ serial_debug((bool) value);
+}
diff --git a/flow-native/src/include/ch_jodersky_flow_UnsafeSerial.h b/flow-native/src/include/ch_jodersky_flow_UnsafeSerial.h
new file mode 100644
index 0000000..f80ada0
--- /dev/null
+++ b/flow-native/src/include/ch_jodersky_flow_UnsafeSerial.h
@@ -0,0 +1,45 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class ch_jodersky_flow_UnsafeSerial */
+
+#ifndef _Included_ch_jodersky_flow_UnsafeSerial
+#define _Included_ch_jodersky_flow_UnsafeSerial
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: ch_jodersky_flow_UnsafeSerial
+ * Method: read
+ * Signature: (Ljava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL Java_ch_jodersky_flow_UnsafeSerial_read
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: ch_jodersky_flow_UnsafeSerial
+ * Method: cancelRead
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_ch_jodersky_flow_UnsafeSerial_cancelRead
+ (JNIEnv *, jobject);
+
+/*
+ * Class: ch_jodersky_flow_UnsafeSerial
+ * Method: write
+ * Signature: (Ljava/nio/ByteBuffer;I)I
+ */
+JNIEXPORT jint JNICALL Java_ch_jodersky_flow_UnsafeSerial_write
+ (JNIEnv *, jobject, jobject, jint);
+
+/*
+ * Class: ch_jodersky_flow_UnsafeSerial
+ * Method: close
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_ch_jodersky_flow_UnsafeSerial_close
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/flow-native/src/include/ch_jodersky_flow_UnsafeSerial__.h b/flow-native/src/include/ch_jodersky_flow_UnsafeSerial__.h
new file mode 100644
index 0000000..617875f
--- /dev/null
+++ b/flow-native/src/include/ch_jodersky_flow_UnsafeSerial__.h
@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class ch_jodersky_flow_UnsafeSerial__ */
+
+#ifndef _Included_ch_jodersky_flow_UnsafeSerial__
+#define _Included_ch_jodersky_flow_UnsafeSerial__
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: ch_jodersky_flow_UnsafeSerial__
+ * Method: open
+ * Signature: (Ljava/lang/String;IIZI)J
+ */
+JNIEXPORT jlong JNICALL Java_ch_jodersky_flow_UnsafeSerial_00024_open
+ (JNIEnv *, jobject, jstring, jint, jint, jboolean, jint);
+
+/*
+ * Class: ch_jodersky_flow_UnsafeSerial__
+ * Method: debug
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL Java_ch_jodersky_flow_UnsafeSerial_00024_debug
+ (JNIEnv *, jobject, jboolean);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/flow-native/src/include/com_github_jodersky_flow_internal_NativeSerial.h b/flow-native/src/include/com_github_jodersky_flow_internal_NativeSerial.h
deleted file mode 100644
index 04364fb..0000000
--- a/flow-native/src/include/com_github_jodersky_flow_internal_NativeSerial.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class com_github_jodersky_flow_internal_NativeSerial */
-
-#ifndef _Included_com_github_jodersky_flow_internal_NativeSerial
-#define _Included_com_github_jodersky_flow_internal_NativeSerial
-#ifdef __cplusplus
-extern "C" {
-#endif
-#undef com_github_jodersky_flow_internal_NativeSerial_PARITY_NONE
-#define com_github_jodersky_flow_internal_NativeSerial_PARITY_NONE 0L
-#undef com_github_jodersky_flow_internal_NativeSerial_PARITY_ODD
-#define com_github_jodersky_flow_internal_NativeSerial_PARITY_ODD 1L
-#undef com_github_jodersky_flow_internal_NativeSerial_PARITY_EVEN
-#define com_github_jodersky_flow_internal_NativeSerial_PARITY_EVEN 2L
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: open
- * Signature: (Ljava/lang/String;IIZI)J
- */
-JNIEXPORT jlong JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_open
- (JNIEnv *, jclass, jstring, jint, jint, jboolean, jint);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: readDirect
- * Signature: (JLjava/nio/ByteBuffer;)I
- */
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_readDirect
- (JNIEnv *, jclass, jlong, jobject);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: read
- * Signature: (J[B)I
- */
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_read
- (JNIEnv *, jclass, jlong, jbyteArray);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: cancelRead
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_cancelRead
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: writeDirect
- * Signature: (JLjava/nio/ByteBuffer;I)I
- */
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_writeDirect
- (JNIEnv *, jclass, jlong, jobject, jint);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: write
- * Signature: (J[BI)I
- */
-JNIEXPORT jint JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_write
- (JNIEnv *, jclass, jlong, jbyteArray, jint);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: close
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_close
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: com_github_jodersky_flow_internal_NativeSerial
- * Method: debug
- * Signature: (Z)V
- */
-JNIEXPORT void JNICALL Java_com_github_jodersky_flow_internal_NativeSerial_debug
- (JNIEnv *, jclass, jboolean);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/flow-native/src/include/flow.h b/flow-native/src/include/flow.h
index 44e2a47..e3f33b9 100644
--- a/flow-native/src/include/flow.h
+++ b/flow-native/src/include/flow.h
@@ -8,22 +8,25 @@ extern "C" {
#include <stdbool.h>
#include <stddef.h>
-//general error codes that are returned by functions
-#define E_IO -1 //IO error
-#define E_ACCESS_DENIED -2 //access denied
-#define E_BUSY -3 // port is busy
-#define E_INVALID_SETTINGS -4 // some port settings are invalid
-#define E_INTERRUPT -5 // not really an error, function call aborted because port is closed
-#define E_NO_PORT -6 //requested port does not exist
+// general error codes, whose that are returned by functions
+#define E_IO 1 // IO error
+#define E_ACCESS_DENIED 2 // access denied
+#define E_BUSY 3 // port is busy
+#define E_INVALID_SETTINGS 4 // some port settings are invalid
+#define E_INTERRUPT 5 // not really an error, function call aborted because port is closed
+#define E_NO_PORT 6 // requested port does not exist
#define PARITY_NONE 0
#define PARITY_ODD 1
#define PARITY_EVEN 2
-/** Contains internal configuration of an open serial port. */
+/**
+ * Contains internal configuration of an open serial port.
+ */
struct serial_config;
-/**Opens a serial port and allocates memory for storing configuration. Note: if this function fails,
+/**
+ * Opens a serial port and allocates memory for storing configuration. Note: if this function fails,
* any internally allocated resources will be freed.
* @param port_name name of port
* @param baud baud rate
@@ -32,59 +35,69 @@ struct serial_config;
* @param parity kind of parity checking to use
* @param serial pointer to memory that will be allocated with a serial structure
* @return 0 on success
- * @return E_NO_PORT if the given port does not exist
- * @return E_ACCESS_DENIED if permissions are not sufficient to open port
- * @return E_BUSY if port is already in use
- * @return E_INVALID_SETTINGS if any of the specified settings are invalid
- * @return E_IO on other error */
+ * @return -E_NO_PORT if the given port does not exist
+ * @return -E_ACCESS_DENIED if permissions are not sufficient to open port
+ * @return -E_BUSY if port is already in use
+ * @return -E_INVALID_SETTINGS if any of the specified settings are invalid
+ * @return -E_IO on other error
+ */
int serial_open(
- const char* port_name,
- int baud,
- int char_size,
- bool two_stop_bits,
- int parity,
- struct serial_config** const serial);
+ const char* port_name,
+ int baud,
+ int char_size,
+ bool two_stop_bits,
+ int parity,
+ struct serial_config** const serial);
-/**Closes a previously opened serial port and frees memory containing the configuration. Note: after a call to
+/**
+ * Closes a previously opened serial port and frees memory containing the configuration. Note: after a call to
* this function, the 'serial' pointer will become invalid, make sure you only call it once. This function is NOT
- * thread safe, make sure no read or write is in prgress when this function is called (the reason is that per
- * close manual page, close should not be called on a file descriptor that is in use by another thread).
+ * thread safe, make sure no read or write is in prgress when this function is called (the reason is that per
+ * close manual page, close should not be called on a file descriptor that is in use by another thread).
* @param serial pointer to serial configuration that is to be closed (and freed)
* @return 0 on success
- * @return E_IO on error */
+ * @return -E_IO on error
+ */
int serial_close(struct serial_config* const serial);
-/**Starts a read from a previously opened serial port. The read is blocking, however it may be
+/**
+ * Starts a read from a previously opened serial port. The read is blocking, however it may be
* interrupted by calling 'serial_cancel_read' on the given serial port.
* @param serial pointer to serial configuration from which to read
* @param buffer buffer into which data is read
* @param size maximum buffer size
* @return n>0 the number of bytes read into buffer
- * @return E_INTERRUPT if the call to this function was interrupted
- * @return E_IO on IO error */
+ * @return -E_INTERRUPT if the call to this function was interrupted
+ * @return -E_IO on IO error
+ */
int serial_read(struct serial_config* const serial, char* const buffer, size_t size);
-/**Cancels a blocked read call. This function is thread safe, i.e. it may be called from a thread even
+/**
+ * Cancels a blocked read call. This function is thread safe, i.e. it may be called from a thread even
* while another thread is blocked in a read call.
* @param serial_config the serial port to interrupt
* @return 0 on success
- * @return E_IO on error */
+ * @return -E_IO on error
+ */
int serial_cancel_read(struct serial_config* const serial);
-/**Writes data to a previously opened serial port. Non bocking.
+/**
+ * Writes data to a previously opened serial port. Non bocking.
* @param serial pointer to serial configuration to which to write
* @param data data to write
* @param size number of bytes to write from data
* @return n>0 the number of bytes written
- * @return E_IO on IO error */
+ * @return -E_IO on IO error
+ */
int serial_write(struct serial_config* const serial, char* const data, size_t size);
-/**Sets debugging option. If debugging is enabled, detailed error message are printed from method calls. */
+/**
+ * Sets debugging option. If debugging is enabled, detailed error message are printed from method calls.
+ */
void serial_debug(bool value);
#ifdef __cplusplus
}
#endif
-
#endif /* FLOW_H */
diff --git a/flow-native/src/platform/posix/flow.c b/flow-native/src/platform/posix/flow.c
index a2a239c..969949b 100644
--- a/flow-native/src/platform/posix/flow.c
+++ b/flow-native/src/platform/posix/flow.c
@@ -5,64 +5,77 @@
#include <termios.h>
#include <fcntl.h>
#include <sys/file.h>
+#include <sys/select.h>
#include "flow.h"
-
#define DATA_CANCEL 0xffffffff
static bool debug = false;
-#define DEBUG(f) if (debug) {f}
-void serial_debug(bool value) {
- debug = value;
+static void print_debug(const char* const msg, int en)
+{
+ if (debug) {
+ if (errno == 0) {
+ fprintf(stderr, "%s", msg);
+ } else {
+ fprintf(stderr, "%s: %d\n", msg, en);
+ }
+ fflush(stderr);
+ }
+}
+
+void serial_debug(bool value)
+{
+ debug = value;
}
//contains file descriptors used in managing a serial port
struct serial_config {
- int port_fd; // file descriptor of serial port
+ int port_fd; // file descriptor of serial port
- /* a pipe is used to abort a serial read by writing something into the
- * write end of the pipe */
- int pipe_read_fd; // file descriptor, read end of pipe
- int pipe_write_fd; // file descriptor, write end of pipe
+ /* a pipe is used to abort a serial read by writing something into the
+ * write end of the pipe */
+ int pipe_read_fd; // file descriptor, read end of pipe
+ int pipe_write_fd; // file descriptor, write end of pipe
};
int serial_open(
- const char* const port_name,
- int baud,
- int char_size,
- bool two_stop_bits,
- int parity,
- struct serial_config** serial) {
-
- int fd = open(port_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
-
- if (fd < 0) {
- int en = errno;
- DEBUG(perror("error obtaining port file descriptor"););
- if (en == EACCES) return E_ACCESS_DENIED;
- if (en == ENOENT) return E_NO_PORT;
- return E_IO;
- }
-
- if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
- DEBUG(perror("error acquiring lock on port"););
- close(fd);
- return E_BUSY;
- }
-
- /* configure new port settings */
- struct termios newtio;
-
- /* initialize serial interface */
- newtio.c_iflag = 0;
- newtio.c_oflag = 0;
- newtio.c_lflag = 0;
- newtio.c_cflag = CREAD;
-
- /* set speed */
- speed_t bd;
- switch (baud) {
+ const char* const port_name,
+ int baud,
+ int char_size,
+ bool two_stop_bits,
+ int parity,
+ struct serial_config** serial)
+{
+
+ int fd = open(port_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
+
+ if (fd < 0) {
+ int en = errno;
+ print_debug("Error obtaining file descriptor for port", en);
+ if (en == EACCES) return -E_ACCESS_DENIED;
+ if (en == ENOENT) return -E_NO_PORT;
+ return -E_IO;
+ }
+
+ if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
+ print_debug("Error acquiring lock on port", errno);
+ close(fd);
+ return -E_BUSY;
+ }
+
+ /* configure new port settings */
+ struct termios newtio;
+
+ /* initialize serial interface */
+ newtio.c_iflag = 0;
+ newtio.c_oflag = 0;
+ newtio.c_lflag = 0;
+ newtio.c_cflag = CREAD;
+
+ /* set speed */
+ speed_t bd;
+ switch (baud) {
case 50: bd = B50; break;
case 75: bd = B75; break;
case 110: bd = B110; break;
@@ -82,166 +95,169 @@ int serial_open(
case 115200: bd = B115200; break;
case 230400: bd = B230400; break;
default:
- close(fd);
- DEBUG(fprintf(stderr, "invalid baud rate %d\n", baud););
- return E_INVALID_SETTINGS;
- }
-
- if (cfsetspeed(&newtio, bd) < 0) {
- DEBUG(perror("error setting baud rate"););
- close(fd);
- return E_IO;
- }
-
- /* set char size*/
- switch (char_size) {
+ close(fd);
+ print_debug("Invalid baud rate", 0);
+ return -E_INVALID_SETTINGS;
+ }
+
+ if (cfsetspeed(&newtio, bd) < 0) {
+ print_debug("Error setting baud rate", errno);
+ close(fd);
+ return -E_IO;
+ }
+
+ /* set char size*/
+ switch (char_size) {
case 5: newtio.c_cflag |= CS5; break;
case 6: newtio.c_cflag |= CS6; break;
case 7: newtio.c_cflag |= CS7; break;
case 8: newtio.c_cflag |= CS8; break;
default:
- close(fd);
- DEBUG(fprintf(stderr, "invalid character size %d\n", char_size););
- return E_INVALID_SETTINGS;
- }
-
- /* use two stop bits */
- if (two_stop_bits){
- newtio.c_cflag |= CSTOPB;
- }
-
- /* set parity */
- switch (parity) {
+ close(fd);
+ print_debug("Invalid character size", 0);
+ return -E_INVALID_SETTINGS;
+ }
+
+ /* use two stop bits */
+ if (two_stop_bits){
+ newtio.c_cflag |= CSTOPB;
+ }
+
+ /* set parity */
+ switch (parity) {
case PARITY_NONE: break;
case PARITY_ODD: newtio.c_cflag |= (PARENB | PARODD); break;
case PARITY_EVEN: newtio.c_cflag |= PARENB; break;
default:
- close(fd);
- DEBUG(fprintf(stderr, "invalid parity %d\n", parity););
- return E_INVALID_SETTINGS;
- }
-
- if (tcflush(fd, TCIOFLUSH) < 0) {
- DEBUG(perror("error flushing serial settings"););
- close(fd);
- return E_IO;
- }
-
- if (tcsetattr(fd, TCSANOW, &newtio) < 0) {
- DEBUG(perror("error applying serial settings"););
- close(fd);
- return E_IO;
- }
-
- int pipe_fd[2];
- if (pipe(pipe_fd) < 0) {
- DEBUG(perror("error opening pipe"););
- close(fd);
- return E_IO;
- }
-
- if (fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK) < 0 || fcntl(pipe_fd[1], F_SETFL, O_NONBLOCK) < 0) {
- DEBUG(perror("error setting pipe to non-blocking"););
- close(fd);
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- return E_IO;
- }
-
- struct serial_config* s = malloc(sizeof(s));
- if (s == NULL) {
- DEBUG(perror("error allocating memory for serial configuration"););
- close(fd);
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- return E_IO;
- }
-
- s->port_fd = fd;
- s->pipe_read_fd = pipe_fd[0];
- s->pipe_write_fd = pipe_fd[1];
- (*serial) = s;
-
- return 0;
+ close(fd);
+ print_debug("Invalid parity", 0);
+ return -E_INVALID_SETTINGS;
+ }
+
+ if (tcflush(fd, TCIOFLUSH) < 0) {
+ print_debug("Error flushing serial settings", errno);
+ close(fd);
+ return -E_IO;
+ }
+
+ if (tcsetattr(fd, TCSANOW, &newtio) < 0) {
+ print_debug("Error applying serial settings", errno);
+ close(fd);
+ return -E_IO;
+ }
+
+ int pipe_fd[2];
+ if (pipe(pipe_fd) < 0) {
+ print_debug("Error opening pipe", errno);
+ close(fd);
+ return -E_IO;
+ }
+
+ if (fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK) < 0 || fcntl(pipe_fd[1], F_SETFL, O_NONBLOCK) < 0) {
+ print_debug("Error setting pipe to non-blocking", errno);
+ close(fd);
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return -E_IO;
+ }
+
+ struct serial_config* s = malloc(sizeof(s));
+ if (s == NULL) {
+ print_debug("Error allocating memory for serial configuration", errno);
+ close(fd);
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return -E_IO;
+ }
+
+ s->port_fd = fd;
+ s->pipe_read_fd = pipe_fd[0];
+ s->pipe_write_fd = pipe_fd[1];
+ (*serial) = s;
+
+ return 0;
}
+int serial_close(struct serial_config* const serial)
+{
+ if (close(serial->pipe_write_fd) < 0) {
+ print_debug("Error closing write end of pipe", errno);
+ return -E_IO;
+ }
+ if (close(serial->pipe_read_fd) < 0) {
+ print_debug("Error closing read end of pipe", errno);
+ return -E_IO;
+ }
+
+ if (flock(serial->port_fd, LOCK_UN) < 0){
+ print_debug("Error releasing lock on port", errno);
+ return -E_IO;
+ }
+ if (close(serial->port_fd) < 0) {
+ print_debug("Error closing port", errno);
+ return -E_IO;
+ }
-int serial_close(struct serial_config* const serial) {
- if (close(serial->pipe_write_fd) < 0) {
- DEBUG(perror("error closing write end of pipe"););
- return E_IO;
- }
- if (close(serial->pipe_read_fd) < 0) {
- DEBUG(perror("error closing read end of pipe"););
- return E_IO;
- }
-
- if (flock(serial->port_fd, LOCK_UN) < 0){
- DEBUG(perror("error releasing lock on port"););
- return E_IO;
- }
- if (close(serial->port_fd) < 0) {
- DEBUG(perror("error closing port"););
- return E_IO;
- }
-
- free(serial);
- return 0;
+ free(serial);
+ return 0;
}
-int serial_read(struct serial_config* const serial, char* const buffer, size_t size) {
- int port = serial->port_fd;
- int pipe = serial->pipe_read_fd;
-
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(port, &rfds);
- FD_SET(pipe, &rfds);
-
- int nfds = pipe + 1;
- if (pipe < port) nfds = port + 1;
-
- int n = select(nfds, &rfds, NULL, NULL, NULL);
- if (n < 0) {
- DEBUG(perror("error trying to call select on port and pipe"););
- return E_IO;
- }
-
- if (FD_ISSET(pipe, &rfds)) {
- return E_INTERRUPT;
- } else if (FD_ISSET(port, &rfds)) {
- int r = read(port, buffer, size);
-
- //treat 0 bytes read as an error to avoid problems on disconnect
- //anyway, after a poll there should be more than 0 bytes available to read
- if (r <= 0) {
- DEBUG(perror("error data not available after select"););
- return E_IO;
- }
- return r;
- } else {
- fprintf(stderr, "select returned unknown read sets\n");
- return E_IO;
- }
+int serial_read(struct serial_config* const serial, char* const buffer, size_t size)
+{
+ int port = serial->port_fd;
+ int pipe = serial->pipe_read_fd;
+
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(port, &rfds);
+ FD_SET(pipe, &rfds);
+
+ int nfds = pipe + 1;
+ if (pipe < port) nfds = port + 1;
+
+ int n = select(nfds, &rfds, NULL, NULL, NULL);
+ if (n < 0) {
+ print_debug("Error trying to call select on port and pipe", errno);
+ return -E_IO;
+ }
+
+ if (FD_ISSET(pipe, &rfds)) {
+ return -E_INTERRUPT;
+ } else if (FD_ISSET(port, &rfds)) {
+ int r = read(port, buffer, size);
+
+ // treat 0 bytes read as an error to avoid problems on disconnect
+ // anyway, after a poll there should be more than 0 bytes available to read
+ if (r <= 0) {
+ print_debug("Error data not available after select", errno);
+ return -E_IO;
+ }
+ return r;
+ } else {
+ print_debug("Select returned unknown read sets", 0);
+ return -E_IO;
+ }
}
-int serial_cancel_read(struct serial_config* const serial) {
- int data = DATA_CANCEL;
-
- //write to pipe to wake up any blocked read thread (self-pipe trick)
- if (write(serial->pipe_write_fd, &data, 1) < 0) {
- DEBUG(perror("error writing to pipe during read cancel"););
- return E_IO;
- }
-
- return 0;
+int serial_cancel_read(struct serial_config* const serial)
+{
+ int data = DATA_CANCEL;
+
+ //write to pipe to wake up any blocked read thread (self-pipe trick)
+ if (write(serial->pipe_write_fd, &data, 1) < 0) {
+ print_debug("Error writing to pipe during read cancel", errno);
+ return -E_IO;
+ }
+
+ return 0;
}
-int serial_write(struct serial_config* const serial, char* const data, size_t size) {
- int r = write(serial->port_fd, data, size);
- if (r < 0) {
- DEBUG(perror("error writing to port"););
- return E_IO;
- }
- return r;
-} \ No newline at end of file
+int serial_write(struct serial_config* const serial, char* const data, size_t size)
+{
+ int r = write(serial->port_fd, data, size);
+ if (r < 0) {
+ print_debug("Error writing to port", errno);
+ return -E_IO;
+ }
+ return r;
+}