In my project to communicate between my notebook and an Arduino over
XBees I need to send binary commands to the XBee. The protocol is defined approx. like this: every packet start with 0x7E and then two bytes containing the length of the packed then the payload and afterwards a checksum.
So I decided to write a little library that allows me to parse and compose these commands in a natural way. The parsing should use pattern matching.
To define a structure use something like this:
val myPattern = <<(byte, integer, integer, byte)>>
('<<' is a imported function, the '>>' is just decoration, that returns itself)
then you can use
val bytes: Seq[Byte] = myPattern(12, 33321, 24432, 0)
to generate a binary representation (i.e 0x12, 0x00, 0x00, 0x82, 0x29, ...). To a byte sequence use
bytes match {
case myPattern((a,b,c,d), rest) =>
a should be(12)
b should be(33321)
c should be(24432)
d should be(0)
rest should be(Nil)
}
The variable "Rest" in the example will contain everything in the Seq[Byte] after the matched sequence.
It also allows to check for fixed values (in the example above 0x7E in the first byte):
val myPattern2 = <<(fix_byte(0x7E), integer, integer, byte) drop1
myPattern2(1234, 4321, 12) //will be 0x7E, 0x00, 0x00, 0x04, 0xD2
And you can map a pattern to some class:
case class Color(red: Byte, green: Byte, blue: Byte)
val rgbPattern = <<(byte, byte, byte)>>>(
(c: Color) => (color.red, color.green, color.blue),
t => Some(Color(t._1, t._2, t._3))
)
But what makes it really powerful is the ability to nest those patterns
val colorfulPattern = <<(fix_byte(0x7E), rgbPattern, rgbPattern, integer) drop1
val data = (0x7E :: 33 :: 21 :: 11 :: 0 :: 100 :: 12 :: 0 :: 0 :: 0 :: 4 :: Nil).map(_.toByte)
data match {
case colorfulPattern((foregroundColor, backgroundColor, pixelsToFill), _) =>
foregroundColor should be(Color(33,21,11))
backgroundColor should be(Color(0, 100, 12))
pixelsToFill should be(4)
}
so it's pretty easy to define complex structures pretty fast, easy and reusable. The framework also provides possibilities to parse/serialize lists (even of "complex" objects) and optional values.
Just check out the
code a GitHub and feel free to use it and contribute to it!