aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2015-09-13 19:26:52 +0200
committerJakob Odersky <jodersky@gmail.com>2015-09-13 19:26:52 +0200
commita5c0b584749059cced2b3358ddb1ff7c5768bc4d (patch)
tree5bcb32860a96b4e4f03079fa5c10a57a069bee71
parentf4fa02b23c38976249852fa0b93d4e6087b78f79 (diff)
downloadakka-serial-2.2.4.tar.gz
akka-serial-2.2.4.tar.bz2
akka-serial-2.2.4.zip
prepare release 2.2.4v2.2.4
-rw-r--r--Documentation/flow.html231
-rw-r--r--Documentation/getting-started.md4
-rw-r--r--project/Build.scala2
3 files changed, 234 insertions, 3 deletions
diff --git a/Documentation/flow.html b/Documentation/flow.html
new file mode 100644
index 0000000..7f1a95b
--- /dev/null
+++ b/Documentation/flow.html
@@ -0,0 +1,231 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="generator" content="pandoc">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
+ <meta name="author" content="Jakob Odersky">
+ <title>flow - Serial Communication Library for Akka</title>
+ <style type="text/css">code{white-space: pre;}</style>
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+ <style type="text/css">
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
+ margin: 0; padding: 0; vertical-align: baseline; border: none; }
+table.sourceCode { width: 100%; line-height: 100%; }
+td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
+td.sourceCode { padding-left: 5px; }
+code > span.kw { color: #007020; font-weight: bold; }
+code > span.dt { color: #902000; }
+code > span.dv { color: #40a070; }
+code > span.bn { color: #40a070; }
+code > span.fl { color: #40a070; }
+code > span.ch { color: #4070a0; }
+code > span.st { color: #4070a0; }
+code > span.co { color: #60a0b0; font-style: italic; }
+code > span.ot { color: #007020; }
+code > span.al { color: #ff0000; font-weight: bold; }
+code > span.fu { color: #06287e; }
+code > span.er { color: #ff0000; font-weight: bold; }
+ </style>
+</head>
+<body>
+<header>
+<h1 class="title">flow - Serial Communication Library for Akka</h1>
+<h2 class="author">Jakob Odersky</h2>
+</header>
+<nav id="TOC">
+<ul>
+<li><a href="#getting-started"><span class="toc-section-number">1</span> Getting Started</a><ul>
+<li><a href="#including-native-library"><span class="toc-section-number">1.1</span> Including Native Library</a><ul>
+<li><a href="#the-easy-way"><span class="toc-section-number">1.1.1</span> The Easy Way</a></li>
+<li><a href="#maximum-portability"><span class="toc-section-number">1.1.2</span> Maximum Portability</a></li>
+</ul></li>
+</ul></li>
+<li><a href="#communication-protocol"><span class="toc-section-number">2</span> Communication Protocol</a><ul>
+<li><a href="#opening-a-port"><span class="toc-section-number">2.1</span> Opening a Port</a></li>
+<li><a href="#writing-data"><span class="toc-section-number">2.2</span> Writing Data</a></li>
+<li><a href="#receiving-data"><span class="toc-section-number">2.3</span> Receiving Data</a></li>
+<li><a href="#closing-a-port"><span class="toc-section-number">2.4</span> Closing a Port</a></li>
+<li><a href="#resources-and-error-handling"><span class="toc-section-number">2.5</span> Resources and Error Handling</a></li>
+</ul></li>
+<li><a href="#watching-ports"><span class="toc-section-number">3</span> Watching Ports</a><ul>
+<li><a href="#subscribing"><span class="toc-section-number">3.1</span> Subscribing</a></li>
+<li><a href="#notifications"><span class="toc-section-number">3.2</span> Notifications</a></li>
+<li><a href="#unsubscribing"><span class="toc-section-number">3.3</span> Unsubscribing</a></li>
+<li><a href="#resource-handling"><span class="toc-section-number">3.4</span> Resource Handling</a></li>
+<li><a href="#requirements"><span class="toc-section-number">3.5</span> Requirements</a></li>
+</ul></li>
+<li><a href="#building-from-source"><span class="toc-section-number">4</span> Building from Source</a><ul>
+<li><a href="#building-scala-sources"><span class="toc-section-number">4.1</span> Building Scala Sources</a></li>
+<li><a href="#building-native-sources"><span class="toc-section-number">4.2</span> Building Native Sources</a><ul>
+<li><a href="#creating-a-fat-jar"><span class="toc-section-number">4.2.1</span> Creating a Fat Jar</a></li>
+<li><a href="#note-about-versioning"><span class="toc-section-number">4.2.2</span> Note About Versioning</a></li>
+</ul></li>
+</ul></li>
+</ul>
+</nav>
+<h1 id="getting-started"><span class="header-section-number">1</span> Getting Started</h1>
+<p>Flow uses SBT as build system. To get started, include a dependency to flow-core in your project:</p>
+<pre><code>libraryDependencies += &quot;com.github.jodersky&quot; %% &quot;flow&quot; % &quot;2.2.2&quot;</code></pre>
+<h2 id="including-native-library"><span class="header-section-number">1.1</span> Including Native Library</h2>
+<p><em>NOTICE: flow uses native libraries to back serial communication, therefore before you can run any application depending on flow you must include flow’s native library! To do so, you have two options.</em></p>
+<h3 id="the-easy-way"><span class="header-section-number">1.1.1</span> The Easy Way</h3>
+<p>In case your OS/architecture combination is present in the table below, add a second dependency to your project:</p>
+<pre><code>libraryDependencies += &quot;com.github.jodersky&quot; % &quot;flow-native&quot; % &quot;2.2.2&quot;</code></pre>
+<table>
+<thead>
+<tr class="header">
+<th style="text-align: left;">OS</th>
+<th style="text-align: left;">Architecture</th>
+<th style="text-align: left;">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Linux</td>
+<td style="text-align: left;">x86<br/>x86_64<br/>ARM (v7)</td>
+<td style="text-align: left;">A user accessing a serial port will probably need to be in the <code>dialout</code> group.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Mac OS X</td>
+<td style="text-align: left;">x86_64</td>
+<td style="text-align: left;"></td>
+</tr>
+</tbody>
+</table>
+<p>This will add a jar to your classpath containing native libraries for various platforms. At run time, the correct library for the current platform is selected, extracted and loaded. This solution enables running applications seamlessly, as if they were pure JVM applications. However, since the JVM does not enable full determination of the current platform (only OS and rough architecture are known), only a couple of platforms can be supported through this solution at the same time.</p>
+<h3 id="maximum-portability"><span class="header-section-number">1.1.2</span> Maximum Portability</h3>
+<p>Do not include the second dependency above. Instead, for every end-user application that relies on flow, manually add the native library for the current platform to the JVM’s library path. This can be achieved through various ways, notably:</p>
+<ul>
+<li><p>Per application: Run your program with the command-line option <code>-Djava.library.path=&quot;.:&lt;folder containing libflow3.so&gt;&quot;</code>. E.g. <code>java -Djava.library.path=&quot;.:/home/&lt;folder containing libflow3.so&gt;&quot; -jar your-app.jar</code></p></li>
+<li><p>System- or user-wide:</p>
+<ul>
+<li><p>Copy the native library to a place that is on the default Java library path and run your application normally. Such places usually include <code>/usr/lib</code> and <code>/usr/local/lib</code>.</p></li>
+<li><p>Use a provided installer (currently Debian archive and Mac .pkg, available in releases)</p></li>
+</ul></li>
+</ul>
+<p>The native library can either be obtained by building flow (see section Build) or by taking a pre-compiled one, found in releases in the GitHub project. Native libraries need to be of major version 3 to work with this version of flow.</p>
+<p>It is recommended that you use the first option only for testing purposes or end-user applications. The second option is recomended for libraries, since it leaves more choice to the end-user.</p>
+<h1 id="communication-protocol"><span class="header-section-number">2</span> Communication Protocol</h1>
+<p>The following is a general guide on the usage of flow. If you prefer a complete example, check out the code contained in the <code>flow-samples</code> directory.</p>
+<p>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:</p>
+<ol type="1">
+<li><p>Serial “manager”. The manager is a singleton actor that is instantiated once per actor system, a reference to it may be obtained with <code>IO(Serial)</code>. It is typically used to open serial ports (see following section).</p></li>
+<li><p>Serial “operators”. 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.</p></li>
+</ol>
+<p>The messages understood by flow’s actors are all contained in the <code>com.github.jodersky.flow.Serial</code> object. They are well documented and should serve as the entry point when searching the API documentation.</p>
+<h2 id="opening-a-port"><span class="header-section-number">2.1</span> Opening a Port</h2>
+<p>A serial port is opened by sending an <code>Open</code> message to the serial manager. The response varies on the outcome of opening the underlying serial port.</p>
+<ol type="1">
+<li><p>In case of failure, the serial manager will respond with a <code>CommandFailed</code> message to the original sender. The message contains details on the reason to why the opening failed.</p></li>
+<li><p>In case of success, the sender is notified with an <code>Opened</code> message. This message is sent from an operator actor, spawned by the serial manager. It is useful to capture the sender (i.e. the operator) of this message as all further communication with the newly opened port must pass through the operator.</p></li>
+</ol>
+<pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> com.<span class="fu">github</span>.<span class="fu">jodersky</span>.<span class="fu">flow</span>.{ Serial, SerialSettings, AccessDeniedException }
+
+<span class="kw">val</span> port = <span class="st">&quot;/dev/ttyXXX&quot;</span>
+<span class="kw">val</span> settings = <span class="fu">SerialSettings</span>(
+ baud = <span class="dv">115200</span>,
+ characterSize = <span class="dv">8</span>,
+ twoStopBits = <span class="kw">false</span>,
+ parity = Parity.<span class="fu">None</span>
+)
+
+<span class="fu">IO</span>(Serial) ! Serial.<span class="fu">Open</span>(port, settings)
+
+<span class="kw">def</span> receive = {
+ <span class="kw">case</span> Serial.<span class="fu">CommandFailed</span>(cmd: Serial.<span class="fu">Open</span>, reason: AccessDeniedException) =&gt;
+ <span class="fu">println</span>(<span class="st">&quot;You&#39;re not allowed to open that port!&quot;</span>)
+ <span class="kw">case</span> Serial.<span class="fu">CommandFailed</span>(cmd: Serial.<span class="fu">Open</span>, reason) =&gt;
+ <span class="fu">println</span>(<span class="st">&quot;Could not open port for some other reason: &quot;</span> + reason.<span class="fu">getMessage</span>)
+ <span class="kw">case</span> Serial.<span class="fu">Opened</span>(settings) =&gt; {
+ <span class="kw">val</span> operator = sender
+ <span class="co">//do stuff with the operator, e.g. context become opened(op)</span>
+ }
+}</code></pre>
+<h2 id="writing-data"><span class="header-section-number">2.2</span> Writing Data</h2>
+<p>Writing data is as simple as sending a <code>Write</code> message to an operator. The data to send is an instance of <code>akka.util.ByteString</code>:</p>
+<pre class="sourceCode scala"><code class="sourceCode scala">operator ! Serial.<span class="fu">Write</span>(data)</code></pre>
+<p>Optionally, an acknowledgement for sent data can be requested by adding an <code>ack</code> parameter to a <code>Write</code> message. The <code>ack</code> parameter is of type <code>Int =&gt; Serial.Event</code>, i.e. a function that takes the number of actual bytes written and returns an event. Note that “bytes written” refers to bytes enqueued in a kernel buffer; no guarantees can be made on the actual transmission of the data.</p>
+<pre class="sourceCode scala"><code class="sourceCode scala">
+<span class="kw">case</span> <span class="kw">class</span> <span class="fu">MyPacketAck</span>(wrote: Int) <span class="kw">extends</span> Serial.<span class="fu">Event</span>
+
+operator ! Serial.<span class="fu">Write</span>(data, <span class="fu">MyPacketAck</span>(_))
+operator ! Serial.<span class="fu">Write</span>(data, n =&gt; <span class="fu">MyPacketAck</span>(n))
+
+<span class="kw">def</span> receive = {
+ <span class="kw">case</span> <span class="fu">MyPacketAck</span>(n) =&gt; <span class="fu">println</span>(<span class="st">&quot;Wrote &quot;</span> + n + <span class="st">&quot; bytes of data&quot;</span>)
+}</code></pre>
+<h2 id="receiving-data"><span class="header-section-number">2.3</span> Receiving Data</h2>
+<p>The actor that opened a serial port (referred to as the client), exclusively receives incomming messages from the operator. These messages are in the form of <code>akka.util.ByteString</code>s and wrapped in a <code>Received</code> object.</p>
+<pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> receive = {
+ <span class="kw">case</span> Serial.<span class="fu">Received</span>(data) =&gt; <span class="fu">println</span>(<span class="st">&quot;Received data: &quot;</span> + data.<span class="fu">toString</span>)
+}</code></pre>
+<h2 id="closing-a-port"><span class="header-section-number">2.4</span> Closing a Port</h2>
+<p>A port is closed by sending a <code>Close</code> message to its operator:</p>
+<pre class="sourceCode scala"><code class="sourceCode scala">operator ! Serial.<span class="fu">Close</span></code></pre>
+<p>The operator will close the underlying serial port and respond with a final <code>Closed</code> message before terminating.</p>
+<h2 id="resources-and-error-handling"><span class="header-section-number">2.5</span> Resources and Error Handling</h2>
+<p>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.</p>
+<p>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.</p>
+<h1 id="watching-ports"><span class="header-section-number">3</span> Watching Ports</h1>
+<p>As of version 2.2.0, flow can watch directories for new files. On most unix systems this can be used for watching for new serial ports in <code>/dev/</code>. Watching happens through a message-based, publish-subscribe protocol as explained in the sections below.</p>
+<h2 id="subscribing"><span class="header-section-number">3.1</span> Subscribing</h2>
+<p>A client actor may watch – i.e subscribe to notifications on – a directory by sending a <code>Watch</code> command to the serial manager.</p>
+<p>Should an error be encountered whilst trying to obtain the watch, the manager will respond with a <code>CommandFailed</code> message. Otherwise, the client may be considered “subscribed” to the directory and the serial manager will thenceforth notify the client on new files.</p>
+<pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">IO</span>(Serial) ! Serial.<span class="fu">Watch</span>(<span class="st">&quot;/dev/&quot;</span>)
+
+<span class="kw">def</span> receive = {
+ <span class="kw">case</span> Serial.<span class="fu">CommandFailed</span>(w: Watch, reason) =&gt;
+ <span class="fu">println</span>(s<span class="st">&quot;Cannot obtain a watch on ${w.directory}: ${reason.getMessage}&quot;</span>)
+}</code></pre>
+<h2 id="notifications"><span class="header-section-number">3.2</span> Notifications</h2>
+<p>Whilst subscribed to a directory, a client actor is informed of any new files in said directory by receiving <code>Connected</code> messages from the manager.</p>
+<pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> receive = {
+ <span class="kw">case</span> Serial.<span class="fu">Connected</span>(port) <span class="kw">if</span> port matches <span class="st">&quot;/dev/ttyUSB</span><span class="ch">\\</span><span class="st">d+&quot;</span> =&gt;
+ <span class="co">// do something with the available port, e.g.</span>
+ <span class="co">// IO(Serial) ! Open(port, settings)</span>
+}</code></pre>
+<h2 id="unsubscribing"><span class="header-section-number">3.3</span> Unsubscribing</h2>
+<p>Unsubscribing from events on a directory is done by sending an <code>Unsubscribe</code> message to the serial manager.</p>
+<pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">IO</span>(Serial) ! <span class="fu">Unwatch</span>(<span class="st">&quot;/dev/&quot;</span>)</code></pre>
+<h2 id="resource-handling"><span class="header-section-number">3.4</span> Resource Handling</h2>
+<p>Note that the manager has a deathwatch on every subscribed client. Hence, should a client die, any underlying resources will be freed.</p>
+<h2 id="requirements"><span class="header-section-number">3.5</span> Requirements</h2>
+<p>Flow uses Java’s <code>WatchService</code>s under the hood, therefore a Java runtime of a version of at least 1.7 is required.</p>
+<h1 id="building-from-source"><span class="header-section-number">4</span> Building from Source</h1>
+<p>A complete build of flow involves two parts</p>
+<ol type="1">
+<li><p>Building Scala sources (the front-end), resulting in a platform independent artifact (i.e. a jar file).</p></li>
+<li><p>Building C sources (the back-end), yielding a native library that may only be used on systems resembling the platform for which it was compiled</p></li>
+</ol>
+<p>Both steps are independent, their only interaction being a header file generated by the JDK utility <code>javah</code> (see <code>sbt javah</code> for details), and may therefore be built in any order.</p>
+<h2 id="building-scala-sources"><span class="header-section-number">4.1</span> Building Scala Sources</h2>
+<p>Run <code>sbt flow/packageBin</code> in the base directory. This simply compiles Scala sources as with any standard SBT project and packages the resulting class-files in a jar.</p>
+<h2 id="building-native-sources"><span class="header-section-number">4.2</span> Building Native Sources</h2>
+<p>The back-end is managed by GNU Autotools and all relevant files are contained in <code>flow-native</code>.</p>
+<p>Several steps are involved in producing the native library:</p>
+<ol type="1">
+<li><p>When compiling for the first time, initialize Autotools by running the script <code>./bootstrap</code>.</p></li>
+<li><p>Once initialized, <code>./configure &amp;&amp; make</code> will build the back-end.</p></li>
+<li><p>The native library is now ready and can be:</p>
+<ul>
+<li><p>copied to a local directory: <code>DESTDIR=$(pwd)/&lt;directory&gt; make install</code></p></li>
+<li><p>installed system-wide: <code>make install</code></p></li>
+<li><p>put into a “fat” jar, useful for dependency management with SBT (see next section)</p></li>
+</ul></li>
+</ol>
+<h3 id="creating-a-fat-jar"><span class="header-section-number">4.2.1</span> Creating a Fat Jar</h3>
+<p>The native library produced in the previous step may be bundled into a “fat” jar so that it can be included in SBT projects through its regular dependency mechanisms. In this process, SBT basically acts as a wrapper script around Autotools, calling the native build process and packaging generated libraries. Running <code>sbt flow-native/packageBin</code> in the base directory produces the fat jar in <code>flow-native-sbt/target</code>.</p>
+<p>Note: an important feature of fat jars is to include native libraries for several platforms. To copy binaries compiled on other platforms to the fat jar, place them in a subfolder of <code>flow-native-sbt/lib_native</code>. The subfolder should have the name <code>$(os.name)-$(os.arch)</code>, where <code>os.name</code> and <code>os.arch</code> are the Java system properties of the respective platforms.</p>
+<h3 id="note-about-versioning"><span class="header-section-number">4.2.2</span> Note About Versioning</h3>
+<p>The project and package versions follow a sematic pattern: <code>M.m.p</code>, where</p>
+<ul>
+<li><p><code>M</code> is the major version, representing backwards incompatible changes</p></li>
+<li><p><code>m</code> is the minor version, indicating backwards compatible changes such as new feature additions</p></li>
+<li><p><code>p</code> is the patch number, representing internal modifications such as bug-fixes</p></li>
+</ul>
+<p>Usually (following most Linux distribution’s conventions), shared libraries produced by a project <code>name</code> of version <code>M.m.p</code> are named <code>libname.so.M.m.p</code>. However, since when accessing shared libraries through the JVM, only the <code>name</code> can be specified and no particular version, the convention adopted by flow is to append <code>M</code> to the library name and always keep the major version at zero. E.g. <code>libflow.so.3.1.2</code> becomes <code>libflow3.so.0.1.2</code>.</p>
+</body>
+</html>
diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md
index 798b5be..c58195b 100644
--- a/Documentation/getting-started.md
+++ b/Documentation/getting-started.md
@@ -1,7 +1,7 @@
# Getting Started
Flow uses SBT as build system. To get started, include a dependency to flow-core in your project:
- libraryDependencies += "com.github.jodersky" %% "flow" % "2.2.3"
+ libraryDependencies += "com.github.jodersky" %% "flow" % "2.2.4"
## Including Native Library
*NOTICE: flow uses native libraries to back serial communication, therefore before you can run any application depending on flow you must include flow's native library! To do so, you have two options.*
@@ -9,7 +9,7 @@ Flow uses SBT as build system. To get started, include a dependency to flow-core
### The Easy Way
In case your OS/architecture combination is present in the table below, add a second dependency to your project:
- libraryDependencies += "com.github.jodersky" % "flow-native" % "2.2.3"
+ libraryDependencies += "com.github.jodersky" % "flow-native" % "2.2.4"
| OS | Architecture | Notes |
|-------------------|-----------------------------|---------------------------------------------------------------------------------|
diff --git a/project/Build.scala b/project/Build.scala
index 4c7e0ba..972d972 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -9,7 +9,7 @@ object FlowBuild extends Build {
val scalaVersions = List("2.11.7", "2.10.5")
lazy val commonSettings: Seq[Setting[_]] = Seq(
- version := "2.2.4-SNAPSHOT",
+ version := "2.2.4",
scalaVersion in ThisBuild := scalaVersions.head,
crossScalaVersions in ThisBuild := scalaVersions.reverse,
scalacOptions ++= Seq("-deprecation", "-unchecked", "-feature", "-target:jvm-1.7"),