From 23959966760174477a6b0fcbf9dd1e8ef37c643b Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Sun, 8 Jan 2017 21:16:25 +0100 Subject: Rename project to akka-serial --- samples/README.md | 3 + .../akka/serial/samples/terminalstream/Main.scala | 66 +++++++++++++++++++ .../serial/samples/terminal/ConsoleReader.scala | 29 +++++++++ .../scala/akka/serial/samples/terminal/Main.scala | 30 +++++++++ .../akka/serial/samples/terminal/Terminal.scala | 75 ++++++++++++++++++++++ .../scala/akka/serial/samples/watcher/main.scala | 50 +++++++++++++++ 6 files changed, 253 insertions(+) create mode 100644 samples/README.md create mode 100644 samples/terminal-stream/src/main/scala/akka/serial/samples/terminalstream/Main.scala create mode 100644 samples/terminal/src/main/scala/akka/serial/samples/terminal/ConsoleReader.scala create mode 100644 samples/terminal/src/main/scala/akka/serial/samples/terminal/Main.scala create mode 100644 samples/terminal/src/main/scala/akka/serial/samples/terminal/Terminal.scala create mode 100644 samples/watcher/src/main/scala/akka/serial/samples/watcher/main.scala (limited to 'samples') diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 0000000..d51b9c2 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,3 @@ +This directory contains fully functional application examples of akka-serial. To run an example, change to the base directory of akka-serial (this parent's directory) and run `sbt samples/run`. + +All projects, including samples, can be listed by running `sbt projects`. diff --git a/samples/terminal-stream/src/main/scala/akka/serial/samples/terminalstream/Main.scala b/samples/terminal-stream/src/main/scala/akka/serial/samples/terminalstream/Main.scala new file mode 100644 index 0000000..de626a3 --- /dev/null +++ b/samples/terminal-stream/src/main/scala/akka/serial/samples/terminalstream/Main.scala @@ -0,0 +1,66 @@ +package akka.serial +package samples.terminalstream + +import scala.concurrent.Future +import scala.concurrent.duration._ +import scala.io.StdIn + +import akka.actor.ActorSystem +import akka.stream.ActorMaterializer +import akka.stream.scaladsl.{Flow, Keep, Sink, Source} +import akka.util.ByteString + +import stream.Serial + +object Main { + + final val Delay = FiniteDuration(500, MILLISECONDS) + + implicit val system = ActorSystem("terminal-stream") + implicit val materializer = ActorMaterializer() + + def ask(label: String, default: String) = { + print(label + " [" + default.toString + "]: ") + val in = StdIn.readLine() + println("") + if (in.isEmpty) default else in + } + + def main(args: Array[String]): Unit = { + import system.dispatcher + + val port = ask("Device", "/dev/ttyACM0") + val baud = ask("Baud rate", "115200").toInt + val cs = ask("Char size", "8").toInt + val tsb = ask("Use two stop bits", "false").toBoolean + val parity = Parity(ask("Parity (0=None, 1=Odd, 2=Even)", "0").toInt) + val settings = SerialSettings(baud, cs, tsb, parity) + + val serial: Flow[ByteString, ByteString, Future[Serial.Connection]] = + Serial().open(port, settings) + + val printer: Sink[ByteString, _] = Sink.foreach[ByteString]{data => + println("server says: " + data.decodeString("UTF-8")) + } + + val ticker: Source[ByteString, _] = Source.tick(Delay, Delay, ()).scan(0){case (x, _) => + x + 1 + }.map{ x => + println(x) + ByteString(x.toString) + } + + val connection: Future[Serial.Connection] = ticker.viaMat(serial)(Keep.right).to(printer).run() + + connection map { conn => + println("Connected to " + conn.port) + StdIn.readLine("Press enter to exit") + } recover { case err => + println("Cannot connect: " + err) + } andThen { case _ => + system.terminate() + } + + } + +} diff --git a/samples/terminal/src/main/scala/akka/serial/samples/terminal/ConsoleReader.scala b/samples/terminal/src/main/scala/akka/serial/samples/terminal/ConsoleReader.scala new file mode 100644 index 0000000..cc14dd4 --- /dev/null +++ b/samples/terminal/src/main/scala/akka/serial/samples/terminal/ConsoleReader.scala @@ -0,0 +1,29 @@ +package akka.serial +package samples.terminal + +import akka.actor.Actor +import scala.io.StdIn + +class ConsoleReader extends Actor { + import context._ + import ConsoleReader._ + + def receive = { + case Read => + StdIn.readLine() match { + case ":q" | null => parent ! EOT + case s => { + parent ! ConsoleInput(s) + } + } + } + +} + +object ConsoleReader { + + case object Read + case object EOT + case class ConsoleInput(in: String) + +} diff --git a/samples/terminal/src/main/scala/akka/serial/samples/terminal/Main.scala b/samples/terminal/src/main/scala/akka/serial/samples/terminal/Main.scala new file mode 100644 index 0000000..0226e72 --- /dev/null +++ b/samples/terminal/src/main/scala/akka/serial/samples/terminal/Main.scala @@ -0,0 +1,30 @@ +package akka.serial +package samples.terminal + +import akka.actor.ActorSystem +import scala.io.StdIn + +object Main { + + def ask(label: String, default: String) = { + print(label + " [" + default.toString + "]: ") + val in = StdIn.readLine() + println("") + if (in.isEmpty) default else in + } + + def main(args: Array[String]): Unit = { + val port = ask("Device", "/dev/ttyACM0") + val baud = ask("Baud rate", "115200").toInt + val cs = ask("Char size", "8").toInt + val tsb = ask("Use two stop bits", "false").toBoolean + val parity = Parity(ask("Parity (0=None, 1=Odd, 2=Even)", "0").toInt) + val settings = SerialSettings(baud, cs, tsb, parity) + + println("Starting terminal system, enter :q to exit.") + Serial.debug(true) + val system = ActorSystem("akka-serial") + val terminal = system.actorOf(Terminal(port, settings), name = "terminal") + system.registerOnTermination(println("Stopped terminal system.")) + } +} diff --git a/samples/terminal/src/main/scala/akka/serial/samples/terminal/Terminal.scala b/samples/terminal/src/main/scala/akka/serial/samples/terminal/Terminal.scala new file mode 100644 index 0000000..55b0422 --- /dev/null +++ b/samples/terminal/src/main/scala/akka/serial/samples/terminal/Terminal.scala @@ -0,0 +1,75 @@ +package akka.serial +package samples.terminal + +import akka.actor.{ Actor, ActorLogging, ActorRef, Props, Terminated, 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.terminate() + } + + def receive = { + case Serial.CommandFailed(cmd, reason) => { + log.error(s"Connection failed, stopping terminal. Reason: ${reason}") + context stop self + } + case Serial.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 Serial.Received(data) => { + log.info(s"Received data: ${formatData(data)}") + } + + case Terminal.Wrote(data) => log.info(s"Wrote data: ${formatData(data)}") + + case Serial.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 ! Serial.Close + } + + case ConsoleReader.ConsoleInput(input) => { + val data = ByteString(input.getBytes) + operator ! Serial.Write(data, length => Wrote(data.take(length))) + reader ! ConsoleReader.Read + } + } + +} + +object Terminal { + case class Wrote(data: ByteString) extends Serial.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")) + +} diff --git a/samples/watcher/src/main/scala/akka/serial/samples/watcher/main.scala b/samples/watcher/src/main/scala/akka/serial/samples/watcher/main.scala new file mode 100644 index 0000000..d9a0d4e --- /dev/null +++ b/samples/watcher/src/main/scala/akka/serial/samples/watcher/main.scala @@ -0,0 +1,50 @@ +package akka.serial +package samples.watcher + +import akka.actor.{ Actor, ActorLogging, ActorSystem, Props } +import akka.io.IO +import scala.io.StdIn + +class Watcher extends Actor with ActorLogging { + import context._ + + val ports = List( + "/dev/ttyUSB\\d+", + "/dev/ttyACM\\d+", + "/dev/cu\\d+", + "/dev/ttyS\\d+" + ) + + override def preStart() = { + val cmd = Serial.Watch() + IO(Serial) ! cmd //watch for new devices + log.info(s"Watching ${cmd.directory} for new devices.") + } + + def receive = { + + case Serial.CommandFailed(w: Serial.Watch, err) => + log.error(err, s"Could not get a watch on ${w.directory}.") + context stop self + + case Serial.Connected(path) => + log.info(s"New device: ${path}") + ports.find(path matches _) match { + case Some(port) => log.info(s"Device is a serial device.") + case None => log.warning(s"Device is NOT serial device.") + } + + } + +} + +object Main { + + def main(args: Array[String]): Unit = { + val system = ActorSystem("akka-serial") + val watcher = system.actorOf(Props(classOf[Watcher]), name = "watcher") + StdIn.readLine() + system.terminate() + } + +} -- cgit v1.2.3