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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
package com.github.jodersky.flow.samples.terminal
import com.github.jodersky.flow.Serial
import com.github.jodersky.flow.Serial.Close
import com.github.jodersky.flow.Serial.Closed
import com.github.jodersky.flow.Serial.CommandFailed
import com.github.jodersky.flow.Serial.Event
import com.github.jodersky.flow.Serial.Opened
import com.github.jodersky.flow.Serial.Received
import com.github.jodersky.flow.Serial.Write
import com.github.jodersky.flow.SerialSettings
import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.ActorRef
import akka.actor.Props
import akka.actor.Terminated
import akka.actor.actorRef2Scala
import akka.io.IO
import akka.util.ByteString
class Terminal(port: String, settings: SerialSettings) extends Actor with ActorLogging {
import Terminal._
import context._
val reader = actorOf(Props[ConsoleReader])
log.info(s"Requesting manager to open port: ${port}, baud: ${settings.baud}")
IO(Serial) ! Serial.Open(port, settings)
override def postStop() = {
system.shutdown()
}
def receive = {
case CommandFailed(cmd, reason) => {
log.error(s"Connection failed, stopping terminal. Reason: ${reason}")
context stop self
}
case Opened(port) => {
log.info(s"Port ${port} is now open.")
val operator = sender
context become opened(operator)
context watch operator
reader ! ConsoleReader.Read
}
}
def opened(operator: ActorRef): Receive = {
case Received(data) => {
log.info(s"Received data: ${formatData(data)}")
}
case Wrote(data) => log.info(s"Wrote data: ${formatData(data)}")
case Closed => {
log.info("Operator closed normally, exiting terminal.")
context unwatch operator
context stop self
}
case Terminated(`operator`) => {
log.error("Operator crashed, exiting terminal.")
context stop self
}
case ConsoleReader.EOT => {
log.info("Initiating close.")
operator ! Close
}
case ConsoleReader.ConsoleInput(input) => {
val data = ByteString(input.getBytes)
operator ! Write(data, length => Wrote(data.take(length)))
reader ! ConsoleReader.Read
}
}
}
object Terminal {
case class Wrote(data: ByteString) extends Event
def apply(port: String, settings: SerialSettings) = Props(classOf[Terminal], port, settings)
private def formatData(data: ByteString) = data.mkString("[", ",", "]") + " " + (new String(data.toArray, "UTF-8"))
}
|