summaryrefslogtreecommitdiff
path: root/ebus-scala
diff options
context:
space:
mode:
authorYves Fischer <yvesf-git@xapek.org>2011-12-17 21:47:25 +0100
committerYves Fischer <yvesf-git@xapek.org>2011-12-17 21:47:25 +0100
commitc25d4d9c49fab29abea0d85b4f4190d5bc7330c1 (patch)
treea29d6ef5e875d387db6fbb6248502957c24f95bc /ebus-scala
parentf700bb5400cffae5ba8b13923406be5e063036d3 (diff)
downloadebus-alt-c25d4d9c49fab29abea0d85b4f4190d5bc7330c1.tar.gz
ebus-alt-c25d4d9c49fab29abea0d85b4f4190d5bc7330c1.zip
ebus-scala cleanup, fixup - master-slave packets
Diffstat (limited to 'ebus-scala')
-rw-r--r--ebus-scala/Main.scala343
1 files changed, 218 insertions, 125 deletions
diff --git a/ebus-scala/Main.scala b/ebus-scala/Main.scala
index e91de0a..070240f 100644
--- a/ebus-scala/Main.scala
+++ b/ebus-scala/Main.scala
@@ -45,8 +45,6 @@ class EbusL2Packet(val source: Int,
val payload: List[Int],
val crc: Int,
val rawLength: Int) {
- val length = 6 + payload.size
-
override def toString: String = {
val p = if (payload.size == 0)
""
@@ -54,9 +52,9 @@ class EbusL2Packet(val source: Int,
payload.map(a => "%02x".format(a.toInt)).
reduceLeft((a: Any, b: String) => a + " " + b)
- "L2Packet: d=%02x pC=%02x sC=%02x pL=%02x crc=%02x p=%s".format(
+ "L2Packet: d=%02x pC=%02x sC=%02x pL=%02x crc=%02x p=%s rawL=%d".format(
destination.toInt, primaryCommand.toInt, secondaryCommand.toInt, payloadLength.toInt,
- crc.toInt, p.toString)
+ crc.toInt, p.toString, rawLength)
}
/**
@@ -75,7 +73,65 @@ class EbusL2Packet(val source: Int,
}
}
-class FakePacket(val length : Int);
+class EbusL2MasterSlavePacket(source: Int,
+ destination: Int,
+ primaryCommand: Int,
+ secondaryCommand: Int,
+ payloadLength: Int,
+ payload: List[Int],
+ crc: Int,
+ val payloadSlaveLength : Int,
+ val payloadSlave : List[Int],
+ val crcSlave : Int,
+ rawLength: Int) extends EbusL2Packet(source,
+ destination,
+ primaryCommand,
+ secondaryCommand,
+ payloadLength,
+ payload,
+ crc,
+ rawLength);
+
+class FakePacket(val rawLength : Int);
+
+class EbusParseException(val message : String, val data : List[Int]);
+
+object CRC {
+ val crcTab = List[Int](
+ 0, 155, 173, 54, 193, 90, 108, 247, 25, 130, //0 -9
+ 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, //10-19
+ 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, //20
+ 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, //30
+ 125, 230, 208, 75, 188, 39, 17, 138, 86, 205,
+ 251, 96, 151, 12, 58, 161, 79, 212, 226, 121,
+ 142, 21, 35, 184, 200, 83, 101, 254, 9, 146,
+ 164, 63, 209, 74, 124, 231, 16, 139, 189, 38,
+ 250, 97, 87, 204, 59, 160, 150, 13, 227, 120,
+ 78, 213, 34, 185, 143, 20, 172, 55, 1, 154,
+ 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, //100
+ 217, 66, 158, 5, 51, 168, 95, 196, 242, 105,
+ 135, 28, 42, 177, 70, 221, 235, 112, 11, 144,
+ 166, 61, 202, 81, 103, 252, 18, 137, 191, 36,
+ 211, 72, 126, 229, 57, 162, 148, 15, 248, 99,
+ 85, 206, 32, 187, 141, 22, 225, 122, 76, 215,
+ 111, 244, 194, 89, 174, 53, 3, 152, 118, 237,
+ 219, 64, 183, 44, 26, 129, 93, 198, 240, 107,
+ 156, 7, 49, 170, 68, 223, 233, 114, 133, 30,
+ 40, 179, 195, 88, 110, 245, 2, 153, 175, 52,
+ 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, //200
+ 92, 199, 48, 171, 157, 6, 232, 115, 69, 222,
+ 41, 178, 132, 31, 167, 60, 10, 145, 102, 253,
+ 203, 80, 190, 37, 19, 136, 127, 228, 210, 73,
+ 149, 14, 56, 163, 84, 207, 249, 98, 140, 23,
+ 33, 186, 77, 214, 224, 123)
+
+ def apply(data : List[Int]) : Int = {
+ // initialCrc=0
+ return data.foldLeft(0){ (crc,byte) => crcTab(crc) ^ byte}
+ }
+}
+
+
object EbusL2Packet {
/**
@@ -86,105 +142,158 @@ object EbusL2Packet {
* sonst None
*/
def apply(stream: Stream[Int]): Option[Any] = {
- try {
- var rawLength = 0
- val source = stream(0)
- val destination = stream(1)
- val primaryCommand = stream(2)
- val secondaryCommand = stream(3)
- val payloadLength = stream(4)
- rawLength = 5
-
- println("source=0x%02x destination=0x%02x primaryCommand=0x%02x secondaryCommand=0x%02x payloadLength=0x%02x".format(
- source, destination, primaryCommand, secondaryCommand, payloadLength))
-
- // Maximale payload Grösse = 16 Byte
- if (payloadLength > 16) {
- println("Erkannte payload Groesse zu gross: %d".format(payloadLength))
+ var mystream = stream
+ var rawLength = 0
+ def readBytes(n:Int) : List[Int] = {
+ val d = mystream.slice(rawLength,rawLength+n).toList
+ rawLength = rawLength + n
+ println("RAW: " + d.map((it) => "0x%02x".format(it)).foldLeft(""){(s1,s2) => s1+","+s2})
+ return d
+ }
+ val source :: destination :: primaryCommand :: secondaryCommand :: payloadLength :: _ = readBytes(5)
+
+ println("source=0x%02x destination=0x%02x primaryCommand=0x%02x secondaryCommand=0x%02x payloadLength=0x%02x".format(
+ source, destination, primaryCommand, secondaryCommand, payloadLength))
+
+ // 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));
+ } else {
+ println("Payload = " + payloadLength);
+ }
+
+ // "eBUS Spezifikation Physikalische Schicht – OSI 1
+ // Verbindungsschicht – OSI 2 V.1.3.1" page 8
+ val payload = Range(0,payloadLength).map({ i =>
+ readBytes(1)(0) match {
+ case 0xa9 => {
+ readBytes(1)(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
+ println("Payload: " + payload.map((it) => "0x%02x".format(it)).foldLeft(""){(s1,s2) => s1+","+s2})
+
+ val crc = readBytes(1)(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
+ }
+
+ // Broadcast Packet ends here
+ if (destination == 0xfe) {
+ val syn = readBytes(1)(0)
+ if (syn != 0xaa) {
+ App.println("bad SYN 0x%02x".format(syn))
return None
- } else {
- println("Payload = " + payloadLength);
}
+ return Some(new EbusL2Packet(source, destination,
+ primaryCommand, secondaryCommand,
+ payloadLength, payload, crc, rawLength))
+ }
- var payload = List[Int]()
- for (i <- 0 until payloadLength) {
- var it = stream(rawLength)
- rawLength += 1
- // Handle escape sequences
- // "eBUS Spezifikation Physikalische Schicht – OSI 1
- // Verbindungsschicht – OSI 2 V.1.3.1" auf Seite 8
- if (it == 0xa9) {
- val itNext = stream.apply(rawLength)
- rawLength += 1
- if (itNext == 0x00) {
- it = 0xa9
- } else if (itNext == 0x01) {
- it = 0xaa
- } else {
- App.println("Ignore escape sequence 0xa9 0x%02x".format(itNext))
- rawLength -= 1
- }
- }
- payload = payload :+ it
- println("Payload: " + payload.map((it) => "0x%02x".format(it)).foldLeft(""){(s1,s2) => s1+","+s2})
+ val ack = readBytes(1)(0)
+ println("ACK=0x%02x".format(ack))
+
+ val syn = readBytes(1)(0)
+ // Master-Master Packet ends here
+ if (syn == 0xaa) {
+ if (ack != 0x00) {
+ App.println("bad ACK=0x%02x".format(syn))
}
- val crc = stream.apply(rawLength + 0)
- println("CRC=0x%x".format(crc))
- val ack = stream.apply(rawLength + 1)
- println("ACK=0x%02x".format(ack))
- if (destination == 0xfe) {
- // Broadcast
- if (ack != 0xaa) {
- println("ACK Bei Broadcast Paket unerwertet nicht 0xaa sondern 0x%02x".format(ack))
- }
- } else {
- if (ack != 0x00) {
- println("ACK unerwartet nicht 0x00 sondern 0x%02x".format(ack))
+ 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
+ println("payloadSlaveLength = 0x%02x".format(payloadSlaveLength))
+ if (payloadSlaveLength > 16) {
+ println("payloadSlaveLength > 16: 0x%02x".format(payloadSlaveLength))
+ return None
+ }
+
+ val payloadSlave = Range(0,payloadSlaveLength).map({ i =>
+ readBytes(1)(0) match {
+ case 0xa9 => {
+ readBytes(1)(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
}
- rawLength += 0
-
- if (stream.apply(rawLength + 4) == 0xaa) {
- // Broadcast oder Master-Master
- return Some(new EbusL2Packet(source, destination,
- primaryCommand, secondaryCommand,
- payloadLength, payload, crc, rawLength))
- } else {
- // Master-Slave
- return Some(new FakePacket(rawLength))
- }
- } catch {
- case exc: IndexOutOfBoundsException => {
- App.println(exc.toString)
- exc.printStackTrace
- return None
- }
+ }).toList
+ println("PayloadSlave: " + payloadSlave.map((it) => "0x%02x".format(it)).foldLeft(""){(s1,s2) => s1+","+s2})
+
+ val crcSlave = readBytes(1)(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
+ }
+
+ val ackSlave = readBytes(1)(0)
+ App.println("ACKslave = 0x%02x".format(ackSlave))
+ if (ackSlave != 0x00) {
+ App.println("Master-Slave ACK nicht 0x00 sondern 0x%02x".format(ackSlave))
+ return None
+ }
+
+ val synSlave= readBytes(1)(0)
+ if (synSlave != 0xaa) {
+ App.println("Master-Slave SYN nicht 0xaa sondern 0x%02x".format(synSlave))
+ return None
}
+
+ return Some(new EbusL2MasterSlavePacket(source, destination,
+ primaryCommand, secondaryCommand,
+ payloadLength, payload, crc,
+ payloadSlaveLength, payloadSlave, crcSlave, rawLength));
}
}
-object EbusReader {
- def apply(streamI: Stream[Int]) : EbusL2Packet = {
- var stream = streamI
+class EbusReader(var stream : Stream[Int]) {
+ def next() : EbusL2Packet = {
while (true) {
- // Synchronisiere
- while (stream(0) != 0xaa && stream(1) != 0xaa) {
- stream = stream.drop(1)
- }
// Überspringe Synchronisationszeichen
- while (stream(0).toChar == 0xaa) {
+ 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.length))
- stream = stream.drop(packet.length)
+ println("Fake paket - forward %d bytes".format(packet.rawLength))
+ stream = stream.drop(packet.rawLength)
}
case None => {
// Es konnte kein Paket eingelesen werden
@@ -194,33 +303,30 @@ object EbusReader {
}
}
}
- null
+ return null;
}
}
-object EbusL7Packet {
- def apply(l2packet : EbusL2Packet, ebusDefinition : EbusDefinition) : Option[EbusL7Packet] = {
- val packetDef = ebusDefinition.packetFromCommandId(
- l2packet.primaryCommand, l2packet.secondaryCommand)
+// object EbusL7Packet {
+// def apply(l2packet : EbusL2Packet, ebusDefinition : EbusDefinition) : Option[EbusL7Packet] = {
+// val packetDef = ebusDefinition.packetFromCommandId(
+// l2packet.primaryCommand, l2packet.secondaryCommand)
- if (packetDef.isEmpty)
- return None
- else
- return Some(new EbusL7Packet(l2packet, packetDef))
- }
-}
-
-
-
-class EbusL7Packet(val l2packet : EbusL2Packet, val packetDefinition : NodeSeq) {
- def name : String = {
- packetDefinition.map({p :Node => p.attributes.apply("name")}).mkString
- }
+// if (packetDef.isEmpty)
+// return None
+// else
+// return Some(new EbusL7Packet(l2packet, packetDef))
+// }
+// }
+// class EbusL7Packet(val l2packet : EbusL2Packet, val packetDefinition : NodeSeq) {
+// def name : String = {
+// packetDefinition.map({p :Node => p.attributes.apply("name")}).mkString
+// }
- override def toString : String = {
- "EbusL7: name=%s".format(name)
- }
-}
+// override def toString : String = {
+// "EbusL7: name=%s".format(name)
+// }
+// }
object App {
val ebusDefinition = new EbusDefinition("/home/yvesf/vcs/ebus/ebus/ebus-xml/ebus.xml")
@@ -276,29 +382,16 @@ object App {
var stream: Stream[Int] = Stream.continually(read())
+
+ // Synchronisiere
+ while (stream(0) != 0xaa && stream(1) != 0xaa) {
+ stream = stream.drop(1)
+ }
+
+ val reader = new EbusReader(stream)
while (true) {
try {
- EbusReader(stream) match {
- case l2packet : EbusL2Packet => {
- println("Read l2 packaet: " + l2packet);
- /*
- EbusL7Packet(l2packet, ebusDefinition) match {
- case Some(l7packet) => {
- println(l7packet)
- }
- case _ => {}
- }
- */
- println(l2packet)
-
- // Spule den Stream zur naechstmoeglichen Paketposition
- stream = stream.drop(l2packet.rawLength)
- }
- case null => {
- println("null")
- System.exit(1)
- }
- }
+ println(reader.next)
} catch {
case exc : EOFException => {
println("EOF")