aboutsummaryrefslogtreecommitdiff
path: root/flow
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2015-05-06 10:51:29 +0200
committerJakob Odersky <jodersky@gmail.com>2015-05-06 12:13:11 +0200
commit5e611b35a891ab35d15a5eb8fcb8fcee6de1bb08 (patch)
treeaf3d48f72ac401fae995b8c9e31f4c96c038c7b2 /flow
parent8a5734ed1bf73838a274409a929d1728bbd8cd40 (diff)
downloadakka-serial-5e611b35a891ab35d15a5eb8fcb8fcee6de1bb08.tar.gz
akka-serial-5e611b35a891ab35d15a5eb8fcb8fcee6de1bb08.tar.bz2
akka-serial-5e611b35a891ab35d15a5eb8fcb8fcee6de1bb08.zip
refactor build
Diffstat (limited to 'flow')
-rw-r--r--flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java145
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/Parity.scala9
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/Serial.scala93
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/SerialExt.scala10
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/SerialManager.scala48
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala68
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/SerialSettings.scala10
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/exceptions.scala19
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala58
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/internal/Reader.scala40
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/internal/ReaderDied.scala3
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/internal/SerialConnection.scala157
12 files changed, 0 insertions, 660 deletions
diff --git a/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java b/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java
deleted file mode 100644
index c159058..0000000
--- a/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.github.jodersky.flow.internal;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import com.github.jodersky.flow.AccessDeniedException;
-import com.github.jodersky.flow.InvalidSettingsException;
-import com.github.jodersky.flow.NoSuchPortException;
-import com.github.jodersky.flow.PortInUseException;
-import com.github.jodersky.flow.PortInterruptedException;
-
-/**
- * Low-level wrapper on top of native serial backend.
- *
- * WARNING: Methods in this class allocate native structures and deal with pointers.
- * These pointers are handled as longs by java and are NOT checked for correctness,
- * therefore passing invalid pointers may have unexpected results, including but not
- * limited to crashing the VM.
- *
- * See SerialConnection for a higher level, more secured wrapper
- * of serial communication.
- *
- * @see com.github.jodersky.flow.internal.SerialConnection
- */
-final class NativeSerial {
-
- static {
- NativeLoader.load("flow3");
- }
-
- final static int PARITY_NONE = 0;
- final static int PARITY_ODD = 1;
- final static int PARITY_EVEN = 2;
-
- /**
- * Opens a serial port.
- *
- * @param port name of serial port to open
- * @param characterSize size of a character of the data sent through the serial port
- * @param twoStopBits set to use two stop bits instead of one
- * @param parity type of parity to use with serial port
- * @return address of natively allocated serial configuration structure
- * @throws NoSuchPortException if the given port does not exist
- * @throws AccessDeniedException if permissions of the current user are not sufficient to open port
- * @throws PortInUseException if port is already in use
- * @throws InvalidSettingsException if any of the specified settings are invalid
- * @throws IOException on IO error
- */
- native static long open(String port, int baud, int characterSize, boolean twoStopBits, int parity)
- throws NoSuchPortException, AccessDeniedException, PortInUseException, InvalidSettingsException, IOException;
-
- /**
- * Reads from a previously opened serial port into a direct ByteBuffer. Note that data is only read into the
- * buffer's allocated memory, its position or limit are not changed.
- *
- * The read is blocking, however it may be interrupted by calling cancelRead() on the given serial port.
- *
- * @param serial address of natively allocated serial configuration structure
- * @param buffer direct ByteBuffer to read into
- * @return number of bytes actually read
- * @throws IllegalArgumentException if the ByteBuffer is not direct
- * @throws PortInterruptedException if the call to this function was interrupted
- * @throws IOException on IO error
- */
- native static int readDirect(long serial, ByteBuffer buffer)
- throws IllegalArgumentException, PortInterruptedException, IOException;
-
- /**
- * Reads data from a previously opened serial port into an array.
- *
- * The read is blocking, however it may be interrupted by calling cancelRead() on the given serial port.
- *
- * @param serial address of natively allocated serial configuration structure
- * @param buffer array to read data into
- * @return number of bytes actually read
- * @throws PortInterruptedException if the call to this function was interrupted
- * @throws IOException on IO error
- */
- native static int read(long serial, byte[] buffer)
- throws PortInterruptedException, IOException;
-
- /**
- * Cancels a read (any caller to read or readDirect will return with a PortInterruptedException). This function may be called from any thread.
- *
- * @param serial address of natively allocated serial configuration structure
- * @throws IOException on IO error
- */
- native static void cancelRead(long serial)
- throws IOException;
-
- /**
- * Writes data from a direct ByteBuffer to a previously opened serial port. Note that data is only taken from
- * the buffer's allocated memory, its position or limit are not changed.
- *
- * The write is non-blocking, this function returns as soon as the data is copied into the kernel's
- * transmission buffer.
- *
- * @param serial address of natively allocated serial configuration structure
- * @param buffer direct ByteBuffer from which data is taken
- * @param length actual amount of data that should be taken from the buffer (this is needed since the native
- * backend does not provide a way to query the buffer's current limit)
- * @return number of bytes actually written
- * @throws IllegalArgumentException if the ByteBuffer is not direct
- * @throws IOException on IO error
- */
- native static int writeDirect(long serial, ByteBuffer buffer, int length)
- throws IllegalArgumentException, IOException;
-
- /**
- * Writes data from an array to a previously opened serial port.
- *
- * The write is non-blocking, this function returns as soon as the data is copied into the kernel's
- * transmission buffer.
- *
- * @param serial address of natively allocated serial configuration structure
- * @param buffer array from which data is taken
- * @param length actual amount of data that should be taken from the buffer
- * @return number of bytes actually written
- * @throws IOException on IO error
- */
- native static int write(long serial, byte[] buffer, int length)
- throws IOException;
-
- /**
- * Closes an previously open serial port. Natively allocated resources are freed and the serial pointer becomes invalid,
- * therefore this function should only be called ONCE per open serial port.
- *
- * A port should not be closed while it is used (by a read or write) as this
- * results in undefined behaviour.
- *
- * @param serial address of natively allocated serial configuration structure
- * @throws IOException on IO error
- */
- native static void close(long serial)
- throws IOException;
-
- /**
- * Sets native debugging mode. If debugging is enabled, detailed error messages
- * are printed (to stderr) from native method calls.
- *
- * @param value set to enable debugging
- */
- native static void debug(boolean value);
-
-}
diff --git a/flow/src/main/scala/com/github/jodersky/flow/Parity.scala b/flow/src/main/scala/com/github/jodersky/flow/Parity.scala
deleted file mode 100644
index 9bf52a6..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/Parity.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.github.jodersky.flow
-
-/** Specifies available parities used in serial communication. */
-object Parity extends Enumeration {
- type Parity = Value
- val None = Value(0)
- val Odd = Value(1)
- val Even = Value(2)
-} \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/Serial.scala b/flow/src/main/scala/com/github/jodersky/flow/Serial.scala
deleted file mode 100644
index b6e9d62..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/Serial.scala
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.github.jodersky.flow
-
-import akka.actor.ExtensionKey
-import akka.util.ByteString
-
-/** Defines messages used by flow's serial IO layer. */
-object Serial extends ExtensionKey[SerialExt] {
-
- /** Base trait for any flow-related messages. */
- sealed trait Message
-
- /** A message extending this trait is to be viewed as a command, an out-bound message issued by the client to flow's API. */
- trait Command extends Message
-
- /** A message extending this trait is to be viewed as an event, an in-bound message issued by flow to the client. */
- trait Event extends Message
-
- /** A command has failed. */
- case class CommandFailed(command: Command, reason: Throwable) extends Event
-
- /**
- * Open a new serial port.
- *
- * Send this command to the serial manager to request the opening of a serial port. The manager will
- * attempt to open a serial port with the specified parameters and, if successful, create a `SerialOperator` actor associated to the port.
- * The operator actor acts as an intermediate to the underlying native serial port, dealing with threading issues and dispatching messages.
- *
- * In case the port is successfully opened, the operator will respond with an `Opened` message.
- * In case the port cannot be opened, the manager will respond with a `CommandFailed` message.
- *
- * @param port name of serial port to open
- * @param settings settings of serial port to open
- * @param bufferSize maximum read and write buffer sizes
- */
- case class Open(port: String, settings: SerialSettings, bufferSize: Int = 1024) extends Command
-
- /**
- * A port has been successfully opened.
- *
- * Event sent by a port operator, indicating that a serial port was successfully opened. The sender
- * of this message is the operator associated to the given serial port.
- *
- * @param port name of opened serial port
- */
- case class Opened(port: String) extends Event
-
- /**
- * Data has been received.
- *
- * Event sent by an operator, indicating that data was received on the operator's serial port.
- *
- * @param data data received on the port
- */
- case class Received(data: ByteString) extends Event
-
- /**
- * Write data to a serial port.
- *
- * Send this command to an operator to write the given data to its associated serial port.
- * An acknowledgment may be set, in which case it is sent back to the sender on a successful write.
- * Note that a successful write does not guarantee the actual transmission of data through the serial port,
- * it merely guarantees that the data has been stored in the operating system's kernel buffer, ready to
- * be transmitted.
- *
- * @param data data to be written to port
- * @param ack acknowledgment sent back to sender once data has been enqueued in kernel for sending (the acknowledgment
- * is a function 'number of bytes written => event')
- */
- case class Write(data: ByteString, ack: Int => Event = NoAck) extends Command
-
- /**
- * Special type of acknowledgment that is not sent back.
- */
- case object NoAck extends Function1[Int, Event] {
- def apply(length: Int) = sys.error("cannot apply NoAck")
- }
-
- /**
- * Request closing of port.
- *
- * Send this command to an operator to close its associated port. The operator will respond
- * with a `Closed` message upon closing the serial port.
- */
- case object Close extends Command
-
- /**
- * A port has been closed.
- *
- * Event sent from operator, indicating that its port has been closed.
- */
- case object Closed extends Event
-
-}
diff --git a/flow/src/main/scala/com/github/jodersky/flow/SerialExt.scala b/flow/src/main/scala/com/github/jodersky/flow/SerialExt.scala
deleted file mode 100644
index 38e140a..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/SerialExt.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.github.jodersky.flow
-
-import akka.actor.ExtendedActorSystem
-import akka.actor.Props
-import akka.io.IO
-
-/** Provides the serial IO manager. */
-class SerialExt(system: ExtendedActorSystem) extends IO.Extension {
- lazy val manager = system.systemActorOf(Props(classOf[SerialManager]), name = "IO-SERIAL")
-} \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/SerialManager.scala b/flow/src/main/scala/com/github/jodersky/flow/SerialManager.scala
deleted file mode 100644
index eb8c44e..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/SerialManager.scala
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.github.jodersky.flow
-
-import scala.util.Failure
-import scala.util.Success
-import scala.util.Try
-
-import com.github.jodersky.flow.internal.SerialConnection
-
-import Serial.CommandFailed
-import Serial.Open
-import akka.actor.Actor
-import akka.actor.ActorLogging
-import akka.actor.OneForOneStrategy
-import akka.actor.SupervisorStrategy.Stop
-import akka.actor.actorRef2Scala
-
-/**
- * Entry point to the serial API. Actor that manages serial port creation. Once opened, a serial port is handed over to
- * a dedicated operator actor that acts as an intermediate between client code and the native system serial port.
- * @see SerialOperator
- */
-class SerialManager extends Actor with ActorLogging {
- import SerialManager._
- import context._
-
- override val supervisorStrategy = OneForOneStrategy() {
- case _: Exception => Stop
- }
-
- def receive = {
- case open @ Open(port, settings, bufferSize) => Try {
- SerialConnection.open(port, settings)
- } match {
- case Success(connection) => context.actorOf(SerialOperator(connection, bufferSize, sender), name = escapePortString(connection.port))
- case Failure(err) => sender ! CommandFailed(open, err)
- }
- }
-
-}
-
-object SerialManager {
-
- private def escapePortString(port: String) = port collect {
- case '/' => '-'
- case c => c
- }
-
-} \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala b/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala
deleted file mode 100644
index 5524125..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.github.jodersky.flow
-
-import java.nio.ByteBuffer
-
-import com.github.jodersky.flow.internal.Reader
-import com.github.jodersky.flow.internal.ReaderDied
-import com.github.jodersky.flow.internal.SerialConnection
-
-import Serial.Close
-import Serial.Closed
-import Serial.NoAck
-import Serial.Opened
-import Serial.Write
-import akka.actor.Actor
-import akka.actor.ActorLogging
-import akka.actor.ActorRef
-import akka.actor.Props
-import akka.actor.Terminated
-import akka.actor.actorRef2Scala
-
-/**
- * Operator associated to an open serial port. All communication with a port is done via an operator. Operators are created though the serial manager.
- * @see SerialManager
- */
-class SerialOperator(connection: SerialConnection, bufferSize: Int, client: ActorRef) extends Actor with ActorLogging {
- import SerialOperator._
- import context._
-
- val readBuffer = ByteBuffer.allocateDirect(bufferSize)
- val reader = new Reader(connection, readBuffer, self, client)
- val writeBuffer = ByteBuffer.allocateDirect(bufferSize)
-
- context.watch(client)
- client ! Opened(connection.port)
- reader.start()
-
- override def postStop = {
- connection.close()
- }
-
- def receive: Receive = {
-
- case Write(data, ack) => {
- writeBuffer.clear()
- data.copyToBuffer(writeBuffer)
- val sent = connection.write(writeBuffer)
- if (ack != NoAck) sender ! ack(sent)
- }
-
- case Close => {
- client ! Closed
- context stop self
- }
-
- case Terminated(`client`) => {
- context stop self
- }
-
- //go down with reader thread
- case ReaderDied(ex) => throw ex
-
- }
-
-}
-
-object SerialOperator {
- def apply(connection: SerialConnection, bufferSize: Int, client: ActorRef) = Props(classOf[SerialOperator], connection, bufferSize, client)
-} \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/SerialSettings.scala b/flow/src/main/scala/com/github/jodersky/flow/SerialSettings.scala
deleted file mode 100644
index 08a5556..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/SerialSettings.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.github.jodersky.flow
-
-/**
- * Groups settings used in communication over a serial port.
- * @param baud baud rate to use with serial port
- * @param characterSize size of a character of the data sent through the serial port
- * @param twoStopBits set to use two stop bits instead of one
- * @param parity type of parity to use with serial port
- */
-case class SerialSettings(baud: Int, characterSize: Int = 8, twoStopBits: Boolean = false, parity: Parity.Parity = Parity.None) \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/exceptions.scala b/flow/src/main/scala/com/github/jodersky/flow/exceptions.scala
deleted file mode 100644
index adefcea..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/exceptions.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.github.jodersky.flow
-
-/** The requested port could not be found. */
-class NoSuchPortException(message: String) extends Exception(message)
-
-/** The requested port is in use by someone else. */
-class PortInUseException(message: String) extends Exception(message)
-
-/** Permissions are not sufficient to open a serial port. */
-class AccessDeniedException(message: String) extends Exception(message)
-
-/** The settings specified are invalid. */
-class InvalidSettingsException(message: String) extends Exception(message)
-
-/** A blocking operation on a port was interrupted, most likely indicating that the port is closing. */
-class PortInterruptedException(message: String) extends Exception(message)
-
-/** The specified port has been closed. */
-class PortClosedException(message: String) extends Exception(message) \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala b/flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala
deleted file mode 100644
index 2526293..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.github.jodersky.flow.internal
-
-import java.io.File
-import java.io.FileOutputStream
-import java.io.InputStream
-import java.io.OutputStream
-
-/** Handles loading of the current platform's native library for flow. */
-object NativeLoader {
-
- private final val BufferSize = 4096
-
- private def os = System.getProperty("os.name").toLowerCase.replaceAll("\\s", "")
-
- private def arch = System.getProperty("os.arch").toLowerCase
-
- /** Extract a resource from this class loader to a temporary file. */
- private def extract(path: String, prefix: String): Option[File] = {
- var in: Option[InputStream] = None
- var out: Option[OutputStream] = None
-
- try {
- in = Option(NativeLoader.getClass.getResourceAsStream(path))
- if (in.isEmpty) return None
-
- val file = File.createTempFile(prefix, "")
- out = Some(new FileOutputStream(file))
-
- val buffer = new Array[Byte](BufferSize)
- var length = -1;
- do {
- length = in.get.read(buffer)
- if (length != -1) out.get.write(buffer, 0, length)
- } while (length != -1)
-
- Some(file)
- } finally {
- in.foreach(_.close)
- out.foreach(_.close)
- }
- }
-
- private def loadFromJar(library: String) = {
- val fqlib = System.mapLibraryName(library) //fully qualified library name
- extract(s"/native/${os}-${arch}/${fqlib}", fqlib) match {
- case Some(file) => System.load(file.getAbsolutePath)
- case None => throw new UnsatisfiedLinkError("Cannot extract flow's native library, " +
- "the native library may not exist for your specific architecture/OS combination.")
- }
- }
-
- def load(library: String) = try {
- System.loadLibrary(library)
- } catch {
- case ex: UnsatisfiedLinkError => loadFromJar(library)
- }
-
-} \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/internal/Reader.scala b/flow/src/main/scala/com/github/jodersky/flow/internal/Reader.scala
deleted file mode 100644
index 7b3f2ef..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/internal/Reader.scala
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.github.jodersky.flow.internal
-
-import java.nio.ByteBuffer
-
-import com.github.jodersky.flow.PortInterruptedException
-import com.github.jodersky.flow.Serial.Received
-
-import akka.actor.Actor
-import akka.actor.ActorRef
-import akka.util.ByteString
-
-class Reader(serial: SerialConnection, buffer: ByteBuffer, operator: ActorRef, client: ActorRef) extends Thread {
- def readLoop() = {
- var stop = false
- while (!serial.isClosed && !stop) {
- try {
- buffer.clear()
- val length = serial.read(buffer)
- buffer.limit(length)
- val data = ByteString.fromByteBuffer(buffer)
- client.tell(Received(data), operator)
- } catch {
-
- //don't do anything if port is interrupted
- case ex: PortInterruptedException => {}
-
- //stop and tell operator on other exception
- case ex: Exception => {
- stop = true
- operator.tell(ReaderDied(ex), Actor.noSender)
- }
- }
- }
- }
-
- override def run() {
- this.setName("flow-reader " + serial.port)
- readLoop()
- }
-} \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/internal/ReaderDied.scala b/flow/src/main/scala/com/github/jodersky/flow/internal/ReaderDied.scala
deleted file mode 100644
index 7dd9954..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/internal/ReaderDied.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.github.jodersky.flow.internal
-
-case class ReaderDied(reason: Exception) \ No newline at end of file
diff --git a/flow/src/main/scala/com/github/jodersky/flow/internal/SerialConnection.scala b/flow/src/main/scala/com/github/jodersky/flow/internal/SerialConnection.scala
deleted file mode 100644
index b4242fe..0000000
--- a/flow/src/main/scala/com/github/jodersky/flow/internal/SerialConnection.scala
+++ /dev/null
@@ -1,157 +0,0 @@
-package com.github.jodersky.flow.internal
-
-import java.nio.ByteBuffer
-import java.util.concurrent.atomic.AtomicBoolean
-
-import com.github.jodersky.flow.PortClosedException
-import com.github.jodersky.flow.SerialSettings
-
-/**
- * Represents a serial connection in a more secure and object-oriented style than `NativeSerial`. In contrast
- * to the latter, this class encapsulates and secures any pointers used to communicate with the native
- * backend and is thread-safe.
- *
- * The underlying serial port is assumed open when this class is initialized.
- */
-class SerialConnection private (
- val port: String,
- val settings: SerialSettings,
- private val pointer: Long) {
-
- import SerialConnection._
-
- private var reading: Boolean = false
- private val readLock = new Object
-
- private var writing: Boolean = false
- private val writeLock = new Object
-
- private val closed = new AtomicBoolean(false)
-
- /**
- * Checks if this serial port is closed.
- */
- def isClosed = closed.get()
-
- /**
- * Closes the underlying serial connection. Any callers blocked on read or write will return.
- * A call of this method has no effect if the serial port is already closed.
- * @throws IOException on IO error
- */
- def close(): Unit = this.synchronized {
- if (!closed.get) {
- closed.set(true)
- NativeSerial.cancelRead(pointer)
- readLock.synchronized {
- while (reading) this.wait()
- }
- writeLock.synchronized {
- while (writing) this.wait()
- }
- NativeSerial.close(pointer)
- }
- }
-
- /**
- * Reads data from underlying serial connection into a ByteBuffer.
- * Note that data is read into the buffer's memory, its attributes
- * such as position and limit are not modified.
- *
- * A call to this method is blocking, however it is interrupted
- * if the connection is closed.
- *
- * This method works for direct and indirect buffers but is optimized
- * for the former.
- *
- * @param buffer a ByteBuffer into which data is read
- * @return the actual number of bytes read
- * @throws PortInterruptedException if port is closed while reading
- * @throws IOException on IO error
- */
- def read(buffer: ByteBuffer): Int = readLock.synchronized {
- if (!closed.get) {
- reading = true
- try {
- transfer(
- b => NativeSerial.readDirect(pointer, b),
- b => NativeSerial.read(pointer, b.array()))(buffer)
- } finally {
- reading = false
- if (closed.get) readLock.notify()
- }
- } else {
- throw new PortClosedException(s"port ${port} is closed")
- }
- }
-
- /**
- * Writes data from a ByteBuffer to underlying serial connection.
- * Note that data is read from the buffer's memory, its attributes
- * such as position and limit are not modified.
- *
- * The write is non-blocking, this function returns as soon as the data is copied into the kernel's
- * transmission buffer.
- *
- * This method works for direct and indirect buffers but is optimized
- * for the former.
- *
- * @param buffer a ByteBuffer from which data is taken
- * @return the actual number of bytes written
- * @throws IOException on IO error
- */
- def write(buffer: ByteBuffer): Int = writeLock.synchronized {
- if (!closed.get) {
- writing = true
- try {
- transfer(
- b => NativeSerial.writeDirect(pointer, b, b.position()),
- b => NativeSerial.write(pointer, b.array(), b.position()))(buffer)
- } finally {
- writing = false
- if (closed.get) writeLock.notify()
- }
- } else {
- throw new PortClosedException(s"port ${port} is closed")
- }
- }
-
- private def transfer[A](direct: ByteBuffer => A, indirect: ByteBuffer => A)(buffer: ByteBuffer): A = if (buffer.isDirect()) {
- direct(buffer)
- } else if (buffer.hasArray()) {
- indirect(buffer)
- } else {
- throw new IllegalArgumentException("buffer is not direct and has no array");
- }
-
-}
-
-object SerialConnection {
- import NativeSerial._
-
- /**
- * Opens a new connection to a serial port.
- * This method acts as a factory to creating serial connections.
- *
- * @param port name of serial port to open
- * @param settings settings with which to initialize the connection
- * @return an instance of the open serial connection
- * @throws NoSuchPortException if the given port does not exist
- * @throws AccessDeniedException if permissions of the current user are not sufficient to open port
- * @throws PortInUseException if port is already in use
- * @throws InvalidSettingsException if any of the specified settings are invalid
- * @throws IOException on IO error
- */
- def open(port: String, settings: SerialSettings): SerialConnection = synchronized {
- val pointer = NativeSerial.open(port, settings.baud, settings.characterSize, settings.twoStopBits, settings.parity.id)
- new SerialConnection(port, settings, pointer)
- }
-
- /**
- * Sets native debugging mode. If debugging is enabled, detailed error messages
- * are printed (to stderr) from native method calls.
- *
- * @param value set to enable debugging
- */
- def debug(value: Boolean) = NativeSerial.debug(value)
-
-} \ No newline at end of file