diff options
Diffstat (limited to 'flow-main/src/main/scala/com/github/jodersky')
7 files changed, 47 insertions, 30 deletions
diff --git a/flow-main/src/main/scala/com/github/jodersky/flow/Parity.scala b/flow-main/src/main/scala/com/github/jodersky/flow/Parity.scala index 9a0d3ac..9bf52a6 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/Parity.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/Parity.scala @@ -1,5 +1,6 @@ package com.github.jodersky.flow +/** Specifies available parities used in serial communication. */ object Parity extends Enumeration { type Parity = Value val None = Value(0) diff --git a/flow-main/src/main/scala/com/github/jodersky/flow/Serial.scala b/flow-main/src/main/scala/com/github/jodersky/flow/Serial.scala index adcfb06..5c34487 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/Serial.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/Serial.scala @@ -4,18 +4,22 @@ import akka.actor.ActorRef import akka.actor.ExtensionKey import akka.util.ByteString -/** Defines messages used by serial IO layer. */ +/** Defines messages used by flow's serial IO layer. */ object Serial extends ExtensionKey[SerialExt] { - /** A message extending this trait is to be viewed as a command, that is an outbound message. */ + /** A message extending this trait is to be viewed as a command, that is an out-bound message. */ trait Command - /** A message extending this trait is to be viewed as an event, that is an inbound message. */ + /** A message extending this trait is to be viewed as an event, that is an in-bound message. */ trait Event /** - * Open a new serial port. Send this command to the serial manager to request the opening of a new port. - * @param handler actor that will receive events from the specified serial port + * 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 the such. It will send any events + * to the given `handler` actorref. + * The manager will respond with an `Opened` in case the port was successfully opened, or `OpenFailed` in case of failure. + * @param handler actor that will receive events from the specified serial port (via an operator) * @param port name of 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 @@ -25,7 +29,7 @@ object Serial extends ExtensionKey[SerialExt] { case class Open(handler: ActorRef, port: String, baud: Int, characterSize: Int = 8, twoStopBits: Boolean = false, parity: Parity.Parity = Parity.None) extends Command /** - * Event sent from a port operator, indicating that a serial port was successfully opened. + * Event sent from 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 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 @@ -35,7 +39,7 @@ object Serial extends ExtensionKey[SerialExt] { case class Opened(port: String, baud: Int, characterSize: Int, twoStopBits: Boolean, parity: Parity.Parity) extends Event /** - * Event sent from manager, indicating that a serial port could not be opened. + * Event sent from the serial manager, indicating that a serial port could not be opened. * @param reason throwable containing reason to why the requested port could not be opened * @param port name of serial port * @param baud baud rate to use with serial port @@ -52,7 +56,7 @@ object Serial extends ExtensionKey[SerialExt] { case class Received(data: ByteString) extends Event /** - * Command sent to operator, requesting the writing of data to the operator's serial port. Optionally request acknowledgment when data is written. + * Write data to serial port. Send this command to an operator to write the given data to its associated serial port. * @param data data to be written to port * @param ack set to true to receive acknowledgment on successful write * @see Wrote @@ -61,16 +65,16 @@ object Serial extends ExtensionKey[SerialExt] { /** * Event sent by operator, acknowledging that data was written to its serial port. Note that such an acknowledgment only guarantees that data has been written - * to the serial port's output buffer (managed by the operating system), the actual reception of the data on the remote device is not guaranteed. + * to the serial port's output buffer (managed by the operating system), the actual sending of the data to the remote device is not guaranteed. * @param data the data that has been written */ case class Wrote(data: ByteString) extends Event - /** Command sent to operator to request the closing of its serial port. */ + /** Request closing of port. Send this command to an operator to close its associated port. */ case object Close extends Command /** - * Event sent from operator, indicating that its port has been closed. An optional reason explains the error that caused the closing of the port. + * Event sent from operator, indicating that its port has been closed. An optional reason explains the error (if any) that caused the closing of the port. * @param reason Some(exception) explaining the exception that caused the closing, None if the port was closed by sending a `Close` message. */ case class Closed(reason: Option[Exception]) extends Event diff --git a/flow-main/src/main/scala/com/github/jodersky/flow/SerialExt.scala b/flow-main/src/main/scala/com/github/jodersky/flow/SerialExt.scala index 080ddd3..826a4e9 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/SerialExt.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/SerialExt.scala @@ -4,6 +4,7 @@ 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.actorOf(Props(classOf[SerialManager]), name = "IO-SERIAL") }
\ No newline at end of file diff --git a/flow-main/src/main/scala/com/github/jodersky/flow/SerialManager.scala b/flow-main/src/main/scala/com/github/jodersky/flow/SerialManager.scala index 1f32ecd..993ebda 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/SerialManager.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/SerialManager.scala @@ -18,6 +18,10 @@ import akka.actor.SupervisorStrategy.Escalate import akka.actor.SupervisorStrategy.Stop import akka.actor.actorRef2Scala +/** + * 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. + */ class SerialManager extends Actor with ActorLogging { import SerialManager._ import context._ @@ -30,16 +34,8 @@ class SerialManager extends Actor with ActorLogging { def receive = { case Open(handler, port, baud, cs, tsb, parity) => Try { InternalSerial.open(port, baud, cs, tsb, parity.id) } match { - case Failure(t) => { - log.debug(s"failed to open low serial port at ${port}, baud ${baud}, reason: " + t.getMessage()) - handler ! OpenFailed(t, port, baud, cs, tsb, parity) - } - - case Success(serial) => { - log.debug(s"opened low-level serial port at ${port}, baud ${baud}") - context.actorOf(Props(classOf[SerialOperator], handler, serial), name = escapePortString(port)) - } - + case Failure(t) => handler ! OpenFailed(t, port, baud, cs, tsb, parity) + case Success(serial) => context.actorOf(Props(classOf[SerialOperator], handler, serial), name = escapePortString(port)) } } diff --git a/flow-main/src/main/scala/com/github/jodersky/flow/SerialOperator.scala b/flow-main/src/main/scala/com/github/jodersky/flow/SerialOperator.scala index 4e46343..194abd3 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/SerialOperator.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/SerialOperator.scala @@ -17,12 +17,12 @@ import akka.actor.Terminated import akka.actor.actorRef2Scala import akka.util.ByteString +/** Operator associated to an open serial port. All communication with a port is done via an operator. Operators are created though the serial manager. */ class SerialOperator(handler: ActorRef, serial: InternalSerial) extends Actor with ActorLogging { + import SerialOperator._ import context._ - case class ReadException(ex: Exception) - - object Reader extends Thread { + private object Reader extends Thread { def enterReadLoop() = { var continueReading = true @@ -47,12 +47,12 @@ class SerialOperator(handler: ActorRef, serial: InternalSerial) extends Actor wi } def name = this.getName() - + override def run() { this.setName("flow-reader " + serial.port) enterReadLoop() } - + } override def preStart() = { @@ -94,4 +94,8 @@ class SerialOperator(handler: ActorRef, serial: InternalSerial) extends Actor wi } +} + +object SerialOperator { + private case class ReadException(ex: Exception) }
\ No newline at end of file diff --git a/flow-main/src/main/scala/com/github/jodersky/flow/exceptions.scala b/flow-main/src/main/scala/com/github/jodersky/flow/exceptions.scala index f91aa1b..5923ba6 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/exceptions.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/exceptions.scala @@ -2,9 +2,20 @@ package com.github.jodersky.flow import java.io.IOException +/** 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-main/src/main/scala/com/github/jodersky/flow/internal/InternalSerial.scala b/flow-main/src/main/scala/com/github/jodersky/flow/internal/InternalSerial.scala index c7752b2..e69f91a 100644 --- a/flow-main/src/main/scala/com/github/jodersky/flow/internal/InternalSerial.scala +++ b/flow-main/src/main/scala/com/github/jodersky/flow/internal/InternalSerial.scala @@ -4,7 +4,7 @@ import java.io.IOException import com.github.jodersky.flow._ import java.util.concurrent.atomic.AtomicBoolean -/** Wraps NativeSerial in a more object-oriented style, still quite low level. */ +/** Wraps `NativeSerial` in a more object-oriented style, still quite low level. */ class InternalSerial private (val port: String, val baud: Int, val characterSize: Int, val twoStopBits: Boolean, val parity: Int, private val pointer: Long) { import InternalSerial._ @@ -17,7 +17,7 @@ class InternalSerial private (val port: String, val baud: Int, val characterSize if (!closed.get()) { closed.set(true) except(NativeSerial.interrupt(pointer), port) - if (writing.get()) wait() // if reading, wait for read to finish + if (writing.get()) wait() if (reading.get()) wait() except(NativeSerial.close(pointer), port) } @@ -36,7 +36,7 @@ class InternalSerial private (val port: String, val baud: Int, val characterSize } finally { synchronized { reading.set(false) - if (closed.get) notify(); //read was interrupted by close + if (closed.get) notify() } } } else { @@ -86,7 +86,7 @@ object InternalSerial { new InternalSerial(port, baud, characterSize, twoStopBits, parity, pointer(0)) } - /** Set debugging for all serial connections. Debugging results in printing extra messages (from the native library) in case of errors. */ + /** Set debugging for all serial connections. Debugging results in printing extra messages from the native library in case of errors. */ def debug(value: Boolean) = NativeSerial.debug(value) }
\ No newline at end of file |