1+ /*
2+ * KBus.c
3+ * Part of project: GearIndicator
4+ * Created: 25.05.2015 8:54:04
5+ * Author: Andrej Hradnansky, 2022
6+ *
7+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU
8+ * (General Public License as published by the Free Software Foundation, either version 3 of the License,
9+ * or (at your option) any later version.
10+ *
11+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13+ * See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along with this program.
16+ * If not, see <https://www.gnu.org/licenses/>.
17+ */
18+
19+ #include "global.h"
20+ #include <util/delay.h>
21+ #include <avr/interrupt.h>
22+ #include <avr/io.h>
23+ #include <avr/wdt.h>
24+ #include "uart.h"
25+ #include "bikes.h"
26+ #include "kbus.h"
27+ #include "timers.h"
28+ #include "eeproma.h"
29+ #include <string.h>
30+
31+ //State of the K-Bus communication
32+ tKBUS_state KBUS_state = KBUS_S_IDLE ;
33+
34+ ////////////////////////////////////////////
35+ //KBUS commands - partially :-)
36+ ////////////////////////////////////////////
37+ //StartCommunication Request
38+ tKBUS_Msg KBUS_STC_req = {.form = ADDRESS_NO_LBYTE , //Message with address without additional message length byte
39+ .header = {
40+ .HForm_MsgLen = PHYSICAL_ADDR + 1 ,//Physical addressing + message lenght (1 byte)
41+ .Tgt = 0x11 , //Target address -> ECU address (0x11 - Kawa)
42+ .Src = IND_ADDR //Source address = Indicator address
43+ },
44+ .data .Sld = STC , //startCommunication Request Service Id
45+ .cs = 0x04 //Check sum
46+ };
47+
48+
49+ //Byte Name Value Description
50+ //-----------------------------------------------
51+ //0 Fmt 0x81 Physical addressing PHYSICAL_ADDR<<6 + length of information (1 byte) = 0x81
52+ //1 Tgt <Ttg> Address of target device (ECU)
53+ //2 Src IND_ADDR Address of source device (GEAR INDICATOR)
54+ //3 STC 0x81 startCommunication Request Service Id
55+ //4 CS <CS> Example: CHS = 04 = 81+11+F1+81 modulo 0x100 -> 0x81,0x11,0xF1,0x81,0x04
56+ //
57+ ////////////////////////////////////////////
58+ //startCommunication Positive Response
59+ unsigned char KeyBytes [2 ]= {0xEA ,0x8F };
60+
61+ tKBUS_Msg KBUS_STC_res = {.form = ADDRESS_LBYTE , //Message with address and with extra length byte
62+ .header = {
63+ .HForm_MsgLen = PHYSICAL_ADDR , //Physical addressing
64+ .Tgt = IND_ADDR , //Target address = Indicator address
65+ .Src = 0x11 , //Source address = ECU
66+ .Len = 3 //Data length - number of data bytes
67+ },
68+ .data .Sld = STCPR , //startCommunication Positive Response Service Id
69+ .data .Data = KeyBytes ,
70+ .cs = 0xBF //Check sum
71+ };
72+
73+ //Byte Name Value Description
74+ //------------------------------------------------------------------------------
75+ //0 Fmt 0x80 Address mode: physical addressing + Len
76+ //1 Tgt IND_ADDR Address of target devide (GEAR INDICATOR)
77+ //2 Src <ADDR> Address of source device (ECU)
78+ //3 Len 0x03 3 Bytes following...
79+ //4 STCPR 0xC1 startCommunication Positive Response Service Id
80+ //5 KB1 0xEA Header with target and source address information
81+ //6 KB2 0x8F Additional length byte used
82+ //7 CS <CS> Example: CHS BF = 80+F1+...+8F modulo 0x100 ->0x80,0x11,0x03,0xC1,0xEA,0x8F,0xBF
83+ //
84+ ////////////////////////////////////////////
85+ //StartDiagnosticSession Request
86+ unsigned char KBUS_START_DIAG [7 ] = {PHYSICAL_ADDR ,0x11 ,IND_ADDR ,0x02 ,SDS ,0x80 ,0x14 };
87+
88+ unsigned char diagnosticMode = 0x80 ; //manufacterSpecific - 00-7F reserved, 80-FF for vehicle manufacturer specific use
89+ tKBUS_Msg KBUS_SDS_req = {.form = ADDRESS_LBYTE , //Message with address and with extra length byte
90+ .header = {
91+ .HForm_MsgLen = PHYSICAL_ADDR , //Physical addressing
92+ .Tgt = 0x11 , //Target address -> ECU address (0x11 - Kawa)
93+ .Src = IND_ADDR , //Source address = Indicator address
94+ .Len = 2 //Data length - number of data bytes
95+ },
96+ .data .Sld = SDS , //startDiagnosticSession Request Service Id
97+ .data .Data = & diagnosticMode , //manufacterSpecific - 00-7F reserved, 80-FF for vehicle manufacturer specific use
98+ .cs = 0x14 //Check sum
99+ };
100+
101+ //Byte Name Value Description
102+ //-------------------------------------------------------------------------------------
103+ //0 Fmt 0x80 Address mode: physical addressing + Len
104+ //1 Tgt <ADDR> Address of target device (ECU)
105+ //2 Src IND_ADDR Address of source device (GEAR INDICATOR)
106+ //3 Len 0x02 2 Bytes following...
107+ //4 SDS 0x10 startDiagnosticSession Request Service Id
108+ //5 diagnosticMode 0x80 manufacterSpecific - 00-7F reserved, 80-FF for vehicle manufacturer specific use
109+ //6 CS <CS> Example: CHS = 14 = 80+11+F1+02+10+80 modulo 0x100 ->0x80,0x11,0xF1,0x02,0x10,0x80,0x14
110+ //
111+ ////////////////////////////////////////////
112+ //startDiagnosticSession Positive Response
113+ unsigned char KBUS_START_DIAG_RPL [7 ] = {PHYSICAL_ADDR ,IND_ADDR ,0x11 ,0x02 ,SDSPR ,0x80 ,0x54 };
114+
115+ tKBUS_Msg KBUS_SDS_res = {.form = ADDRESS_LBYTE , //Message with address and with extra length byte
116+ .header = {
117+ .HForm_MsgLen = PHYSICAL_ADDR , //Physical addressing
118+ .Tgt = IND_ADDR , //Target address = indicator address
119+ .Src = 0x11 , //Source address = ECU
120+ .Len = 2 //Data length - number of data bytes
121+ },
122+ .data .Sld = SDSPR , //startDiagnosticSession Request Service Id
123+ .data .Data = & diagnosticMode , //manufacterSpecific - 00-7F reserved, 80-FF for vehicle manufacturer specific use
124+ .cs = 0x54 //Check sum
125+ };
126+
127+ //Byte Name Value Description
128+ //-----------------------------------------------------------------------------------
129+ //0 Fmt 0x80 Address mode: physical addressing +Len
130+ //1 Tgt IND_ADDR Address of target device (GEAR INDICATOR)
131+ //2 Src <ADDR> Address of source device (ECU)
132+ //3 Len 0x02 2 Bytes following...
133+ //4 SDSPR 0x50 startDiagnosticSession Positive Response Service Id
134+ //5 Diagnostic mode 0x80 manufacterSpecific
135+ //6 Checksum <CS> Example: CS = 54 ->0x80,0xF1,0x11,0x02,0x50,0x80,0x54
136+ //
137+ ////////////////////////////////////////////
138+ //readDataByLocalIdentifier Request
139+ unsigned char KBUS_READ_DATA [7 ] = {PHYSICAL_ADDR ,0x11 ,IND_ADDR ,0x02 ,RDBLID ,0x0B ,0xB0 };
140+
141+ unsigned char RLOCID = 0xB0 ;
142+ tKBUS_Msg KBUS_RDBLID_req = {.form = ADDRESS_LBYTE , //Message with address and with extra length byte
143+ .header = {
144+ .HForm_MsgLen = PHYSICAL_ADDR , //Physical addressing
145+ .Tgt = 0x11 , //Target address = ECU
146+ .Src = IND_ADDR , //Source address = Indicator address
147+ .Len = 2 //Data length - number of data bytes
148+ },
149+ .data .Sld = RDBLID , //readDataByLocalIdentifier Request Service Id
150+ .data .Data = & RLOCID , //recordLocalIdentifier (to be read)
151+ .cs = 0xB0 //Check sum
152+ };
153+
154+ //Byte Name Value Description
155+ //-----------------------------------------------
156+ //0 Fmt 0x80 Address mode: physical addressing + Len
157+ //1 Tgt <ADDR> Address of target devide (ECU)
158+ //2 Src IND_ADDR Address of source device (GEAR INDICATOR)
159+ //3 Len 0x02 Two byte following...
160+ //4 RDBLID 0x21 readDataByLocalIdentifier Request Service Id
161+ //5 RLOCID <RLOCID> recordLocalIdentifier (to be read)
162+ //6 CS <CS> Example: CHS = B0 = 80+11+F1+02+21+0B modulo 0x100 ->0x80,0x11,0xF1,0x02,0x21,0x0B,0xB0
163+ //
164+ //////////////////////////////////////////////
165+ //READ REG - reply
166+ //Differs according to the manufacturer/model
167+ //This is defined in bikes.c & bikes.h
168+ tKBUS_Msg KBUS_reply_msg ;
169+
170+ ////////////////////////////////////////
171+ //KBus protocol check sum calculation
172+ unsigned char KBUS_checksum1 (volatile unsigned char * msg , volatile unsigned char cnt )
173+ {
174+ unsigned char checksum = 0 , i ;
175+
176+ for (i = 0 ;i < cnt ;i ++ )
177+ checksum += * (msg + i );
178+
179+ return (checksum );
180+ }
181+
182+ unsigned char KBUS_checksum (tKBUS_Msg * msg )
183+ {
184+ unsigned char checksum = 0 ;
185+ int i , MsgLen ;
186+
187+ //Header byte always
188+ checksum += msg -> header .HForm_MsgLen ;
189+
190+ //Addresses include only if necessary
191+ if (msg -> form == ADDRESS_NO_LBYTE || msg -> form == ADDRESS_LBYTE )
192+ {
193+ checksum += msg -> header .Src ;
194+ checksum += msg -> header .Tgt ;
195+ }
196+
197+ //Always there
198+ checksum += msg -> data .Sld ;
199+
200+ //Length byte only if necessary
201+ if (msg -> form == ADDRESS_LBYTE || msg -> form == NO_ADDRESS_LBYTE )
202+ {
203+ checksum += msg -> header .Len ;
204+ for (i = 0 ;i < msg -> header .Len - 1 ;i ++ )
205+ checksum += msg -> data .Data [i ];
206+ }
207+ else
208+ {
209+ MsgLen = msg -> header .HForm_MsgLen & 0b00111111 ;
210+ for (i = 0 ;i < MsgLen - 1 ;i ++ )
211+ checksum += msg -> data .Data [i ];
212+ }
213+
214+ msg -> cs = checksum ;
215+ return (checksum );
216+ }
217+
218+ ////////////////////////////////////////
219+ //Performs KBus Fast Init
220+ //25ms pulse to KBUS - Initialization
221+ void KBUS_fast_init (void )
222+ {
223+ cli ();
224+ wdt_disable (); //WDT would expire during fast init
225+
226+ //RX Disable
227+ CLB (UCSR0B , RXEN0 );
228+ //TX Disable
229+ CLB (UCSR0B , TXEN0 );
230+
231+
232+ STB (UARTDR ,TX ); //TXD is output
233+ STB (UARTPORT ,TX ); //TX high
234+ _delay_ms (400 ); //Just be sure we fulfill TIdle time - min.300ms first transmission after power up)
235+
236+ //KBUS FAST INIT
237+ //(--FIRST LOW--)
238+ CLB (UARTPORT ,TX ); //Keep TX Lo for min. 25ms +/- 1ms (TiniL according to ISO14230)
239+ _delay_ms (25 );
240+ STB (UARTPORT ,TX ); //and TX Hi for another 25ms +/- 1ms (TWuP according to ISO14230)
241+ _delay_ms (25 );
242+ //TX Enable
243+ STB (UCSR0B , TXEN0 );
244+ sei (); //Enable all interrupts
245+ wdt_enable (WDTO_250MS ); //Enable watch dog
246+ }
247+
248+ ///////////////////////////////////////////////////
249+ //Store message to UART tx buffer
250+
251+ void KBUS_msg_to_uart (tKBUS_Msg * msg )
252+ {
253+ int MsgLen ;
254+ unsigned char msgout [10 ];
255+ unsigned char * msgptr ;
256+ int i ;
257+
258+ msgptr = msgout ;
259+
260+ //Fmt
261+ * msgptr ++ = msg -> header .HForm_MsgLen ;
262+
263+ //Address
264+ if (msg -> form == ADDRESS_LBYTE || msg -> form == ADDRESS_NO_LBYTE )
265+ {
266+ * msgptr ++ = msg -> header .Tgt ;
267+ * msgptr ++ = msg -> header .Src ;
268+ }
269+
270+ //Additional Length byte
271+ if (msg -> form == ADDRESS_LBYTE || msg -> form == NO_ADDRESS_LBYTE )
272+ {
273+ * msgptr ++ = msg -> header .Len ;
274+ }
275+
276+ //Sld
277+ * msgptr ++ = msg -> data .Sld ;
278+
279+
280+ //Data - Sld is first, so number of data = Len-1
281+ if (msg -> form == ADDRESS_LBYTE || msg -> form == NO_ADDRESS_LBYTE )
282+ {
283+ if (msg -> header .Len > 1 )
284+ for (i = 0 ;i < msg -> header .Len - 1 ;i ++ )
285+ * msgptr ++ = msg -> data .Data [i ];
286+ }
287+ else
288+ {
289+ //Get MsgLen from the header byte
290+ MsgLen = msg -> header .HForm_MsgLen & 0b00111111 ;
291+ if (MsgLen > 1 )
292+ for (i = 0 ;i < MsgLen - 1 ;i ++ )
293+ * msgptr ++ = msg -> data .Data [i ];
294+ }
295+
296+ //Check sum
297+ * msgptr ++ = KBUS_checksum (msg );
298+
299+ //Send it to UART
300+ UARTsend (msgout ,msgptr - msgout );
301+ }
302+
303+ //////////////////////////////////////////////////
304+ //Sends K-Bus message to ECU with particular ECUno
305+ void KBUS_send_msg (volatile unsigned char ECUno )
306+ {
307+ switch (KBUS_state )
308+ {
309+ case KBUS_S_IDLE :
310+ KBUS_STC_req .header .Tgt = BIKES_DATA [ECUno ].ecu_addr ;
311+ KBUS_fast_init ();
312+ KBUS_msg_to_uart (& KBUS_STC_req );
313+ break ;
314+
315+ case KBUS_S_COMM_STARTED :
316+ KBUS_RDBLID_req .header .Tgt = BIKES_DATA [ECUno ].ecu_addr ;
317+ RLOCID = BIKES_DATA [ECUno ].local_id_gear ;
318+ KBUS_msg_to_uart (& KBUS_RDBLID_req );
319+ break ;
320+
321+ case KBUS_S_DATA_POOLING :
322+ //if GEAR localID is different from RPM localID, read that different localID and we need to read RPM (if RPM is programmed or we are in programming mode)
323+ if (BIKES_DATA [ECUno ].local_id_gear != BIKES_DATA [ECUno ].local_id_rpm && (rpmValue .rpm > 0 || rpmValue .prgmode == 0 ))
324+ {
325+ if (RLOCID == BIKES_DATA [ECUno ].local_id_gear )
326+ RLOCID = BIKES_DATA [ECUno ].local_id_rpm ;
327+ else
328+ RLOCID = BIKES_DATA [ECUno ].local_id_gear ;
329+ }
330+ KBUS_msg_to_uart (& KBUS_RDBLID_req );
331+ break ;
332+
333+ default :
334+ break ;
335+ }
336+ }
337+
338+ /////////////////////////////////////////////////////////////
339+ //Checks reply from remote ECU according to actual KBus state
340+ unsigned char KBUS_check_reply (volatile unsigned char ECUno , volatile unsigned char * msg )
341+ {
342+ int replylen ;
343+
344+ // Reply length: <FMT> <IND_ADDR> <ECUaddr> <Bytes Follow> <Sdl> byte[0]...byte[Bytes Follow-1] <CHS> => replylen=<Bytes Follow>+5
345+ replylen = msg [3 ]+ 5 ;
346+
347+ switch (KBUS_state )
348+ {
349+ case KBUS_S_IDLE :
350+ //KBUS_START_COMM_RPL
351+ //{<FMT> <IND_ADDR> <ECUaddr> <0x03> <STCPR> <0xEA> <0x8F> <CHS>};
352+ if ( msg [1 ]== IND_ADDR && \
353+ msg [2 ]== BIKES_DATA [ECUno ].ecu_addr && \
354+ msg [4 ]== STCPR && \
355+ msg [replylen - 1 ]== KBUS_checksum1 (msg ,replylen - 1 )
356+ )
357+ {
358+ KBUS_state = KBUS_S_COMM_STARTED ;
359+ return (TRUE);
360+ break ;
361+ }
362+ else
363+ return (FALSE);
364+ break ;
365+
366+ case KBUS_S_COMM_STARTED :
367+ case KBUS_S_DATA_POOLING :
368+ //{<B0> <B1> <B2> <B3> <B4> <B5> <B6> <BN> <CHS>};
369+ //{<FMT> <IND_ADDR> <ECUaddr> <Bytes Follows> <RDBLIDPR> <Loc_Id> <B6>... ... ... ... ... ... <BN> <CHS>};
370+ //{<FMT> <IND_ADDR> <0x11> <0x03> <RDBLIDPR> <0x0B> <GEAR> <CHS>}; KAWASAKI01
371+ //{<FMT> <IND_ADDR> <0x11> <0x04> <RDBLIDPR> <0x09> <RPM1> <RPM2> <CHS>}; KAWASAKI01
372+ //{<FMT> <IND_ADDR> <0x12> <0x34> <RDBLIDPR> <0x08> <B6>...<B16> <RPM1> <RPM2> ...<B25>,<GEAR>,<B27>... ...<Byte55> <CHS>}; SUZUKI01
373+ if ( msg [1 ]== IND_ADDR && \
374+ msg [2 ]== BIKES_DATA [ECUno ].ecu_addr && \
375+ msg [4 ]== RDBLIDPR && \
376+ (msg [5 ]== BIKES_DATA [ECUno ].local_id_gear || msg [5 ]== BIKES_DATA [ECUno ].local_id_rpm ) && \
377+ msg [replylen - 1 ]== KBUS_checksum1 (msg ,replylen - 1 )
378+ )
379+ {
380+ KBUS_state = KBUS_S_DATA_POOLING ;
381+ return (TRUE);
382+ break ;
383+ }
384+ else
385+ return (FALSE);
386+ break ;
387+
388+ default :
389+ return (FALSE);
390+ break ;
391+ }
392+ }
0 commit comments