From 494b80da610fe2b4cb1790ae237437a17ac6ef62 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Sat, 2 Mar 2013 12:06:03 +0100 Subject: simplify scala implementation --- .../scala/com/github/jodersky/ace/Framer.scala | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala (limited to 'scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala') diff --git a/scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala b/scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala new file mode 100644 index 0000000..8546c48 --- /dev/null +++ b/scala/ace/src/main/scala/com/github/jodersky/ace/Framer.scala @@ -0,0 +1,83 @@ +package com.github.jodersky.ace + +import scala.collection.mutable.ArrayBuffer +import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global + +/** A framer takes bytes (as unsigned integers) and creates frames. + * Note that the input type of this reactive layer is also a sequence of + * integers for performance reasons (i.e. a future will not be created for every byte sent). + */ +class Framer extends ReactiveLayer[Seq[Int], Seq[Int]] { + import Framer._ + + private var state: State = Waiting + private val buffer = new ArrayBuffer[Int] + + protected def receive(bytes: Seq[Int]) = bytes foreach receive + + protected def receive(byte: Int): Unit = { + + state match { + case Escaping => { + buffer += byte + state = Receiving + } + case Waiting => if (byte == Start) { + buffer.clear() + state = Receiving + } + case Receiving => byte match { + case Escape => state = Escaping + case Start => buffer.clear() + case Stop => { + state = Waiting + if (checksum(buffer.init) == buffer.last) + notifyHigher(buffer.init) + } + case datum => buffer += datum + } + } + } + + def send(data: Seq[Int]): Future[Seq[Int]] = { + val buffer = new ArrayBuffer[Int] + + buffer += Start + data foreach { byte => + byte match { + case Start | Stop | Escape => { + buffer += Escape + buffer += byte + } + case _ => buffer += byte + } + } + val c = checksum(data) + c match { + case Start | Stop | Escape => { + buffer += Escape + buffer += c + } + case _ => buffer += c + } + buffer += Stop + sendToLower(buffer) map (_ => data) + } +} + +object Framer { + sealed trait State + case object Waiting extends State + case object Receiving extends State + case object Escaping extends State + + final val Escape = 0x10 + final val Start = 0x02 + final val Stop = 0x03 + + def checksum(unsignedData: Seq[Int]) = { + unsignedData.fold(0)(_ ^ _) + } + +} \ No newline at end of file -- cgit v1.2.3