Shop OBEX P1 Docs P2 Docs Learn Events
Can the propeller be used as a CAN sniffer? (bit collection project idea) — Parallax Forums

Can the propeller be used as a CAN sniffer? (bit collection project idea)

turbosupraturbosupra Posts: 1,088
edited 2014-10-31 15:01 in Propeller 1
I'd like to build a Prop Sniffer. Toyota has a CAN like network called Bo dy Electronic Area Net work and it is not encrypted. It uses 2 multiplex lines, MPX1 and MPX2. For those of you that have done something like this, or are more experienced than I, is this feasible?

The specification for the network is

1 SOF (1 bit) (start of frame)
2-5 PRI (4 bits) (priority of bits)
6-9 ML (4 bits) (message length, length of message and number of bytes, [ID + DATA] (3-13)
10-17 DST-ID (8 bits) (the id showing the communication destination)
18-25 MES-ID (8 bits) (is an area showing message contents)
26-113 DATA (8 to 88 bits) (1 to 11 bytes of data, variable length, could be as small as bits 26-33, reskewing the bit number slots for the remaining bit groups)
114-121 CRC (8 bits) (error check code remainder from polynomial)
122-129 EOM (8 bits) (end of message and controls time to prepare response for sending)
130-132 RSP (2 bits) (represents the response area)
133-138 EOF (6 bits) (shows the end of the frame)

More specs

CSMA/CD

Bit encoding: NRZ
Media Access: Contention
Error Detection: 8-bit CRC
Header Length: 25bits
Data length: 1-11bytes
Overhead: 28%
In-message response: NO
Bit rate: 10Kb/s
Maximum Bus Length: Not Specified
Maximum Nodes: 20
u Needed?: YES
Sleep / Wakeup: NO
H/W Avail?: YES (?)
Cost: Low

Communication speed: Max 10kbps
Communication wire: av single wire
Drive type: single wire voltage drive
Data length: 1-11 byte (variable)

It also employs bit stuffing where an inverted bit is inserted when 5 consecutive bits have the same value from the SOF to CRC bit groups



With that being said, could the prop monitor the lines for binary and convert it to hex? I'd like to reverse engineer the CRC poly as well once I get this information so that I could send my own messages. On the net I found partial examples of data captured by them, that data is in quotes below.

DID 62
MID BF
DATA1 00
CRC 78
EOM 7E
DID 62
MID D2
DATA1 00
DATA2 A0
DATA3 08
CRC 0A
EOM 7E
DID 98
MID CC
DATA1 02
DATA2 A8
CRC 35
EOM 7E
DID EF
MID 6A
DATA1 04
CRC 44
EOM 3F
«1

Comments

  • MJBMJB Posts: 1,235
    edited 2014-10-20 07:50
    the most important information is missing --- at what bitrate is the NW running?

    so how much time is there to process the bits - and then the message ...
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-10-20 08:33
    If you're willing to add a bit of hardware, it's very easy to sniff CAN buss -- I did it and wrote about it for my March 2012 column in Nuts & Volts. I've attached the demo code and schematic. I built the circuit as a shield for my Propeller Platform.

    I tested everything with a USB-CAN interface called PCAN (provided by client). In the end, the object I wrote was used for node-to-node comms in an HVAC system.

    There is a software CAN object somewhere, that only requires the interface chip (MCP2551, 8-pin DIP in photo). I've not used it, but it might be worth looking at. I went the full hardware route because I had been asked to code a client project with that circuit and it worked very well.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-20 08:35
    I added some info with bit rate, up to 10kbps
    MJB wrote: »
    the most important information is missing --- at what bitrate is the NW running?

    so how much time is there to process the bits - and then the message ...
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-20 08:36
    Yes I am! This looks awesome and I hope it is not out of my reach. Thank you Jon.

    JonnyMac wrote: »
    If you're willing to add a bit of hardware, it's very easy -- I did it and wrote about it for my March 2012 column in Nuts & Volts. I've attached the demo code and schematic. I built the circuit as a shield for my Propeller Platform.

    I tested everything with a USB-CAN interface called PCAN (provided by client). In the end, the object I wrote was used for node-to-node comms in an HVAC system.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-20 10:31
    Most of the pre-made objects rely on the MCP2515 chip, which can only decode CAN messages, which look like:
       Standard frame:                                                                                                  CRC delimiter     
                     RTR                                                                                                │ ACK                                                   
       SOF           │ IDE   Data length (0 - 8 bytes)                                                                  │ │ ACK delimiter                                       
       │ Ident A     │ │ R0  │  Byte 0   Byte 1   Byte 2   Byte 3   Byte 4   Byte 5   Byte 6   Byte 7   CRC             │ │ │ EOF                                               
       │ │           │ │ │   │  │        │        │        │        │        │        │        │        │               │ │ │ │
       0_xxxxxxxxxxx_0_0_0_xxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxxxxxxx_1_i_1_1111111     
    
    So while the signalling might be similar, the protocol appears completely different.

    I've written a few Prop-based objects that should work with some modifications to the parse_bit routine in the reader section.

    What are the signal levels?
    Does it idle high or low?
    Are the bits inverted?

    You may not even need the 2551 line driver. I'm currently working on a modification to the above CANbus routines that'll work with a GMLAN class-2 databus, which uses the same CAN protocol, but the messages are inverted, uses 5V for dominant '0' bits and gnd for recessive '1' bits, so all I need for that is a transistor driver for tx, and a current limiter for rx.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-20 11:22
    I was expecting to start with the resistor ladder and transistor method and see how things go. I'll have to check with my scope to answer the idle question, from what I have read the bits are not inverted. What do you mean by "signal levels"? It is 0 to 12/14v I believe if that is what you

    I was able to ask for more complete data sets that the person used matlab to get.

    Did you use a scope to gather your information, or can I use a scope to answer the questions you've asked me?

    PRI|ML 53
    DID D2
    MID C8
    DATA1 00
    CRC E9
    check crc: E9
    CRC OK
    EOM 7E
    PRI|ML 63
    DID D2
    MID 2C
    DATA1 00
    CRC B5
    check crc: B5
    CRC OK
    EOM 7E
    PRI|ML 64
    DID 98
    MID CC
    DATA1 02
    DATA2 A7
    CRC D4
    check crc: D4
    CRC OK
    EOM 7E


    Using the first code set
        PRI
        |                           DATA (variable                   RSP
     SOF|    ML   DID      MID      | length)      CRC      EOM      |  EOF
      | |    |    |        |        |              |        |        |  |
      x_xxxx_xxxx_xxxxxxxx_xxxxxxxx_[8 to 88 bits]_xxxxxxxx_xxxxxxxx_xx_xxxxxx 
      
    



    ChrisGadd wrote: »
    Most of the pre-made objects rely on the MCP2515 chip, which can only decode CAN messages, which look like:
       Standard frame:                                                                                                  CRC delimiter     
                     RTR                                                                                                │ ACK                                                   
       SOF           │ IDE   Data length (0 - 8 bytes)                                                                  │ │ ACK delimiter                                       
       │ Ident A     │ │ R0  │  Byte 0   Byte 1   Byte 2   Byte 3   Byte 4   Byte 5   Byte 6   Byte 7   CRC             │ │ │ EOF                                               
       │ │           │ │ │   │  │        │        │        │        │        │        │        │        │               │ │ │ │
       0_xxxxxxxxxxx_0_0_0_xxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxxxxxxx_1_i_1_1111111     
    
    So while the signalling might be similar, the protocol appears completely different.

    I've written a few Prop-based objects that should work with some modifications to the parse_bit routine in the reader section.

    What are the signal levels?
    Does it idle high or low?
    Are the bits inverted?

    You may not even need the 2551 line driver. I'm currently working on a modification to the above CANbus routines that'll work with a GMLAN class-2 databus, which uses the same CAN protocol, but the messages are inverted, uses 5V for dominant '0' bits and gnd for recessive '1' bits, so all I need for that is a transistor driver for tx, and a current limiter for rx.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-20 11:59
    Also, do you have any idea how to calculate the CRC polynomial? I thought it could be calculated from the data below? But my message length isn't even working out.

    SOF 1
    PRI|ML 53 01010011 (83 in decimal)
    DID D2 11010010
    MID C8 11001000
    DATA1 00 00000000
    CRC E9 11101001
    check crc: E9 110110
    CRC OK
    EOM 7E 01111110
    RSP 01
    EOF 001100
    PRI|ML 63 01100011 (99 in decimal)
    DID D2 11010010
    MID 2C 00101100
    DATA1 00 00000000
    CRC B5 10110101
    check crc: B5 10110101
    CRC OK
    EOM 7E 01111110
    PRI|ML 64 01100100 (100 in decimal)
    DID 98 10011000
    MID CC 11001100
    DATA1 02 00000010
    DATA2 A7 10100111
    CRC D4 11010100
    check crc: D4 11010100
    CRC OK
    EOM 7E 01111110
  • ksltdksltd Posts: 163
    edited 2014-10-20 13:09
    Chris,

    You show a Standard Frame and say it's the only frame kind that the MCP2515 decodes. Did you omit the Extended Frame kind or have you encountered problems with the MCP2515 and Extended Frames?

    Thanks
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-10-20 15:08
    First thing to solve is the hw interface.
    Do you know if it is CAN?
    If yes, then the MCP2551 or similar would do for the interface chip.

    But your mention here seems to not be CAN
    Communication speed: Max 10kbps
    Communication wire: av single wire
    Drive type: single wire voltage drive
    COuld it be LIN?

    At 10kbs the prop should handle it fine.
    Initially it might be better to snoop the bus/line(s) using an optoisolator - a 6N137 or similar should do the job.

    For the CRC, often the address/header is not included in the CRC. Check the CAN bus spec as this might be the CRC used.
    There are online calculators that include setting the CRC algorithm and using that, hopefully you can determine which CRC is used. There are only a few common ones.
    Since it is only a single byte CRC it may just be a simple XOR function.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-20 15:20
    @turbosupra
    I managed to find a CRC that works with two of your messages, but fails all of the others, not sure what to make of that. Every search for more info about this BEAN protocol sends me to the SAE paywalled paper.
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    CRC8 = %100010011
      
    OBJ
      fds : "FullDuplexSerial"
    
    DAT
    
    message1  byte          "10101001111010010110010000000000011101001",00         
    message1d byte          "0101001111010010110010000000000011101001",00           ' 100010011  ignore the start bit 
    
    message2  byte          "1011000111101001000101100000000001011010110110101",00
    message2d byte          "011000111101001000101100000000001011010110110101",00   ' none found
    
    message3  byte          "1011001001001100011001100000000101010011111010100",00
    message3d byte          "011001001001100011001100000000101010011111010100",00   ' 100010011
    
    message4  byte          "01100010110111110000000001111000",00
    message5  byte          "011000101101001000000000101000000000100000001010",00   ' none found 
    message6  byte          "1001100011001100000000101010100000110101",00           ' none found 
    message7  byte          "1110111101101010000001000100010000111111",00           ' none found 
    
    
    PUB main | i, temp, crc_result, length, crc
      fds.start(31,30,0,115200)
      waitcnt(cnt + clkfreq)
      fds.tx($00)
    
      temp := 0
      length := strsize(@message1d)
      crc := 0
      repeat 
        crc++
        crc_result := 0
        temp := 0
        repeat i from 0 to length - 1
          temp := message1d[i] - "0"
          crc_result := crc_result << 1 | temp
          if crc_result => %100000000
            crc_result := crc_result ^ CRC
        if crc_result == 0
          fds.str(string("Valid CRC = "))
          fds.bin(crc,9)
          repeat
        if crc > %111111111
          fds.str(string("None found"))
          repeat
    
    PUB check | i, temp, crc_result, length, crc    
                
      crc_result := 0
      temp := 0
      length := strsize(@message3d)
    
      fds.tx($0D)
      
      repeat i from 0 to length - 1
        temp := message3d[i] - "0"
        crc_result := crc_result << 1 | temp
        if crc_result => %100000000
          crc_result := crc_result ^ CRC8
        fds.bin(crc_result,17)
        fds.tx($0D)
      repeat
    
    The above code stops searching once the CRC reaches 10 bits. I'm currently (for the past half-hour) letting it run up to the full 32 bits just to see.

    @ksltd
    Extended and remote frames work fine; I didn't see a reason to show them as they closely resemble the standard frame, and are nothing like what turbosupra is describing:
       Standard frame:                                                                                                  CRC delimiter     
                     RTR                                                                                                | ACK                                                   
       SOF           | IDE   Data length (0 - 8 bytes)                                                                  | | ACK delimiter                                       
       | Ident A     | | R0  |  Byte 0   Byte 1   Byte 2   Byte 3   Byte 4   Byte 5   Byte 6   Byte 7   CRC             | | | EOF                                               
       | |           | | |   |  |        |        |        |        |        |        |        |        |               | | | |                                                        
       0_xxxxxxxxxxx_0_0_0_xxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxxxxxxx_1_i_1_1111111     
    
       Extended frame:                                                                                                                         CRC delimiter    
                     SRR                    RTR                                                                                                | ACK            
       SOF           | IDE                  | R1    Data length                                                                                | | ACK delimiter
       | Ident A     | | Ident B            | | R0  |  Byte 0   Byte 1   Byte 2   Byte 3   Byte 4   Byte 5   Byte 6   Byte 7   CRC             | | | EOF        
       | |           | | |                  | | |   |  |        |        |        |        |        |        |        |        |               | | | |          
       0_xxxxxxxxxxx_1_1_xxxxxxxxxxxxxxxxxx_0_0_0_xxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxxxxxxx_1_i_1_1111111
    
       Standard remote frame:                   CRC delimiter                                              
                     RTR                        | ACK                                                      
       SOF           | IDE   Data length        | | ACK delimiter                                          
       | Ident A     | | R0  |  CRC             | | | EOF        
       | |           | | |   |  |               | | | |          
       0_xxxxxxxxxxx_1_0_0_0000_xxxxxxxxxxxxxxx_1_i_1_1111111    
    
       Extended remote frame:                                          CRC delimiter                       
                     SRR                    RTR                        | ACK                                                                   
       SOF           | IDE                  | R1    Data length        | | ACK delimiter                                                       
       | Ident A     | | Ident B            | | R0  |  CRC             | | | EOF                                                               
       | |           | | |                  | | |   |  |               | | | |                                                                 
       0_xxxxxxxxxxx_1_1_xxxxxxxxxxxxxxxxxx_1_0_0_0000_xxxxxxxxxxxxxxx_1_i_1_1111111
    

    Chris
  • jmgjmg Posts: 15,173
    edited 2014-10-20 15:25
    turbosupra wrote: »
    I added some info with bit rate, up to 10kbps...

    <paste>
    What do you mean by "signal levels"? It is 0 to 12/14v I believe

    That does not sound like CAN, looks like a Custom Automotive Network, using LIN bus hardware drivers
    (which are 10KHz region, single pin, 12V signaling)
    You might like to change the heading from CAN

    I'd also suggest you look into LIN bus a little, even if this is not a LIN clone, LIN has things like an Autobaud preamble this might use.


    10KHz is quite low speed, so I'd suggest doing a Bridge device in a Prop - that can Read/Write on this bus, and converts to a Generic UART PC serial stream.

    eg One simple way is to nibble encode, where lower 4 bits are a half byte payload, and the upper 4 bits give 16 choices of what to do with it. 2 of those can tag DataH,DataL, which leaves 14 spare for control and commands
    That allows the complex reverse engineering stuff to be managed on a PC, which is MUCH easier than a microcontroller.

    You need to run the PC link at > 2x the Toyota bus, with some buffering, but 10KHz is very slow.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-20 19:21
    Thank you for the help with this, I sent you a PM but the basics are below.

    I'm struggling trying to understand the code and decode process from start to finish, which bits are computed for message length, which are computed for the CRC, why you need the RSP field, how you know what the SOF bit is and similar questions. I'm going to try and read your code and see what you've done, why do you have ,00 at the end of the string in SPIN, is that to terminate the byte? How does bit stuffing work? How would the receiver know if you had 1111111 but bit stuffing translated it to 1111011 or 11111011 (depending if it inserts or replaces)? And that it wasn't originally 1111011 or 11111011 (depending on if it inserts or replaces) in the first place?

    About the B.E.A.N protocol, it was said to
    concatenate all the fields rather than summing them. And then run a variety of 8-bit polynomials against them
    Also note that bit stuffing is applied on informational fields

    DID & MID fields were needed to properly calculate the CRC. Each packet needed a different initialization pattern but the same CRC polynom, and the initialization data was exactly the DID & MID ))

    Here are the SAE papers for you

    https://drive.google.com/folderview?id=0B7FYCjMZX9RtejhDbGRvRGo5RVE&usp=sharing

    ChrisGadd wrote: »
    @turbosupra
    I managed to find a CRC that works with two of your messages, but fails all of the others, not sure what to make of that. Every search for more info about this BEAN protocol sends me to the SAE paywalled paper.
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    CRC8 = %100010011
      
    OBJ
      fds : "FullDuplexSerial"
    
    DAT
    
    message1  byte          "10101001111010010110010000000000011101001",00         
    message1d byte          "0101001111010010110010000000000011101001",00           ' 100010011  ignore the start bit 
    
    message2  byte          "1011000111101001000101100000000001011010110110101",00
    message2d byte          "011000111101001000101100000000001011010110110101",00   ' none found
    
    message3  byte          "1011001001001100011001100000000101010011111010100",00
    message3d byte          "011001001001100011001100000000101010011111010100",00   ' 100010011
    
    message4  byte          "01100010110111110000000001111000",00
    message5  byte          "011000101101001000000000101000000000100000001010",00   ' none found 
    message6  byte          "1001100011001100000000101010100000110101",00           ' none found 
    message7  byte          "1110111101101010000001000100010000111111",00           ' none found 
    
    
    PUB main | i, temp, crc_result, length, crc
      fds.start(31,30,0,115200)
      waitcnt(cnt + clkfreq)
      fds.tx($00)
    
      temp := 0
      length := strsize(@message1d)
      crc := 0
      repeat 
        crc++
        crc_result := 0
        temp := 0
        repeat i from 0 to length - 1
          temp := message1d[i] - "0"
          crc_result := crc_result << 1 | temp
          if crc_result => %100000000
            crc_result := crc_result ^ CRC
        if crc_result == 0
          fds.str(string("Valid CRC = "))
          fds.bin(crc,9)
          repeat
        if crc > %111111111
          fds.str(string("None found"))
          repeat
    
    PUB check | i, temp, crc_result, length, crc    
                
      crc_result := 0
      temp := 0
      length := strsize(@message3d)
    
      fds.tx($0D)
      
      repeat i from 0 to length - 1
        temp := message3d[i] - "0"
        crc_result := crc_result << 1 | temp
        if crc_result => %100000000
          crc_result := crc_result ^ CRC8
        fds.bin(crc_result,17)
        fds.tx($0D)
      repeat
    
    The above code stops searching once the CRC reaches 10 bits. I'm currently (for the past half-hour) letting it run up to the full 32 bits just to see.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-20 21:25
    turbosupra wrote: »
    Thank you for the help with this, I sent you a PM but the basics are below.

    I'm struggling trying to understand the code and decode process from start to finish, which bits are computed for message length, which are computed for the CRC, why you need the RSP field, how you know what the SOF bit is and similar questions. I'm going to try and read your code and see what you've done, why do you have ,00 at the end of the string in SPIN, is that to terminate the byte? How does bit stuffing work? How would the receiver know if you had 1111111 but bit stuffing translated it to 1111011 or 11111011 (depending if it inserts or replaces)? And that it wasn't originally 1111011 or 11111011 (depending on if it inserts or replaces) in the first place?
    The code that I posted attempts to brute force a CRC polynomial, starting at 0 and going up to %1_11111111. I ran the code against the messages that you posted, using the priority, message length, destination ID, message ID, data, and the CRC. I initially tried with the SOF, but going by experience with CAN, also tried without, which got a couple positive responses. If the message is valid, with the correct polynomial, the result will be zero after going through the CRC field.
    For one of the messages you gave me:
      SOF     1                                         
      PRI|ML 53       01010011 (83 in decimal)          
      DID D2  11010010                                  
      MID C8  11001000                                  
      DATA1 00        00000000                          
      CRC E9  11101001                                  
      check crc: E9   110110                            
      CRC OK                                            
      EOM 7E  01111110                                  
      RSP     01                                        
      EOF     001100
      
    Re-written from priority through CRC as 0101_0011_11010010_11001000_00000000_11101001
    Spaces removed: 0101001111010010110010000000000011101001
    CRC polynomial:  100010011
    xor:            0001011100010010110010000000000011101001
    shift:             100010011
    xor:            0000011000100010110010000000000011101001
    shift:               100010011
    xor:            0000001001101110110010000000000011101001
    shift:                100010011
    xor:            0000000001001000110010000000000011101001
    shift:                   100010011
    xor:            0000000000001100000010000000000011101001
    shift:                      100010011
    xor:            0000000000000100100100000000000011101001
    shift:                       100010011
    xor:            0000000000000000110111000000000011101001
    shift:                          100010011
    xor:            0000000000000000010101011000000011101001
    shift:                           100010011
    xor:            0000000000000000000100010100000011101001
    shift:                             100010011
    xor:            0000000000000000000000000111000011101001
    shift:                                   100010011
    xor:            0000000000000000000000000011010000101001
    shift:                                    100010011
    xor:            0000000000000000000000000001011001001001
    shift:                                     100010011
    xor:            0000000000000000000000000000011101111001
    shift:                                       100010011
    xor:            0000000000000000000000000000001100110101
    shift:                                        100010011
    xor:            0000000000000000000000000000000100010011
    shift:                                         100010011
    xor:            0000000000000000000000000000000000000000
    
    It doesn't make sense to include anything following the CRC in the calculation, which is why end-of-message and rsp aren't included. I don't yet understand just what message-length is; message-length three is one byte of data, length four is two bytes of data, maybe including the destination ID and message ID fields in the message length.

    For the 00 at the end of the strings, I've written all of the messages as text strings to allow me to parse one bit at a time, and the 00 is a null-terminator so Spin knows where the end of the string is.

    For bit stuffing, the bus is non-return-to-zero, and there is no clock line, so it relies on transitions in order to maintain synchronization. If there are no transitions for five bits, a stuffed, opposite, bit is inserted in order to force a transition. A sequence of 1111100000 will be stuffed as 111110000010, where the underlined bits are stuffed. To unstuff, if you count five similar bits in a row, discard the bit that follows. 111110111110000 unstuffs to 1111111111000. The exception to that where you might see six or more identical bits in a row is in error-frames (at least with CAN) and also for end-of-frame.

    I'll hopefully know more after I get a chance to study the papers.

    Chris
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-21 06:01
    I think I understand message length and priority now (you may have already figured this out), the hex byte gets split in half to two nibbles. The first 4 bits is the priority, the second 4 bits is the message length. The first nibble makes sense with the priority being a lower number at 5 or 6, but still being in the realm of 1 through 10 which one would expect. The second nibble matches the number of DID, MID and DATA fields. Using the output below where I have the message length the message length checks out if you check to see how many fields there are for DID, MID and DATA1-DATA11. What do you think?

    I'm going to wrap my head around the bit stuffing a little more, thank you for the explanation though. I need to see it in practice and working to really feel confident in how it works. I'll keep studying, thank you.

    --------
    PRI|ML 53  [b]0101[/b] for the first nibble, [b]0011[/b] for the second nibble -  5 and 3
    DID D2    11010010              (field 1)            
    MID C8    11001000              (field 2)
            = 00011010
    DATA1 00  00000000              (field 3)
    CRC E9
    check crc: E9 11101001
    CRC OK
    EOM 7E
    --------
    PRI|ML 63  [b]0110[/b] for the first nibble, [b]0011[/b] for the second nibble -  6 and 3
    DID D2  11010010                (field 1)
    MID 2C  00101100                (field 2)
         =  11111110
    DATA1 00  00000000              (field 3)
    CRC B5                         
    check crc: B5                   
    CRC OK
    EOM 7E
    --------
    PRI|ML 64  [b]0110[/b] for the first nibble, [b]0100[/b] for the second nibble -   6 and 4
    DID 98                          (field 1)
    MID CC                          (field 2)
    DATA1 02                        (field 3)
    DATA2 A7                        (field 4)
    CRC D4
    check crc: D4
    CRC OK
    EOM 7E
    -------- 
    



    *In the set below, italicized means I'm guessing at this field
    
    --------
    [i]PRI|ML*[/i] [b]0101 or 0110[/b] for the first nibble, [b]0011[/b] for the second nibble - 5 or 6 and 3
    DID 62                          (field 1)
    MID BF                          (field 2)
    DATA1 00                        (field 3)
    CRC 78
    EOM 7E
    --------
    [i]PRI|ML*[/i] [b]0101 or 0110[/b] for the first nibble, [b]0101[/b] for the second nibble - 5 or 6 and 5
    DID 62                          (field 1)
    MID D2                          (field 2)
    DATA1 00                        (field 3)
    DATA2 A0                        (field 4)
    DATA3 08                        (field 5)
    CRC 0A
    EOM 7E
    --------
    [i]PRI|ML*[/i] [b]0101 or 0110[/b] for the first nibble, [b]0100[/b] for the second nibble - 5 or 6 and 4
    DID 98                          (field 1)
    MID CC                          (field 2)
    DATA1 02                        (field 3)
    DATA2 A8                        (field 4)
    CRC 35
    EOM 7E
    --------
    [i]PRI|ML*[/i] [b]0101 or 0110[/b] for the first nibble, [b]0011[/b] for the second nibble - 5 or 6 and 3
    DID EF                          (field 1)
    MID 6A                          (field 2)                                  
    DATA1 04                        (field 3)
    CRC 44
    EOM 3F
    --------
    
    
    
    ChrisGadd wrote: »
    The code that I posted attempts to brute force a CRC polynomial, starting at 0 and going up to %1_11111111. I ran the code against the messages that you posted, using the priority, message length, destination ID, message ID, data, and the CRC. I initially tried with the SOF, but going by experience with CAN, also tried without, which got a couple positive responses. If the message is valid, with the correct polynomial, the result will be zero after going through the CRC field.
    For one of the messages you gave me:
      SOF     1                                         
      PRI|ML 53       01010011 (83 in decimal)          
      DID D2  11010010                                  
      MID C8  11001000                                  
      DATA1 00        00000000                          
      CRC E9  11101001                                  
      check crc: E9   110110                            
      CRC OK                                            
      EOM 7E  01111110                                  
      RSP     01                                        
      EOF     001100
      
    Re-written from priority through CRC as 0101_0011_11010010_11001000_00000000_11101001
    Spaces removed: 0101001111010010110010000000000011101001
    CRC polynomial:  100010011
    xor:            0001011100010010110010000000000011101001
    shift:             100010011
    xor:            0000011000100010110010000000000011101001
    shift:               100010011
    xor:            0000001001101110110010000000000011101001
    shift:                100010011
    xor:            0000000001001000110010000000000011101001
    shift:                   100010011
    xor:            0000000000001100000010000000000011101001
    shift:                      100010011
    xor:            0000000000000100100100000000000011101001
    shift:                       100010011
    xor:            0000000000000000110111000000000011101001
    shift:                          100010011
    xor:            0000000000000000010101011000000011101001
    shift:                           100010011
    xor:            0000000000000000000100010100000011101001
    shift:                             100010011
    xor:            0000000000000000000000000111000011101001
    shift:                                   100010011
    xor:            0000000000000000000000000011010000101001
    shift:                                    100010011
    xor:            0000000000000000000000000001011001001001
    shift:                                     100010011
    xor:            0000000000000000000000000000011101111001
    shift:                                       100010011
    xor:            0000000000000000000000000000001100110101
    shift:                                        100010011
    xor:            0000000000000000000000000000000100010011
    shift:                                         100010011
    xor:            0000000000000000000000000000000000000000
    
    It doesn't make sense to include anything following the CRC in the calculation, which is why end-of-message and rsp aren't included. I don't yet understand just what message-length is; message-length three is one byte of data, length four is two bytes of data, maybe including the destination ID and message ID fields in the message length.

    For the 00 at the end of the strings, I've written all of the messages as text strings to allow me to parse one bit at a time, and the 00 is a null-terminator so Spin knows where the end of the string is.

    For bit stuffing, the bus is non-return-to-zero, and there is no clock line, so it relies on transitions in order to maintain synchronization. If there are no transitions for five bits, a stuffed, opposite, bit is inserted in order to force a transition. A sequence of 1111100000 will be stuffed as 111110000010, where the underlined bits are stuffed. To unstuff, if you count five similar bits in a row, discard the bit that follows. 111110111110000 unstuffs to 1111111111000. The exception to that where you might see six or more identical bits in a row is in error-frames (at least with CAN) and also for end-of-frame.

    I'll hopefully know more after I get a chance to study the papers.

    Chris
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-21 07:49
    I tried this for the first 3 that there is a full set of data for, I tried XOR ing different bytes which may be over complicating it? Is there a possibility that everything is inverted?

    Maybe bit stuffing plays into it?

    How could the DID + MID be an initialization pattern for the CRC polynomial? Below are the combos I have tried, I cannot find a pattern.

    --------
    PRI|ML 53 0101 0011   5 and 3
    DID D2    11010010              (field 1)            
    MID C8    11001000              (field 2)
            = 00011010
    DATA1 00  00000000              (field 3)
    CRC E9
    check crc: E9 OR 11101001
    CRC OK
    EOM 7E
                                                                                                                 
    DID + MID + DATA = D2C800 OR 110100101100100000000000                                                   ' Valid CRC = 101011100  
    PRI + ML + DID + MID + DATA = 53D2C800 OR 01010011110100101100100000000000                              ' Valid CRC = 100000000 
    PRI + ML + DID + MID + DATA + CRC = 53D2C800E9 OR 0101001111010010110010000000000011101001              ' Valid CRC = 100010011
    
    (PRI/ML XOR) + DID + MID + DATA = 110110100101100100000000000                                           ' Valid CRC = 100000000
    (PRI/ML XOR) + DID + MID + DATA + CRC = 11011010010110010000000000011101001                             ' None found
    
    PRI + ML + (DID/MID XOR) + DATA = 010100110001101000000000                                              ' Valid CRC = 10101110
    PRI + ML + (DID/MID XOR) + DATA + CRC = 01010011000110100000000011101001                                ' Valid CRC = 100000000
    
    ML + DID + MID + DATA = 0011110100101100100000000000                                                    ' Valid CRC = 101010000
    ML + DID + MID + DATA + CRC = 001111010010110010000000000011101001                                      ' Valid CRC = 100010110
    
    
    
    --------
    PRI|ML 63  0110 0011    6 and 3
    DID D2  11010010                (field 1)
    MID 2C  00101100                (field 2)
         =  11111110
    DATA1 00  00000000              (field 3)
    CRC B5                         
    check crc: B5 OR 10110101                  
    CRC OK
    EOM 7E
                                                                                                            
    DID + MID + DATA = D22C00 OR 110100100010110000000000                                                   ' Valid CRC = 10101110                
    PRI + ML + DID + MID + DATA = 63D22C00 OR 01100011110100100010110000000000                              ' Valid CRC = 100010011   
    PRI + ML + DID + MID + DATA + CRC = 63D22C00B5 OR 0110001111010010001011000000000010110101              ' None found
    
    (PRI/ML XOR) + DID + MID + DATA = 00000101110100100010110000000000                                      ' Valid CRC = 101011100
    (PRI/ML XOR) + DID + MID + DATA + CRC = 0000010111010010001011000000000010110101                        ' Valid CRC = 101011100       
    
    PRI + ML + (DID/MID XOR) + DATA = 011000111111111000000000                                              ' Valid CRC = 10101110        
    PRI + ML + (DID/MID XOR) + DATA + CRC = 01100011111111100000000010110101                                ' Valid CRC = 100000000               
    
    ML + DID + MID + DATA = 0011110100100010110000000000                                                    ' Valid CRC = 100010110
    ML + DID + MID + DATA + CRC = 001111010010001011000000000010110101                                      ' Valid CRC = 100010110    
    
    
    
    --------
    PRI|ML 64  0110 0100   6 and 4
    DID 98  10011000                (field 1)
    MID CC  11001100                (field 2)
         =  1010100
    DATA1 02  00000010              (field 3)
    DATA2 A7  10100111              (field 4)
    CRC D4
    check crc: D4 OR 11010100
    CRC OK
    EOM 7E
    
    DID + MID + DATA = 98CC02A7 OR 10011000110011000000001010100111                                         ' Valid CRC = 100000000      
    PRI + ML + DID + MID + DATA = 6498CC02A7 OR 0110010010011000110011000000001010100111                    ' Valid CRC = 10001001
    PRI + ML + DID + MID + DATA + CRC = 6498CC02A7D4 OR 011001001001100011001100000000101010011111010100    ' None found
    
    (PRI/ML XOR) + DID + MID + DATA = 000000101001100011001100000000101010011111010100                      ' None found            
    (PRI/ML XOR) + DID + MID + DATA + CRC = 00000010100110001100110000000010101001111101010011010100        ' None found      
    
    PRI + ML + (DID/MID XOR) + DATA = 0110010010101000000001010100111                                       ' Valid CRC = 1000000                  
    PRI + ML + (DID/MID XOR) + DATA + CRC = 011001001010100000000101010011111010100                         ' Valid CRC = 100110110       
    
    ML + DID + MID + DATA = 010010011000110011000000001010100111                                            ' Valid CRC = 100010110      
    ML + DID + MID + DATA + CRC = 01001001100011001100000000101010011111010100                              ' None found
    
    
    
    -------- 
    
    
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-21 10:55
    I made a mistake when converting the second message to a text string; I mistakenly entered the CRC twice.
    I also didn't realize that messages 4 through 7 were posted without a priority and message length, and I mis-copied some of those as well. Message 6 matches when prefaced with a priority 6 and message length 4 %01100100.
    Frustratingly, I still can't get matches to messages 4, 5, or 7 even trying every priority from $0 to $F. A couple messages matching to the same polynomial might be a coincidence, but 4 out of 7?

    I've tried inverting, I've tried without headers, I've tried subtractions instead of xor's, I've tried comparing to => crc instead of => $100; nothing gives as consistent a result as with header, non-inverted, xor'ing when => $100.

    Stuffed bits cannot be part of the CRC, as the CRC field may also be stuffed. I dunno why priority and message-length wouldn't be part of the calculation, but omitting them doesn't seem to help.
    I had guessed at the message length and verified it in the paper you posted. The paper also shows a typical bitstream with levels for SOF, EOM, and EOF, so I should be able to get a reader coded from that.

    My CRC calculator wasn't very well thought out, stopping at the first positive match. This should be easier to use.
    DAT
      message1    byte        "0101001111010010110010000000000011101001",00                     ' 53, D2, C8, 00, E9
      message2    byte        "0110001111010010001011000000000010110101",00                     ' 63, D2, 2C, 00, B5
      message3    byte        "011001001001100011001100000000101010011111010100",00             ' 64, 98, CC, 02, A7, D4
      message4    byte        "____001101100010101111110000000001111000",00                     ' _3, 62, BF, 00, 78
      message5    byte        "____0101011000101101001000000000101000000000100000001010",00     ' _5, 62, D2, 00, A0, 08, 0A
      message6    byte        "011001001001100011001100000000101010100000110101",00             ' 64, 98, CC, 02, A8, 35
      message7    byte        "____001111101111011010100000010001000100",00                     ' _3, EF, 6A, 04, 44
    
    PUB main | i, temp, crc_result, length, crc, message
      fds.start(31,30,0,115_200)
      waitcnt(cnt + clkfreq)
      fds.tx($00)
    
      message := @message1
    
      temp := 0
      length := strsize(message)
      crc := 0
      repeat until crc == %1_1111_1111
        crc++
        crc_result := 0
        temp := 0
        repeat i from 0 to length - 1
          temp := byte[message][i] - "0"
          crc_result := crc_result << 1 | temp
          if crc_result => %1_0000_0000
            crc_result := crc_result ^ crc
          if crc_result == 0
            fds.str(string("Valid CRC = "))
            fds.bin(crc,9)
            fds.tx($09)
            fds.hex(crc,3)
            fds.tx($0D)
      fds.str(string("Finished"))
    
    Chris
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-21 12:52
    Hi Chris.

    The other hint I was given (and didn't realize until today) was that it had something to do with encryption. The person that said they've cracked it said to check out this site

    http://cryptopals.com/

    Have you ever seen a CRC that could been encrypted by the MID and DID? Could that be what this means? Maybe repeating key XOR? Or an XOR of the MID and DID used in the repeating key, or a single byte XOR cipher? The single byte xor cipher makes the most sense based on what was written below I think?
    DID & MID fields were needed to properly calculate the CRC. Each packet needed a different initialization pattern
    but the same CRC polynom, and the initialization data was exactly the DID & MID ))
    you should concatenate all the fields rather than summing them. Ant then run a variety of 8-bit polynomials against them
    Also note that bit stuffing is applied on informational fields
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-22 04:35
    Update, he said it is not encrypted, it just shows an example of how to brute force a key, just like the CRC has to be brute forced.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-22 14:30
    I've been following the conversation over on toymods, and honestly I have no idea what george is talking about with using the MID and DID fields to preset a value for the polynomial. In my calculator routine, the CRC field is zeroed out, and while it's certainly possible to initialize it to some other value, it makes no sense for that initial value to come from a field in the received message. In order to get those values at least part of the message has to have already been received, so does that mean storing the un-parsed message in memory and only starting the calculation after those two fields have come in and been parsed? The CRC is simply there to ensure that the message is received correctly, there's no reason to make it any more complicated. As far as I can tell, the polynomial is $113. It works with every message that we have complete data for, including the six most recent messages.

    I'm modifying my GMLAN reader to work with BEAN, but I really need to see an actual signal from an o'scope as the tech paper doesn't really say much about it.

    The papers show the frame format in figure 9 with high and low levels for each bit field. According to that figure, the bus idles low.
    However figure 3 shows a bus interface circuit with what looks like a pull-up resistor and a transistor driver to assert a low. It also labels the connections to the microcontroller as Rx-not and Tx-not.
    Kinda hard to tell what's going on in the interface circuit in figure 7 but that one appears to be biased low, with Tx asserting a high.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-22 18:23
    Some of the shorthand you used in your spin routine I was unsure about so I thought I'd write a quick brute force program in C# to give me some import capability and better understand it. Here I am 12 hours later and I still can't get it to work! I'm not sure if I have forgotten something about how to do binary division or I've forgotten how to write in C#. Any chance you could explain your latest spin routine line by line?

    Then I can try and insert the poly and see what happens?

    I have an ECU that uses bean, I'll have to fabricate something up for it and try and get you an Oscope, the only problem is that I have a propscope and I don't think it will record/archive data, it just displays it onscreen.

    ChrisGadd wrote: »
    I've been following the conversation over on toymods, and honestly I have no idea what george is talking about with using the MID and DID fields to preset a value for the polynomial. In my calculator routine, the CRC field is zeroed out, and while it's certainly possible to initialize it to some other value, it makes no sense for that initial value to come from a field in the received message. In order to get those values at least part of the message has to have already been received, so does that mean storing the un-parsed message in memory and only starting the calculation after those two fields have come in and been parsed? The CRC is simply there to ensure that the message is received correctly, there's no reason to make it any more complicated. As far as I can tell, the polynomial is $113. It works with every message that we have complete data for, including the six most recent messages.

    I'm modifying my GMLAN reader to work with BEAN, but I really need to see an actual signal from an o'scope as the tech paper doesn't really say much about it.

    The papers show the frame format in figure 9 with high and low levels for each bit field. According to that figure, the bus idles low.
    However figure 3 shows a bus interface circuit with what looks like a pull-up resistor and a transistor driver to assert a low. It also labels the connections to the microcontroller as Rx-not and Tx-not.
    Kinda hard to tell what's going on in the interface circuit in figure 7 but that one appears to be biased low, with Tx asserting a high.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-22 20:18
    Took me a bit to get it figured too, but essentially it boils down to:
    Shift the bitstream left into a working register
    If bit 8 of the working register is set, then xor it with the polynomial
    Repeat until all bits are shifted

    That's for decoding. To encode it, repeat the loop until the entire bitstream has been shifted plus eight "0" bits for the crc field. I've included an example in the latest code, which I've yet again modified to deal with strings of hexadecimal characters rather than binary.

    A screen capture of the propscope should be fine. Just hit 'printscreen', create a new bitmap image, edit in ms-paint, paste the captured image, save as jpg. Simple.

    CRC calculator 2.spin
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-23 06:49
    I'm unsure as to why you do this. I modified your code in the second code block and then pasted the output below in case it was a good example for explaining.

    I usually do screen caps with my prop scope, so if that is sufficient, I will do that in this case as well.
    crc_result := crc_result << 1 | (nib <-= 1) & 1
    
                fds.bin(nib, 32)
                fds.str(string(" - nib"))
                fds.tx(13)
                fds.bin(crc_result, 32)
                fds.str(string(" - crc_result before"))
                fds.tx(13)                                      
                crc_result := crc_result << 1 | (nib <-= 1) & 1    ' Shift crc_result left one bit and append the most-significant bit of nib, rotate nib to get the next msb  
                fds.bin(nib, 32)
                fds.tx(13)}
                fds.bin(crc_result, 32)
                fds.str(string(" - crc_result after"))
                fds.tx(13)
                fds.tx(13) 
    


    E
    11100000000000000000000000000000 - nib
    01010011101011010011011111111111 - crc_result before
    10100111010110100110111111111111 - crc_result after

    11000000000000000000000000000001 - nib
    10100111010110100110111111111111 - crc_result before
    01001110101101001101111111111111 - crc_result after

    10000000000000000000000000000011 - nib
    01001110101101001101111111111110 - crc_result before
    10011101011010011011111111111101 - crc_result after

    00000000000000000000000000000111 - nib
    10011101011010011011111111111101 - crc_result before
    00111010110100110111111111111010 - crc_result after

  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-23 09:45
    That line simply copies a bit from the top of nib and appends it to the end of crc_result. That one line can be re-written as:
    ' Read a character from the text string - each character represents a hexadecimal value $0 through $F, which is four bits %0000 through %1111
    ' Those four bits are shifted to the uppermost bits of nib.  [b]nib := nib << 28[/b]
    ' The following lines are then executed
    
      nib := nib <- 1                              ' rotate nib left one bit, the value in bit 31 is rotated into bit 0
      next_bit := nib & 1                          ' set next_bit to the value of nib bit 0
      crc_result := crc_result << 1                ' shift crc_result left 1 bit, appends a '0' onto the end of crc_result
      crc_result := crc_result | next_bit          ' combine crc_result with next_bit
    
    ' do it three more times to move all of the bits from nib into crc_result
    '                                                entry                  exit
      nib := nib <- 1                              ' nib = %101......0      nib = %01.....01                         
      next_bit := nib & 1                          ' next_bit = 0           next_bit = 1
      crc_result := crc_result << 1                ' crc_result = 11100     crc_result = 111000
      crc_result := crc_result | next_bit          ' crc_result = 111000    crc_result = 111001
    
      nib := nib <- 1                              ' nib = %01......01      nib = %1.....010                         
      next_bit := nib & 1                          ' next_bit = 1           next_bit = 0
      crc_result := crc_result << 1                ' crc_result = 111001    crc_result = 1110010
      crc_result := crc_result | next_bit          ' crc_result = 1110010   crc_result = 1110010
    
      nib := nib <- 1                              ' nib = %1......010      nib = %....0101
      next_bit := nib & 1                          ' next_bit = 0           next_bit = 1
      crc_result := crc_result << 1                ' crc_result = 1110010   crc_result = 11100100
      crc_result := crc_result | next_bit          ' crc_result = 11100100  crc_result = 11100101
    
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-24 06:14
    Thank you for breaking down your code above.

    So is the basic premise to

    1.) count the number of hex digits
    2.) go into a loop based on that count
    3.) get first hex digit, get first character, get 4 digit binary value of that character
    4.) bit shift the nibble lsb to the nibble msb 4 times in a loop
    5.) bit shift the crc_result bits 4 to 0 shifted to 8-4
    6.) append the bits from the nibble to the crc_result bits 3-0
    7.) Xor them with the crc you are testing
    8.) If the Xor value is 0, the crc is valid


    What is the crc_result value before it is appended and where does it come from?
    Why does the CRC8 have 9 values?
    Why does it need that leading 1?
    Is that to give it significant digits in case the value behind it is a 0?
    Is the CRC field in the stream of bits a value that is calculated and inserted to allow the poly to work?
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-24 13:31
    Getting there, steps 4, 5, and 6 need to be performed one bit at a time, and step 7 should only be executed if bit 8 of crc_result is set. Maybe a flowchart will illustrate better than my descriptions:
    flowchart.jpg


    What is the crc_result value before it is appended and where does it come from?
    The crc_result is initially zero, it's a working register that the bitstream is shifted into and xor'd with the polynomial.

    Why does the CRC8 have 9 values?
    Wikipedia has some good info on the Cyclic redundancy check. Regarding the naming convention for why CRC8 has nine bits:
    From Wikipedia
    A CRC is called an n-bit CRC when its check value is n bits. For a given n, multiple CRCs are possible, each with a different polynomial. Such a polynomial has highest degree n, which means it has n + 1 terms. In other words, the polynomial has a length of n + 1; its encoding requires n + 1 bits. Note that most polynomial specifications either drop the MSB or LSB bit, since they are always 1. The CRC and associated polynomial typically have a name of the form CRC-n-XXX as in the table below.
    I suppose I should've been saying the polynomial is $13 rather than $113, but that's just an extra layer of confusion I didn't wanna deal with.

    Is the CRC field in the stream of bits a value that is calculated and inserted to allow the poly to work?
    The CRC field is calculated in the exact same manner as verifying the message. Suppose the bitstream from priority/message-length through the final data byte is $64, $98, $CC, $02, $A7. In order to get the crc field, append an empty byte to the end of the string to hold the crc, run it through the same process in the flowchart, and value remaining in the crc_result register will be $D4.

    In other words:
    Running the string $64, $98, $CC, $02, $A7, $00 through the flowchart process leaves $D4 in the crc_result register.
    Running the string $64, $98, $CC, $02, $A7, $D4 through the flowchart process leaves $00 in the crc_result register.

    Clear as mud?
    763 x 1162 - 154K
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-27 11:51
    Thanks for trying to explain this to me Chris, I know you've went above and beyond, I just don't understand the big picture. Using this calculator, if the hex string was hex 53, I don't understand how the bean poly hex 13 100010011 that equals 10011010 is an answer? (I tried going a hex character at a time on paper) I'm confused about how the CRC is calculated, which I need to be solid on before I try to figure out how to backwards engineer it.

    using 113 or 100010011

    5 = 01011111
    3 = 00110101
    D = 11000111
    2 = 00100110
    C = 11010100
    8 = 10011000
    0 = 00000000
    0 = 00000000
    E = 11110010
    9 = 10001011

    53 = 10011010
    D2 = 10000010
    C8 = 00011111
    00 = 00000000
    E9 = 01001010

    53D2 = 00010100
    C800E9 = 11101011

    but

    53D2C800E9 = 00000000

    I'm going to keep reading and hope it clicks.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-27 13:33
    I made a mistake, here's how $05 = $5F
    In order to find the crc field, every bit must be shifted, plus eight bits to hold the crc result.
    Simplest way to do that is to append an empty byte $00 to the end of the bitstream.
    
                     |--05--||--00--|
           000000000_0000010100000000  start
                         10100000000   shift left until bit 8 of working register is set
                        10100000000     shift
                       10100000000      shift
                      10100000000       shift
                     10100000000        shift
                   1_0100000000         shift
                  10_100000000          shift
                 101_00000000           shift
                1010_0000000            shift
               10100_000000             shift
              101000_00000              shift
             1010000_0000               shift
            10100000_000                shift
           101000000_00                 shift - bit 8 set
           100010011                    xor
           001010011_00                 result
            10100110_0                  shift
           101001100                    shift - bit 8 set 
           100010011                    xor
           001011111                    result, finished, all bits shifted, result = $5F
           
       
      Going the other way:
    
                 |--05--||--5F--|                                                                                     
                %0000010101011111                                                                                     
                                                                                                                      
       000000000_0000010101011111       start                                                  
               0_000010101011111        shift left until bit 8 of working register is set               
              00_00010101011111          shift                                                          
             000_0010101011111           shift                                                          
            0000_010101011111            shift                                                          
           00000_10101011111             shift                                                          
          000001_0101011111              shift                                                          
         0000010_101011111               shift                                                          
        00000101_01011111                shift                                                          
       000001010_1011111                 shift                                                          
       000010101_011111                  shift                                                          
       000101010_11111                   shift                                                          
       001010101_1111                    shift                                                          
       010101011_111                     shift                                                          
       101010111_11                      shift - bit 8 set                                                                                  
       100010011                         xor                                                            
       001000100_11                      result                                                         
        10001001_1                       shift                                               
       100010011                         shift - bit 8 set                                                         
       100010011                         xor                     
       000000000                         result - finished, all bits shifted, result = $00
    
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-27 18:51
    Haha, this is actually starting to make sense to me :) ... thank you very much.

    After I read this, I was able to read through and understand the code block you put in your object as well. I'm going to start fresh and write code tomorrow and try to implement what you've taught me.

    In the second code block, why do you take the extra step to xor the poly with the resulting xored value at the bottom? Is this to check your answer?

    ChrisGadd wrote: »
    I made a mistake, here's how $05 = $5F
    In order to find the crc field, every bit must be shifted, plus eight bits to hold the crc result.
    Simplest way to do that is to append an empty byte $00 to the end of the bitstream.
    
                     |--05--||--00--|
           000000000_0000010100000000  start
                         10100000000   shift left until bit 8 of working register is set
                        10100000000     shift
                       10100000000      shift
                      10100000000       shift
                     10100000000        shift
                   1_0100000000         shift
                  10_100000000          shift
                 101_00000000           shift
                1010_0000000            shift
               10100_000000             shift
              101000_00000              shift
             1010000_0000               shift
            10100000_000                shift
           101000000_00                 shift - bit 8 set
           100010011                    xor
           001010011_00                 result
            10100110_0                  shift
           101001100                    shift - bit 8 set 
           100010011                    xor
           001011111                    result, finished, all bits shifted, result = $5F
           
       
      Going the other way:
    
                 |--05--||--5F--|                                                                                     
                %0000010101011111                                                                                     
                                                                                                                      
       000000000_0000010101011111       start                                                  
               0_000010101011111        shift left until bit 8 of working register is set               
              00_00010101011111          shift                                                          
             000_0010101011111           shift                                                          
            0000_010101011111            shift                                                          
           00000_10101011111             shift                                                          
          000001_0101011111              shift                                                          
         0000010_101011111               shift                                                          
        00000101_01011111                shift                                                          
       000001010_1011111                 shift                                                          
       000010101_011111                  shift                                                          
       000101010_11111                   shift                                                          
       001010101_1111                    shift                                                          
       010101011_111                     shift                                                          
       101010111_11                      shift - bit 8 set                                                                                  
       100010011                         xor                                                            
       001000100_11                      result                                                         
        10001001_1                       shift                                               
       100010011                         shift - bit 8 set                                                         
       100010011                         xor                     
       000000000                         result - finished, all bits shifted, result = $00
    
    {{&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
      &#9474; CRC calculator                     &#9474;                
      &#9474; Author: Chris Gadd                 &#9474; 
      &#9474; Copyright (c) 2014 Chris Gadd      &#9474;     
      &#9474; See end of file for terms of use.  &#9474;     
      &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;                    11101001 
    
        Using the message $53,$D2,$C8,$00,$E9
                                             |--53--||--D2--||--C8--||--00--||--E9--|          
        Rewritten in binary:                 0101001111010010110010000000000011101001                 
        Shift the bitstream                  40                                     0
         left into a new register            |                                      |
         until the bit 8 is set    000000000_0101001111010010110010000000000011101001
                                   000000000_101001111010010110010000000000011101001
                                   000000001_01001111010010110010000000000011101001
                                   000000010_1001111010010110010000000000011101001
                                   000000101_001111010010110010000000000011101001
                                   000001010_01111010010110010000000000011101001
                                   000010100_1111010010110010000000000011101001
                                   000101001_111010010110010000000000011101001
                                   001010011_11010010110010000000000011101001
                                   010100111_1010010110010000000000011101001
           Bit 8 is now set        101001111_010010110010000000000011101001
           Xor with the polynomial 100010011
           Result                  001011100_010010110010000000000011101001
     Shift left until bit 8 is set 010111000_10010110010000000000011101001
           Bit 8 is set            101110001_0010110010000000000011101001
           Xor with the polynomial 100010011
           Result                  001100010_0010110010000000000011101001
           Shift                   011000100_010110010000000000011101001
           Bit 8 set               110001000_10110010000000000011101001   
           Xor                     100010011
           Result                  010011011_10110010000000000011101001
           Shift, bit 8 set        100110111_0110010000000000011101001  
           Xor                     100010011
           Result                  000100100_0110010000000000011101001    
           Shift                   001001000_110010000000000011101001
                                   010010001_10010000000000011101001
           Bit 8 set               100100011_0010000000000011101001
           Xor                     100010011
           Result                  000110000_0010000000000011101001
           Shift                   001100000_010000000000011101001   
                                   011000000_10000000000011101001    
           Bit 8 set               110000001_0000000000011101001     
           Xor                     100010011
           Result                  010010010_0000000000011101001
           Shift, bit 8 set        100100100_000000000011101001
           Xor                     100010011
           Result                  000110111_000000000011101001  
           Shift                   001101110_00000000011101001
                                   011011100_0000000011101001
           Bit 8 set               110111000_000000011101001
           Xor                     100010011 
           Result                  010101011_000000011101001
           Shift, bit 8 set        101010110_00000011101001
           Xor                     100010011
           Result                  001000101_00000011101001 
           Shift                   010001010_0000011101001
           Bit 8 set               100010100_000011101001
           Xor                     100010011
           Result                  000000111_000011101001
           Shift                   000001110_00011101001
                                   000011100_0011101001
                                   000111000_011101001
                                   001110000_11101001      <- At this point all bits except the crc have been shifted (crc was E9 from specification paper)
                                   
                                   011100001_1101001           in order to find the crc field value, shift 8 zeroes in
           Bit 8 set               111000011_101001            001110000_00000000
           Xor                     100010011                   011100000_0000000
           Result                  011010000_101001            111000000_000000
           Shift, bit 8 set        110100001_01001             100010011            Xor with poly
           Xor                     100010011                   011010011_000000
           Result                  010110010_01001             110100110_00000
           Shift, bit 8 set        101100100_1001              100010011            Xor with poly
           Xor                     100010011                   010110101_00000
           Result                  001110111_1001              101101010_0000  
           Shift                   011101111_001               100010011            Xor with poly
           Bit 8 set               111011110_01                001111001_0000
           Xor                     100010011                   011110010_000
           Result                  011001101_01                111100100_00
           Shift, bit 8 set        110011010_1                 100010011            Xor with poly
           Xor                     100010011                   011110111_00
           Result                  010001001_1                 111101110_0
           Shift, bit 8 set        100010011                   100010011            Xor with poly
           Xor                     100010011                   011111101_0
           Result                  000000000                   111111010
           All bits shifted, finished                          100010011            Xor with poly
                                                               011101001
                                                               All bits shifted, crc field = %0_1110_1001 = $E9
    
      The decode process can be summed up as:
    
      Loop:
        Shift bits left into crc_result
        Is bit 8 of crc_result set?
          Yes - xor crc_result with polynomial
        All bits shifted?
          No - continue looping
          Yes - finished, crc_result will be clear for a properly received message
    
       The encode process is just like the above, but it needs to loop for an additional eight bits (crc field length)
    
                                   
    }}
    
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-28 19:03
    I have the calculator working, to a point now.

    I cannot for the life of me figure out how this problem works though, your answer was $14, the online calculator's
    answer was $14 but I keep getting 100100 $24 or 1001000 $48 when I do it by hand and when I input those numbers into my calculator. Even when I try the wikipedia way, I still get 1001000, what am I doing wrong?
              |--53--||--D2--|                                                                         
               %0101001111010010                                                                         
                                                                                                         
      000000000_0101001111010010   start                                                                 
      000000000_101001111010010    shift the bitstream left until bit 8 of the working register is set   
      000000001_01001111010010     shift                                                                 
      000000010_1001111010010      shift                                                                 
      000000101_001111010010       shift                                                                 
      000001010_01111010010        shift                                                                 
      000010100_1111010010         shift                                                                 
      000101001_111010010          shift                                                                 
      001010011_11010010           shift                                                                 
      010100111_1010010            shift                                                                 
      101001111_010010             shift - bit 8 is set      101001111                                   
      100010011                    xor with the polynomial: 100010011                                       
      001011100_010010             result                 = 001011100                                  
      101110001_0010               shift - bit 8 is set                                                  
      100010011                    xor                                                                                    
      001100010_0010               result                                                                              
      110001000_10                 shift - bit 8 is set                                                  
      100010011                    xor                                                                     
      010011011_10                 result                                                               
      100110111_0                  shift - bit 8 is set                                                    
      100010011                    xor                                                                            
      000100100_0                  result - all bits are shifted
      001001000                    shift - out of bits 
    
    


    Wikipedia way
           
            53D2 / 00010100 or $14
    
      0101001111010010 00000000     <--- input right padded by 8 bits (n bits) 
       100010011                     <--- divisor 
       001011100010010 00000000 
         100010011
         0011000100010 00000000
           100010011
           01001101110 00000000
            100010011
            0001001000 00000000
            ___________________
               1000100 11
               0001100 11000000           
                  1000 10011
                  0100 01011000
                   100 01000000
                   100 010011
                   000 000011
                   
      -------------------
              
    
    
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-28 19:32
    For the first code block, you forgot to pad the bitstream with 8 bits; try converting 53,D2,00.
    For the second code block, you somehow inserted an extra line:
            53D2 / 00010100 or $14
    
      0101001111010010 00000000     <--- input right padded by 8 bits (n bits) 
       100010011                     <--- divisor 
       001011100010010 00000000 
         100010011
         0011000100010 00000000
           100010011
           01001101110 00000000
            100010011
            0001001000 00000000
            ___________________
               1000100 11
               0001100 11000000           
                  1000 10011
                  0100 01011000
                   100 01000000  <- where did this line come from?  
                   100 010011       It should be the polynomial
                   000 000011
    
    
     corrected version:
            ___________________
               1000100 11
               0001100 11000000           
                  1000 10011
                  0100 01011000
                   100 010011
                   000 00010100 <- $14
    
Sign In or Register to comment.