1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include <mbmaster.h>
6 #include "pdu.h"
7
8 /**
9 * Used for 122 format frame assemble: 1byte 2byte 2byte
10 * The function code that conform to this format : 0x01 0x02 0x03 0x4 0x05 0x6
11 */
pdu_type122_assemble(mb_handler_t * req_handler,uint8_t field0,uint16_t field1,uint16_t field2)12 mb_status_t pdu_type122_assemble(mb_handler_t *req_handler, uint8_t field0, uint16_t field1, uint16_t field2)
13 {
14 mb_status_t status = MB_SUCCESS;
15 uint8_t *pdu_buf = &req_handler->mb_frame_buff[req_handler->pdu_offset];
16
17 if (req_handler->slave_addr > SLAVE_ADDR_MAX) {
18 status = MB_INVALID_SLAVE_ADDR;
19 return status;
20 }
21
22 pdu_buf[0] = field0;
23 pdu_buf[1] = htobe16(field1) & 0xFF;
24 pdu_buf[2] = (htobe16(field1) >> 8) & 0xFF;
25 pdu_buf[3] = htobe16(field2) & 0xFF;
26 pdu_buf[4] = (htobe16(field2) >> 8) & 0xFF;
27
28 req_handler->pdu_length = 5;
29
30 return status;
31 }
32
33 /**
34 * Used for 1221n format frame assemble: 1byte function_code:2byte start address:2byte quantity:1byte counts: n byte outputs data
35 * The function code that conform to this format : 0x0F 0x10
36 */
pdu_type1221n_assemble(mb_handler_t * req_handler,uint8_t function_code,uint16_t start_addr,uint16_t quantity,uint8_t byte_count,uint8_t * outputs_buf)37 mb_status_t pdu_type1221n_assemble(mb_handler_t *req_handler, uint8_t function_code, uint16_t start_addr,
38 uint16_t quantity, uint8_t byte_count, uint8_t *outputs_buf)
39 {
40 uint8_t i;
41 mb_status_t status = MB_SUCCESS;
42 uint8_t *pdu_buf = &req_handler->mb_frame_buff[req_handler->pdu_offset];
43 uint16_t *register_data = NULL;
44
45 if (req_handler->slave_addr > SLAVE_ADDR_MAX) {
46 status = MB_INVALID_SLAVE_ADDR;
47 return status;
48 }
49
50 pdu_buf[0] = function_code;
51 pdu_buf[1] = htobe16(start_addr) & 0xFF;
52 pdu_buf[2] = (htobe16(start_addr) >> 8) & 0xFF;
53 pdu_buf[3] = htobe16(quantity) & 0xFF;
54 pdu_buf[4] = (htobe16(quantity) >> 8) & 0xFF;
55 pdu_buf[5] = byte_count;
56
57 memcpy(&pdu_buf[6], outputs_buf, byte_count);
58
59 register_data = (uint16_t *)&pdu_buf[6];
60 if (function_code == FUNC_CODE_WRITE_MULTIPLE_REGISTERS) {
61 for (i = 0; i < quantity; i++) {
62 register_data[i] = htobe16(register_data[i]);
63 }
64 }
65
66 req_handler->pdu_length = 6 + byte_count;
67
68 return status;
69 }
70
71 /**
72 * Used for 11n format frame disassemble : 1 byte function code:1 byte count:n byte data
73 * when exception the format is: 1 byte error code:1 byte excepton code
74 * The function code that conform to this format : 0x01 0x02 0x03 0x4
75 */
pdu_type11n_disassemble(mb_handler_t * req_handler,uint8_t function_code,uint8_t * respond_buf,uint8_t * respond_count)76 mb_status_t pdu_type11n_disassemble(mb_handler_t *req_handler, uint8_t function_code, uint8_t *respond_buf,
77 uint8_t *respond_count)
78 {
79 uint32_t i;
80 mb_status_t status = MB_SUCCESS;
81 uint8_t *pdu_buf = &req_handler->mb_frame_buff[req_handler->pdu_offset];
82 uint16_t *register_data;
83
84 if ((respond_buf == NULL) || (respond_count == NULL)) {
85 status = MB_INVALID_PARAM;
86 return status;
87 }
88
89 if ((pdu_buf[0] & 0x80) != 0) {
90 respond_buf[0] = pdu_buf[1];
91 *respond_count = 1;
92
93 status = MB_RESPOND_EXCEPTION;
94 return status;
95 }
96
97 *respond_count = pdu_buf[1];
98
99 /* pdu_length = (1 byte function code) + (1 byte count) + (n byte data) */
100 if ((*respond_count + 2) != req_handler->pdu_length) {
101 status = MB_RESPOND_LENGTH_ERR;
102 return status;
103 }
104
105 register_data = (uint16_t *)&pdu_buf[2];
106
107 if ((function_code == FUNC_CODE_READ_HOLDING_REGISTERS) || (function_code == FUNC_CODE_READ_INPUT_REGISTERS)) {
108 for (i = 0; i < (*respond_count / 2); i++) {
109 register_data[i] = betoh16(register_data[i]);
110 }
111 }
112
113 memcpy(respond_buf, register_data, *respond_count);
114 return status;
115 }
116
117 /**
118 * Used for 112 format frame disassemble : 1 byte function code:2 byte data:2 byte data
119 * when exception the format is: 1 byte error code:1 byte excepton code
120 * The function code that conform to this format : 0x05 0x06
121 */
pdu_type122_disassemble(mb_handler_t * req_handler,uint8_t function_code,uint16_t * data1,uint16_t * data2,uint8_t * exception_code)122 mb_status_t pdu_type122_disassemble(mb_handler_t *req_handler, uint8_t function_code, uint16_t *data1,
123 uint16_t *data2, uint8_t* exception_code)
124 {
125 mb_status_t status = MB_SUCCESS;
126 uint8_t *pdu_buf = &req_handler->mb_frame_buff[req_handler->pdu_offset];
127 uint16_t revdata;
128
129 if ((pdu_buf[0] & 0x80) != 0 ) {
130 if (exception_code != NULL) {
131 *exception_code = pdu_buf[1];
132 }
133 status = MB_RESPOND_EXCEPTION;
134 return status;
135 }
136
137 /* For FUNC_CODE_WRITE_SINGLE_COIL, 0xff00 means ON and 0x0000 means OFF,
138 * so conversion is also required */
139 if (data1 != NULL) {
140 revdata = pdu_buf[2];
141 revdata = pdu_buf[1] | (revdata << 8);
142 *data1 = betoh16(revdata);
143 }
144
145 /* For FUNC_CODE_WRITE_SINGLE_COIL, 0xff00 means ON and 0x0000 means OFF,
146 * so conversion is also required */
147 if (data2 != NULL) {
148 revdata = pdu_buf[4];
149 revdata = pdu_buf[3] | (revdata << 8);
150 *data2 = betoh16(revdata);
151 }
152
153 return status;
154 }
155