Skip to content

Instantly share code, notes, and snippets.

@joesan
Created January 10, 2017 05:11
Show Gist options
  • Save joesan/9e7bbc991d5999ad409e28046276fa65 to your computer and use it in GitHub Desktop.
Save joesan/9e7bbc991d5999ad409e28046276fa65 to your computer and use it in GitHub Desktop.
package my.samples.deviceManager
import akka.actor.{Actor, ActorLogging, ActorRef, Kill, Props, Terminated}
import akka.io.IO
import akka.util.ByteString
import ch.jodersky.flow.Serial.Command
import ch.jodersky.flow.{Parity, Serial, SerialSettings}
import my.samples.deviceManager.DeviceExplorerActor.DeviceSerialNumber
import my.samples.deviceManager.DeviceWatcherActor.InitializeSerialPort
class Device1Actor(parent: ActorRef) extends Actor with ActorLogging {
val serialSettings = SerialSettings(38400, 8, twoStopBits = true, Parity(0))
val writeMessage = "{<}D000 ~C5" + "\r\n"
val ioSerial = IO(Serial)
override def receive: Receive = {
case InitializeSerialPort(serialPort) =>
ioSerial ! Serial.Open(serialPort, serialSettings)
case Serial.CommandFailed(cmd, reason) =>
log.error(s"Connection failed, stopping terminal. Reason: $reason")
parent ! Kill
case Serial.Opened(port) =>
log.info(s"Port $port is now open.")
self ! writeMessage
context become checkSerial(sender, "", "")
}
def parseSerialNumber(message: String): Option[String] = {
val regex = """D003 S/N\|([^~]+)~""".r.unanchored
message match {
case regex(c) => Some(c)
case _ => None
}
}
def parseEndOfSerial(message: String): Option[String] = {
val regex = """D006 ([^~]+)~""".r.unanchored
message match {
case regex(c) => Some(c)
case _ => None
}
}
def checkSerial(operator: ActorRef, appendedMsg: String, serial: String): Receive = {
case Serial.Received(data) =>
val newMsg = data.decodeString("windows-1250")
val latestMessages = s"$appendedMsg$newMsg"
if (serial.isEmpty) {
parseSerialNumber(latestMessages) match {
case Some(serialNumber) =>
// TODO inject serialNumber into ThingWorx
log.info(s"serial number parsed is $serialNumber")
context become checkSerial(operator, latestMessages, serialNumber)
case None =>
context become checkSerial(operator, latestMessages, "")
}
} else {
parseEndOfSerial(latestMessages) match {
case Some(_) =>
context become opened(operator, "", serial)
case None =>
context become checkSerial(operator, latestMessages, serial)
}
}
case str: String =>
operator ! Serial.Write(ByteString(str))
}
def opened(operator: ActorRef, appendedMsg: String, serial: String): Receive = {
case Serial.Received(data) =>
val newMsg = data.decodeString("windows-1250")
val latestMessages = s"$appendedMsg$newMsg"
log.info(s"Received data: $latestMessages with serial $serial ${context.parent.path}")
context become opened(operator, latestMessages, serial)
case Serial.Closed =>
log.info("Operator closed normally, exiting terminal.")
context stop self
case Terminated(`operator`) =>
log.error("Operator crashed unexpectedly, exiting terminal.")
context stop self
case ":q" =>
log.info("q from opened ")
operator ! Serial.Close
case DeviceSerialNumber =>
log.info("device serial request")
parent ! serial
}
}
object Device1Actor {
def props(parent: ActorRef) = Props(new Device1Actor(parent))
}
package my.samples.deviceManager
import akka.actor.{Actor, ActorLogging, ActorRef, Props}
import akka.util.Timeout
import my.samples.deviceManager.DeviceExplorerActor.DeviceSerialNumber
import my.samples.deviceManager.DeviceWatcherActor.InitializeSerialPort
import akka.pattern.ask
import scala.concurrent.Await
import scala.concurrent.duration._
class DeviceExplorerActor extends Actor with ActorLogging {
implicit val timeout = Timeout(4.seconds)
def tryDevices(port: String, actorRef: ActorRef): String = {
actorRef ! InitializeSerialPort(port)
Await.result((actorRef ? DeviceSerialNumber).mapTo[String], 4.seconds)
}
def receive: Receive = {
case InitializeSerialPort(serialPort) =>
val device1Actor = s"device1$serialPort"
val device2Actor = s"device2$serialPort"
if(tryDevices(serialPort, context.actorOf(Device1Actor.props(self), device1Actor)) == "") { // try Device1
log.info(s"found Device1 serial device at port $serialPort")
} else if (tryDevices(serialPort, context.actorOf(Device2Actor.props(self), device2Actor)) == "") { // try Device2
log.info(s"found Device2 serial device at port $serialPort")
} else { // nothing worked out, log and send a message to SupervisorActor
log.info(s"unknown serial device on port $serialPort")
}
}
}
object DeviceExplorerActor {
case object DeviceSerialNumber
def props = Props(new DeviceExplorerActor)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment