aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2014-03-29 14:00:43 +0100
committerJakob Odersky <jodersky@gmail.com>2014-03-29 14:00:43 +0100
commit4bba77357940f7397ea52a28114bb765116cdd74 (patch)
tree22097b59ffab8b4966af7eb73a83effae3385959
parentf34d5ccc120d2d2014a052966b183da7383bdc61 (diff)
downloadakka-serial-4bba77357940f7397ea52a28114bb765116cdd74.tar.gz
akka-serial-4bba77357940f7397ea52a28114bb765116cdd74.tar.bz2
akka-serial-4bba77357940f7397ea52a28114bb765116cdd74.zip
update documentation
-rw-r--r--documentation/basics.md52
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/Serial.scala9
-rw-r--r--flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala2
3 files changed, 37 insertions, 26 deletions
diff --git a/documentation/basics.md b/documentation/basics.md
index 68a58c1..1982f66 100644
--- a/documentation/basics.md
+++ b/documentation/basics.md
@@ -1,9 +1,9 @@
-#Introduction
+# Introduction
The following is a general guide on the usage of flow. If you prefer a complete example, check out the code contained in the flow-samples directory.
Flow's API follows that of an actor based system, where each actor is assigned specific functions involved in serial communication. The two main actor types are the serial "manager" and serial "operators".
-The manager is a singleton actor that is instantiated once per actor system, a reference to it may be obtained with the code `IO(Serial)`. It is typically used to open serial ports (see following section).
+The manager is a singleton actor that is instantiated once per actor system, a reference to it may be obtained with `IO(Serial)`. It is typically used to open serial ports (see following section).
Serial operators are created once per open serial port and serve as an intermediate between client code and native code dealing with serial data transmission and reception. They isolate the user from threading issues and enable the reactive dispatch of incoming data. A serial operator is said to be "associated" to its underlying open serial port.
@@ -15,25 +15,28 @@ A serial port is opened by sending an `Open` message to the serial manager. The
2. In case of success, the sender is notified with an `Opened` message. This message is sent from an operator actor, spawned by the serial manager. It is useful to capture the sender (=operator) of this message as all further communication with the newly opened port must pass through the operator.
```scala
+val port = "/dev/ttyXXX"
val settings = SerialSettings(
- port = "/dev/ttyXXX",
- baud = 115200
+ baud = 115200,
+ characterSize = 8,
+ twoStopBits = false,
+ parity = Parity.None
)
-IO(Serial) ! Serial.Open(settings)
+IO(Serial) ! Serial.Open(port, settings)
def receive = {
case CommandFailed(cmd: Open, reason: AccessDeniedException) => println("you're not allowed to open that port!")
case CommandFailed(cmd: Open, reason) => println("could not open port for some other reason: " + reason.getMessage)
- case Opened(settings, op) => {
- val operator = sender //notice that a reference to the operator is also sent as a parameter to Opened, we could have equally said operator = op
- //do stuff with the operator
+ case Opened(settings) => {
+ val operator = sender
+ //do stuff with the operator, e.g. context become opened(op)
}
}
```
-#Communicating
+# Communicating
## Writing data
Writing data is as simple as sending a `Write` message containing data to an operator. The type of data is an instance of `akka.util.ByteString`:
@@ -41,34 +44,31 @@ Writing data is as simple as sending a `Write` message containing data to an ope
operator ! Write(data)
```
-To receive an acknowledgement when data has been sent (this means queued in the kernel buffer; no guarantees can be made on the actual transmission of the data), the sender may add an additional `ack` parameter to a `Write` message:
+To receive an acknowledgement when data has been sent (this means queued in the kernel buffer; no guarantees can be made on the actual transmission of the data), the sender may add an additional `ack` parameter to a `Write` message. The `ack` parameter is of type `Int => Serial.Event`, i.e. a function that takes the number of actual bytes written and returns an event.
+
```scala
-case class MyPacketAck(id: Int) extends Serial.Event
+case class MyPacketAck(wrote: Int) extends Serial.Event
-operator ! Write(data, MyPacketAck(0))
-operator ! Write(data, MyPacketAck(1))
-operator ! Write(data, MyPacketAck(2))
+operator ! Write(data, MyPacketAck(_))
+operator ! Write(data, MyPacketAck(_))
+operator ! Write(data, n => MyPacketAck(n))
def receive = {
- case MyPacketAck(x) => println("Wrote packet #" + x)
+ case MyPacketAck(x) => println("Wrote " + x + " bytes of data")
}
```
-In that case, the sender will be notified with `MyPacketAck(0)`, `MyPacketAck(1)` and `MyPacketAck(2)` once the data has been sent.
## Receiving data
-To be notified when data is received on a serial port, a client actor must first register with its associated operator:
-```scala
-operator ! Register(client)
-```
-From that moment on, the client will receive `Received` messages when data comes in through the serial port:
+The actor that opened a serial port (refered to as the client), exclusively receives incomming messages from the operator. These messages are in the form of `ByteStrings` and wrapped in a `Received` object.
+
```scala
def receive = {
case Received(data) => println("got data: " + data.toString)
}
```
-To unregister, simply send an `Unregister` message.
+
#Closing a port
A port is closed by sending a `Close` message to its operator:
@@ -76,3 +76,11 @@ A port is closed by sending a `Close` message to its operator:
operator ! Serial.Close
```
The operator will close the underlying serial port and respond with a final `Closed` message before terminating.
+
+
+# Resources and error handling
+The operator has a deathwatch on the client actor that opened the port, this means that if the latter crashes, the operator closes the port and equally terminates, freeing any allocated resources.
+
+The opposite is not true by default, i.e. if the operator crashes (this can happen for example on IO errors) it dies silently and the client is not informed. Therefore, it is recommended that the client keep a deathwatch on the operator.
+
+
diff --git a/flow/src/main/scala/com/github/jodersky/flow/Serial.scala b/flow/src/main/scala/com/github/jodersky/flow/Serial.scala
index 6c05e14..4c3a173 100644
--- a/flow/src/main/scala/com/github/jodersky/flow/Serial.scala
+++ b/flow/src/main/scala/com/github/jodersky/flow/Serial.scala
@@ -7,6 +7,7 @@ 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. */
@@ -28,7 +29,9 @@ object Serial extends ExtensionKey[SerialExt] {
* 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
@@ -46,7 +49,6 @@ object Serial extends ExtensionKey[SerialExt] {
* Data has been received.
*
* Event sent by an operator, indicating that data was received on the operator's serial port.
- * Clients must register (see `Register`) with a serial operator to receive these events.
*
* @param data data received on the port
*/
@@ -59,10 +61,11 @@ object Serial extends ExtensionKey[SerialExt] {
* 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 written.
+ * 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
+ * @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
diff --git a/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala b/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala
index 0592ae0..4918bc6 100644
--- a/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala
+++ b/flow/src/main/scala/com/github/jodersky/flow/SerialOperator.scala
@@ -17,7 +17,7 @@ import com.github.jodersky.flow.internal.ReaderDied
/**
* 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
+ * @see SerialManager
*/
class SerialOperator(connection: SerialConnection, bufferSize: Int, client: ActorRef) extends Actor with ActorLogging {
import SerialOperator._