blob: 5f8d228ef621330e86215b7cf1242de0e0392037 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
package com.github.jodersky.ace.protocol
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
class LinkLayer extends ReactiveLayer[Array[Byte], Packet] {
import LinkLayer._
private var state: State = Waiting
private val buffer = new ArrayBuffer[Int]
def receive(data: Array[Byte]) = for (d <- data) receive(d)
def receive(data: Byte): Unit = {
val unsigned = data & 0xff
state match {
case Escaping => {
buffer += unsigned
state = Receiving
}
case Waiting => if (unsigned == Start) {
buffer.clear()
state = Receiving
}
case Receiving => unsigned match {
case Escape => state = Escaping
case Start => buffer.clear()
case End => {
state = Waiting
if (checksum(buffer.init.toArray) == buffer.last)
notifyHigher(Packet(buffer.init.toArray))
}
case datum => buffer += datum
}
}
}
def write(packet: Packet): Future[Packet] = {
val buffer = new ArrayBuffer[Int]
buffer += Start
packet.data foreach { unsigned =>
unsigned match {
case Start | End | Escape => {
buffer += Escape
buffer += unsigned
}
case _ => buffer += unsigned
}
}
buffer += checksum(packet.data)
buffer += End
writeToLower(buffer.map(_.toByte).toArray).map(_ => packet)
}
}
object LinkLayer {
sealed trait State
case object Waiting extends State
case object Receiving extends State
case object Escaping extends State
final val Escape = 0x02
final val Start = 0x03
final val End = 0x10
def checksum(unsignedData: Seq[Int]) = {
unsignedData.fold(0)(_ ^ _)
}
}
|