1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include "aos/kernel.h"
6 #include "mbmaster.h"
7 #include "ulog/ulog.h"
8 #if AOS_COMP_CLI
9 #include "aos/cli.h"
10 #endif
11 
12 /* Define the parameters */
13 #define SERIAL_PORT             (1)    /* uart port */
14 #define SERIAL_BAUD_RATE        (9600) /* uart baud rate */
15 #define DEVICE1_SLAVE_ADDR_1    (0x1)  /* remote deveice address */
16 #define DEVICE1_SLAVE_ADDR_2    (0x2)  /* remote deveice address */
17 #define DEVICE1_REG1_ADDR       (0x0)  /* register address of remote device */
18 #define RECV_LEN_MAX            (20)   /* buffer len, must >=  (REQ_REGISTER_NUMBER * 2) */
19 #define REQ_REGISTER_NUMBER     (10)    /* Number of registers requested */
20 
21 /* mode name used by ulog */
22 #define MODBUSM_APP "modbus_app"
23 
mb_master_main(void)24 void mb_master_main(void)
25 {
26     uint8_t     buf[RECV_LEN_MAX];
27     uint8_t     len;
28     mb_status_t status;
29     uint16_t    simulator1 = 0, simulator2 = 0;
30     uint16_t    data_write = 0, data_resp = 0;
31     uint16_t   *register_buf;
32 
33     /* The handler is allocated by calling the aos_mbmaster_rtu_init */
34     mb_handler_t *mb_handler_master;
35 
36     /**
37      * Initialize the modbus communication port, using rtu mode.
38      * Need to set the appropriatet port number, baud rate, parity
39      * according to the actual situation.
40      */
41     status = mbmaster_rtu_init(&mb_handler_master, SERIAL_PORT, SERIAL_BAUD_RATE, MB_PAR_NONE, 500);
42     LOGD(MODBUS_MOUDLE, "mbmaster_rtu_init status is %d\n", status);
43     if (status != MB_SUCCESS) {
44         LOGE(MODBUSM_APP, "mbmaster init error\n");
45         return;
46     }
47 
48     /* note: This example loops every 2 seconds, first sending a write request, then sending a read request. */
49     while (1) {
50 #if 1
51         /**
52          * Initiate write single registers request.
53          * data_resp: respond from the remote device. If the write operation succeeds,
54          * it's equal to data_write.
55          */
56         status = mbmaster_write_single_register(mb_handler_master, DEVICE1_SLAVE_ADDR_1, DEVICE1_REG1_ADDR,
57                                                 data_write, NULL, &data_resp, NULL, AOS_WAIT_FOREVER);
58         if (status == MB_SUCCESS) {
59             if (data_write != data_resp) {
60                 LOGE(MODBUSM_APP, "write single register error\n");
61             } else {
62                 LOGI(MODBUSM_APP, "write single register ok\n");
63             }
64         } else {
65             LOGE(MODBUSM_APP, "write single register error\n");
66         }
67 
68         data_write++; /* generate a new value */
69 
70         aos_msleep(1000 * 3);
71 #endif
72 
73 #if 1
74         memset(buf, 0, RECV_LEN_MAX);
75         /**
76          * Initiate read holding registers request
77          * The buf length needs to be greater than or equal to (REQ_REGISTER_NUMBER * 2)
78          */
79         status = mbmaster_read_holding_registers(mb_handler_master, DEVICE1_SLAVE_ADDR_2, DEVICE1_REG1_ADDR,
80                                                  REQ_REGISTER_NUMBER, buf, &len, AOS_WAIT_FOREVER);
81         if (status == MB_SUCCESS) {
82             /* The register length on modbus is 16 bits */
83             register_buf = (uint16_t *)buf;
84             simulator1 = register_buf[0];
85             simulator2 = register_buf[1];
86             LOGI(MODBUSM_APP, "read holding register simulator1: %d,simulator2: %d\n", simulator1, simulator2);
87         } else {
88             LOGE(MODBUSM_APP, "read holding register error\n");
89         }
90 #endif
91         aos_msleep(1000 * 3);
92     }
93 }
94 
mb_slave_main(uint8_t dev_addr)95 void mb_slave_main(uint8_t dev_addr)
96 {
97     uint8_t     buf[RECV_LEN_MAX];
98     uint8_t     len;
99     mb_status_t status;
100     uint16_t    simulator1 = 0, simulator2 = 0;
101     uint16_t    data_write = 0, data_resp = 0;
102     uint16_t   *register_buf;
103 
104     /* The handler is allocated by calling the aos_mbmaster_rtu_init */
105     mb_handler_t *mb_handler_slave = NULL;
106 
107     /**
108      * Initialize the modbus communication port, using rtu mode.
109      * Need to set the appropriatet port number, baud rate, parity
110      * according to the actual situation.
111      */
112     status = mbmaster_rtu_init(&mb_handler_slave, SERIAL_PORT, SERIAL_BAUD_RATE, MB_PAR_NONE, 100);
113     LOGD(MODBUS_MOUDLE, "mbmaster_rtu_init status is %d\n", status);
114     if (status != MB_SUCCESS) {
115         LOGE(MODBUSM_APP, "mbmaster init error\n");
116         return;
117     }
118 
119     /* wait slave respond */
120     LOGD(MODBUS_MOUDLE, "device [0x%x] waiting for cmd\n", dev_addr);
121     while (1) {
122         /* frame recv */
123         status = mb_handler_slave->frame_recv(mb_handler_slave);
124         if (status == MB_SUCCESS) {
125             /* frame handle and response */
126             status = mb_handler_slave->adu_disassemble(mb_handler_slave);
127             if (status == MB_SUCCESS) {
128                 uint8_t addr = mb_handler_slave->slave_addr;
129                 uint8_t len = mb_handler_slave->pdu_length;
130                 uint8_t offset = mb_handler_slave->pdu_offset;
131                 uint8_t *data = mb_handler_slave->mb_frame_buff;
132 
133                 if (addr == dev_addr) {
134                     switch (addr) {
135                         case DEVICE1_SLAVE_ADDR_1:
136                         // no need to process 0x06
137                             mb_handler_slave->pdu_length = len;
138                             break;
139 
140                         case DEVICE1_SLAVE_ADDR_2:
141                         // 0x01 0x03 0x00 0x00 0x00 0x0a 0xc5 0xcd
142                         {
143                             uint16_t reg_start = data[2] << 8 | data[3];
144                             uint16_t reg_len   = data[4] << 8 | data[5];
145 
146                             mb_handler_slave->pdu_length = reg_len * 2 + 2;
147 
148                             data[ADU_SER_PDU_OFF + 1] = reg_len * 2;
149                             for (uint16_t k = 0; k < reg_len; k++) {
150                                 data[ADU_SER_PDU_OFF + 2 + k * 2] = 0x00;
151                                 data[ADU_SER_PDU_OFF + 2 + k * 2 + 1] = k & 0xFF;
152                             }
153                             break;
154                         }
155 
156                         default:
157                             LOGE(MODBUS_MOUDLE, "Unsupported device addr [0x%2X]\n", addr);
158                     }
159 
160                     status = mb_handler_slave->adu_assemble(mb_handler_slave);
161                     status = mb_handler_slave->frame_send(mb_handler_slave, 100);
162                     if (status != MB_SUCCESS) {
163                         LOGD(MODBUS_MOUDLE, "Failed to send response to master\n");
164                     }
165                 }
166             }
167         }
168     }
169 }
170 
mbmaster_comp_example(int argc,char * argv[])171 int mbmaster_comp_example(int argc, char *argv[])
172 {
173     aos_set_log_level(AOS_LL_DEBUG);
174 
175     LOGI(MODBUSM_APP, "mbmaster test\n");
176 
177     mb_master_main();
178 
179     return 0;
180 }
181 
mbslave_comp_example(int argc,char * argv[])182 int mbslave_comp_example(int argc, char *argv[])
183 {
184     aos_set_log_level(AOS_LL_DEBUG);
185 
186     if (argc == 1) {
187         mb_slave_main(DEVICE1_SLAVE_ADDR_1);
188     } else {
189         mb_slave_main(*argv[1] - 48);
190     }
191 
192     return 0;
193 }
194 
195 #if AOS_COMP_CLI
196 /* reg args: fun, cmd, description*/
197 ALIOS_CLI_CMD_REGISTER(mbmaster_comp_example, mbmaster_example, mbmaster component base master example)
198 ALIOS_CLI_CMD_REGISTER(mbslave_comp_example, mbslave_example, mbmaster component base salve example)
199 #endif
200 
201