Modbus 0.3
Библиотека Modbus для STM
Loading...
Searching...
No Matches
modbus_coils.c
Go to the documentation of this file.
1/**
2*******************************************************************************
3* @file modbus_coils.c
4* @brief Реализация работы с коилами Modbus
5*******************************************************************************
6* @details
7Модуль для доступа к coils внутри программы:
8- Функции для доступа к coils по глобальным адресам
9- Макросы для доступа к coils по локальным адресам
10
11Модуль обработки команд для coils (битовых данных):
12- Чтение coils (0x01) - упаковка битов в байты для передачи
13- Запись одиночного coil (0x05) - установка/сброс бита
14- Запись множественных coils (0x0F) - распаковка битов из байтов
15
16@section cvalid Валидация данных:
17- Проверка соответствия количества байт и регистров
18- Валидация адресов через MB_DefineRegistersAddress()
19- Обработка исключений при некорректных запросах
20******************************************************************************/
21#include "modbus_coils.h"
22
23#ifdef MODBUS_ENABLE_COILS
24
25/**
26 * @brief Выставить/сбросить коил по глобальному адресу.
27 * @param Addr Адрес коила.
28 * @param WriteVal Что записать в коил: 0 или 1.
29 * @return ExceptionCode Код исключения если коила по адресу не существует, и ET_NO_ERRORS если все ок.
30 *
31 * @details Позволяет обратиться к любому коилу по его глобальному адрессу.
32 Вне зависимости от того как коилы размещены в памяти.
33 */
35{
36 //---------CHECK FOR ERRORS----------
38 uint16_t *coils;
39 uint16_t start_shift = 0; // shift in coils register
40
41 //------------WRITE COIL-------------
42 Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1);
43 if(Exception == ET_NO_ERRORS)
44 {
45 switch(WriteVal)
46 {
47 case SET_COIL:
48 *coils |= (1<<start_shift);
49 break;
50
51 case RESET_COIL:
52 *coils &= ~(1<<start_shift);
53 break;
54
55 case TOOGLE_COIL:
56 *coils ^= (1<<start_shift);
57 break;
58
59 }
60 }
61 return Exception;
62}
63
64
65/**
66 * @brief Считать коил по глобальному адресу.
67 * @param Addr Адрес коила.
68 * @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
69 * @return uint16_t Возвращает весь регистр с маской на запрошенном коиле.
70 *
71 * @details Позволяет обратиться к любому коилу по его глобальному адрессу.
72 Вне зависимости от того как коилы размещены в памяти.
73 */
74uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
75{
76 //---------CHECK FOR ERRORS----------
77 MB_ExceptionTypeDef Exception_tmp;
78 if(Exception == NULL) // if exception is not given to func fill it
79 Exception = &Exception_tmp;
80
81 uint16_t *coils;
82 uint16_t start_shift = 0; // shift in coils register
83
84 //------------READ COIL--------------
85 *Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0);
86 if(*Exception == ET_NO_ERRORS)
87 {
88 return ((*coils)&(1<<start_shift));
89 }
90 else
91 {
92 return 0;
93 }
94}
95
96
97/**
98 * @brief Обработать функцию Read Coils (01 - 0x01).
99 * @param modbus_msg Указатель на структуру собщения modbus.
100 * @return fMessageHandled Статус о результате обработки комманды.
101 * @details Обработка команды Read Coils.
102 */
104{
105 //---------CHECK FOR ERRORS----------
106 uint16_t *coils;
107 uint16_t start_shift = 0; // shift in coils register
108
109 modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0);
110 if(modbus_msg->Except_Code != ET_NO_ERRORS)
111 return 0;
112
113 //-----------READING COIL------------
114 // setup output message data size
115 modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8);
116 // create mask for coils
117 uint16_t mask_for_coils = 0; // mask for coils that've been chosen
118 uint16_t setted_coils = 0; // value of setted coils
119 uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen
120 uint16_t coil_cnt = 0; // counter for processed coils
121
122 // cycle until all registers with requered coils would be processed
123 int shift = start_shift; // set shift to first coil in first register
124 int ind = 0; // index for coils registers and data
125 for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
126 {
127 //----SET MASK FOR COILS REGISTER----
128 mask_for_coils = 0;
129 for(; shift < 0x10; shift++)
130 {
131 mask_for_coils |= 1<<(shift); // choose certain coil
132 if(++coil_cnt >= modbus_msg->Qnt)
133 break;
134 }
135 shift = 0; // set shift to zero for the next step
136
137 //-----------READ COILS--------------
138 modbus_msg->MbData[ind] = (*(coils+ind)&mask_for_coils) >> start_shift;
139 if(ind > 0)
140 modbus_msg->MbData[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift;
141
142 }
143 // т.к. MbData 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты
144 for(; ind >= 0; --ind)
145 modbus_msg->MbData[ind] = ByteSwap16(modbus_msg->MbData[ind]);
146
147 return 1;
148}
149
150/**
151 * @brief Обработать функцию Write Single Coils (05 - 0x05).
152 * @param modbus_msg Указатель на структуру собщения modbus.
153 * @return fMessageHandled Статус о результате обработки комманды.
154 * @details Обработка команды Write Single Coils.
155 */
157{
158 //---------CHECK FOR ERRORS----------
159 if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
160 {
162 return 0;
163 }
164 // define position of coil
165 uint16_t *coils;
166 uint16_t start_shift = 0; // shift in coils register
167 modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1);
168 if(modbus_msg->Except_Code != ET_NO_ERRORS)
169 return 0;
170
171
172 //----------WRITTING COIL------------
173 if(modbus_msg->Qnt == 0xFF00)
174 *(coils) |= 1<<start_shift; // write flags corresponding to received data
175 else
176 *(coils) &= ~(1<<start_shift); // write flags corresponding to received data
177
178 return 1;
179}
180
181/**
182 * @brief Обработать функцию Write Multiple Coils (15 - 0x0F).
183 * @param modbus_msg Указатель на структуру собщения modbus.
184 * @return fMessageHandled Статус о результате обработки комманды.
185 * @details Обработка команды Write Multiple Coils.
186 */
188{
189 //---------CHECK FOR ERRORS----------
190 if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8))
191 { // if quantity too large OR if quantity and bytes count arent match
193 return 0;
194 }
195 // define position of coil
196 uint16_t *coils; // pointer to coils
197 uint16_t start_shift = 0; // shift in coils register
198 modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1);
199 if(modbus_msg->Except_Code != ET_NO_ERRORS)
200 return 0;
201
202 //----------WRITTING COILS-----------
203 // create mask for coils
204 uint16_t mask_for_coils = 0; // mask for coils that've been chosen
205 uint32_t setted_coils = 0; // value of setted coils
206 uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen
207 uint16_t coil_cnt = 0; // counter for processed coils
208
209 // cycle until all registers with requered coils would be processed
210 int shift = start_shift; // set shift to first coil in first register
211 for(int ind = 0; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
212 {
213 //----SET MASK FOR COILS REGISTER----
214 mask_for_coils = 0;
215 for(; shift < 0x10; shift++)
216 {
217 mask_for_coils |= 1<<(shift); // choose certain coil
218 if(++coil_cnt >= modbus_msg->Qnt)
219 break;
220 }
221 shift = 0; // set shift to zero for the next step
222
223
224
225 //-----------WRITE COILS-------------
226 // get current coils
227 temp_reg = *(coils+ind);
228 // set coils
229 setted_coils = ByteSwap16(modbus_msg->MbData[ind]) << start_shift;
230 if(ind > 0)
231 {
232 setted_coils |= ((ByteSwap16(modbus_msg->MbData[ind-1]) << start_shift) >> 16);
233 }
234 // write coils
235
236 *(coils+ind) = setted_coils & mask_for_coils;
237 // restore untouched coils
238 *(coils+ind) |= temp_reg&(~mask_for_coils);
239
240
241 if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle
242 break; // *kind of unnecessary
243 }
244
245 return 1;
246}
247
248#endif //MODBUS_ENABLE_COILS
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg)
Обработать функцию Read Coils (01 - 0x01).
uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
Обработать функцию Write Multiple Coils (15 - 0x0F).
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
Обработать функцию Write Single Coils (05 - 0x05).
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag)
Define Address Origin for coils.
uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
Считать коил по глобальному адресу.
MB_CoilsOpTypeDef
Enum for coils operation.
MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal)
Выставить/сбросить коил по глобальному адресу.
MB_ExceptionTypeDef
Enum for modbus exception codes.
Definition modbus_core.h:76
@ ET_ILLEGAL_DATA_VALUE
Значение, содержащееся в поле данных запроса, является недопустимой величиной
Definition modbus_core.h:81
@ ET_NO_ERRORS
no errors
Definition modbus_core.h:78
Работа с коилами Modbus.
Structure for modbus messsage.
uint16_t Qnt
Quantity of modbus data.
MB_ExceptionTypeDef Except_Code
Exception Code for the command.
uint8_t ByteCnt
Quantity of bytes of data in message to transmit/receive.
uint16_t MbData[DATA_SIZE]
Modbus Data.
uint16_t Addr
Modbus Address of data.