summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryvesf <yvesf-git@xapek.org>2011-07-03 11:38:28 +0200
committeryvesf <yvesf-git@xapek.org>2011-07-03 11:38:28 +0200
commitffaec1ddc9118eb07a30b2d759f0204484fa9ec4 (patch)
treefba1bfeb7d1fbec0544a7d80338a862f33519344
parentc9f7b9f93a7048e06c212b3dad5bf0752e2672f2 (diff)
downloadebus-alt-ffaec1ddc9118eb07a30b2d759f0204484fa9ec4.tar.gz
ebus-alt-ffaec1ddc9118eb07a30b2d759f0204484fa9ec4.zip
ebus-scala
-rw-r--r--ebus-scala/.classpath7
-rw-r--r--ebus-scala/.gitignore1
-rw-r--r--ebus-scala/.project18
-rw-r--r--ebus-scala/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--ebus-scala/src/App.scala194
5 files changed, 232 insertions, 0 deletions
diff --git a/ebus-scala/.classpath b/ebus-scala/.classpath
new file mode 100644
index 0000000..bc01bff
--- /dev/null
+++ b/ebus-scala/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ebus-scala/.gitignore b/ebus-scala/.gitignore
new file mode 100644
index 0000000..be9619d
--- /dev/null
+++ b/ebus-scala/.gitignore
@@ -0,0 +1 @@
+.scala_dependencies
diff --git a/ebus-scala/.project b/ebus-scala/.project
new file mode 100644
index 0000000..a19eae3
--- /dev/null
+++ b/ebus-scala/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>ebus-scala</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.scala-ide.sdt.core.scalabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.scala-ide.sdt.core.scalanature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ebus-scala/.settings/org.eclipse.jdt.core.prefs b/ebus-scala/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..33e19bd
--- /dev/null
+++ b/ebus-scala/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Sat Jul 02 17:29:58 CEST 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/ebus-scala/src/App.scala b/ebus-scala/src/App.scala
new file mode 100644
index 0000000..8bd27e9
--- /dev/null
+++ b/ebus-scala/src/App.scala
@@ -0,0 +1,194 @@
+import Stream._
+import java.io.{ InputStream, EOFException }
+import java.net.{ InetAddress, InetSocketAddress, Socket }
+
+class EbusDefinition(val ebusXmlFile: String) {
+ import scala.xml.XML
+ import scala.xml.NodeSeq
+
+ val xml = XML.loadFile(ebusXmlFile)
+
+ def packetFromCommandId(primaryCommand: Char, secondaryCommand: Char): NodeSeq = {
+ val packet = (xml \ "packets" \ "packet").filter(n =>
+ n.attribute("primary").get.text.toInt == primaryCommand &&
+ n.attribute("secondary").get.text.toInt == secondaryCommand)
+ packet
+ }
+}
+
+object EbusPacket {
+ /**
+ * Wird von {@link EbusReader} mit einer Streamposition aufgerufen.
+ * Ausgehend von dieser Position wird versucht ein Paket aufzubauen,
+ * und anschliesend die Checksumme geprüft.
+ * Im Erfolgsfall wird eine EbusPacket-Instanz als Option zurückgegen,
+ * sonst None
+ */
+ def apply(stream: Stream[Int]): Option[EbusPacket] = {
+ try {
+ var rawLength = 0
+ val source = stream.apply(0).toChar
+ val destination = stream.apply(1).toChar
+ val primaryCommand = stream.apply(2).toChar
+ val secondaryCommand = stream.apply(3).toChar
+ val payloadLength = stream.apply(4).toChar
+ rawLength = 5
+
+ var payload = new Array[Char](payloadLength)
+ for (i <- 0 until payloadLength) {
+ var it = stream.apply(rawLength).toChar
+ rawLength += 1
+ // Handle escape sequences
+ // "eBUS Spezifikation Physikalische Schicht – OSI 1
+ // Verbindungsschicht – OSI 2 V.1.3.1" auf Seite 8
+ if (it == 0xa9.toChar) {
+ val itNext = stream.apply(rawLength).toChar
+ rawLength += 1
+ if (itNext == 0x00.toChar) {
+ it = 0xa9.toChar
+ } else if (itNext == 0x01.toChar) {
+ it = 0xaa.toChar
+ } else {
+ println("Ignore escape sequence 0xa9 0x%02x".format(itNext))
+ rawLength -= 1
+ }
+ }
+ payload.update(i, it)
+ }
+ val crc = stream.apply(5 + payloadLength).toChar
+ rawLength += 1
+
+ return Some(new EbusPacket(source, destination,
+ primaryCommand, secondaryCommand,
+ payloadLength, payload, crc, rawLength))
+ } catch {
+ case exc: IndexOutOfBoundsException => {
+ println(exc.toString)
+ exc.printStackTrace
+ return None
+ }
+ }
+ }
+}
+
+class EbusPacket(val source: Char,
+ val destination: Char,
+ val primaryCommand: Char,
+ val secondaryCommand: Char,
+ val payloadLength: Char,
+ val payload: Array[Char],
+ val crc: Char,
+ val rawLength: Int) {
+ val length = 6 + payload.size
+
+ override def toString: String = {
+ val p = if (payload.size == 0)
+ ""
+ else
+ payload.map(a => "%02x".format(a.toInt)).
+ reduceLeft((a: Any, b: String) => a + " " + b)
+
+ "Ebus: d=%02x pC=%02x sC=%02x pL=%02x crc=%02x p=%s".format(
+ destination.toInt, primaryCommand.toInt, secondaryCommand.toInt, payloadLength.toInt,
+ crc.toInt, p.toString)
+ }
+
+ /**
+ * Die CRC-Prüfsumme wird vom jeweiligen Sender über der expandierten Bytesendefolge mit dem
+ * Generatorpolynom X8 +X7 + X4 + X3 + X +1 gebildet und als letztes Byte der Nachricht,
+ * sofern notwendig, sogar expandiert gesendet.
+ *
+ * Generatorpol. 11001101
+ */
+ private def calcCrc: Char = {
+ val sum = destination + primaryCommand + secondaryCommand + payloadLength +
+ payload.reduce((a, b) => ((a.intValue + b.intValue) % 256).toChar)
+ val crc = 1 + 1
+ 1
+ }
+}
+
+object EbusReader {
+ def apply(streamI: Stream[Int]): EbusPacket = {
+ var stream = streamI
+ while (true) {
+ // Überspringe Synchronisationszeichen
+ stream = stream.dropWhile(v => v.toChar == 0xaa.toChar)
+
+ EbusPacket(stream) match {
+ case Some(packet) => {
+ stream = stream.drop(packet.rawLength)
+ return packet
+ }
+ case None => {
+ // Es konnte kein Paket eingelesen werden
+ // verschieben die Anfangsposition um ein Byte
+ stream = stream.drop(1)
+ println("skip 1 byte")
+ }
+ }
+ }
+ null
+ }
+}
+
+object App {
+ val ebusDefinition = new EbusDefinition("/home/yvesf/vcs/ebus/ebus/ebus-xml/ebus.xml")
+ var source: InputStream = null
+
+ def main(args: Array[String]): Unit = {
+ if (args.size == 1) {
+ println("Use stdin as source")
+ source = System.in
+ } else if (args.size == 2) {
+ val addr = InetAddress.getByName(args(0))
+ val sockAddr = new InetSocketAddress(addr, args(1).toInt)
+ val s = new Socket()
+ s.connect(sockAddr)
+ println("Connected to %s %d".format(args(0), args(1).toInt))
+ source = s.getInputStream
+ } else if (args.size == 3 && args(0) == "dump") {
+ val addr = InetAddress.getByName(args(1))
+ val sockAddr = new InetSocketAddress(addr, args(2).toInt)
+ val s = new Socket()
+ s.connect(sockAddr)
+ System.err.println("Connected to %s %d".format(args(1), args(2).toInt))
+ while (true) {
+ val v = s.getInputStream.read
+ if (v == -1)
+ System.exit(1)
+ print(v.toChar)
+ }
+ } else {
+ println("Missing Arguments")
+ println(" Read from stdin: -")
+ println(" Read from TCP: HOST PORT")
+ println(" Read from TCP and dump to stdout: dump HOST PORT")
+ System.exit(1)
+ }
+
+ val read = (() => {
+ val value = source.read
+ if (value == -1)
+ throw new EOFException("End of File reached (read returned -1)")
+ value
+ })
+ val stream: Stream[Int] = Stream.continually(read())
+
+ while (true) {
+ EbusReader(stream) match {
+ case x: EbusPacket => {
+ println(x)
+ val p = ebusDefinition.packetFromCommandId(x.primaryCommand, x.secondaryCommand)
+ if (p.size == 1)
+ println(p(0).attribute("name").get)
+ }
+ case null => {
+ println("null")
+ }
+ }
+ }
+ println("exiting")
+ source.close
+ }
+}