GCC Code Coverage Report


Directory: ./
File: firmware/hw_layer/kline.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 100.0% 15 0 15
Functions: 100.0% 4 0 4
Branches: 66.7% 4 0 6
Decisions: 66.7% 4 - 6

Line Branch Decision Exec Source
1 /**
2 * this file is mostly about SEFMJ early 2000s specific honda K-line protocol
3 * https://rusefi.com/forum/viewtopic.php?f=4&t=2514
4 */
5
6 #include "pch.h"
7 #include "kline.h"
8 #include "hellen_meta.h"
9 #include "crc8hondak.h"
10
11 1 size_t readWhileGives(ByteSource source, uint8_t *buffer, size_t bufferSize) {
12 1 size_t totalBytes = 0;
13
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 12 times.
✗ Decision 'false' not taken.
12 while (totalBytes < bufferSize) {
14 12 size_t readThisTime = source(&buffer[totalBytes], bufferSize - totalBytes);
15
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 11 times.
2/2
✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 11 times.
12 if (readThisTime == 0) {
16 // looks like idle gap
17 1 break;
18 }
19 11 totalBytes += readThisTime;
20 }
21 1 return totalBytes;
22 }
23
24 #ifdef EFI_KLINE
25
26 static uint8_t kvalues[8];
27
28 #define HONDA_K_BCM_STATUS_NIBBLE 0x0
29 #define HONDA_K_BCM_REQ_NIBBLE 0x1
30
31 bool kAcRequestState;
32
33 static void handleHonda(uint8_t *bufferIn) {
34
35 // no headlights 0x40, with headlights 0x60
36 uint8_t statusByte1 = bufferIn[1];
37 // no cabin blower 0x06, with blower 0x86
38 uint8_t statusByte2 = bufferIn[2];
39 kAcRequestState = statusByte2 & 0x80;
40 if (engineConfiguration->verboseKLine) {
41 efiPrintf("honda status packet with 0x%02x 0x%02x state %d", statusByte1, statusByte2, kAcRequestState);
42 }
43 }
44
45 static SerialDriver* const klDriver = &KLINE_SERIAL_DEVICE;
46 static THD_WORKING_AREA(klThreadStack, UTILITY_THREAD_STACK_SIZE);
47
48 static int totalBytes = 0;
49
50 void kLineThread(void*) {
51 // due to single wire we read everything we've transmitted
52 bool ignoreRecentTransmit = false;
53 int sendCounter = 0;
54 while (1) {
55
56 /**
57 * under the hood there is SERIAL_BUFFERS_SIZE which we hope to help us
58 */
59
60 uint8_t bufferIn[16];
61 // a bit of a busy read open question if this would affect performance?
62 // on 2003 Honda for instance the bus seems to be 70%-ish busy. 9600 baud is 1.04ms per byte, a bit below 1kHz
63 ByteSource serialSource = [] (uint8_t * buffer, int maxSize) {
64 return chnReadTimeout(klDriver,buffer, maxSize, TIME_US2I(engineConfiguration->kLinePeriodUs));
65 };
66 size_t len = readWhileGives(serialSource, bufferIn, sizeof(bufferIn));
67
68 if (engineConfiguration->verboseKLine) {
69 // efiPrintf("ignoreRecentTransmit %d", ignoreRecentTransmit);
70 }
71
72 // to begin with just write byte to console
73 if (len > 0) {
74 if (engineConfiguration->verboseKLine) {
75 efiPrintf("kline: got count 0x%02x", len);
76 }
77 for (size_t i =0;i<len;i++) {
78 if (engineConfiguration->verboseKLine) {
79 efiPrintf("kline: got 0x%02x", bufferIn[i]);
80 }
81 totalBytes++;
82 }
83 if (len > 1) {
84 int crc = crc_hondak_calc(bufferIn, len - 1);
85 uint8_t low = bufferIn[0] & 0xF;
86 if (crc == bufferIn[len - 1]) {
87 if (engineConfiguration->verboseKLine) {
88 efiPrintf("happy CRC 0x%02x", crc);
89 }
90 if (low == HONDA_K_BCM_STATUS_NIBBLE) {
91 handleHonda(bufferIn);
92 }
93
94 if (low == HONDA_K_BCM_REQ_NIBBLE) {
95 if (engineConfiguration->verboseKLine) {
96 efiPrintf("BCM request 0x%02x", bufferIn[0]);
97 }
98 }
99
100 } else if (low == HONDA_K_BCM_STATUS_NIBBLE && bufferIn[4] == crc_hondak_calc(bufferIn, 4)) {
101 if (engineConfiguration->verboseKLine) {
102 efiPrintf("hack for now, happy CRC 0x%02x", crc);
103 }
104 handleHonda(bufferIn);
105 }
106
107
108 if (engineConfiguration->kLineDoHondaSend && !ignoreRecentTransmit) {
109 sendCounter++;
110 #define OUT_SIZE 6
111 // const uint8_t out2[] = {0x2, 0x0, 0x0, 0x50, 0x0, 0x0};
112 //static_assert(sizeof(out2) == OUT_SIZE);
113 // const uint8_t outB[] = {0x42, 0x0, 0x0, 0x50, 0x0, 0x0};
114 // static_assert(sizeof(outB) == OUT_SIZE);
115 //const uint8_t *out = (sendCounter % 3 == 0) ? outB : out2;
116 // const uint8_t *out = out2;
117
118 if (sendCounter % 30 == 0) {
119 // no idea what this, maybe "i am running"?
120 kvalues[0] = 0x82;
121 kvalues[2] = 0x10;
122 } else {
123 kvalues[0] = 0x2;
124 kvalues[2] = 0;
125 }
126
127 if (engineConfiguration->verboseKLine) {
128 efiPrintf("kline doSend");
129 }
130 int positiveCltWithHighishValueInCaseOfSensorIssue = maxI(1,
131 #ifdef HW_HELLEN_HONDA
132 /* temporary while we are playing with calibration */
133 config->hondaKcltGaugeAdder
134 #else
135 50
136 #endif
137 + Sensor::get(SensorType::Clt).value_or(140)
138 );
139 // 125 about horizontal
140 // 162 points at red mark, looks like gauge has hysteresis?
141 // value 200 way above red mark
142 kvalues[3] = positiveCltWithHighishValueInCaseOfSensorIssue;
143
144 chnWrite(klDriver, (const uint8_t *)kvalues, OUT_SIZE);
145 crc = crc_hondak_calc(kvalues, OUT_SIZE);
146 chnWrite(klDriver, (const uint8_t *)&crc, 1);
147 ignoreRecentTransmit = true;
148 } else {
149 ignoreRecentTransmit = false;
150 }
151 }
152 }
153 }
154 }
155 #endif // EFI_KLINE
156
157 219 void startKLine() {
158 #ifdef EFI_KLINE
159 if (!engineConfiguration->enableKline) {
160 return;
161 }
162 #if EFI_PROD_CODE
163 efiSetPadMode("K-Line UART RX", Gpio::KLINE_SERIAL_DEVICE_RX, PAL_MODE_ALTERNATE(TS_SERIAL_AF));
164 efiSetPadMode("K-Line UART TX", Gpio::KLINE_SERIAL_DEVICE_TX, PAL_MODE_ALTERNATE(TS_SERIAL_AF));
165 #endif /* EFI_PROD_CODE */
166
167 static SerialConfig cfg = {
168 #if EFI_PROD_CODE
169 .speed = 0,
170 .cr1 = 0,
171 .cr2 = USART_CR2_STOP1_BITS | USART_CR2_LINEN,
172 .cr3 = 0
173 #endif // EFI_PROD_CODE
174 };
175
176 if (engineConfiguration->kLineBaudRate < 100)
177 engineConfiguration->kLineBaudRate = KLINE_BAUD_RATE;
178 cfg.speed = engineConfiguration->kLineBaudRate;
179
180 sdStart(klDriver, &cfg);
181 #endif // EFI_KLINE
182 219 }
183
184 219 void stopKLine() {
185 #ifdef EFI_KLINE
186 #if EFI_PROD_CODE
187 if (activeConfiguration.enableKline) {
188 efiSetPadUnused(Gpio::KLINE_SERIAL_DEVICE_RX);
189 efiSetPadUnused(Gpio::KLINE_SERIAL_DEVICE_TX);
190
191 sdStop(klDriver);
192 }
193
194 #endif /* EFI_PROD_CODE */
195 #endif // EFI_KLINE
196 219 }
197
198 583 void initKLine() {
199
1/2
✓ Branch 0 taken 583 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 583 times.
✗ Decision 'false' not taken.
583 if (!engineConfiguration->enableKline) {
200 583 return;
201 }
202 #ifdef EFI_KLINE
203 startKLine();
204
205 memset(kvalues, 0, sizeof(kvalues));
206 kvalues[0] = 0x2;
207
208 chThdCreateStatic(klThreadStack, sizeof(klThreadStack), NORMALPRIO + 1, kLineThread, nullptr);
209 addConsoleAction("kline", [](){
210 efiPrintf("kline totalBytes %d", totalBytes);
211 });
212 addConsoleAction("klineyes", [](){
213 engineConfiguration->kLineDoHondaSend = true;
214 efiPrintf("kline send %d", engineConfiguration->kLineDoHondaSend);
215 });
216 addConsoleAction("klineno", [](){
217 engineConfiguration->kLineDoHondaSend = false;
218 efiPrintf("kline send %d", engineConfiguration->kLineDoHondaSend);
219 });
220 addConsoleActionII("temp_k", [](int index, int value) {
221 kvalues[index] = value;
222 });
223
224 #endif // EFI_KLINE
225 }
226