aboutsummaryrefslogtreecommitdiff
path: root/flow-samples/terminal/src/main/scala/com/github/jodersky/flow/samples/terminal/Terminal.scala
blob: cf75d98b107314422ec34c84c5dd146b5c26ec6b (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
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"))
  
}