A CASE of confusion
JonnyMac
Posts: 9,209
I decided to toss a last-minute section into my column and am now kicking myself and seriously confused.
What I decided to do is develop a simple implementation of the Renard protocol which is very popular amongst DIY Christmas lighting enthusiasts. The protocol is very simple
sync ($7E)
addr ($8x)
channel levels
$7F is used as an escape character for levels that require two bytes encoding. Easy-peezy. Right.
Well, yes -- and this works with my little 12-channel board:
I thought, however, that a state-machine would be more elegant and be better suited to trap an error in the stream. So I recoded to....
I'm stumped and a tad frustrated because I'm sure it's something ridiculously simple that I'm looking right past. Your input is appreciated
What I decided to do is develop a simple implementation of the Renard protocol which is very popular amongst DIY Christmas lighting enthusiasts. The protocol is very simple
sync ($7E)
addr ($8x)
channel levels
$7F is used as an escape character for levels that require two bytes encoding. Easy-peezy. Right.
Well, yes -- and this works with my little 12-channel board:
repeat c := cmd.rx if (c == SYNC) c := cmd.rx if (c == ADDR) repeat ch from 0 to CHANNELS-1 c := cmd.rx if (c <> ESC) leds.set(ch, c) else c := cmd.rx if (c => $30) and (c =< $32) leds.set(ch, $AF-c) else quit
I thought, however, that a state-machine would be more elegant and be better suited to trap an error in the stream. So I recoded to....
state := 0 repeat c := cmd.rx case state 0 : if (c == SYNC) state := 1 1 : if (c == ADDR) state := 2 ch := 0 else state := 0 2 : if (c <> ESC) leds.set(ch, c) ch += 1 else state := 3 3 : if (c => $30) and (c =< $32) leds.set(ch, $AF-c) ch += 1 state := 2 else state := 0 if (ch == CHANNELS) state := 0
I'm stumped and a tad frustrated because I'm sure it's something ridiculously simple that I'm looking right past. Your input is appreciated
Comments
I thought that might be the case, too, but it's not (what's not shown is that ch is pre-initialized to 0 before the repeat loop).
This is the dolled-up working version; for now I'm going to live with the redundant channel limit check.
I would be surprised if there were a compiler bug at this late date. I've used state machines like this one including a statement after the end of the CASE statement, but inside the REPEAT and it's worked for me.
I agree that it's probably not a compiler bug, but there does seem to be an unknown (to me, that is). For now I have working code and I'm pressing forward. Thanks for looking.
I'm not sure about the CASE issue, but I do notice that if you get two SYNCs (or any even number) in a row, starting from WAIT_SYNC, and followed by an address, your interpreter will not do what you probably want it to:
I think that SYNCs arriving at WAIT_ADDR should not change state, but remain at WAIT_ADDR. In fact, if I understand the protocol correctly, a SYNC arriving at any state should force the next state to WAIT_ADDR.
-Phil