7 #include <libopencm3/cm3/nvic.h>
8 #include <libopencm3/stm32/gpio.h>
9 #include <libopencm3/stm32/usart.h>
10 #include <libopencm3/stm32/timer.h>
21 #define RX_BUFSIZE 256
22 #define TX_BUFSIZE 256
24 static byte rx_buf[RX_BUFSIZE];
27 static byte state; // STATE_xxx
29 static byte *rx_frame;
30 static byte *rx_frame_end;
32 static byte tx_buf[TX_BUFSIZE];
36 #define MB_OUR_ADDRESS 42
38 static void rx_init(void)
43 usart_set_mode(USART2, USART_MODE_RX);
44 usart_enable_rx_interrupt(USART2);
47 static void rx_done(void)
49 state = STATE_RX_DONE;
50 usart_disable_rx_interrupt(USART2);
53 static void tx_init(void)
57 gpio_set(GPIOA, GPIO1);
58 usart_set_mode(USART2, USART_MODE_TX);
59 usart_enable_tx_interrupt(USART2);
62 static void tx_done(void)
64 state = STATE_TX_DONE;
65 // usart_disable_tx_interrupt(USART2); // Already done by irq handler
66 gpio_clear(GPIOA, GPIO1);
69 void modbus_init(void)
71 timer_set_prescaler(TIM2, 71); // 1 tick = 1 μs
72 timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_DOWN);
73 timer_update_on_overflow(TIM2);
74 timer_disable_preload(TIM2);
75 timer_one_shot_mode(TIM2);
76 timer_enable_irq(TIM2, TIM_DIER_UIE);
77 nvic_enable_irq(NVIC_TIM2_IRQ);
79 gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);
80 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
82 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO1);
83 gpio_clear(GPIOA, GPIO1);
85 usart_set_baudrate(USART2, 19200);
86 usart_set_databits(USART2, 9);
87 usart_set_stopbits(USART2, USART_STOPBITS_1);
88 // usart_set_parity(USART2, USART_PARITY_NONE);
89 usart_set_parity(USART2, USART_PARITY_EVEN);
90 usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
94 nvic_enable_irq(NVIC_USART2_IRQ);
100 u32 status = USART_SR(USART2);
102 if (status & USART_SR_RXNE) {
103 uint ch = usart_recv(USART2);
104 if (state == STATE_RX) {
105 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
107 } else if (rx_size < RX_BUFSIZE) {
108 rx_buf[rx_size++] = ch;
113 timer_set_period(TIM2, 7500); // 0.75 ms timeout for end of frame (FIXME: right value?)
114 timer_generate_event(TIM2, TIM_EGR_UG);
115 timer_enable_counter(TIM2);
119 if (state == STATE_TX) {
120 if (status & USART_SR_TXE) {
121 if (tx_pos < tx_size) {
122 usart_send(USART2, tx_buf[tx_pos++]);
124 // The transmitter is double-buffered, so at this moment, it is transmitting
125 // the last byte of the frame. Wait until transfer is completed.
126 usart_disable_tx_interrupt(USART2);
127 USART_CR1(USART2) |= USART_CR1_TCIE;
128 state = STATE_TX_LAST;
131 } else if (state == STATE_TX_LAST) {
132 if (status & USART_SR_TC) {
133 // Transfer of the last byte is complete. Release the bus.
134 USART_CR1(USART2) &= ~USART_CR1_TCIE;
143 if (TIM_SR(TIM2) & TIM_SR_UIF) {
144 TIM_SR(TIM2) &= ~TIM_SR_UIF;
145 if (state == STATE_RX)
152 static const byte crc_hi[] = {
153 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
154 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
155 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
156 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
157 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
158 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41,
159 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
160 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
161 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
162 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
163 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
164 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
165 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
166 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
167 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
168 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
169 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
170 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
171 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
172 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
173 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
174 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
175 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
176 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
177 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
178 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40
181 static const byte crc_lo[] = {
182 0x00, 0xc0, 0xc1, 0x01, 0xc3, 0x03, 0x02, 0xc2, 0xc6, 0x06,
183 0x07, 0xc7, 0x05, 0xc5, 0xc4, 0x04, 0xcc, 0x0c, 0x0d, 0xcd,
184 0x0f, 0xcf, 0xce, 0x0e, 0x0a, 0xca, 0xcb, 0x0b, 0xc9, 0x09,
185 0x08, 0xc8, 0xd8, 0x18, 0x19, 0xd9, 0x1b, 0xdb, 0xda, 0x1a,
186 0x1e, 0xde, 0xdf, 0x1f, 0xdd, 0x1d, 0x1c, 0xdc, 0x14, 0xd4,
187 0xd5, 0x15, 0xd7, 0x17, 0x16, 0xd6, 0xd2, 0x12, 0x13, 0xd3,
188 0x11, 0xd1, 0xd0, 0x10, 0xf0, 0x30, 0x31, 0xf1, 0x33, 0xf3,
189 0xf2, 0x32, 0x36, 0xf6, 0xf7, 0x37, 0xf5, 0x35, 0x34, 0xf4,
190 0x3c, 0xfc, 0xfd, 0x3d, 0xff, 0x3f, 0x3e, 0xfe, 0xfa, 0x3a,
191 0x3b, 0xfb, 0x39, 0xf9, 0xf8, 0x38, 0x28, 0xe8, 0xe9, 0x29,
192 0xeb, 0x2b, 0x2a, 0xea, 0xee, 0x2e, 0x2f, 0xef, 0x2d, 0xed,
193 0xec, 0x2c, 0xe4, 0x24, 0x25, 0xe5, 0x27, 0xe7, 0xe6, 0x26,
194 0x22, 0xe2, 0xe3, 0x23, 0xe1, 0x21, 0x20, 0xe0, 0xa0, 0x60,
195 0x61, 0xa1, 0x63, 0xa3, 0xa2, 0x62, 0x66, 0xa6, 0xa7, 0x67,
196 0xa5, 0x65, 0x64, 0xa4, 0x6c, 0xac, 0xad, 0x6d, 0xaf, 0x6f,
197 0x6e, 0xae, 0xaa, 0x6a, 0x6b, 0xab, 0x69, 0xa9, 0xa8, 0x68,
198 0x78, 0xb8, 0xb9, 0x79, 0xbb, 0x7b, 0x7a, 0xba, 0xbe, 0x7e,
199 0x7f, 0xbf, 0x7d, 0xbd, 0xbc, 0x7c, 0xb4, 0x74, 0x75, 0xb5,
200 0x77, 0xb7, 0xb6, 0x76, 0x72, 0xb2, 0xb3, 0x73, 0xb1, 0x71,
201 0x70, 0xb0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
202 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9c, 0x5c,
203 0x5d, 0x9d, 0x5f, 0x9f, 0x9e, 0x5e, 0x5a, 0x9a, 0x9b, 0x5b,
204 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4b, 0x8b,
205 0x8a, 0x4a, 0x4e, 0x8e, 0x8f, 0x4f, 0x8d, 0x4d, 0x4c, 0x8c,
206 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
207 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
210 static u16 crc16(byte *buf, u16 len)
212 byte hi = 0xff, lo = 0xff;
215 byte i = hi ^ *buf++;
220 return (hi << 8 | lo);
223 static bool check_frame(void)
226 // FIXME: Error counters?
231 // FIXME: Error counters?
235 u16 crc = crc16(rx_buf, rx_size - 2);
236 u16 rx_crc = (rx_buf[rx_size-2] << 8) | rx_buf[rx_size-1];
238 // FIXME: Error counters?
242 rx_frame = rx_buf + 1;
243 rx_frame_end = rx_frame + rx_size - 2;
248 FUNC_READ_COILS = 0x01,
249 FUNC_READ_DISCRETE_INPUTS = 0x02,
250 FUNC_READ_HOLDING_REGISTERS = 0x03,
251 FUNC_READ_INPUT_REGISTERS = 0x04,
252 FUNC_WRITE_SINGLE_COIL = 0x05,
253 FUNC_WRITE_SINGLE_REGISTER = 0x06,
254 FUNC_READ_EXCEPTION_STATUS = 0x07,
255 FUNC_DIAGNOSTICS = 0x08,
256 FUNC_GET_COMM_EVENT_COUNTER = 0x0b,
257 FUNC_GET_COMM_EVENT_LOG = 0x0c,
258 FUNC_WRITE_MULTIPLE_COILS = 0x0f,
259 FUNC_WRITE_MULTIPLE_REGISTERS = 0x10,
260 FUNC_REPORT_SLAVE_ID = 0x11,
261 FUNC_READ_FILE_RECORD = 0x14,
262 FUNC_WRITE_FILE_RECORD = 0x15,
263 FUNC_MASK_WRITE_REGISTER = 0x16,
264 FUNC_READ_WRITE_MULTIPLE_REGISTERS = 0x17,
265 FUNC_READ_FIFO_QUEUE = 0x18,
266 FUNC_ENCAPSULATED_INTERFACE_TRANSPORT = 0x2b,
270 ERR_ILLEGAL_FUNCTION = 0x01,
271 ERR_ILLEGAL_DATA_ADDRESS = 0x02,
272 ERR_ILLEGAL_DATA_VALUE = 0x03,
275 static uint read_remains(void)
277 return rx_frame_end - rx_frame;
280 static byte read_byte(void)
285 static u16 read_u16(void)
287 byte hi = *rx_frame++;
288 byte lo = *rx_frame++;
289 return (hi << 8) | lo;
292 static void write_byte(byte v)
294 tx_buf[tx_size++] = v;
297 static void write_u16(u16 v)
303 static bool body_fits(uint body_len)
305 // body_len excludes slave address, function code, and CRC
306 return (2 + body_len + 2 <= TX_BUFSIZE);
309 static void report_error(byte code)
311 // Discard the partially constructed body of the reply and rewrite the header
317 static void func_read_bits(bool coils)
319 if (read_remains() < 4)
320 return report_error(ERR_ILLEGAL_DATA_VALUE);
322 u16 start = read_u16();
323 u16 count = read_u16();
325 uint bytes = (count+7) / 8;
326 if (!body_fits(1 + bytes))
327 return report_error(ERR_ILLEGAL_DATA_VALUE);
329 for (u16 i = 0; i < count; i++)
330 if (!(coils ? modbus_check_coil : modbus_check_discrete_input)(start + i))
331 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
334 for (u16 i = 0; i < bytes; i++) {
336 for (byte j = 0; j < 8 && 8*i + j < count; j++) {
337 uint addr = start + 8*i + j;
338 if ((coils ? modbus_get_coil : modbus_get_discrete_input)(addr))
345 static void func_read_registers(byte holding)
347 if (read_remains() < 4)
348 return report_error(ERR_ILLEGAL_DATA_VALUE);
350 u16 start = read_u16();
351 u16 count = read_u16();
353 uint bytes = 2*count;
354 if (!body_fits(1 + bytes))
355 return report_error(ERR_ILLEGAL_DATA_VALUE);
357 for (u16 i = 0; i < count; i++)
358 if (!(holding ? modbus_check_holding_register : modbus_check_input_register)(start + i))
359 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
361 // FIXME: Reporting of slave failures?
363 for (u16 i = 0; i < count; i++)
364 write_u16((holding ? modbus_get_holding_register : modbus_get_input_register)(start + i));
367 static void func_write_single_coil(void)
369 if (read_remains() < 4)
370 return report_error(ERR_ILLEGAL_DATA_VALUE);
372 u16 addr = read_u16();
373 u16 value = read_u16();
375 if (!modbus_check_coil(addr))
376 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
377 if (value != 0x0000 && value != 0xff00)
378 return report_error(ERR_ILLEGAL_DATA_VALUE);
380 modbus_set_coil(addr, value);
383 static void func_write_single_register(void)
385 if (read_remains() < 4)
386 return report_error(ERR_ILLEGAL_DATA_VALUE);
388 u16 addr = read_u16();
389 u16 value = read_u16();
391 if (!modbus_check_holding_register(addr))
392 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
394 modbus_set_holding_register(addr, value);
397 static void func_write_multiple_coils(void)
399 if (read_remains() < 5)
400 return report_error(ERR_ILLEGAL_DATA_VALUE);
402 u16 start = read_u16();
403 u16 count = read_u16();
404 byte bytes = read_byte();
406 if (read_remains() < bytes || bytes != (count+7) / 8)
407 return report_error(ERR_ILLEGAL_DATA_VALUE);
409 for (u16 i = 0; i < count; i++)
410 if (!modbus_check_coil(start + i))
411 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
413 for (u16 i = 0; i < count; i++)
414 modbus_set_coil(start + i, rx_frame[i/8] & (1U << (i%8)));
417 static void func_write_multiple_registers(void)
419 if (read_remains() < 5)
420 return report_error(ERR_ILLEGAL_DATA_VALUE);
422 u16 start = read_u16();
423 u16 count = read_u16();
424 byte bytes = read_byte();
426 if (read_remains() < bytes || bytes != 2*count)
427 return report_error(ERR_ILLEGAL_DATA_VALUE);
429 for (u16 i = 0; i < count; i++)
430 if (!modbus_check_holding_register(start + i))
431 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
433 for (u16 i = 0; i < count; i++)
434 modbus_set_holding_register(start + i, read_u16());
437 static void func_mask_write_register(void)
439 if (read_remains() < 6)
440 return report_error(ERR_ILLEGAL_DATA_VALUE);
442 u16 addr = read_u16();
443 u16 and_mask = read_u16();
444 u16 or_mask = read_u16();
446 if (!modbus_check_holding_register(addr))
447 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
449 u16 reg = modbus_get_holding_register(addr);
450 reg = (reg & and_mask) | (or_mask & ~and_mask);
451 modbus_set_holding_register(addr, reg);
454 static void func_read_write_multiple_registers(void)
456 if (read_remains() < 9)
457 return report_error(ERR_ILLEGAL_DATA_VALUE);
459 u16 read_start = read_u16();
460 u16 read_count = read_u16();
461 u16 write_start = read_u16();
462 u16 write_count = read_u16();
463 byte write_bytes = read_byte();
465 if (read_remains() < write_bytes || write_bytes != 2*write_count)
466 return report_error(ERR_ILLEGAL_DATA_VALUE);
468 for (u16 i = 0; i < read_count; i++)
469 if (!modbus_check_holding_register(read_start + i))
470 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
472 for (u16 i = 0; i < write_count; i++)
473 if (!modbus_check_holding_register(write_start + i))
474 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
476 byte read_bytes = 2*write_count;
477 if (!body_fits(1 + read_bytes))
478 return report_error(ERR_ILLEGAL_DATA_VALUE);
480 for (u16 i = 0; i < write_count; i++)
481 modbus_set_holding_register(write_start + i, read_u16());
483 write_byte(read_bytes);
484 for (u16 i = 0; i < read_count; i++)
485 modbus_get_holding_register(read_start + i);
488 static void func_encapsulated_interface_transport(void)
490 if (read_remains() < 3 ||
492 return report_error(ERR_ILLEGAL_DATA_VALUE);
494 byte action = read_byte();
495 byte id = read_byte();
497 byte range_min, range_max;
500 // Streaming access to basic identification
501 range_min = MODBUS_ID_VENDOR_NAME;
502 range_max = MODBUS_ID_MAJOR_MINOR_REVISION;
505 // Streaming access to regular identification
506 range_min = MODBUS_ID_VENDOR_URL;
507 range_max = MODBUS_ID_USER_APP_NAME;
511 if (id >= MODBUS_ID_MAX || !modbus_id_strings[id])
512 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
513 range_min = range_max = id;
516 return report_error(ERR_ILLEGAL_DATA_VALUE);
520 if (id < range_min || id > range_max)
524 write_byte(0x0e); // Repeat a part of the request
528 if (modbus_id_strings[MODBUS_ID_VENDOR_URL] ||
529 modbus_id_strings[MODBUS_ID_PRODUCT_NAME] ||
530 modbus_id_strings[MODBUS_ID_USER_APP_NAME])
531 write_byte(0x82); // Regular identification, both stream and individual access supported
533 write_byte(0x81); // Basic identification only
535 u16 more_follows_at = tx_size;
536 write_byte(0); // More follows: so far not
537 write_byte(0); // Next object ID: so far none
538 write_byte(0); // Number of objects
540 for (id = range_min; id <= range_max; id++) {
541 if (modbus_id_strings[id]) {
542 byte len = strlen(modbus_id_strings[id]);
543 byte remains = TX_BUFSIZE - 4 - tx_size; // 2 for CRC, 2 for object header
545 // If it is the only object, cut it
546 if (!tx_buf[more_follows_at + 2])
549 // More follows, report the next ID
550 tx_buf[more_follows_at] = 0xff;
551 tx_buf[more_follows_at + 1] = id;
555 tx_buf[more_follows_at + 2] ++;
558 memcpy(tx_buf + tx_size, modbus_id_strings[id], len);
564 static void process_frame(void)
566 byte func = read_byte();
568 // Prepare reply frame
569 tx_buf[0] = MB_OUR_ADDRESS;
570 tx_buf[1] = rx_buf[1];
574 case FUNC_READ_COILS:
575 func_read_bits(true);
577 case FUNC_READ_DISCRETE_INPUTS:
578 func_read_bits(false);
580 case FUNC_READ_HOLDING_REGISTERS:
581 func_read_registers(true);
583 case FUNC_READ_INPUT_REGISTERS:
584 func_read_registers(false);
586 case FUNC_WRITE_SINGLE_COIL:
587 func_write_single_coil();
589 case FUNC_WRITE_SINGLE_REGISTER:
590 func_write_single_register();
592 case FUNC_WRITE_MULTIPLE_COILS:
593 func_write_multiple_coils();
595 case FUNC_WRITE_MULTIPLE_REGISTERS:
596 func_write_multiple_registers();
598 case FUNC_MASK_WRITE_REGISTER:
599 func_mask_write_register();
601 case FUNC_READ_WRITE_MULTIPLE_REGISTERS:
602 func_read_write_multiple_registers();
604 case FUNC_ENCAPSULATED_INTERFACE_TRANSPORT:
605 func_encapsulated_interface_transport();
608 report_error(ERR_ILLEGAL_FUNCTION);
611 // Finish reply frame
612 write_u16(crc16(tx_buf, tx_size));
615 void modbus_loop(void)
617 if (state != STATE_RX_DONE)
619 state = STATE_PROCESSING;
621 if (!check_frame()) {
626 if (rx_buf[0] == MB_OUR_ADDRESS) {
627 // Frame addressed to us: process and reply
630 } else if (rx_buf[0] == 0x00) {
631 // Broadcast frame: process, but do not reply
635 // Somebody else's frame: discard
642 bool modbus_check_discrete_input(u16 addr UNUSED)
647 bool modbus_get_discrete_input(u16 addr UNUSED)
652 bool modbus_check_coil(u16 addr UNUSED)
657 bool modbus_get_coil(u16 addr UNUSED)
662 void modbus_set_coil(u16 addr UNUSED, bool value UNUSED)
666 bool modbus_check_input_register(u16 addr UNUSED)
671 u16 modbus_get_input_register(u16 addr UNUSED)
676 bool modbus_check_holding_register(u16 addr UNUSED)
681 u16 modbus_get_holding_register(u16 addr UNUSED)
686 void modbus_set_holding_register(u16 addr UNUSED, u16 value UNUSED)
690 const char * const modbus_id_strings[MODBUS_ID_MAX] = {
691 [MODBUS_ID_VENDOR_NAME] = "United Computer Wizards",
692 [MODBUS_ID_PRODUCT_CODE] = "42",
693 [MODBUS_ID_MAJOR_MINOR_REVISION] = "1.0",
694 [MODBUS_ID_VENDOR_URL] = "http://www.ucw.cz/",
695 [MODBUS_ID_PRODUCT_NAME] = "Magic Gadget",
696 [MODBUS_ID_USER_APP_NAME] = NULL,