Next edition of “Get Noticed!” started, and it’s my third attempt to write a blog in scope of one year, you know what they say, third time’s a charm. Little inspired by idea in post by fellow contender, I’m putting X amount for first post a week, and twice X for second in week, to “pleasure budget” that I can spend without remorse. We’ll see where that leads me. The goal of the project is to create “yet undefined” set of tools to make my work with LIN, a little easier and faster. The bread idea is to have tool generating .NET/F# client based on LDF (a little more on that in next post). Let’s start with short introduction to LIN.
What is LIN?
LIN (Local Interconnect Network) is a low-end and low-cost, single wire Serial Network Protocol that is used in automotive networks to communicate between vehicle components. It consists of 1 master and up to 15 slaves.
Each message is identified by ID. Valid IDs are within range <0,63>, where 0 to 56 are used for signal carrying, 60 and 61 for diagnostics, 62 for user defined extensions, and 64 reserved for future enhancements. on lower 6 bits, while the two upper bits contain parity.
let calcPID ID = let ID0 = ID &&& 1uy let ID1 = ID >>> 1 &&& 1uy let ID2 = ID >>> 2 &&& 1uy let ID3 = ID >>> 3 &&& 1uy let ID4 = ID >>> 4 &&& 1uy let ID5 = ID >>> 5 &&& 1uy let P0 = ID0 ^^^ ID1 ^^^ ID2 ^^^ ID4 let P1 = ~~~(ID1 ^^^ ID3 ^^^ ID4 ^^^ ID5) &&& 1uy ID ||| (P0 <<< 6) ||| (P1 <<< 7)
Message data consists from at least 1 byte and up to 8, and checksum. LIN 1.x uses Classic Checksum, while LIN 2.x uses Enhanced Checksum with the exceptions of messages with IDs from 60 to 63 which should be calculated with Classic Checksum.
Classic and Enhanced Checksum
Classic checksum is calculated using only message data, while in Enhanced Checksum we also include Protected ID, In order to calculate checksum we sum all bytes, subtracting 255 each time sum is greater or equal to 256, and then invert resulting value.
let carry255 a b = match a + (b |> uint16) with | s when s > 255us -> s-255us | s -> s let calcEnhancedChecksum pid = List.fold carry255 (pid |> uint16) >> byte let calcClassicChecksum = calcEnhancedChecksum 0uy
Before we continue, let’s describe imaginary example device will be working with further. Let’s say it’s comfort system with following functions:
- run massage, 12 air cells in 2 rows, 6 cells each. In order to run it we select:
- one of 3 predefined programs – varying in order of cell inflating/deflating
- one of 3 intensity levels
- one of 5 speed levels
- inflate, deflate:
- 2 lumbar cells – operating in 4 modes FORWARD (inflate both lumbar cells), BACKWARD (deflate both lumbar cells), UP (inflate lumbar 1 and deflate lumbar 2), DOWN (deflate lumbar 1 and inflate lumbar 2)
- 2 cushions bolsters – inflate/deflate both at the same time
- 2 back bolsters – inflate/deflate both at the same time
To give a picture how such a system could look in reality, it could consist of:
- 2 valve blocks, each having 4 bidirectional valves inflate+deflate
- 1 valve block, having 6 bidirectional valves inflate+deflate
where 6VB would be LIN slave, and master for both 4VB and pump, in other words, we would only communicate with 6VB, while 6VB would then delegate “some work” to two 4VB and pump, on a protocol beyond our concern.
For the convenience of our diagnostics let’s add few more functions to the system:
- massage status
- is massage running
- currently inflating/deflating air cells
- lumbar and bolster status:
- is pump running
- is valve working
- direct operations on pump and valves (to give example when such would come handy, we could need to test power consumption while operating pump and valves):
- pump speed 0-100%
- inflate/deflate singe valve in each valve block