summaryrefslogtreecommitdiff
path: root/ebus-scala/Main.scala
diff options
context:
space:
mode:
authorYves Fischer <yvesf-git@xapek.org>2011-12-17 22:58:46 +0100
committerYves Fischer <yvesf-git@xapek.org>2011-12-17 22:58:46 +0100
commitb9d158491e243aa9f834dc392e961e8431354b87 (patch)
tree844a9e1197b0677dd5c8c73bdae7c752d59f7648 /ebus-scala/Main.scala
parent3cae6c2fcb3e3f107d2eff94c833554d4ffa3d11 (diff)
downloadebus-alt-b9d158491e243aa9f834dc392e961e8431354b87.tar.gz
ebus-alt-b9d158491e243aa9f834dc392e961e8431354b87.zip
code cleanup
Diffstat (limited to 'ebus-scala/Main.scala')
-rwxr-xr-x[-rw-r--r--]ebus-scala/Main.scala271
1 files changed, 130 insertions, 141 deletions
diff --git a/ebus-scala/Main.scala b/ebus-scala/Main.scala
index be8daca..05f40c2 100644..100755
--- a/ebus-scala/Main.scala
+++ b/ebus-scala/Main.scala
@@ -1,3 +1,6 @@
+#!/bin/sh
+exec scala "$0" "$@"
+!#
import Stream._
import java.io.{ InputStream, EOFException }
import java.net.{ InetAddress, InetSocketAddress, Socket }
@@ -15,6 +18,7 @@ class EbusDefinition(val ebusXmlFile: String) {
}
abstract class EbusField(val name : String, val offset : Int);
+
class Data2c(override val name: String, override val offset : Int) extends EbusField(name, offset) {
}
@@ -37,6 +41,7 @@ object EbusField {
}
+
class EbusL2Packet(val source: Int,
val destination: Int,
val primaryCommand: Int,
@@ -56,21 +61,6 @@ class EbusL2Packet(val source: Int,
destination.toInt, primaryCommand.toInt, secondaryCommand.toInt, payloadLength.toInt,
crc.toInt, p.toString, rawLength)
}
-
- /**
- * 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
- */
- def calcCrc: Int = {
- //val foo = payload.reduce((a, b) => ((a.intValue + b.intValue) % 256).toChar)
- //val sum = destination + primaryCommand + secondaryCommand + payloadLength + foo
-
- val crc = 1 + 1
- 1
- }
}
class EbusL2MasterSlavePacket(source: Int,
@@ -94,7 +84,7 @@ class EbusL2MasterSlavePacket(source: Int,
class FakePacket(val rawLength : Int);
-class EbusParseException(val message : String, val data : List[Int]);
+class EbusParseException(val message : String, val data : List[Int], val skipbytes : Int) extends Exception;
object CRC {
val crcTab = List[Int](
@@ -132,8 +122,14 @@ object CRC {
}
+object Ebus {
+ def SYN = 0xaa
+ def ACK_OK = 0x00
+ def ACK_FAIL = 0xff
+}
object EbusL2Packet {
+ def PAYLOAD_LENGTH_MAX = 16
/**
* Wird von {@link EbusReader} mit einer Streamposition aufgerufen.
* Ausgehend von dieser Position wird versucht ein Paket aufzubauen,
@@ -144,56 +140,55 @@ object EbusL2Packet {
def apply(stream: Stream[Int]): Option[Any] = {
var mystream = stream
var rawLength = 0
- def readBytes(n:Int, msg : String = "") : List[Int] = {
+ def readBytes(n:Int, msg : String) : List[Int] = {
val d = mystream.slice(rawLength,rawLength+n).toList
rawLength = rawLength + n
- println("RAW %15s: ".format(msg) + d.map((it) => "0x%02x".format(it)).foldLeft(""){(s1,s2) => s1+","+s2})
+ println("RAW %15s: ".format(msg) + d.map((it) => "0x%02x".format(it)).reduceRight((s1,s2) => s1+","+s2))
return d
}
- val source :: destination :: primaryCommand :: secondaryCommand :: payloadLength :: _ = readBytes(5, "QQ|ZZ|PB|SB|NN")
-
- // Maximale payload Grösse = 16 Byte
- if (payloadLength > 16) {
- println("Erkannte payload Groesse zu gross: %d".format(payloadLength))
- return Some(new FakePacket(rawLength + 1))
- } else if (payloadLength == 0) {
- // Unklar
- println("Überspringe payloadLength mit Länge = 0")
- return Some(new FakePacket(rawLength + 1));
- }
- // "eBUS Spezifikation Physikalische Schicht – OSI 1
- // Verbindungsschicht – OSI 2 V.1.3.1" page 8
- val payload = Range(0,payloadLength).map({ i =>
+ def readPayloadByte(i:Int) : Int =
readBytes(1, "payload " + i)(0) match {
case 0xa9 => {
readBytes(1, "payload esc "+i)(0) match {
case 0x00 => 0xa9
case 0x01 => 0xaa
case code : Int => {
- // throw
- App.println("Invalid escape sequence (0xa9 0x%02x)".format(code))
- return None
+ throw new EbusParseException("Invalid escape sequence (0xa9 0x%02x)".format(code),
+ stream.slice(0, rawLength).toList, rawLength);
}
}
}
case value : Int => value
}
- }).toList
-
+
+ val source :: destination :: primaryCommand :: secondaryCommand :: payloadLength :: _ = readBytes(5, "QQ|ZZ|PB|SB|NN")
+
+ // Maximale payload Grösse = 16 Byte
+ if (payloadLength > PAYLOAD_LENGTH_MAX) {
+ throw new EbusParseException("Erkannte payload Groesse zu gross: %d".format(payloadLength),
+ stream.slice(0, rawLength).toList, rawLength);
+ } else if (payloadLength == 0) {
+ // Unklar
+ throw new EbusParseException("Skip packet with payloadLength = 0",
+ stream.slice(0, rawLength).toList, rawLength + 1);
+ }
+
+ val payload = Range(0,payloadLength).map(readPayloadByte).toList
+
val crc = readBytes(1,"CRC")(0)
val crcCalc = CRC(List(source, destination, primaryCommand, secondaryCommand, payloadLength) ++ payload)
if (crc != crcCalc) {
- println("CRC mismatch (read) 0x%02x != 0x%02x (calc)".format(crc, crcCalc))
- return Some(new FakePacket(rawLength + 1)) // + SYN
+ throw new EbusParseException("CRC mismatch (read) 0x%02x != 0x%02x (calc)".format(crc, crcCalc),
+ stream.slice(0, rawLength).toList, rawLength + 1);
}
// Broadcast Packet ends here
if (destination == 0xfe) {
val syn = readBytes(1,"SYN(broadcast)")(0)
- if (syn != 0xaa) {
- App.println("bad SYN 0x%02x".format(syn))
- return None
+ if (syn != Ebus.SYN) {
+ throw new EbusParseException("Bad SYN: 0x%02x".format(syn),
+ stream.slice(0, rawLength).toList, rawLength);
}
return Some(new EbusL2Packet(source, destination,
primaryCommand, secondaryCommand,
@@ -204,56 +199,43 @@ object EbusL2Packet {
val syn = readBytes(1, "SYN/NN2")(0)
// Master-Master Packet ends here
- if (syn == 0xaa) {
- if (ack != 0x00) {
- App.println("bad ACK=0x%02x".format(syn))
+ if (syn == Ebus.SYN) {
+ if (ack != Ebus.ACK_OK) {
+ throw new EbusParseException("Bad ACK: 0x%02x".format(ack),
+ stream.slice(0, rawLength).toList, rawLength);
}
return Some(new EbusL2Packet(source, destination,
primaryCommand, secondaryCommand,
payloadLength, payload, crc, rawLength))
}
+
// otherwise this is a Master-Slave Telegramm
// and syn is payloadSlave length
val payloadSlaveLength = syn
- if (payloadSlaveLength > 16) {
- println("payloadSlaveLength > 16: 0x%02x".format(payloadSlaveLength))
- return None
+ if (payloadSlaveLength > PAYLOAD_LENGTH_MAX) {
+ throw new EbusParseException("payloadSlaveLength > 16: 0x%02x".format(payloadSlaveLength),
+ stream.slice(0, rawLength).toList, rawLength);
}
- val payloadSlave = Range(0,payloadSlaveLength).map({ i =>
- readBytes(1, "payloadSlave "+i)(0) match {
- case 0xa9 => {
- readBytes(1,"payloadSlave(esc) "+i)(0) match {
- case 0x00 => 0xa9
- case 0x01 => 0xaa
- case code : Int => {
- // throw
- App.println("Invalid escape sequence (0xa9 0x%02x)".format(code))
- return None
- }
- }
- }
- case value : Int => value
- }
- }).toList
+ val payloadSlave = Range(0,payloadSlaveLength).map(readPayloadByte).toList
val crcSlave = readBytes(1,"crcSlave")(0)
val crcSlaveCalc = CRC(List(payloadSlaveLength) ++ payloadSlave)
if (crcSlave != crcSlaveCalc) {
- println("CRC mismatch (read) 0x%02x != 0x%02x (calc)".format(crcSlave, crcSlaveCalc))
- return Some(new FakePacket(rawLength + 2)) // + ACK + SYN
+ throw new EbusParseException("CRC mismatch (read) 0x%02x != 0x%02x (calc)".format(crcSlave, crcSlaveCalc),
+ stream.slice(0, rawLength).toList, rawLength);
}
val ackSlave = readBytes(1,"ACKslave")(0)
- if (ackSlave != 0x00) {
- App.println("Master-Slave ACK nicht 0x00 sondern 0x%02x".format(ackSlave))
- return None
+ if (ackSlave != Ebus.ACK_OK) {
+ throw new EbusParseException("Master-Slave ACK nicht 0x00 sondern 0x%02x".format(ackSlave),
+ stream.slice(0, rawLength).toList, rawLength);
}
val synSlave= readBytes(1,"SYNslave")(0)
- if (synSlave != 0xaa) {
- App.println("Master-Slave SYN nicht 0xaa sondern 0x%02x".format(synSlave))
- return None
+ if (synSlave != Ebus.SYN) {
+ throw new EbusParseException("Master-Slave SYN nicht 0xaa sondern 0x%02x".format(synSlave),
+ stream.slice(0, rawLength).toList, rawLength);
}
return Some(new EbusL2MasterSlavePacket(source, destination,
@@ -269,28 +251,31 @@ class EbusReader(var stream : Stream[Int]) {
def next() : EbusL2Packet = {
while (true) {
// Überspringe Synchronisationszeichen
- var i = 0
- while (stream(0) == 0xaa) {
- stream = stream.drop(1)
- i = i +1
- }
- println("Skipped " + i + " SYNs")
-
- EbusL2Packet(stream) match {
- case Some(packet : EbusL2Packet) => {
- stream = stream.drop(packet.rawLength)
- return packet
- }
- case Some(packet : FakePacket) => {
- println("Fake paket - forward %d bytes".format(packet.rawLength))
- stream = stream.drop(packet.rawLength)
+ stream = stream.dropWhile(_ == Ebus.SYN)
+
+ try {
+ EbusL2Packet(stream) match {
+ case Some(packet : EbusL2Packet) => {
+ stream = stream.drop(packet.rawLength)
+ return packet
+ }
+ case Some(packet : FakePacket) => {
+ println("Fake paket - forward %d bytes".format(packet.rawLength))
+ stream = stream.drop(packet.rawLength)
+ }
+ case None => {
+ // Es konnte kein Paket eingelesen werden
+ // verschiebe die Anfangsposition um ein Byte
+ App.println("Paket konnte nicht gelesen werden, verschiebe start um 1 byte")
+ stream = stream.drop(1)
+ }
+ }
+ } catch {
+ case exc : EbusParseException => {
+ stream = stream.drop(exc.skipbytes)
+ App.println("Exception: " + exc.message + "\n\tData: " +
+ exc.data.map((it) => "0x%02x".format(it)).reduceRight((s1,s2) => s1+","+s2))
}
- case None => {
- // Es konnte kein Paket eingelesen werden
- // verschiebe die Anfangsposition um ein Byte
- App.println("Paket konnte nicht gelesen werden, verschiebe start um 1 byte")
- stream = stream.drop(1)
- }
}
}
return null;
@@ -323,76 +308,80 @@ object App {
var source: InputStream = null
def println(msg : Any) {
- Predef.println("[ebus] " + msg.toString)
+ Predef.println("[ebus]\t" + msg.toString)
}
def main(args: Array[String]): Unit = {
- if (args.size == 1 && args(0) == "-") {
- 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) {
- println("Fehler: read == -1")
- System.exit(1)
+ args.toList match {
+ case "-" :: List() => {
+ source = System.in
+ }
+ case host :: port :: List() => {
+ val addr = InetAddress.getByName(host)
+ val sockAddr = new InetSocketAddress(addr, port.toInt)
+ val s = new Socket()
+ s.connect(sockAddr)
+ println("Connected to %s %d".format(args(0), args(1).toInt))
+ source = s.getInputStream
+ }
+ case "dump" :: host :: port :: List() => {
+ val addr = InetAddress.getByName(host)
+ val sockAddr = new InetSocketAddress(addr, port.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) {
+ println("Fehler: read == -1")
+ System.exit(1)
+ }
+ System.out.write(v)
}
- System.out.write(v)
}
- } else {
- println("Missing Arguments")
- println(" -")
- println(" Read from stdin")
- println("HOST PORT")
- println(" Read from TCP Server")
- println("dump HOST PORT")
- println(" Dump TCP-Stream")
- System.exit(1)
+ case _ => println(
+"""Usage: PROGRAM <ARGUMENTS>
+ARGUMENTS:
+-
+ Parse Ebus from stdin
+dump HOST PORT
+ Read and Dump TCP Connection
+HOST PORT
+ Parse Ebus from TCP Connection
+""")
}
- val read = (() => {
+ var stream: Stream[Int] = Stream.continually({
val value = source.read
if (value == -1)
- throw new EOFException("End of File reached (read returned -1)")
+ throw new EOFException("End of File reached (read returned -1)")
value
})
-
-
- var stream: Stream[Int] = Stream.continually(read())
// Synchronisiere
- while (stream(0) != 0xaa && stream(1) != 0xaa) {
+ while (stream(0) != Ebus.SYN) {
stream = stream.drop(1)
}
val reader = new EbusReader(stream)
- while (true) {
- try {
- println(reader.next)
- } catch {
- case exc : EOFException => {
- println("EOF")
- source.close
- exit(0)
+ (() => {
+ while (true) {
+ try {
+ println(reader.next)
+ } catch {
+ case exc : EOFException => {
+ println("EOF")
+ return;
+ }
}
}
- }
+ })()
println("exiting")
source.close
}
}
-App.main(Array("-"))
+
+
+App.main(args)