aboutsummaryrefslogtreecommitdiff
path: root/flow-core/src/main/scala/ch/jodersky/flow/Serial.scala
blob: 43b1d19df1da9c8185c935960f54f207637a6857 (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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package ch.jodersky.flow

import akka.actor.ExtensionKey
import akka.util.ByteString

/** Defines messages used by flow's serial IO layer. */
object Serial extends ExtensionKey[SerialExt] {

  /** Base trait for any flow-related messages. */
  sealed trait Message

  /** A message extending this trait is to be viewed as a command, an out-bound message issued by the client to flow's API. */
  trait Command extends Message

  /** A message extending this trait is to be viewed as an event, an in-bound message issued by flow to the client. */
  trait Event extends Message

  /** A command has failed. */
  case class CommandFailed(command: Command, reason: Throwable) extends Event

  /**
   * Open a new serial port.
   *
   * Send this command to the serial manager to request the opening of a serial port. The manager will
   * attempt to open a serial port with the specified parameters and, if successful, create a `SerialOperator` actor associated to the port.
   * The operator actor acts as an intermediate to the underlying native serial port, dealing with threading issues and dispatching messages.
   *
   * In case the port is successfully opened, the operator will respond with an `Opened` message.
   * In case the port cannot be opened, the manager will respond with a `CommandFailed` message.
   *
   * @param port name of serial port to open
   * @param settings settings of serial port to open
   * @param bufferSize maximum read and write buffer sizes
   */
  case class Open(port: String, settings: SerialSettings, bufferSize: Int = 1024) extends Command

  /**
   * A port has been successfully opened.
   *
   * Event sent by a port operator, indicating that a serial port was successfully opened. The sender
   * of this message is the operator associated to the given serial port.
   *
   * @param port name of opened serial port
   */
  case class Opened(port: String) extends Event

  /**
   * Data has been received.
   *
   * Event sent by an operator, indicating that data was received on the operator's serial port.
   *
   * @param data data received on the port
   */
  case class Received(data: ByteString) extends Event

  /**
   * Write data to a serial port.
   *
   * Send this command to an operator to write the given data to its associated serial port.
   * An acknowledgment may be set, in which case it is sent back to the sender on a successful write.
   * Note that a successful write does not guarantee the actual transmission of data through the serial port,
   * it merely guarantees that the data has been stored in the operating system's kernel buffer, ready to
   * be transmitted.
   *
   * @param data data to be written to port
   * @param ack acknowledgment sent back to sender once data has been enqueued in kernel for sending (the acknowledgment
   * is a function 'number of bytes written => event')
   */
  case class Write(data: ByteString, ack: Int => Event = NoAck) extends Command

  /**
   *  Special type of acknowledgment that is not sent back.
   */
  case object NoAck extends Function1[Int, Event] {
    def apply(length: Int) = sys.error("cannot apply NoAck")
  }

  /**
   *  Request closing of port.
   *
   *  Send this command to an operator to close its associated port. The operator will respond
   *  with a `Closed` message upon closing the serial port.
   */
  case object Close extends Command

  /**
   * A port has been closed.
   *
   * Event sent from operator, indicating that its port has been closed.
   */
  case object Closed extends Event

  /**
   * Watch a directory for new ports.
   *
   * Send this command to the manager to get notifications when a new port (i.e. file) is created in
   * the given directory.
   * In case the given directory cannot be watched, the manager responds with a `CommandFailed` message.
   *
   * Note: the sender is also notified of currently existing ports.
   *
   * @param directory the directory to watch
   * @param skipInitial don't get notified of already existing ports
   *
   * @see Unwatch
   * @see Connected
   */
  case class Watch(directory: String = "/dev", skipInitial: Boolean = false) extends Command

  /**
   * Stop receiving notifications about a previously watched directory.
   *
   * @param directory the directory to unwatch
   */
  case class Unwatch(directory: String = "/dev") extends Command

  /**
   * A new port (i.e. file) has been detected.
   *
   * @param port the absolute file name of the connected port
   */
  case class Connected(port: String) extends Event

  /**
   * Sets native debugging mode. If debugging is enabled, detailed error messages
   * are printed (to stderr) from native method calls.
   *
   * @param value set to enable debugging
   */
  def debug(value: Boolean) = UnsafeSerial.debug(value)

}