Reading DEX files with propeller. Need some help with code.
I am working on a project to read a DEX file from a Vending Machine Controller (VMC). DEX files contain audit data for transactions in a vending machine. It utilizes a 9600 baud 8 bit data link. Nothing fancy. The data is standard ASCII characters and contains line feeds and carriage returns for formatting.
I have tried to condense as much as possible my code to read in the data. Maybe too much
The data stream has a max limit of 245 characters. The messages start with a $10 (DLE) $02 (STX) ... ASCII DATA... $10 (DLE) $17 (ETB) then a 2 byte CRC-16 checksum The data block is then ACK'd by the VMC with a DLE 1 ($10 $31) the first time then a DLE 0 then next time then back to a DLE 1. The ACK alternates between DLE 1 and DLE 0 starting with a DLE 1.
My problem lies beginning in this section. See below:
It sends the ACK's all in a row without waiting for the data block to be received in. I think it has somethng to do with my logic of looking for a DLE ($10) since it is in the beginning and end of a block.
Also I don't know what happens to the end DLE ETB and 2 byte checksum.
Here's the full code I worite. Don't laugh as I am vey much a novice at this yet.
I have tried to condense as much as possible my code to read in the data. Maybe too much

The data stream has a max limit of 245 characters. The messages start with a $10 (DLE) $02 (STX) ... ASCII DATA... $10 (DLE) $17 (ETB) then a 2 byte CRC-16 checksum The data block is then ACK'd by the VMC with a DLE 1 ($10 $31) the first time then a DLE 0 then next time then back to a DLE 1. The ACK alternates between DLE 1 and DLE 0 starting with a DLE 1.
My problem lies beginning in this section. See below:
inx := 1 ' initialize index counter to 1 i := dex.rxtime(20) ' receive in dex data and assign it to variable i if i == $10 ' check to see if byte is DLE i := dex.rx ' receive in next byte if i == $02 ' check to see if next byte is STX. if so start repeat loop repeat until i == $10 ' do repeat until byte received is DLE then quit i := dex.rx ' receive in nexy byte and assign to variable i dexdata[inx] := i ' assign received byte i to dexdata variable indexed by index counter inx term.tx(dexdata[inx]) ' send data byte to terminal for printing inx += 1 ' increment index counter dex.tx($10) ' send ACK - DLE 1 dex.tx($31) ' ACK's alternate between DLE 0 and DLE 1 inx := 1 ' repeat process again for next batch of data i := dex.rxtime(20) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) ' send ACK - DLE 0 dex.tx($30) inx := 1 ' repeat process again for next batch of data i := dex.rxtime(250) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) dex.tx($31)
It sends the ACK's all in a row without waiting for the data block to be received in. I think it has somethng to do with my logic of looking for a DLE ($10) since it is in the beginning and end of a block.
Also I don't know what happens to the end DLE ETB and 2 byte checksum.
Here's the full code I worite. Don't laugh as I am vey much a novice at this yet.
'' ================================================================================================= '' '' File....... DEX_Prop.spin '' Purpose.... DEX Reader '' Author..... Don Merchant '' -- see below for terms of use '' E-mail..... '' Started.... 06 SEP 2011 '' Updated.... 08 SEP 2011 This version excluded PST control and prints data in ASCII format '' '' ================================================================================================= con _clkmode = xtal1 + pll16x ' Feedback and PLL multiplier _xinfreq = 5_000_000 ' External oscillator = 5 MHz MS_001 = 80_000_000 / 1_000 ' ticks in 1ms DEX_TX = 0 ' DEX -> VMC DEX_RX = 1 ' VMC -> DEX obj dex : "fullduplexserialplus" term : "fullduplexserialplus" var byte dexstrng[24], dexdata[245] pub main | i, d, inx term.start(31, 30, %0000, 115_200) ' start terminal (use PST) dex.start(1, 0, %0000, 9_600) ' start DEX read pause (1000) ' pause for PST to start dex.tx($05) ' send ENQ to start term.str(string("Start DEX_Prop Ver 0.2", 13)) i := dex.rxtime(100) ' look for response from VMC if i == $10 ' if DLE received from VMC start handshake i := dex.rx if i == $30 term.str(string("Start 1st Handshake", 13)) dex.tx($10) ' send DLE pause(15) dex.tx($01) ' send SOH pause(15) dex.str(string("1234567890RR01L01")) ' send string pause(15) dex.tx($10) ' send DLE pause(15) dex.tx($03) ' send ETX pause(15) dex.tx($DE) ' send upper byte of CRC checksum pause(15) dex.tx($4D) ' send lower byte of CRC checksum pause(15) else term.str(string(2, 1, 3, "No response")) ' If no DLE received from VMC then indicate no communication i := dex.rx ' In this section we look for a DLE response from the VMC to end first handshake if i == $15 term.str(string(2, 1, 5, "NAK")) ' if checksum isn't right let us know else if i == $10 i := dex.rx if i == $31 term.str(string("First Handshake Successful", 13)) dex.tx($04) ' send EOT else term.str(string(2, 1, 5, "Didn't recognize DLE...")) i := dex.rx if i == $05 ' look for ENQ term.str(string("Start 2nd Handshake")) dex.tx($10) ' acknowledge the ENQ by sending DLE 0 dex.tx($30) else term.str(string(2, 1, 7, "Didn't recognize ENQ...")) pause(15) inx := 1 ' receive id data from VMC but do nothing with it repeat 24 i := dex.rxtime(40) dexstrng[inx] := i 'term.tx(dexstrng[inx]) inx += 1 term.tx(13) dex.tx($10) dex.tx($31) i := dex.rxtime(100) ' look for response from VMC if i == $04 ' if DLE received from VMC start handshake term.str(string("Second Handshake Successful", 13)) i := dex.rx if i == $05 term.str(string("Begin DEX dump from VMC...", 13)) dex.tx($10) dex.tx($30) inx := 1 ' initialize index counter to 1 i := dex.rxtime(20) ' receive in dex data and assign it to variable i if i == $10 ' check to see if byte is DLE i := dex.rx ' receive in next byte if i == $02 ' check to see if next byte is STX. if so start repeat loop repeat until i == $10 ' do repeat until byte received is DLE then quit i := dex.rx ' receive in nexy byte and assign to variable i dexdata[inx] := i ' assign received byte i to dexdata variable indexed by index counter inx term.tx(dexdata[inx]) ' send data byte to terminal for printing inx += 1 ' increment index counter dex.tx($10) ' send ACK - DLE 1 dex.tx($31) ' ACK's alternate between DLE 0 and DLE 1 inx := 1 ' repeat process again for next batch of data i := dex.rxtime(20) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) ' send ACK - DLE 0 dex.tx($30) inx := 1 ' repeat process again for next batch of data i := dex.rxtime(250) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) dex.tx($31) inx := 1 i := dex.rxtime(250) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) dex.tx($30) inx := 1 i := dex.rxtime(250) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) dex.tx($31) inx := 1 i := dex.rxtime(250) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 dex.tx($10) dex.tx($30) inx := 1 i := dex.rxtime(250) if i == $10 i := dex.rx if i == $02 repeat until i == $10 i := dex.rx dexdata[inx] := i term.tx(dexdata[inx]) inx += 1 term.tx(13) dex.tx($10) dex.tx($31) i := dex.rx ' look for EOT to end routine if i == $04 term.str(string(" DEX finished")) pub pause(ms) | t '' Delays program for ms milliseconds t := cnt repeat ms waitcnt(t += MS_001)
Comments
I don't have time to look over your code but I do wonder if FullDuplexSerial could be causing you trouble because of its small buffer.
I posted a modified version of Tim Moore's four port driver with a 512 byte rx buffer. You should be able to safely receive the whole message and then manipulate it after it has all arrived.
Post #9 of the thread is a modification I frequently use. The driver monitors for an end of message flag so the parent object knows when a complete message has arrived.
Duane
I personally would do something like this (completely untested):
Here's the code portion that works and a logic trace of the result-
Here's the code that gives me trouble and a logic trace of its result. You can see all the ACK's it sends in a row unlike the code above-
I want to make the second code work as the message length may vary. In the first code I hand coded the message length.
@rosco_pc- yes I know I am not doing anything with the checksums at this point and just assuming they are correct to get started. I was going to implement them in the next go around after I get this portion to work better. Thanks for your code help. I'll look it over and see what I can learn from it.
I'd think you'd want your "dex.tx($10)" to line up with "repeat until" so you only acknowledged after receiving a full message.
Duane
Now on to more refinement....
I messed with the code that rosco_pc suggested but I didn't get anywhere with it due to some code needed for CRC-16 calculation which I don't have.... yet.
You'll need to change the calling of the crc routine to I had never heard of DEX, so I after some quick googling l found some interesting links:
http://saturn.ece.ndsu.nodak.edu/ecewiki/images/0/06/SD0802Technical_Report.pdf
http://bonusdata.ch/Download/DEX-UCS/dexucs_english.htm
First link contains some flow charts on how DEX is supposed to work (there is no source code)
The second link contains some source code (it's C++ though) and you'll have a reference implementation for DEX.
Is there a command to clear the buffer?
This only clears the variable i (reading from the buffer removes the data)
FDS buffer is 64 byte, do you only get 64 characters? If you get more or less then you most likely have a problem with handshaking.
Different manufacturers report different amounts of DEX data. It just so happens that one board I have this whole routine works fine on. It takes approx 5 seconds to go through the whole process. The board I'm having trouble with reports quite a bit more data and runs along fine for about 12 seconds then just hangs. There is a DLE ETB sent from the board but my program then decides not to ACK it for some reason after that time even though it was ACKing fine in the seconds preceeding.
This one is from the board that the code works fine on. You can see the long data stream on the bottom line and the ACK's on the top line. It then shows the final EOT on the bottom line from the board. Life is good.
This is the one from the board that hangs after a while. You can see where the data is ACK'd then it decides not to ACK at the end.
You'll also notice that the packets of data are shorter on the second board than the first. Maybe that has something to do with it I don't know.
What I did to find this problem was to insert some string statements in different strategic points in my code to print on PST. The problem then showed up where it was quitting. Should have thought of this sooner....
Anyway here is the updated portion that works. I'll work on finding a checksum method that I can add to this.
Don't pay much attention to the comments in the code as they are somewhat messed up from editing code.