dfitz
03-07-08, 08:29 AM
Hi there,
I'm chasing a quick way to decode my serial data stream than has a number of different commands. My initial approach (seeing as forth doesn't have a nice built in case statement) was to go for a series of nested if statements.
Basically my code reads in a byte each time through the loop, keeps track of where in the packet it's up to, verifies the packet (checksum) then proceeds to go through the pain-staking process of checking my command data byte against all the possible commands.
Again, this is done in a nested if-else-then routine.
The code looks something like:
-------------------------------------------------------
SCI0 RX
\ DECODE Packets
\ ---------------------
\ look for header (0x24)
DUP 36 = \ 0x24 in hex
0 iReceiveCommandPos @ = \ and if 0 == iReceiveCommandPos
AND
IF
1 iReceiveCommandPos ! \ indicates we've rx the header
ELSE
1 iReceiveCommandPos @ = \ and if 1 ==
IF
2 iReceiveCommandPos !
DUP iReceiveCommand ! \ save command byte
ELSE
2 iReceiveCommandPos @ = \ and if 2 ==
IF
3 iReceiveCommandPos !
DUP iReceiveDataByte1 ! \ save data byte 1
ELSE
3 iReceiveCommandPos @ = \ and if 3 ==
IF
4 iReceiveCommandPos !
DUP iReceiveDataByte2 ! \ save data byte 2
ELSE
4 iReceiveCommandPos @ = \ and if 4 ==
IF
5 iReceiveCommandPos !
DUP iReceiveChecksum ! \ save checksum
ELSE
\ look for termination byte (0x40)
DUP 64 = \ 0x40
5 iReceiveCommandPos @ = \ and if 5 ==
AND
IF
\ checksum test
iReceiveCommand @
iReceiveDataByte1 @ +
iReceiveDataByte2 @ +
iReceiveChecksum @ +
255 MOD
0=
IF
\ checksum test passed; test command byte
...
..
Then a whole pile of tests on the command byte to actually do something!!!
...
...
THEN THEN THEN.....
-------------------------------------------------------
Now the problem is that i'm wanting to decode the serial fairly fast, and as I increase the number of commands to decode, I get to a point (quite quickly) where it hangs, because I'm presuming it can't keep up / taking too much time in this routine. If i comment out a few of the commands then it's back working.
Anyway, so i went hunting on the forums, thinking i might be able to find a case statement that would help me and i did find a few examples,
HOWEVER, I don't think this will fix my problems, as there are a lot of commands and I feel i'm going to run into the same problem using a case.... AND, I want the code to be expandable, such that if i want to add in other commands later I don't have to go and tweak the rates of the different loops etc, to get something that works.
SOO, I decided that it's time for a re-think of the problem. I've come up with a strategy that I think will be helpful for people out there... However, I need a bit of help on the exact syntax because I'm not an expert with forth yet.
Ok here goes:
1) decode packet in a similar manner to above up until the command interpretation stage (the packet is only 6 bytes long, so it's in the section of the code where we're interpretting the command that burns the time. Also if you have any kind of even simple system, you can easily have say 20-30 commands which result in a nested if-else-then 30 deep which will own you).
2) relate the command byte number to a row in a lookup table. By this I mean to create a lookup table similar to:
CREATE SERIAL_CMD_TABLE
\ Lookup table
0 P,
2 P,
4 P,
7 P,
EEWORD
but instead of the numbers (0, 2, 4, 7), have some way of having function names or perhaps the memory address pointing to the functions. Each row would point to the specific command. So if we're talking about 1 command byte, we could have up to 255 rows in this table.
Note we'd need to have some way of having blank entries. For example the code i have at the moment has commands every 5 (ie: first command is byte 0x00, second is 0x05, third is 0x0A, etc...), so the table would have to be:
cmd_1, null, null, null, null, cmd_2, null, null, null, null, cmd_3, ...)
3) depending on whichever byte is received, you can simply do 1 call to a function that gets the function we need to call from the lookup table. I know for numbers in a lookup table you could do something like this:
: DMD_TABLE_GET_VAL
DMD_TABLE + P@
; EEWORD
4) then magically call the function somehow that does whatever you need to do when receving that particular command.
That's basically the intention. If this is possible then the commands can be increased (provided we can store the lookup table) indefinately - well at leat up to 255 commands, without any increase in time to run the decoding routine... which would be very sweet.
I did find some stuff here:
for example:
http://www.newmicros.com/discussion/showthread.php?t=543&highlight=case+statement
which I thought may have been starting to get on the track to maybe achieve what i've described above, but I can't really decifer the code.
So in summary, what I need to work out is:
- how to declare a number of functions that can be listed somehow in a lookup table
- how to declare the look up table
- how to grab a row from the lookup table and execute the function it's pointing to
thanks a million.
regards,
Daniel
I'm chasing a quick way to decode my serial data stream than has a number of different commands. My initial approach (seeing as forth doesn't have a nice built in case statement) was to go for a series of nested if statements.
Basically my code reads in a byte each time through the loop, keeps track of where in the packet it's up to, verifies the packet (checksum) then proceeds to go through the pain-staking process of checking my command data byte against all the possible commands.
Again, this is done in a nested if-else-then routine.
The code looks something like:
-------------------------------------------------------
SCI0 RX
\ DECODE Packets
\ ---------------------
\ look for header (0x24)
DUP 36 = \ 0x24 in hex
0 iReceiveCommandPos @ = \ and if 0 == iReceiveCommandPos
AND
IF
1 iReceiveCommandPos ! \ indicates we've rx the header
ELSE
1 iReceiveCommandPos @ = \ and if 1 ==
IF
2 iReceiveCommandPos !
DUP iReceiveCommand ! \ save command byte
ELSE
2 iReceiveCommandPos @ = \ and if 2 ==
IF
3 iReceiveCommandPos !
DUP iReceiveDataByte1 ! \ save data byte 1
ELSE
3 iReceiveCommandPos @ = \ and if 3 ==
IF
4 iReceiveCommandPos !
DUP iReceiveDataByte2 ! \ save data byte 2
ELSE
4 iReceiveCommandPos @ = \ and if 4 ==
IF
5 iReceiveCommandPos !
DUP iReceiveChecksum ! \ save checksum
ELSE
\ look for termination byte (0x40)
DUP 64 = \ 0x40
5 iReceiveCommandPos @ = \ and if 5 ==
AND
IF
\ checksum test
iReceiveCommand @
iReceiveDataByte1 @ +
iReceiveDataByte2 @ +
iReceiveChecksum @ +
255 MOD
0=
IF
\ checksum test passed; test command byte
...
..
Then a whole pile of tests on the command byte to actually do something!!!
...
...
THEN THEN THEN.....
-------------------------------------------------------
Now the problem is that i'm wanting to decode the serial fairly fast, and as I increase the number of commands to decode, I get to a point (quite quickly) where it hangs, because I'm presuming it can't keep up / taking too much time in this routine. If i comment out a few of the commands then it's back working.
Anyway, so i went hunting on the forums, thinking i might be able to find a case statement that would help me and i did find a few examples,
HOWEVER, I don't think this will fix my problems, as there are a lot of commands and I feel i'm going to run into the same problem using a case.... AND, I want the code to be expandable, such that if i want to add in other commands later I don't have to go and tweak the rates of the different loops etc, to get something that works.
SOO, I decided that it's time for a re-think of the problem. I've come up with a strategy that I think will be helpful for people out there... However, I need a bit of help on the exact syntax because I'm not an expert with forth yet.
Ok here goes:
1) decode packet in a similar manner to above up until the command interpretation stage (the packet is only 6 bytes long, so it's in the section of the code where we're interpretting the command that burns the time. Also if you have any kind of even simple system, you can easily have say 20-30 commands which result in a nested if-else-then 30 deep which will own you).
2) relate the command byte number to a row in a lookup table. By this I mean to create a lookup table similar to:
CREATE SERIAL_CMD_TABLE
\ Lookup table
0 P,
2 P,
4 P,
7 P,
EEWORD
but instead of the numbers (0, 2, 4, 7), have some way of having function names or perhaps the memory address pointing to the functions. Each row would point to the specific command. So if we're talking about 1 command byte, we could have up to 255 rows in this table.
Note we'd need to have some way of having blank entries. For example the code i have at the moment has commands every 5 (ie: first command is byte 0x00, second is 0x05, third is 0x0A, etc...), so the table would have to be:
cmd_1, null, null, null, null, cmd_2, null, null, null, null, cmd_3, ...)
3) depending on whichever byte is received, you can simply do 1 call to a function that gets the function we need to call from the lookup table. I know for numbers in a lookup table you could do something like this:
: DMD_TABLE_GET_VAL
DMD_TABLE + P@
; EEWORD
4) then magically call the function somehow that does whatever you need to do when receving that particular command.
That's basically the intention. If this is possible then the commands can be increased (provided we can store the lookup table) indefinately - well at leat up to 255 commands, without any increase in time to run the decoding routine... which would be very sweet.
I did find some stuff here:
for example:
http://www.newmicros.com/discussion/showthread.php?t=543&highlight=case+statement
which I thought may have been starting to get on the track to maybe achieve what i've described above, but I can't really decifer the code.
So in summary, what I need to work out is:
- how to declare a number of functions that can be listed somehow in a lookup table
- how to declare the look up table
- how to grab a row from the lookup table and execute the function it's pointing to
thanks a million.
regards,
Daniel