aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2015-03-20 12:07:41 +0100
committerJakob Odersky <jodersky@gmail.com>2015-03-20 12:07:41 +0100
commit3147aba7dc79e64d2da50d7d1c705bfd0e99eeca (patch)
tree6c0babfa3e227e3407a0fe250059724f303ad08a
parent1cf6e37dc356144f3da2a2dcde75d1ced8bc5ad6 (diff)
downloadsbt-mavlink-3147aba7dc79e64d2da50d7d1c705bfd0e99eeca.tar.gz
sbt-mavlink-3147aba7dc79e64d2da50d7d1c705bfd0e99eeca.tar.bz2
sbt-mavlink-3147aba7dc79e64d2da50d7d1c705bfd0e99eeca.zip
implement testing
-rw-r--r--.gitignore12
-rw-r--r--README.md12
-rw-r--r--mavlink-library/src/main/twirl/org/mavlink/Assembler.scala.txt2
-rw-r--r--mavlink-library/src/main/twirl/org/mavlink/MavlinkBuffer.scala.txt2
-rw-r--r--mavlink-library/src/main/twirl/org/mavlink/Packet.scala.txt29
-rw-r--r--mavlink-library/src/main/twirl/org/mavlink/Parser.scala.txt2
-rw-r--r--mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala14
-rw-r--r--mavlink-plugin/src/sbt-test/sbt-mavlink/codec/build.sbt11
-rw-r--r--mavlink-plugin/src/sbt-test/sbt-mavlink/codec/mavlink.xml115
-rw-r--r--mavlink-plugin/src/sbt-test/sbt-mavlink/codec/project/plugins.sbt1
-rw-r--r--mavlink-plugin/src/sbt-test/sbt-mavlink/codec/src/main/scala/Main.scala53
-rw-r--r--mavlink-plugin/src/sbt-test/sbt-mavlink/codec/test3
-rw-r--r--project/Build.scala9
-rw-r--r--project/scripted.sbt3
-rw-r--r--project/twirl.sbt (renamed from project/plugins.sbt)0
15 files changed, 243 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index e38fe35..1d1019c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,12 +10,12 @@ project/boot/
project/plugins/project/
# scala-ide specific
-/.settings
-/.scala_dependencies
-/.project
-/.classpath
-/.cache
-/.history
+.settings
+.scala_dependencies
+.project
+.classpath
+.cache
+.history
# ensime
.ensime
diff --git a/README.md b/README.md
index bb894af..716a2d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,13 @@
# SBT-MAVLink Plugin
-This plugin aims to provide generation of Scala sources from MAVLink message definition files. \ No newline at end of file
+This plugin provides generation of Scala sources from MAVLink message definition files.
+It translates a MAVLink dialect defined in XML to useable scala objects and provides utilities for parsing
+and creating MAVLink packets.
+
+See an example
+
+## Usage
+Add the following to your plugins:
+
+ addSbtPlugin("com.github.jodersky" % "sbt-mavlink" % "0.1")
+
diff --git a/mavlink-library/src/main/twirl/org/mavlink/Assembler.scala.txt b/mavlink-library/src/main/twirl/org/mavlink/Assembler.scala.txt
index e3571e6..fc5becf 100644
--- a/mavlink-library/src/main/twirl/org/mavlink/Assembler.scala.txt
+++ b/mavlink-library/src/main/twirl/org/mavlink/Assembler.scala.txt
@@ -15,5 +15,5 @@ class Assembler(systemId: Byte, componentId: Byte) {
val p = Packet(seq.toByte, systemId, componentId, messageId, payload)
seq += 1
p
- }
+ }
} \ No newline at end of file
diff --git a/mavlink-library/src/main/twirl/org/mavlink/MavlinkBuffer.scala.txt b/mavlink-library/src/main/twirl/org/mavlink/MavlinkBuffer.scala.txt
index 9a01dbe..ebcd643 100644
--- a/mavlink-library/src/main/twirl/org/mavlink/MavlinkBuffer.scala.txt
+++ b/mavlink-library/src/main/twirl/org/mavlink/MavlinkBuffer.scala.txt
@@ -5,7 +5,7 @@ import java.nio.ByteBuffer
import java.nio.ByteOrder
/** Utility functions for using ByteBuffers. */
-class MavlinkBuffer {
+object MavlinkBuffer {
/**
* Allocates a ByteBuffer for using in MAVLink message processing.
diff --git a/mavlink-library/src/main/twirl/org/mavlink/Packet.scala.txt b/mavlink-library/src/main/twirl/org/mavlink/Packet.scala.txt
index a0d11a5..6802a0a 100644
--- a/mavlink-library/src/main/twirl/org/mavlink/Packet.scala.txt
+++ b/mavlink-library/src/main/twirl/org/mavlink/Packet.scala.txt
@@ -20,21 +20,33 @@ case class Packet(
payload: ByteBuffer
) {
- /*
- def crc = {
+ lazy val crc = {
var c = new Crc()
- c = c.accumulate(payload.length.toByte)
+ c = c.accumulate(payload.remaining.toByte)
c = c.accumulate(seq)
c = c.accumulate(systemId)
c = c.accumulate(componentId)
c = c.accumulate(messageId)
- while (payload.)
- for (p <- payload) {
- c = c.accumulate(p)
+ while (payload.hasRemaining) {
+ c = c.accumulate(payload.get())
}
c = c.accumulate(Packet.extraCrc(messageId))
c
- }*/
+ }
+
+ def writeTo(out: Array[Byte], offset: Int = 0): Unit = {
+ out(offset) = Packet.Stx
+ out(offset+1) = payload.remaining.toByte
+ out(offset+2) = seq
+ out(offset+3) = systemId
+ out(offset+4) = componentId
+ out(offset+5) = messageId
+ val r = payload.remaining()
+ payload.get(out, 0, out.length)
+ out(offset + r) = crc.lsb
+ out(offset + r + 1) = crc.msb
+ }
+
}
object Packet {
@@ -45,6 +57,9 @@ object Packet {
/** Maximum length of a payload contained in a packet. */
final val MaxPayloadLength: Int = @__maxPayloadLength
+ /** Maximum over-the-wire size of a packet, i.e. the maximum payload length plus header and footer data. */
+ final val MaxPacketLength: Int = MaxPayloadLength + 8
+
/** Additional CRCs indexed by message ID (see MAVLink specification). */
final val ExtraCrcs: Seq[Byte] = Array[Byte](
@__extraCrcs.map(_ formatted "%3d").grouped(10).map(_.mkString(",")).mkString(",\n ")
diff --git a/mavlink-library/src/main/twirl/org/mavlink/Parser.scala.txt b/mavlink-library/src/main/twirl/org/mavlink/Parser.scala.txt
index ca04ae1..81affc5 100644
--- a/mavlink-library/src/main/twirl/org/mavlink/Parser.scala.txt
+++ b/mavlink-library/src/main/twirl/org/mavlink/Parser.scala.txt
@@ -40,7 +40,7 @@ object Parser {
* @@param receiver called when a valid packet has been received
* @@param error called when invalid data was received
*/
-class Parser(payload: ByteBuffer, receiver: Packet => Unit, error: Parser.Errors.Error => Unit = _ => ()) {
+class Parser(payload: ByteBuffer)(receiver: Packet => Unit, error: Parser.Errors.Error => Unit = _ => ()) {
import Parser._
private var state: States.State = States.Idle
diff --git a/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala b/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala
index 41a6bcf..d04ea43 100644
--- a/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala
+++ b/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala
@@ -16,14 +16,14 @@ object SbtMavlink extends AutoPlugin {
override def requires = JvmPlugin //this is required as sourceGenerators are otherwise reset
override lazy val projectSettings: Seq[Setting[_]] = Seq(
- mavlinkDialect in Compile := (baseDirectory in Compile).value / "conf" / "mavlink.xml",
- mavlinkTarget in Compile := (sourceManaged in Compile).value,
- mavlinkGenerate in Compile := generationTask.value,
- sourceGenerators in Compile += (mavlinkGenerate in Compile).taskValue
+ mavlinkDialect := baseDirectory.value / "conf" / "mavlink.xml",
+ mavlinkTarget := sourceManaged.value,
+ mavlinkGenerate := generationTask.value,
+ sourceGenerators in Compile += mavlinkGenerate.taskValue
)
lazy val generationTask = Def.task[Seq[File]] {
- val dialectDefinitionFile = (mavlinkDialect in Compile).value
+ val dialectDefinitionFile = mavlinkDialect.value
if (!dialectDefinitionFile.exists) sys.error(
"Dialect definition " + dialectDefinitionFile.getAbsolutePath + " does not exist."
@@ -33,13 +33,13 @@ object SbtMavlink extends AutoPlugin {
val dialect = Parser.parseDialect(dialectDefinition)
val pathToSource = (new Generator(dialect)).generate()
- val outDirectory = (mavlinkTarget in Compile).value
+ val outDirectory = mavlinkTarget.value
streams.value.log.info("Generating mavlink files...")
val files = for ((path, source) <- pathToSource) yield {
- streams.value.log.debug("Generating " + path)
val file = outDirectory / path
+ streams.value.log.info("Generating " + file)
IO.write(file, source)
file.getAbsoluteFile
}
diff --git a/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/build.sbt b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/build.sbt
new file mode 100644
index 0000000..d4035f2
--- /dev/null
+++ b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/build.sbt
@@ -0,0 +1,11 @@
+import com.github.jodersky.mavlink.sbt.MavlinkKeys._
+
+mavlinkDialect := baseDirectory.value / "mavlink.xml"
+
+scalaVersion := "2.10.4"
+
+name := "test"
+
+organization := "test"
+
+version := "1.0" \ No newline at end of file
diff --git a/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/mavlink.xml b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/mavlink.xml
new file mode 100644
index 0000000..fcbdc35
--- /dev/null
+++ b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/mavlink.xml
@@ -0,0 +1,115 @@
+<?xml version='1.0'?>
+<mavlink>
+ <version>1</version>
+ <enums>
+ <enum name="MAV_STATE">
+ <entry value="0" name="MAV_STATE_UNINIT">
+ <description>Uninitialized system, state is unknown.</description>
+ </entry>
+ <entry value="1" name="MAV_STATE_BOOT">
+ <description>System is booting up.</description>
+ </entry>
+ <entry value="2" name="MAV_STATE_CALIBRATING">
+ <description>System is calibrating and not flight-ready.</description>
+ </entry>
+ <entry value="3" name="MAV_STATE_STANDBY">
+ <description>System is grounded and on standby. It can be launched any time.</description>
+ </entry>
+ <entry value="4" name="MAV_STATE_ACTIVE">
+ <description>System is active and might be already airborne. Motors are engaged.</description>
+ </entry>
+ <entry value="5" name="MAV_STATE_CRITICAL">
+ <description>System is in a non-normal flight mode. It can however still navigate.</description>
+ </entry>
+ <entry value="6" name="MAV_STATE_EMERGENCY">
+ <description>System is in a non-normal flight mode. It lost control over parts or over the whole airframe. It is in mayday and going down.</description>
+ </entry>
+ <entry value="7" name="MAV_STATE_POWEROFF">
+ <description>System just initialized its power-down sequence, will shut down now.</description>
+ </entry>
+
+ </enum>
+ </enums>
+ <messages>
+ <message id="0" name="HEARTBEAT">
+ <description>The heartbeat message shows that a system is present and responding.</description>
+ <field type="uint8_t" name="system_state" enum="MAV_STATE">Global state of system.</field>
+ </message>
+ <message id="1" name="POWER">
+ <description>Information about the main power source.</description>
+ <field type="uint16_t" name="voltage">Voltage of the source (mV)</field>
+ </message>
+ <message id="2" name="IMU">
+ <description>The IMU readings in a NED body frame</description>
+ <field type="int32_t" name="xacc">X acceleration (mm/s^2)</field>
+ <field type="int32_t" name="yacc">Y acceleration (mm/s^2)</field>
+ <field type="int32_t" name="zacc">Z acceleration (mm/s^2)</field>
+ <field type="int32_t" name="xgyro">Angular speed around X axis (mrad / sec)</field>
+ <field type="int32_t" name="ygyro">Angular speed around Y axis (mrad / sec)</field>
+ <field type="int32_t" name="zgyro">Angular speed around Z axis (mrad / sec)</field>
+ <field type="int32_t" name="xmag">X Magnetic field (uT)</field>
+ <field type="int32_t" name="ymag">Y Magnetic field (uT)</field>
+ <field type="int32_t" name="zmag">Z Magnetic field (uT)</field>
+ <field type="int32_t" name="alt">Altitude to mean sea level (mm)</field>
+ <field type="uint32_t" name="temperature">Ambient temperature (mK)</field>
+ </message>
+ <message id="3" name="DISTANCE">
+ <description>Information on distance sensors</description>
+ <field type="int16_t" name="relative_alt">Relative altitude to ground (mm)</field>
+ </message>
+ <message name="PING" id="4">
+ <description>Ping a target system, usually used to determine latency.</description>
+ <field type="uint8_t" name="target_system">System ID</field>
+ <field type="uint8_t" name="target_component">Component ID</field>
+ </message>
+ <message name="ACK" id="5">
+ <description>Acknowledgement packet</description>
+ <field type="uint8_t" name="target_system">System ID</field>
+ <field type="uint8_t" name="target_component">Component ID</field>
+ </message>
+ <message name="MOTOR" id="6">
+ <description>Status of motors</description>
+ <field type="uint8_t" name="m0">m0</field>
+ <field type="uint8_t" name="m1">m1</field>
+ <field type="uint8_t" name="m2">m2</field>
+ <field type="uint8_t" name="m3">m3</field>
+ </message>
+ <message id="30" name="ATTITUDE">
+ <description>The attitude in the aeronautical frame (right-handed, Z-down, X-front, Y-right).</description>
+ <field type="int16_t" name="roll">Roll angle</field>
+ <field type="int16_t" name="pitch">Pitch angle</field>
+ <field type="uint16_t" name="yaw">Yaw angle</field>
+ </message>
+ <message id="70" name="RC_CHANNELS_OVERRIDE">
+ <description>The RAW values of the RC channels sent to the MAV to override info received from the RC radio. A value of UINT16_MAX means no change to that channel. A value of 0 means control of that channel should be released back to the RC radio. The standard PPM modulation is as follows: 1000 microseconds: 0%, 2000 microseconds: 100%. Individual receivers/transmitters might violate this specification.</description>
+ <field type="uint8_t" name="target_system">System ID</field>
+ <field type="uint8_t" name="target_component">Component ID</field>
+ <field type="uint16_t" name="chan1_raw">RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan2_raw">RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan3_raw">RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan4_raw">RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan5_raw">RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan6_raw">RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan7_raw">RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ <field type="uint16_t" name="chan8_raw">RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field.</field>
+ </message>
+ <message name="RADIO_STATUS" id="109">
+ <description>Status generated by radio</description>
+ <field type="uint8_t" name="rssi">local signal strength</field>
+ <field type="uint8_t" name="remrssi">remote signal strength</field>
+ <field type="uint8_t" name="txbuf">how full the tx buffer is as a percentage</field>
+ <field type="uint8_t" name="noise">background noise level</field>
+ <field type="uint8_t" name="remnoise">remote background noise level</field>
+ <field type="uint16_t" name="rxerrors">receive errors</field>
+ <field type="uint16_t" name="fixed">count of error corrected packets</field>
+ </message>
+ <message name="TEST_MESSAGE" id="110">
+ <description>Test</description>
+ <field type="uint8_t[2]" name="bytearray">a byte array</field>
+ <field type="float[20]" name="floatarray">a float array</field>
+ <field type="char" name="chars">a char</field>
+ <field type="double" name="doubles">a double</field>
+ <field type="char[20]" name="strings">a string</field>
+ </message>
+ </messages>
+</mavlink>
diff --git a/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/project/plugins.sbt b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/project/plugins.sbt
new file mode 100644
index 0000000..c2bb2a1
--- /dev/null
+++ b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/project/plugins.sbt
@@ -0,0 +1 @@
+addSbtPlugin("com.github.jodersky" % "sbt-mavlink" % sys.props("plugin.version")) \ No newline at end of file
diff --git a/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/src/main/scala/Main.scala b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/src/main/scala/Main.scala
new file mode 100644
index 0000000..6c84968
--- /dev/null
+++ b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/src/main/scala/Main.scala
@@ -0,0 +1,53 @@
+import org.mavlink._
+import org.mavlink.messages._
+
+object Main {
+
+ val SenderSystemId = 0: Byte
+ val SenderComponentId = 0: Byte
+ val ReceiverSystemId = 1: Byte
+ val ReceiverComponentId = 0: Byte
+
+ def main(args: Array[String]): Unit = {
+ echoTest()
+ }
+
+ def echoTest() = {
+ //represents the line buffer, i.e. all data going in and out
+ val line = new Array[Byte](Packet.MaxPacketLength)
+
+ //payload of incoming messages
+ val in = MavlinkBuffer.allocate()
+
+ //parser to transform an incoming byte stream into packets
+ val parser = new Parser(in)(
+ pckt => {
+ val msg = Message.unpack(pckt.messageId, pckt.payload)
+ println("received message: " + msg)
+ },
+ err => {
+ sys.error("parse error: " + err)
+ }
+ )
+
+ //payload buffer of outgoing messages
+ val out = MavlinkBuffer.allocate()
+
+ //assembles messages into pakets from a specific sender
+ val assembler = new Assembler(SenderSystemId, SenderComponentId)
+
+ //create an explicit message
+ val message = Heartbeat(0)
+
+ //pack the message into a payload
+ val id = Message.pack(message, out)
+
+ //assemble into packet
+ val packet = assembler.assemble(id, out)
+
+ //simulate wire transfer
+ packet.writeTo(line)
+ parser.push(line)
+ }
+
+} \ No newline at end of file
diff --git a/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/test b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/test
new file mode 100644
index 0000000..c009de9
--- /dev/null
+++ b/mavlink-plugin/src/sbt-test/sbt-mavlink/codec/test
@@ -0,0 +1,3 @@
+# check if the files get created
+> run
+$ exists target/scala-2.10/src_managed/org/mavlink \ No newline at end of file
diff --git a/project/Build.scala b/project/Build.scala
index ddf108e..c0c4f4e 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -2,6 +2,7 @@ import sbt._
import sbt.Keys._
import play.twirl.sbt.SbtTwirl
import play.twirl.sbt.Import._
+import sbt.ScriptedPlugin._
object ApplicationBuild extends Build {
@@ -31,9 +32,15 @@ object ApplicationBuild extends Build {
lazy val plugin = (
Project("mavlink-plugin", file("mavlink-plugin"))
settings(common: _*)
+ settings(ScriptedPlugin.scriptedSettings: _*)
settings(
sbtPlugin := true,
- name := "sbt-mavlink"
+ name := "sbt-mavlink",
+ scriptedLaunchOpts := { scriptedLaunchOpts.value ++
+ Seq("-Xmx1024M", "-XX:MaxPermSize=256M", "-Dplugin.version=" + version.value)
+ },
+ scriptedBufferLog := false,
+ publishLocal <<= publishLocal.dependsOn(publishLocal in library)
)
dependsOn(library)
)
diff --git a/project/scripted.sbt b/project/scripted.sbt
new file mode 100644
index 0000000..c3b4f97
--- /dev/null
+++ b/project/scripted.sbt
@@ -0,0 +1,3 @@
+libraryDependencies <+= (sbtVersion) { sv =>
+ "org.scala-sbt" % "scripted-plugin" % sv
+} \ No newline at end of file
diff --git a/project/plugins.sbt b/project/twirl.sbt
index 7b458b6..7b458b6 100644
--- a/project/plugins.sbt
+++ b/project/twirl.sbt