diff options
author | Jakob Odersky <jodersky@gmail.com> | 2013-02-27 15:53:33 +0100 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2013-02-27 15:53:33 +0100 |
commit | 793983ca31eb05fce655ed5877b6f3faa4577acd (patch) | |
tree | 94929b35094209df2964cd69068a0b9a270095dd /scala | |
parent | 20a2350f9b33a797763413509781d0686fc38fe5 (diff) | |
download | ace-793983ca31eb05fce655ed5877b6f3faa4577acd.tar.gz ace-793983ca31eb05fce655ed5877b6f3faa4577acd.tar.bz2 ace-793983ca31eb05fce655ed5877b6f3faa4577acd.zip |
restructure scala implementation
Diffstat (limited to 'scala')
12 files changed, 166 insertions, 22 deletions
diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/Arq.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/Arq.scala index 3f8f84d..4a4ed8d 100644 --- a/scala/ace/src/main/scala/com/github/jodersky/ace/Arq.scala +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/Arq.scala @@ -1,4 +1,4 @@ -package com.github.jodersky.ace +package com.github.jodersky.ace.protocol import scala.concurrent._ import scala.concurrent.ExecutionContext.Implicits.global @@ -19,7 +19,7 @@ class Arq(timeout: Int, maxResends: Int = 5, maxMessageBuffer: Int = 10) extends // received message sequences private val receivedSequences = Queue[Int]() - def receive(frameData: Seq[Int]) = { + protected def receive(frameData: Seq[Int]) = { val sequence = frameData(SequenceOffset) val command = frameData(CommandOffset) val message = frameData.drop(MessageOffset) @@ -33,7 +33,7 @@ class Arq(timeout: Int, maxResends: Int = 5, maxMessageBuffer: Int = 10) extends } case Data => { - writeToLower(ack(sequence)) + sendToLower(ack(sequence)) if (!(receivedSequences contains sequence)) { if (receivedSequences.size > maxMessageBuffer) receivedSequences.dequeue @@ -45,14 +45,14 @@ class Arq(timeout: Int, maxResends: Int = 5, maxMessageBuffer: Int = 10) extends } } - def write(message: Seq[Int]) = { + def send(message: Seq[Int]) = { val promise = Promise[Seq[Int]] val sequence = nextSequence() val frameData = Seq(sequence, Data) ++ message def send(n: Int): Future[Seq[Int]] = - writeToLower(frameData) map { frameData => + sendToLower(frameData) map { frameData => Await.result(promise.future, timeout.milliseconds) } recoverWith { case t: TimeoutException if (n < maxResends) => send(n + 1) diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/Framer.scala index 52496e4..5558db3 100644 --- a/scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/Framer.scala @@ -1,4 +1,4 @@ -package com.github.jodersky.ace +package com.github.jodersky.ace.protocol import scala.collection.mutable.ArrayBuffer import scala.concurrent.Future @@ -14,9 +14,9 @@ class Framer extends ReactiveLayer[Seq[Int], Seq[Int]] { private var state: State = Waiting private val buffer = new ArrayBuffer[Int] - def receive(bytes: Seq[Int]) = bytes foreach receive + protected def receive(bytes: Seq[Int]) = bytes foreach receive - def receive(byte: Int): Unit = { + protected def receive(byte: Int): Unit = { state match { case Escaping => { @@ -40,7 +40,7 @@ class Framer extends ReactiveLayer[Seq[Int], Seq[Int]] { } } - def write(data: Seq[Int]): Future[Seq[Int]] = { + def send(data: Seq[Int]): Future[Seq[Int]] = { val buffer = new ArrayBuffer[Int] buffer += Start @@ -62,7 +62,7 @@ class Framer extends ReactiveLayer[Seq[Int], Seq[Int]] { case _ => buffer += c } buffer += Stop - writeToLower(buffer) map (_ => data) + sendToLower(buffer) map (_ => data) } } @@ -72,9 +72,9 @@ object Framer { case object Receiving extends State case object Escaping extends State - final val Escape = 0x02 - final val Start = 0x03 - final val Stop = 0x10 + final val Escape = 0x10 + final val Start = 0x02 + final val Stop = 0x03 def checksum(unsignedData: Seq[Int]) = { unsignedData.fold(0)(_ ^ _) diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/ReactiveLayer.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/ReactiveLayer.scala index 663a4a7..c9531c0 100644 --- a/scala/ace/src/main/scala/com/github/jodersky/ace/ReactiveLayer.scala +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/ReactiveLayer.scala @@ -1,4 +1,4 @@ -package com.github.jodersky.ace +package com.github.jodersky.ace.protocol import scala.concurrent.Future @@ -15,14 +15,14 @@ trait ReactiveLayer[L, T] { case None => throw new UnsupportedOperationException("Higher layer doesn't exist.") } - /** Writes data to a lower layer. */ - protected def writeToLower(l: L): Future[L] = lowerLayer match { - case Some(lower) => lower.write(l) + /** Sends data to a lower layer. */ + protected def sendToLower(l: L): Future[L] = lowerLayer match { + case Some(lower) => lower.send(l) case None => Future.failed(new UnsupportedOperationException("Lower layer doesn't exist.")) } /** Connects this layer with a higher layer, effectively linking calls - * `notifyHigher` to `higher.receive` and `higher.writeToLower` to `write`. */ + * `notifyHigher` to `higher.receive` and `higher.sendToLower` to `send`. */ def connect[A](higher: ReactiveLayer[T, A]) = { this.higherLayer = Some(higher) higher.lowerLayer = Some(this) @@ -30,9 +30,9 @@ trait ReactiveLayer[L, T] { } /** Called from lower layer. */ - def receive(data: L): Unit + protected def receive(data: L): Unit - /** Write data to this layer. - * @return a future value containing the data written, or an error */ - def write(data: T): Future[T] + /** Send data to this layer. + * @return a future value containing the data sent, or an error */ + def send(data: T): Future[T] }
\ No newline at end of file diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/SimpleActionLayer.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/SimpleActionLayer.scala new file mode 100644 index 0000000..81e39cb --- /dev/null +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/protocol/SimpleActionLayer.scala @@ -0,0 +1,8 @@ +package com.github.jodersky.ace.protocol + +class SimpleActionLayer[A](action: A => Unit) extends ReactiveLayer[A, A] { + protected def receive(data: A) = action(data) + + def send(data: A) = sendToLower(data) + +}
\ No newline at end of file diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/serial/Serial.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/serial/Serial.scala new file mode 100644 index 0000000..b688ec8 --- /dev/null +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/serial/Serial.scala @@ -0,0 +1,15 @@ +package com.github.jodersky.ace.serial + +import com.github.jodersky.ace.protocol.ReactiveLayer + +trait Serial extends ReactiveLayer[Nothing, Seq[Int]] { + protected def receive(nothing: Nothing) = throw new UnsupportedOperationException("A receive function cannot be called on the lowest layer.") + + def begin(): Unit + def close(): Unit + +} + +object Serial { + def open(port: String, baudRate: Int)(implicit provider: SerialProvider) = provider.open(port, baudRate) +}
\ No newline at end of file diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/serial/SerialProvider.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/serial/SerialProvider.scala new file mode 100644 index 0000000..9c7b95c --- /dev/null +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/serial/SerialProvider.scala @@ -0,0 +1,7 @@ +package com.github.jodersky.ace.serial + +trait SerialProvider { + + def open(port: String, baudRate: Int): Serial + +}
\ No newline at end of file diff --git a/scala/jssc/.gitignore b/scala/jssc/.gitignore new file mode 100644 index 0000000..94730a8 --- /dev/null +++ b/scala/jssc/.gitignore @@ -0,0 +1,18 @@ +*.class +*.log + +# sbt specific +dist/* +target/ +.target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.project +.classpath +.cache +.settings/ diff --git a/scala/jssc/build.sbt b/scala/jssc/build.sbt new file mode 100644 index 0000000..8757f1c --- /dev/null +++ b/scala/jssc/build.sbt @@ -0,0 +1,11 @@ +name := "ace-jssc" + +organization := "com.github.jodersky" + +version := "1.0-SNAPSHOT" + +scalaVersion := "2.10.0" + +scalacOptions ++= Seq("-deprecation","-feature") + +libraryDependencies += "com.github.jodersky" %% "ace" % "1.0-SNAPSHOT" diff --git a/scala/jssc/lib/jssc.jar b/scala/jssc/lib/jssc.jar Binary files differnew file mode 100644 index 0000000..b0d6a82 --- /dev/null +++ b/scala/jssc/lib/jssc.jar diff --git a/scala/jssc/src/main/scala/com/github/jodersky/ace/Main.scala b/scala/jssc/src/main/scala/com/github/jodersky/ace/Main.scala new file mode 100644 index 0000000..55c23b9 --- /dev/null +++ b/scala/jssc/src/main/scala/com/github/jodersky/ace/Main.scala @@ -0,0 +1,30 @@ +package com.github.jodersky.ace + +import com.github.jodersky.ace.protocol._ + +import scala.concurrent.ExecutionContext.Implicits.global + +object Main { + + def main(args: Array[String]): Unit = { + import com.github.jodersky.ace.jssc._ + + val s = serial.Serial.open("/dev/ttyACM0", 9600) + val framer = new Framer + val arq = new Arq(200) + val app = new SimpleActionLayer((s: Seq[Int]) => println(s)) + + s connect framer connect arq connect app + s.begin() + + while (true) { + app.send(Console.readLine.getBytes().map(_.toInt)).map(sent => Console.println("> " + sent)) + + } + + + () + } + + +}
\ No newline at end of file diff --git a/scala/jssc/src/main/scala/com/github/jodersky/ace/jssc/JSSCSerialProvider.scala b/scala/jssc/src/main/scala/com/github/jodersky/ace/jssc/JSSCSerialProvider.scala new file mode 100644 index 0000000..3bfd650 --- /dev/null +++ b/scala/jssc/src/main/scala/com/github/jodersky/ace/jssc/JSSCSerialProvider.scala @@ -0,0 +1,48 @@ +package com.github.jodersky.ace.jssc + +import scala.concurrent._ +import scala.concurrent.ExecutionContext.Implicits.global +import com.github.jodersky.ace.serial._ +import com.github.jodersky.ace.serial.Serial +import jssc.SerialPortEvent +import jssc.SerialPort +import jssc.SerialPortEventListener +import java.io.IOException + +object JSSCSerialProvider extends SerialProvider { + + def open(port: String, baudRate: Int) = new Serial { + val serialPort = new SerialPort(port); + serialPort.openPort() + serialPort.setParams( + baudRate, + SerialPort.DATABITS_8, + SerialPort.STOPBITS_1, + SerialPort.PARITY_NONE) + + val listener = new SerialPortEventListener { + override def serialEvent(event: SerialPortEvent) = { + if (event.isRXCHAR()) { + val bytes = serialPort.readBytes + if (bytes != null) notifyHigher(bytes.map(_ & 0xff)) + } + } + } + + def send(data: Seq[Int]) = future { + serialPort.writeBytes(data.toArray.map(_.toByte)) + } map { success => + if (success) data + else throw new IOException("Could not write to serial port.") + } + + def close() = serialPort.closePort() + + def begin() = { + val mask = SerialPort.MASK_RXCHAR + SerialPort.MASK_CTS + SerialPort.MASK_DSR + serialPort.setEventsMask(mask) + serialPort.addEventListener(listener) + } + } + +}
\ No newline at end of file diff --git a/scala/jssc/src/main/scala/com/github/jodersky/ace/jssc/package.scala b/scala/jssc/src/main/scala/com/github/jodersky/ace/jssc/package.scala new file mode 100644 index 0000000..891e588 --- /dev/null +++ b/scala/jssc/src/main/scala/com/github/jodersky/ace/jssc/package.scala @@ -0,0 +1,7 @@ +package com.github.jodersky.ace + +package object jssc { + + implicit val provider = JSSCSerialProvider + +}
\ No newline at end of file |