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