aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2013-08-04 23:55:22 +0200
committerJakob Odersky <jodersky@gmail.com>2013-08-04 23:55:22 +0200
commitff91a9383ae0e3f410c01cb41d357d2a72157a0d (patch)
tree349ad7811cbe4eb0649d2e2202e03038393e9caa
parent10c5c4e68d027e6bbabaad17381c79df24401027 (diff)
downloadakka-serial-ff91a9383ae0e3f410c01cb41d357d2a72157a0d.tar.gz
akka-serial-ff91a9383ae0e3f410c01cb41d357d2a72157a0d.tar.bz2
akka-serial-ff91a9383ae0e3f410c01cb41d357d2a72157a0d.zip
add basic usage guide
-rw-r--r--README.md16
-rw-r--r--documentation/basics.md78
2 files changed, 86 insertions, 8 deletions
diff --git a/README.md b/README.md
index 40eb122..d9e4bf4 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,13 @@
# flow
-Serial communication library for Scala, designed to be reactive, lightweight and easily integrable with Akka-IO.
+Serial communication library for Scala, designed to be reactive, lightweight and easily integrable with Akka applications.
## Motivation
-The main reason for yet another serial communication library for the JVM is that all other libraries I tested used blocking IO and/or consumed enormous amounts of CPU while being idle, between 2% and 15%. Flow's main goal is therefore to provide a lightweight library that only does work when communication is required. This reactive concept integrates well with the Akka IO layer therefore making flow an ideal library for extending it.
-
-## Native side
-Since hardware is involved in serial communication, a Scala-only solution is not possible. Nevertherless, the native code is kept simple and minimalistic with the burden of dealing with threads left to Scala. The code aims to be POSIX compliant and therefore easily portable.
+The main reason for yet another serial communication library for the JVM is that all other libraries I tested used blocking IO and/or consumed enormous amounts of CPU while being idle, between 2% and 15%. Flow's main goal is therefore to provide a lightweight library that only does work when communication is required. Furthermore, this reactive concept integrates well with the Akka IO layer therefore making flow an ideal library for extending it.
## Basic usage
-(this section will be updated as soon as a maven repository is available)
+For a short guide on how to use flow see the file "documentation/basics.md", accessible on github [here](https://github.com/jodersky/flow/blob/master/documentation/basics.md).
-Clone the repository and run `sbt flow/publish-local` to publish the library locally. From there on, you may use the library in any project simply by adding a library dependency to it.
+Flow is built and its examples run with SBT. To get started, run `sbt flow/publish-local` to publish the library locally. From there on, you may use the library in any project simply by adding a library dependency to it.
libraryDependencies += "com.github.jodersky" % "flow" % "1.0-SNAPSHOT"
@@ -27,6 +24,8 @@ Since flow integrates into the Akka-IO framework, a good resource on its general
Note: flow may work on older versions of the tested OS kernels.
+## Native side
+Since hardware is involved in serial communication, a Scala-only solution is not possible. Nevertherless, the native code is kept simple and minimalistic with the burden of dealing with threads left to Scala. The code aims to be POSIX compliant and therefore easily portable.
## Build
A complete build of flow involves two parts
@@ -34,9 +33,10 @@ A complete build of flow involves two parts
1. compiling scala sources (as in a regular project)
2. compiling native sources
-As any java project, the first part results in a platform independant artifact. However, the second part yields a binary that may only be used on systems resembling the platform for which it was compiled. Nevertheless, to provide multiplatform support, flow produces a "fat executable", a jar containing native binaries compiled for different flavours of operating system and architecture combinations. During runtime, a matching native binary is selected and loaded. To understand how flow can achieve such a mix, it is helpful to look at the project's directory layout.
+As any java or scala project, the first part results in a platform independant artifact. However, the second part yields a binary that may only be used on systems resembling the platform for which it was compiled. Nevertheless, to provide multiplatform support, flow produces a "fat executable", a jar containing native binaries compiled for different flavours of operating system and architecture combinations. During runtime, a matching native binary is selected and loaded. To understand how flow can achieve such a mix, it is helpful to look at the project's directory layout.
flow
+ ├── documentation
├── flow-binaries
├── flow-main
├── flow-native
diff --git a/documentation/basics.md b/documentation/basics.md
new file mode 100644
index 0000000..68a58c1
--- /dev/null
+++ b/documentation/basics.md
@@ -0,0 +1,78 @@
+#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).
+
+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.
+
+The messages understood by flow's actors are all contained in the `com.github.jodersky.flow.Serial` object. They are well documented and should serve as the entry point when searching the API documentation.
+
+#Opening a port
+A serial port is opened by sending an `Open` message to the serial manager. The response varies on the outcome of opening the underlying serial port.
+ 1. In case of failure, the serial manager will respond with a `CommandFailed` message to the original sender. The message contains details on the reason to why the opening failed.
+ 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 settings = SerialSettings(
+ port = "/dev/ttyXXX",
+ baud = 115200
+)
+
+IO(Serial) ! Serial.Open(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
+ }
+}
+```
+
+
+#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`:
+```scala
+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:
+```scala
+
+case class MyPacketAck(id: Int) extends Serial.Event
+
+operator ! Write(data, MyPacketAck(0))
+operator ! Write(data, MyPacketAck(1))
+operator ! Write(data, MyPacketAck(2))
+
+def receive = {
+ case MyPacketAck(x) => println("Wrote packet #" + x)
+}
+
+```
+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:
+```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:
+```scala
+operator ! Serial.Close
+```
+The operator will close the underlying serial port and respond with a final `Closed` message before terminating.