• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_uart_lin.h"
9 
10 #ifndef HPM_UART_LIN_RETRY_COUNT
11 #define HPM_UART_LIN_RETRY_COUNT (50000U)
12 #endif
13 
14 #ifndef HPM_UART_LIN_BREAK_LENGTH
15 #define HPM_UART_LIN_BREAK_LENGTH (13U)
16 #endif
17 
18 
hpm_uart_lin_calculate_protected_id(uint8_t id)19 uint8_t hpm_uart_lin_calculate_protected_id(uint8_t id)
20 {
21     uint8_t id0, id1, id2, id3, id4, id5, p0, p1, pid;
22 
23     /* P0 = ID0 @ ID1 @ ID2 @ ID3 @ ID4 */
24     /* P1 = !(ID1 @ ID2 @ ID3 @ ID4 @ ID5) */
25     id0 = (id >> 0U) & 0x1U;
26     id1 = (id >> 1U) & 0x1U;
27     id2 = (id >> 2U) & 0x1U;
28     id3 = (id >> 3U) & 0x1U;
29     id4 = (id >> 4U) & 0x1U;
30     id5 = (id >> 5U) & 0x1U;
31 
32     p0 = id0 ^ id1 ^ id2 ^ id4;
33     p1 = !(id1 ^ id3 ^ id4 ^ id5);
34     pid  = (p1 << 7) | (p0 << 6) | id;
35     return pid;
36 }
37 
hpm_uart_lin_calculate_checksum(uint8_t id,uint8_t * data,uint8_t length,bool enhanced_checksum)38 static uint8_t hpm_uart_lin_calculate_checksum(uint8_t id, uint8_t *data, uint8_t length, bool enhanced_checksum)
39 {
40     assert(length <= 8U);
41     uint8_t checksum = 0;
42     uint16_t temp;
43     for (uint8_t i = 0; i < length; i++) {
44         temp = checksum + data[i];
45         checksum += data[i] + (temp >> 8U);
46     }
47 
48     if (enhanced_checksum) {
49         temp = checksum + id;
50         checksum += id + (temp >> 8U);
51     }
52 
53     checksum = ~checksum;
54     return checksum;
55 }
56 
hpm_uart_lin_check_checksum(uint8_t id,uint8_t * data,uint8_t length,bool enhanced_checksum,uint8_t checksum)57 static bool hpm_uart_lin_check_checksum(uint8_t id, uint8_t *data, uint8_t length, bool enhanced_checksum, uint8_t checksum)
58 {
59     uint8_t cal_checksum;
60     cal_checksum = hpm_uart_lin_calculate_checksum(id, data, length, enhanced_checksum);
61 
62     if (cal_checksum != checksum) {
63         return false;
64     }
65     return true;
66 }
67 
68 
hpm_uart_lin_send_break(UART_Type * ptr,uart_lin_master_pin_ctrl_t * pin_ctrl)69 static void hpm_uart_lin_send_break(UART_Type *ptr, uart_lin_master_pin_ctrl_t *pin_ctrl)
70 {
71     assert(pin_ctrl->baudrate <= 20000);
72 
73     uint32_t bit_period_us = 1000000 / pin_ctrl->baudrate;
74     uint32_t break_period_us = bit_period_us * HPM_UART_LIN_BREAK_LENGTH;
75     pin_ctrl->config_uart_pin_as_gpio(ptr);
76     gpio_set_pin_output(pin_ctrl->ptr, pin_ctrl->tx_port, pin_ctrl->tx_pin);
77     gpio_write_pin(pin_ctrl->ptr, pin_ctrl->tx_port, pin_ctrl->tx_pin, 0);
78     pin_ctrl->delay_us(break_period_us);
79     gpio_write_pin(pin_ctrl->ptr, pin_ctrl->tx_port, pin_ctrl->tx_pin, 1);
80     pin_ctrl->delay_us(bit_period_us);
81     pin_ctrl->config_uart_pin(ptr);
82 }
83 
hpm_uart_lin_send_sync(UART_Type * ptr)84 static void hpm_uart_lin_send_sync(UART_Type *ptr)
85 {
86     uart_write_byte(ptr, 0x55); /* sync phase */
87 }
88 
hpm_uart_lin_master_send_frame(uart_lin_master_config_t * config)89 uart_lin_stat_t hpm_uart_lin_master_send_frame(uart_lin_master_config_t *config)
90 {
91     uint32_t retry;
92     UART_Type *ptr = config->ptr;
93     uart_lin_data_t data = config->data;
94     uint8_t pid = hpm_uart_lin_calculate_protected_id(config->id);
95     uint8_t checksum = hpm_uart_lin_calculate_checksum(pid, data.buff, data.length, data.enhance_checksum);
96     uint8_t send_data[11] = {0}; /* max 8 data bytes + 1 byte 0x55 + 1 byte pid + 1byte checksum */
97     uint8_t length = data.length + 3;
98 
99     assert(data.length > 0);
100 
101     /* 0x55 - pid  - data - checksum */
102     send_data[0] = 0x55;
103     send_data[1] = pid;
104     memcpy(&send_data[2], data.buff, data.length);
105     send_data[data.length + 2] = checksum;
106 
107     hpm_uart_lin_send_break(ptr, &(config->pin_ctrl));
108 
109     for (uint8_t i = 0; i < length; i++) {
110         retry = 0;
111         while (!uart_check_status(ptr, uart_stat_tx_slot_avail)) {
112             if (retry > HPM_UART_LIN_RETRY_COUNT) {
113                 break;
114             }
115             retry++;
116         }
117 
118         if (retry > HPM_UART_LIN_RETRY_COUNT) {
119             return uart_lin_timeout;
120         }
121 
122         uart_write_byte(ptr, send_data[i]);
123     }
124 
125     return uart_lin_success;
126 }
127 
128 
hpm_uart_lin_master_receive_frame(uart_lin_master_config_t * config)129 uart_lin_stat_t hpm_uart_lin_master_receive_frame(uart_lin_master_config_t *config)
130 {
131     uint32_t retry = 0;
132     UART_Type *ptr = config->ptr;
133     uart_lin_data_t data = config->data;
134     uint8_t pid = hpm_uart_lin_calculate_protected_id(config->id);
135     uint8_t checksum;
136     uint8_t *buff = data.buff;
137 
138     assert(data.length > 0);
139 
140     /* clear data in rx fifo */
141     uart_clear_rx_fifo(ptr);
142 
143     hpm_uart_lin_send_break(ptr, &(config->pin_ctrl));
144 
145     hpm_uart_lin_send_sync(ptr);
146 
147     uart_write_byte(ptr, pid);
148 
149     /* wait for send 0x55 and pid */
150     while (!uart_check_status(ptr, uart_stat_tx_slot_avail)) {
151         if (retry > HPM_UART_LIN_RETRY_COUNT * 2) {
152             break;
153         }
154         retry++;
155     }
156 
157     if (retry > HPM_UART_LIN_RETRY_COUNT * 2) {
158         return uart_lin_timeout;
159     }
160 
161     /* wait for receive complete */
162     for (uint8_t i = 0; i < data.length + 3; i++) {
163         retry = 0;
164         while (!uart_check_status(ptr, uart_stat_data_ready)) {
165             if (retry > HPM_UART_LIN_RETRY_COUNT) {
166                 break;
167             }
168             retry++;
169         }
170 
171         if (retry > HPM_UART_LIN_RETRY_COUNT) {
172             return uart_lin_timeout;
173         }
174 
175         if (i < 2) {
176             uart_read_byte(ptr);
177         } else if (i < data.length + 2) {
178             *(buff++) = uart_read_byte(ptr);
179         } else {
180             checksum = uart_read_byte(ptr);
181         }
182     }
183 
184     if (!hpm_uart_lin_check_checksum(pid, data.buff, data.length, data.enhance_checksum, checksum)) {
185         return uart_lin_checksum_error;
186     }
187 
188     return uart_lin_success;
189 }
190 
191 /* generate break with gpio then write 0x55 and pid into uart tx fifo */
hpm_uart_lin_master_send_head(uart_lin_master_config_t * config)192 void hpm_uart_lin_master_send_head(uart_lin_master_config_t *config)
193 {
194     UART_Type *ptr = config->ptr;
195     uint8_t pid = hpm_uart_lin_calculate_protected_id(config->id);
196 
197     /* clear data in rx fifo */
198     uart_clear_rx_fifo(ptr);
199 
200     hpm_uart_lin_send_break(ptr, &(config->pin_ctrl));
201 
202     hpm_uart_lin_send_sync(ptr);
203 
204     uart_write_byte(ptr, pid);
205 }
206 
207 /* write data into uart tx fifo including data and checksum */
hpm_uart_lin_master_send_data(uart_lin_master_config_t * config)208 void hpm_uart_lin_master_send_data(uart_lin_master_config_t *config)
209 {
210     UART_Type *ptr = config->ptr;
211     uart_lin_data_t data = config->data;
212 
213     assert(data.length > 0);
214 
215     uint8_t pid = hpm_uart_lin_calculate_protected_id(config->id);
216     uint8_t checksum = hpm_uart_lin_calculate_checksum(pid, data.buff, data.length, data.enhance_checksum);
217 
218     for (uint8_t i = 0; i < data.length; i++) {
219         uart_write_byte(ptr, *(data.buff++));
220     }
221 
222     uart_write_byte(ptr, checksum);
223 }
224 
225 /* call this function in rx timeout isr */
226 /* read data from uart rx fifo */
hpm_uart_lin_master_receive_data(uart_lin_master_config_t * config)227 uart_lin_stat_t hpm_uart_lin_master_receive_data(uart_lin_master_config_t *config)
228 {
229     UART_Type *ptr = config->ptr;
230     uart_lin_data_t data = config->data;
231     uint8_t pid = hpm_uart_lin_calculate_protected_id(config->id);
232     uint8_t checksum = 0;
233     uint8_t index = 0;
234     uint8_t *buff = data.buff;
235 
236     assert(data.length > 0);
237 
238     while (uart_check_status(ptr, uart_stat_data_ready)) {
239         if (index >= data.length + 3) {
240             break;
241         }
242         if (index < 2) {
243             uart_read_byte(ptr); /* read 0x55 and pid */
244         } else if (index < data.length + 2) {
245             *(buff++) = uart_read_byte(ptr);
246         } else {
247             checksum = uart_read_byte(ptr);
248         }
249         index++;
250     }
251 
252     if (index != data.length + 3) {
253         return uart_lin_frame_error;
254     }
255 
256     if (!hpm_uart_lin_check_checksum(pid, data.buff, data.length, data.enhance_checksum, checksum)) {
257         return uart_lin_checksum_error;
258     }
259 
260     return uart_lin_success;
261 }
262 
263 /* write data into uart tx fifo including data and checksum */
hpm_uart_lin_slave_send_data(uart_lin_slave_config_t * config)264 void hpm_uart_lin_slave_send_data(uart_lin_slave_config_t *config)
265 {
266     UART_Type *ptr = config->ptr;
267     uart_lin_data_t data = config->data;
268 
269     assert(data.length > 0);
270 
271     uint8_t checksum = hpm_uart_lin_calculate_checksum(config->pid, data.buff, data.length, data.enhance_checksum);
272 
273     for (uint8_t i = 0; i < data.length; i++) {
274         uart_write_byte(ptr, *(data.buff++));
275     }
276 
277     uart_write_byte(ptr, checksum);
278 }
279 
280 /* read data and checksum */
hpm_uart_lin_slave_receive_data(uart_lin_slave_config_t * config)281 uart_lin_stat_t hpm_uart_lin_slave_receive_data(uart_lin_slave_config_t *config)
282 {
283     UART_Type *ptr = config->ptr;
284     uart_lin_data_t data = config->data;
285 
286     assert(data.length > 0);
287 
288     uint8_t index = 0;
289     uint8_t checksum = 0;
290 
291     /* receive data and checksum */
292     while (uart_check_status(ptr, uart_stat_data_ready)) {
293         if (index == data.length) {
294             checksum = uart_read_byte(ptr);
295             break;
296         }
297         *(data.buff + index++) = uart_read_byte(ptr);
298     }
299 
300     if (index != data.length) {
301         return uart_lin_frame_error;
302     }
303 
304     if (!hpm_uart_lin_check_checksum(config->pid, data.buff, data.length, data.enhance_checksum, checksum)) {
305         return uart_lin_checksum_error;
306     }
307 
308     return uart_lin_success;
309 }