2 * Generic MODBUS Library for STM32
4 * (c) 2019 Martin Mareš <mj@ucw.cz>
14 #include <libopencm3/cm3/nvic.h>
15 #include <libopencm3/stm32/gpio.h>
16 #include <libopencm3/stm32/usart.h>
17 #include <libopencm3/stm32/timer.h>
19 /*** Configuration ***/
21 // You should set the following parameters in config.h
23 // USART (pins are expected to be configured by the caller)
24 // #define MODBUS_USART USART2
25 // #define MODBUS_NVIC_USART_IRQ NVIC_USART2_IRQ
26 // #define MODBUS_USART_ISR usart2_isr
28 // GPIO pin for transmitter enable (pins is expected to be configured by the caller)
29 // #define MODBUS_TXEN_GPIO_PORT GPIOA
30 // #define MODBUS_TXEN_GPIO_PIN GPIO1
33 // #define MODBUS_TIMER TIM2
34 // #define MODBUS_NVIC_TIMER_IRQ NVIC_TIM2_IRQ
35 // #define MODBUS_TIMER_ISR tim2_isr
37 // Slave address we are responding at
38 // #define MODBUS_OUR_ADDRESS 42
41 #ifndef MODBUS_BAUD_RATE
42 #define MODBUS_BAUD_RATE 19200
45 // CPU clock frequency
46 // #define CPU_CLOCK_MHZ 72
48 // Receive buffer size (standard specifies 256 bytes, you can make it shorter if necessary)
49 #ifndef MODBUS_RX_BUFSIZE
50 #define MODBUS_RX_BUFSIZE 256
53 // Transmit buffer size (standard specifies 256 bytes, you can make it shorter if necessary)
54 #ifndef MODBUS_TX_BUFSIZE
55 #define MODBUS_TX_BUFSIZE 256
58 // Receive timeout in microseconds
59 #ifndef MODBUS_RX_TIMEOUT
60 #if MODBUS_BAUD_RATE <= 19200
61 // For low baud rates, the standard specifies timeout of 1.5 character times
62 // (1 character = start bit + 8 data bits + parity bit + stop bit = 11 bits)
63 #define MODBUS_RX_TIMEOUT (1000000*11*3/2/MODBUS_BAUD_RATE)
65 // For high rates, the timeout is fixed to 750 μs
66 #define MODBUS_RX_TIMEOUT 750
81 static byte rx_buf[MODBUS_RX_BUFSIZE];
84 static byte state; // STATE_xxx
86 static byte *rx_frame;
87 static byte *rx_frame_end;
89 static byte tx_buf[MODBUS_TX_BUFSIZE];
93 static void rx_init(void)
98 usart_set_mode(MODBUS_USART, USART_MODE_RX);
99 usart_enable_rx_interrupt(MODBUS_USART);
102 static void rx_done(void)
104 state = STATE_RX_DONE;
105 usart_disable_rx_interrupt(MODBUS_USART);
108 static void tx_init(void)
112 gpio_set(MODBUS_TXEN_GPIO_PORT, MODBUS_TXEN_GPIO_PIN);
113 usart_set_mode(MODBUS_USART, USART_MODE_TX);
114 usart_enable_tx_interrupt(MODBUS_USART);
117 static void tx_done(void)
119 state = STATE_TX_DONE;
120 // usart_disable_tx_interrupt(MODBUS_USART); // Already done by irq handler
121 gpio_clear(MODBUS_TXEN_GPIO_PORT, MODBUS_TXEN_GPIO_PIN);
124 void modbus_init(void)
126 timer_set_prescaler(MODBUS_TIMER, CPU_CLOCK_MHZ-1); // 1 tick = 1 μs
127 timer_set_mode(MODBUS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_DOWN);
128 timer_update_on_overflow(MODBUS_TIMER);
129 timer_disable_preload(MODBUS_TIMER);
130 timer_one_shot_mode(MODBUS_TIMER);
131 timer_enable_irq(MODBUS_TIMER, TIM_DIER_UIE);
132 nvic_enable_irq(MODBUS_NVIC_TIMER_IRQ);
134 gpio_clear(MODBUS_TXEN_GPIO_PORT, MODBUS_TXEN_GPIO_PIN);
136 usart_set_baudrate(MODBUS_USART, MODBUS_BAUD_RATE);
137 usart_set_databits(MODBUS_USART, 9);
138 usart_set_stopbits(MODBUS_USART, USART_STOPBITS_1);
139 usart_set_parity(MODBUS_USART, USART_PARITY_EVEN);
140 usart_set_flow_control(MODBUS_USART, USART_FLOWCONTROL_NONE);
144 nvic_enable_irq(MODBUS_NVIC_USART_IRQ);
145 usart_enable(MODBUS_USART);
148 void MODBUS_USART_ISR(void)
150 u32 status = USART_SR(MODBUS_USART);
152 if (status & USART_SR_RXNE) {
153 uint ch = usart_recv(MODBUS_USART);
154 if (state == STATE_RX) {
155 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
157 } else if (rx_size < MODBUS_RX_BUFSIZE) {
158 rx_buf[rx_size++] = ch;
163 timer_set_period(MODBUS_TIMER, MODBUS_RX_TIMEOUT);
164 timer_generate_event(MODBUS_TIMER, TIM_EGR_UG);
165 timer_enable_counter(MODBUS_TIMER);
169 if (state == STATE_TX) {
170 if (status & USART_SR_TXE) {
171 if (tx_pos < tx_size) {
172 usart_send(MODBUS_USART, tx_buf[tx_pos++]);
174 // The transmitter is double-buffered, so at this moment, it is transmitting
175 // the last byte of the frame. Wait until transfer is completed.
176 usart_disable_tx_interrupt(MODBUS_USART);
177 USART_CR1(MODBUS_USART) |= USART_CR1_TCIE;
178 state = STATE_TX_LAST;
181 } else if (state == STATE_TX_LAST) {
182 if (status & USART_SR_TC) {
183 // Transfer of the last byte is complete. Release the bus.
184 USART_CR1(MODBUS_USART) &= ~USART_CR1_TCIE;
191 void MODBUS_TIMER_ISR(void)
193 if (TIM_SR(MODBUS_TIMER) & TIM_SR_UIF) {
194 TIM_SR(MODBUS_TIMER) &= ~TIM_SR_UIF;
195 if (state == STATE_RX)
202 static const byte crc_hi[] = {
203 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
204 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
205 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
206 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
207 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
208 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41,
209 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
210 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
211 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
212 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
213 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
214 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
215 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
216 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
217 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
218 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
219 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
220 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
221 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
222 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
223 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
224 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
225 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
226 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
227 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
228 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40
231 static const byte crc_lo[] = {
232 0x00, 0xc0, 0xc1, 0x01, 0xc3, 0x03, 0x02, 0xc2, 0xc6, 0x06,
233 0x07, 0xc7, 0x05, 0xc5, 0xc4, 0x04, 0xcc, 0x0c, 0x0d, 0xcd,
234 0x0f, 0xcf, 0xce, 0x0e, 0x0a, 0xca, 0xcb, 0x0b, 0xc9, 0x09,
235 0x08, 0xc8, 0xd8, 0x18, 0x19, 0xd9, 0x1b, 0xdb, 0xda, 0x1a,
236 0x1e, 0xde, 0xdf, 0x1f, 0xdd, 0x1d, 0x1c, 0xdc, 0x14, 0xd4,
237 0xd5, 0x15, 0xd7, 0x17, 0x16, 0xd6, 0xd2, 0x12, 0x13, 0xd3,
238 0x11, 0xd1, 0xd0, 0x10, 0xf0, 0x30, 0x31, 0xf1, 0x33, 0xf3,
239 0xf2, 0x32, 0x36, 0xf6, 0xf7, 0x37, 0xf5, 0x35, 0x34, 0xf4,
240 0x3c, 0xfc, 0xfd, 0x3d, 0xff, 0x3f, 0x3e, 0xfe, 0xfa, 0x3a,
241 0x3b, 0xfb, 0x39, 0xf9, 0xf8, 0x38, 0x28, 0xe8, 0xe9, 0x29,
242 0xeb, 0x2b, 0x2a, 0xea, 0xee, 0x2e, 0x2f, 0xef, 0x2d, 0xed,
243 0xec, 0x2c, 0xe4, 0x24, 0x25, 0xe5, 0x27, 0xe7, 0xe6, 0x26,
244 0x22, 0xe2, 0xe3, 0x23, 0xe1, 0x21, 0x20, 0xe0, 0xa0, 0x60,
245 0x61, 0xa1, 0x63, 0xa3, 0xa2, 0x62, 0x66, 0xa6, 0xa7, 0x67,
246 0xa5, 0x65, 0x64, 0xa4, 0x6c, 0xac, 0xad, 0x6d, 0xaf, 0x6f,
247 0x6e, 0xae, 0xaa, 0x6a, 0x6b, 0xab, 0x69, 0xa9, 0xa8, 0x68,
248 0x78, 0xb8, 0xb9, 0x79, 0xbb, 0x7b, 0x7a, 0xba, 0xbe, 0x7e,
249 0x7f, 0xbf, 0x7d, 0xbd, 0xbc, 0x7c, 0xb4, 0x74, 0x75, 0xb5,
250 0x77, 0xb7, 0xb6, 0x76, 0x72, 0xb2, 0xb3, 0x73, 0xb1, 0x71,
251 0x70, 0xb0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
252 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9c, 0x5c,
253 0x5d, 0x9d, 0x5f, 0x9f, 0x9e, 0x5e, 0x5a, 0x9a, 0x9b, 0x5b,
254 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4b, 0x8b,
255 0x8a, 0x4a, 0x4e, 0x8e, 0x8f, 0x4f, 0x8d, 0x4d, 0x4c, 0x8c,
256 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
257 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
260 static u16 crc16(byte *buf, u16 len)
262 byte hi = 0xff, lo = 0xff;
265 byte i = hi ^ *buf++;
270 return (hi << 8 | lo);
273 static bool check_frame(void)
276 // FIXME: Error counters?
281 // FIXME: Error counters?
285 u16 crc = crc16(rx_buf, rx_size - 2);
286 u16 rx_crc = (rx_buf[rx_size-2] << 8) | rx_buf[rx_size-1];
288 // FIXME: Error counters?
292 rx_frame = rx_buf + 1;
293 rx_frame_end = rx_frame + rx_size - 2;
298 FUNC_READ_COILS = 0x01,
299 FUNC_READ_DISCRETE_INPUTS = 0x02,
300 FUNC_READ_HOLDING_REGISTERS = 0x03,
301 FUNC_READ_INPUT_REGISTERS = 0x04,
302 FUNC_WRITE_SINGLE_COIL = 0x05,
303 FUNC_WRITE_SINGLE_REGISTER = 0x06,
304 FUNC_READ_EXCEPTION_STATUS = 0x07,
305 FUNC_DIAGNOSTICS = 0x08,
306 FUNC_GET_COMM_EVENT_COUNTER = 0x0b,
307 FUNC_GET_COMM_EVENT_LOG = 0x0c,
308 FUNC_WRITE_MULTIPLE_COILS = 0x0f,
309 FUNC_WRITE_MULTIPLE_REGISTERS = 0x10,
310 FUNC_REPORT_SLAVE_ID = 0x11,
311 FUNC_READ_FILE_RECORD = 0x14,
312 FUNC_WRITE_FILE_RECORD = 0x15,
313 FUNC_MASK_WRITE_REGISTER = 0x16,
314 FUNC_READ_WRITE_MULTIPLE_REGISTERS = 0x17,
315 FUNC_READ_FIFO_QUEUE = 0x18,
316 FUNC_ENCAPSULATED_INTERFACE_TRANSPORT = 0x2b,
320 ERR_ILLEGAL_FUNCTION = 0x01,
321 ERR_ILLEGAL_DATA_ADDRESS = 0x02,
322 ERR_ILLEGAL_DATA_VALUE = 0x03,
325 static uint read_remains(void)
327 return rx_frame_end - rx_frame;
330 static byte read_byte(void)
335 static u16 read_u16(void)
337 byte hi = *rx_frame++;
338 byte lo = *rx_frame++;
339 return (hi << 8) | lo;
342 static void write_byte(byte v)
344 tx_buf[tx_size++] = v;
347 static void write_u16(u16 v)
353 static bool body_fits(uint body_len)
355 // body_len excludes slave address, function code, and CRC
356 return (2 + body_len + 2 <= MODBUS_TX_BUFSIZE);
359 static void report_error(byte code)
361 // Discard the partially constructed body of the reply and rewrite the header
367 static void func_read_bits(bool coils)
369 if (read_remains() < 4)
370 return report_error(ERR_ILLEGAL_DATA_VALUE);
372 u16 start = read_u16();
373 u16 count = read_u16();
375 uint bytes = (count+7) / 8;
376 if (!body_fits(1 + bytes))
377 return report_error(ERR_ILLEGAL_DATA_VALUE);
379 for (u16 i = 0; i < count; i++)
380 if (!(coils ? modbus_check_coil : modbus_check_discrete_input)(start + i))
381 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
384 for (u16 i = 0; i < bytes; i++) {
386 for (byte j = 0; j < 8 && 8*i + j < count; j++) {
387 uint addr = start + 8*i + j;
388 if ((coils ? modbus_get_coil : modbus_get_discrete_input)(addr))
395 static void func_read_registers(byte holding)
397 if (read_remains() < 4)
398 return report_error(ERR_ILLEGAL_DATA_VALUE);
400 u16 start = read_u16();
401 u16 count = read_u16();
403 uint bytes = 2*count;
404 if (!body_fits(1 + bytes))
405 return report_error(ERR_ILLEGAL_DATA_VALUE);
407 for (u16 i = 0; i < count; i++)
408 if (!(holding ? modbus_check_holding_register : modbus_check_input_register)(start + i))
409 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
411 // FIXME: Reporting of slave failures?
413 for (u16 i = 0; i < count; i++)
414 write_u16((holding ? modbus_get_holding_register : modbus_get_input_register)(start + i));
417 static void func_write_single_coil(void)
419 if (read_remains() < 4)
420 return report_error(ERR_ILLEGAL_DATA_VALUE);
422 u16 addr = read_u16();
423 u16 value = read_u16();
425 if (!modbus_check_coil(addr))
426 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
427 if (value != 0x0000 && value != 0xff00)
428 return report_error(ERR_ILLEGAL_DATA_VALUE);
430 modbus_set_coil(addr, value);
433 static void func_write_single_register(void)
435 if (read_remains() < 4)
436 return report_error(ERR_ILLEGAL_DATA_VALUE);
438 u16 addr = read_u16();
439 u16 value = read_u16();
441 if (!modbus_check_holding_register(addr))
442 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
444 modbus_set_holding_register(addr, value);
447 static void func_write_multiple_coils(void)
449 if (read_remains() < 5)
450 return report_error(ERR_ILLEGAL_DATA_VALUE);
452 u16 start = read_u16();
453 u16 count = read_u16();
454 byte bytes = read_byte();
456 if (read_remains() < bytes || bytes != (count+7) / 8)
457 return report_error(ERR_ILLEGAL_DATA_VALUE);
459 for (u16 i = 0; i < count; i++)
460 if (!modbus_check_coil(start + i))
461 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
463 for (u16 i = 0; i < count; i++)
464 modbus_set_coil(start + i, rx_frame[i/8] & (1U << (i%8)));
467 static void func_write_multiple_registers(void)
469 if (read_remains() < 5)
470 return report_error(ERR_ILLEGAL_DATA_VALUE);
472 u16 start = read_u16();
473 u16 count = read_u16();
474 byte bytes = read_byte();
476 if (read_remains() < bytes || bytes != 2*count)
477 return report_error(ERR_ILLEGAL_DATA_VALUE);
479 for (u16 i = 0; i < count; i++)
480 if (!modbus_check_holding_register(start + i))
481 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
483 for (u16 i = 0; i < count; i++)
484 modbus_set_holding_register(start + i, read_u16());
487 static void func_mask_write_register(void)
489 if (read_remains() < 6)
490 return report_error(ERR_ILLEGAL_DATA_VALUE);
492 u16 addr = read_u16();
493 u16 and_mask = read_u16();
494 u16 or_mask = read_u16();
496 if (!modbus_check_holding_register(addr))
497 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
499 u16 reg = modbus_get_holding_register(addr);
500 reg = (reg & and_mask) | (or_mask & ~and_mask);
501 modbus_set_holding_register(addr, reg);
504 static void func_read_write_multiple_registers(void)
506 if (read_remains() < 9)
507 return report_error(ERR_ILLEGAL_DATA_VALUE);
509 u16 read_start = read_u16();
510 u16 read_count = read_u16();
511 u16 write_start = read_u16();
512 u16 write_count = read_u16();
513 byte write_bytes = read_byte();
515 if (read_remains() < write_bytes || write_bytes != 2*write_count)
516 return report_error(ERR_ILLEGAL_DATA_VALUE);
518 for (u16 i = 0; i < read_count; i++)
519 if (!modbus_check_holding_register(read_start + i))
520 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
522 for (u16 i = 0; i < write_count; i++)
523 if (!modbus_check_holding_register(write_start + i))
524 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
526 byte read_bytes = 2*write_count;
527 if (!body_fits(1 + read_bytes))
528 return report_error(ERR_ILLEGAL_DATA_VALUE);
530 for (u16 i = 0; i < write_count; i++)
531 modbus_set_holding_register(write_start + i, read_u16());
533 write_byte(read_bytes);
534 for (u16 i = 0; i < read_count; i++)
535 modbus_get_holding_register(read_start + i);
538 static void func_encapsulated_interface_transport(void)
540 if (read_remains() < 3 ||
542 return report_error(ERR_ILLEGAL_DATA_VALUE);
544 byte action = read_byte();
545 byte id = read_byte();
547 byte range_min, range_max;
550 // Streaming access to basic identification
551 range_min = MODBUS_ID_VENDOR_NAME;
552 range_max = MODBUS_ID_MAJOR_MINOR_REVISION;
555 // Streaming access to regular identification
556 range_min = MODBUS_ID_VENDOR_URL;
557 range_max = MODBUS_ID_USER_APP_NAME;
561 if (id >= MODBUS_ID_MAX || !modbus_id_strings[id])
562 return report_error(ERR_ILLEGAL_DATA_ADDRESS);
563 range_min = range_max = id;
566 return report_error(ERR_ILLEGAL_DATA_VALUE);
570 if (id < range_min || id > range_max)
574 write_byte(0x0e); // Repeat a part of the request
578 if (modbus_id_strings[MODBUS_ID_VENDOR_URL] ||
579 modbus_id_strings[MODBUS_ID_PRODUCT_NAME] ||
580 modbus_id_strings[MODBUS_ID_USER_APP_NAME])
581 write_byte(0x82); // Regular identification, both stream and individual access supported
583 write_byte(0x81); // Basic identification only
585 u16 more_follows_at = tx_size;
586 write_byte(0); // More follows: so far not
587 write_byte(0); // Next object ID: so far none
588 write_byte(0); // Number of objects
590 for (id = range_min; id <= range_max; id++) {
591 if (modbus_id_strings[id]) {
592 byte len = strlen(modbus_id_strings[id]);
593 byte remains = MODBUS_TX_BUFSIZE - 4 - tx_size; // 2 for CRC, 2 for object header
595 // If it is the only object, cut it
596 if (!tx_buf[more_follows_at + 2])
599 // More follows, report the next ID
600 tx_buf[more_follows_at] = 0xff;
601 tx_buf[more_follows_at + 1] = id;
605 tx_buf[more_follows_at + 2] ++;
608 memcpy(tx_buf + tx_size, modbus_id_strings[id], len);
614 static void process_frame(void)
616 byte func = read_byte();
618 // Prepare reply frame
619 tx_buf[0] = MODBUS_OUR_ADDRESS;
620 tx_buf[1] = rx_buf[1];
624 case FUNC_READ_COILS:
625 func_read_bits(true);
627 case FUNC_READ_DISCRETE_INPUTS:
628 func_read_bits(false);
630 case FUNC_READ_HOLDING_REGISTERS:
631 func_read_registers(true);
633 case FUNC_READ_INPUT_REGISTERS:
634 func_read_registers(false);
636 case FUNC_WRITE_SINGLE_COIL:
637 func_write_single_coil();
639 case FUNC_WRITE_SINGLE_REGISTER:
640 func_write_single_register();
642 case FUNC_WRITE_MULTIPLE_COILS:
643 func_write_multiple_coils();
645 case FUNC_WRITE_MULTIPLE_REGISTERS:
646 func_write_multiple_registers();
648 case FUNC_MASK_WRITE_REGISTER:
649 func_mask_write_register();
651 case FUNC_READ_WRITE_MULTIPLE_REGISTERS:
652 func_read_write_multiple_registers();
654 case FUNC_ENCAPSULATED_INTERFACE_TRANSPORT:
655 func_encapsulated_interface_transport();
658 report_error(ERR_ILLEGAL_FUNCTION);
661 // Finish reply frame
662 write_u16(crc16(tx_buf, tx_size));
665 void modbus_loop(void)
667 if (state != STATE_RX_DONE)
669 state = STATE_PROCESSING;
671 if (!check_frame()) {
676 if (rx_buf[0] == MODBUS_OUR_ADDRESS) {
677 // Frame addressed to us: process and reply
680 } else if (rx_buf[0] == 0x00) {
681 // Broadcast frame: process, but do not reply
685 // Somebody else's frame: discard
692 bool modbus_check_discrete_input(u16 addr UNUSED)
697 bool modbus_get_discrete_input(u16 addr UNUSED)
702 bool modbus_check_coil(u16 addr UNUSED)
707 bool modbus_get_coil(u16 addr UNUSED)
712 void modbus_set_coil(u16 addr UNUSED, bool value UNUSED)
716 bool modbus_check_input_register(u16 addr UNUSED)
721 u16 modbus_get_input_register(u16 addr UNUSED)
726 bool modbus_check_holding_register(u16 addr UNUSED)
731 u16 modbus_get_holding_register(u16 addr UNUSED)
736 void modbus_set_holding_register(u16 addr UNUSED, u16 value UNUSED)
740 const char * const modbus_id_strings[MODBUS_ID_MAX] = {
741 [MODBUS_ID_VENDOR_NAME] = "United Computer Wizards",
742 [MODBUS_ID_PRODUCT_CODE] = "42",
743 [MODBUS_ID_MAJOR_MINOR_REVISION] = "1.0",
744 [MODBUS_ID_VENDOR_URL] = "http://www.ucw.cz/",
745 [MODBUS_ID_PRODUCT_NAME] = "Magic Gadget",
746 [MODBUS_ID_USER_APP_NAME] = NULL,