aboutsummaryrefslogtreecommitdiff
path: root/vfd-uav/src
diff options
context:
space:
mode:
Diffstat (limited to 'vfd-uav/src')
-rw-r--r--vfd-uav/src/main/scala/vfd/uav/Connection.scala59
-rw-r--r--vfd-uav/src/main/scala/vfd/uav/MavlinkUtil.scala46
-rw-r--r--vfd-uav/src/main/scala/vfd/uav/MockConnection.scala77
-rw-r--r--vfd-uav/src/main/scala/vfd/uav/SerialConnection.scala136
-rw-r--r--vfd-uav/src/main/scala/vfd/uav/mock/RandomFlightPlan.scala102
5 files changed, 0 insertions, 420 deletions
diff --git a/vfd-uav/src/main/scala/vfd/uav/Connection.scala b/vfd-uav/src/main/scala/vfd/uav/Connection.scala
deleted file mode 100644
index 223a787..0000000
--- a/vfd-uav/src/main/scala/vfd/uav/Connection.scala
+++ /dev/null
@@ -1,59 +0,0 @@
-package vfd.uav
-
-import scala.collection.mutable.ArrayBuffer
-
-import akka.actor.Actor
-import akka.actor.ActorRef
-import akka.actor.Terminated
-import akka.actor.actorRef2Scala
-import akka.util.ByteString
-
-/** Protocol definition. */
-object Connection {
- trait Event
- trait Command
-
- /** Received data from the uav (or any other systems on the link) */
- case class Received(bstr: ByteString) extends Event
-
- /** The connection closed or could not be opened */
- case class Closed(message: String) extends Event
-
- /** Register the sender to be notified on events */
- case object Register extends Command
-
- /** Send given bytes out to the uav (or any other systems on the link) */
- case class Send(bstr: ByteString) extends Command
-}
-
-/** Common behavior of connection actors. */
-trait Connection { myself: Actor =>
-
- /** Current clients that should be notified on incoming messages. */
- private val _clients = new ArrayBuffer[ActorRef]
- def clients = _clients.toSeq
-
- /** Adds a client to the client list and acquires a deathwatch. */
- protected def register(client: ActorRef) = {
- _clients += client
- myself.context.watch(client)
- }
-
- /** Remove client and release deathwatch. */
- protected def unregister(client: ActorRef) = {
- _clients -= client
- myself.context.unwatch(client)
- }
-
- /** Sends a message to all registered clients. */
- protected def sendAll(msg: Any) = clients foreach (_ ! msg)
-
- /**
- * Common registration behavior. Manages the events `Register` and `Terminated` by
- * registering and unregistering clients.
- */
- protected def registration: Receive = {
- case Connection.Register => register(sender)
- case Terminated(client) if clients contains client => unregister(client)
- }
-} \ No newline at end of file
diff --git a/vfd-uav/src/main/scala/vfd/uav/MavlinkUtil.scala b/vfd-uav/src/main/scala/vfd/uav/MavlinkUtil.scala
deleted file mode 100644
index 8a8c364..0000000
--- a/vfd-uav/src/main/scala/vfd/uav/MavlinkUtil.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-package vfd.uav
-
-import org.mavlink.Assembler
-import org.mavlink.Packet
-import org.mavlink.Parser
-import org.mavlink.messages.Message
-
-import akka.actor.Actor
-import akka.actor.ActorLogging
-import akka.util.ByteString
-
-/** Provides utilities for actors representing a mavlink connection. */
-trait MavlinkUtil { myself: Actor with ActorLogging =>
-
- /** Mavlink system ID of this connection. */
- val systemId: Byte
-
- /** Mavlink component ID of this connection. */
- val componentId: Byte
-
- /** Assembler for creating packets originating from this connection. */
- private lazy val assembler = new Assembler(systemId, componentId)
-
- /** Assembles a message into a bytestring representing a packet sent from this connection. */
- protected def assemble(message: Message): ByteString = {
- val (messageId, payload) = Message.pack(message)
- val packet: Packet = assembler.assemble(messageId, payload)
- ByteString(packet.toArray)
- }
-
- /** Parser for messages being sent to the uav. */
- protected val outgoing: Parser = new Parser(packet => Message.unpack(packet.messageId, packet.payload) match {
- //TODO handle ping
- /*
- case Ping(`systemId`, `componentId`) =>
- val message = Ack(packet.systemId, packet.componentId)
- val data = assemble(message)
- self ! Connection.Received(data)*/
- case _ => ()
- })
-
- /** Parser for messages coming from the uav. */
- protected val incoming: Parser = new Parser(pckt =>
- log.debug("incoming message: " + Message.unpack(pckt.messageId, pckt.payload)))
-
-} \ No newline at end of file
diff --git a/vfd-uav/src/main/scala/vfd/uav/MockConnection.scala b/vfd-uav/src/main/scala/vfd/uav/MockConnection.scala
deleted file mode 100644
index d08a8b6..0000000
--- a/vfd-uav/src/main/scala/vfd/uav/MockConnection.scala
+++ /dev/null
@@ -1,77 +0,0 @@
-package vfd.uav
-
-import java.util.concurrent.TimeUnit.MILLISECONDS
-import scala.concurrent.duration.FiniteDuration
-import scala.util.Random
-import org.mavlink.Packet
-import org.mavlink.enums.MavAutopilot
-import org.mavlink.enums.MavModeFlag
-import org.mavlink.enums.MavState
-import org.mavlink.enums.MavType
-import org.mavlink.messages.Heartbeat
-import Connection.Received
-import akka.actor.Actor
-import akka.actor.ActorLogging
-import akka.actor.Props
-import akka.util.ByteString
-import scala.concurrent.duration._
-import org.mavlink.messages.Message
-import vfd.uav.mock.RandomFlightPlan
-
-class MockConnection(
- localSystemId: Byte,
- localComponentId: Byte,
- remoteSystemId: Byte,
- prescaler: Int)
- extends Actor with ActorLogging with Connection with MavlinkUtil {
-
- import Connection._
- import context._
-
- override val systemId = remoteSystemId
- override val componentId = remoteSystemId
-
- val plan = new RandomFlightPlan
-
- def scheduleMessage(delay: FiniteDuration)(fct: => Message) = system.scheduler.schedule(delay, delay){
- sendAll(Received(assemble(fct)))
- }
- def scheduleBytes(delay: FiniteDuration)(fct: => Array[Byte]) = system.scheduler.schedule(delay, delay){
- sendAll(Received(ByteString(fct)))
- }
-
- override def preStart() = {
- //increment state
- system.scheduler.schedule(0.01.seconds * prescaler, 0.01.seconds * prescaler){plan.tick(0.01)}
-
- //send messages
- scheduleMessage(0.1.seconds * prescaler)(plan.position)
- scheduleMessage(0.05.seconds * prescaler)(plan.attitude)
- scheduleMessage(0.05.seconds * prescaler)(plan.motors)
- scheduleMessage(0.1.seconds * prescaler)(plan.distance)
- scheduleMessage(1.seconds)(plan.heartbeat)
-
- //simulate noisy line
- scheduleBytes(0.3.seconds * prescaler)(MockPackets.invalidCrc)
- scheduleBytes(1.5.seconds * prescaler)(MockPackets.invalidOverflow)
- }
-
- def receive = registration
-
-}
-
-object MockConnection {
- def apply(systemId: Byte, componentId: Byte, remoteSystemId: Byte, prescaler: Int = 1) =
- Props(classOf[MockConnection], systemId, componentId, remoteSystemId, prescaler)
-}
-
-object MockPackets {
- val invalidCrc = Array(254, 1, 123, 13, 13).map(_.toByte)
- val invalidOverflow = {
- val data = Array.fill[Byte](Packet.MaxPayloadLength + 100)(42)
- data(0) = -2
- data(1) = 2
- data(1) = -1
- data
- }
-}
diff --git a/vfd-uav/src/main/scala/vfd/uav/SerialConnection.scala b/vfd-uav/src/main/scala/vfd/uav/SerialConnection.scala
deleted file mode 100644
index 1756cac..0000000
--- a/vfd-uav/src/main/scala/vfd/uav/SerialConnection.scala
+++ /dev/null
@@ -1,136 +0,0 @@
-package vfd.uav
-
-import java.util.concurrent.TimeUnit.MILLISECONDS
-
-import scala.concurrent.duration.FiniteDuration
-
-import org.mavlink.enums.MavAutopilot
-import org.mavlink.enums.MavModeFlag
-import org.mavlink.enums.MavState
-import org.mavlink.enums.MavType
-import org.mavlink.messages.Heartbeat
-
-import com.github.jodersky.flow.Parity
-import com.github.jodersky.flow.Serial
-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
-
-class SerialConnection(
- val systemId: Byte,
- val componentId: Byte,
- heartbeatInterval: Option[FiniteDuration],
- port: String,
- settings: SerialSettings) extends Actor with ActorLogging with Connection with MavlinkUtil {
-
- import context._
-
- override def preStart() = heartbeatInterval foreach { interval =>
- context.system.scheduler.schedule(interval, interval) {
- self ! Connection.Send(
- assemble(
- Heartbeat(
- MavType.MavTypeGeneric.toByte,
- MavAutopilot.MavAutopilotGeneric.toByte,
- 0, //no base mode
- 0, //no custom mode
- MavState.MavStateActive.toByte,
- 0 //TODO properly implement read-only fields
- )
- )
- )
- }
- }
-
- def _closed: Receive = {
-
- case Connection.Register =>
- register(sender)
- IO(Serial) ! Serial.Open(port, settings)
- context become opening
-
- case Connection.Send(_) =>
- IO(Serial) ! Serial.Open(port, settings)
- context become opening
-
- }
-
- def _opening: Receive = {
-
- case Serial.CommandFailed(cmd: Serial.Open, reason) =>
- sendAll(Connection.Closed(reason.toString))
- context become closed
-
- case Serial.Opened(_) =>
- context watch (sender)
- context become opened(sender)
-
- case Connection.Send(_) => () // ignore
- /*
- * During opening, any outgoing messages are discarded.
- * By using some kind of message stashing, maybe messages could be treated
- * once the port has been opened. However, in such a case failure also needs
- * to be considered, thus complicating the protocol. Since opening is typically
- * quite fast and since mavlink uses heartbeats and acknowledgements (in certain
- * circumstances) anyway, keeping messages is not really required.
- */
-
- }
-
- def _opened(operator: ActorRef): Receive = {
-
- case Terminated(`operator`) =>
- sendAll(Connection.Closed("Serial connection crashed."))
- context become closed
-
- case Serial.Closed =>
- sendAll(Connection.Closed("Serial connection was closed."))
- context become closed
-
- case Serial.Received(bstr) =>
- sendAll(Connection.Received(bstr))
- incoming.push(bstr)
-
- case Connection.Send(bstr) =>
- outgoing.push(bstr)
- //no sending is enabled
-
- }
-
- def receive = closed
- def closed = _closed orElse registration
- def opening = _opening orElse registration
- def opened(op: ActorRef) = _opened(op) orElse registration
-
-}
-
-object SerialConnection {
- def apply(
- systemId: Byte,
- componentId: Byte,
- heartbeatInterval: Int,
- port: String,
- baud: Int,
- tsb: Boolean,
- parity: Int): Props = {
-
- val settings = SerialSettings(
- baud,
- 8,
- tsb,
- parity match {
- case 0 => Parity.None
- case 1 => Parity.Odd
- case 2 => Parity.Even
- })
- val hb = if (heartbeatInterval == 0) None else Some(FiniteDuration(heartbeatInterval, MILLISECONDS))
-
- Props(classOf[SerialConnection], systemId, componentId, hb, port, settings)
- }
-} \ No newline at end of file
diff --git a/vfd-uav/src/main/scala/vfd/uav/mock/RandomFlightPlan.scala b/vfd-uav/src/main/scala/vfd/uav/mock/RandomFlightPlan.scala
deleted file mode 100644
index 12e3d5c..0000000
--- a/vfd-uav/src/main/scala/vfd/uav/mock/RandomFlightPlan.scala
+++ /dev/null
@@ -1,102 +0,0 @@
-package vfd.uav.mock
-
-import scala.util.Random
-
-import org.mavlink.Mavlink
-import org.mavlink.enums._
-import org.mavlink.messages._
-
-class RandomFlightPlan {
-
- private var time: Double = 0
- private def millis = (time * 1000).toInt
- private def micros = (time * 1E6).toInt
-
- // an oscilliating function
- private def osc[A](min: A, max: A, period: Double, offset: Double = 0)(implicit n: Numeric[A]): A = {
- val amplitude = (n.toDouble(max) - n.toDouble(min)) / 2
- val base = (n.toDouble(max) + n.toDouble(min)) / 2
- val factor = math.sin(2 * math.Pi * (time + offset) / period)
- n.fromInt((base + amplitude * factor).toInt)
- }
-
- private var x: Double = 0.0
- private var y: Double = 0.0
- private var vX: Double = 0.0
- private var vY: Double = 0.0
-
- def tick(delta: Double) {
- val aX = Random.nextDouble() * 5
- val aY = Random.nextDouble() * 5
-
- x += vX * delta
- y += vY * delta
- vX += aX * delta
- vY += aY * delta
-
- time += delta
- }
-
- private final val EarthRadius = 6000000 //m
- private final val StartLat = 46.518513 //deg N
- private final val StartLon = 6.566923 //deg E
-
- def position = GlobalPositionInt(
- millis,
- (StartLat + x / EarthRadius).toInt,
- (StartLon + y / EarthRadius).toInt,
- 0,
- 0,
- (vX * 100).toShort,
- (vY * 100).toShort,
- 0,
- 0
- )
-
- def attitude = Attitude(
- millis,
- (2 * math.Pi * time / 6).toFloat,
- (math.sin(2 * math.Pi * time / 5) * math.Pi / 6).toFloat,
- (2 * math.Pi * time / 4).toFloat,
- 0,
- 0,
- 0
- )
-
- def heartbeat = Heartbeat(
- MavType.MavTypeGeneric.toByte,
- MavAutopilot.MavAutopilotGeneric.toByte,
- (MavModeFlag.MavModeFlagSafetyArmed | MavModeFlag.MavModeFlagManualInputEnabled).toByte,
- 0, //no custom mode
- MavState.MavStateActive.toByte,
- Mavlink.MavlinkVersion
- )
-
- private final val DistanceMin: Short = 10
- private final val DistanceMax: Short = 500
- def distance = DistanceSensor(
- timeBootMs = millis,
- minDistance = DistanceMin,
- maxDistance = DistanceMax,
- currentDistance = osc(DistanceMin, DistanceMax, 6),
- `type` = MavDistanceSensor.MavDistanceSensorUltrasound.toByte,
- id = 0: Byte,
- orientation = -1: Byte,
- covariance = 3: Byte)
-
- private final val MotorsMax: Short = 2000 //usec, ppm signal => 100%
- private final val MotorsMin: Short = 1000 //usec, ppm signal => 0%
- def motors = ServoOutputRaw(
- timeUsec = micros,
- port = 0: Byte,
- servo1Raw = osc(MotorsMin, MotorsMax, 6, 0),
- servo2Raw = osc(MotorsMin, MotorsMax, 6, 5),
- servo3Raw = osc(MotorsMin, MotorsMax, 6, 2),
- servo4Raw = osc(MotorsMin, MotorsMax, 6, 4),
- servo5Raw = 0,
- servo6Raw = 0,
- servo7Raw = 0,
- servo8Raw = 0
- )
-
-} \ No newline at end of file