├── Cfg └── Template │ ├── mb_cfg.h │ └── mb_data.c ├── LICENSE ├── NOTICE ├── OS ├── None │ ├── mb_os.c │ └── mb_os.h ├── uCOS-II │ ├── mb_os.c │ └── mb_os.h └── uCOS-III │ ├── mb_os.c │ └── mb_os.h ├── Ports ├── ARM7 │ ├── LH79520 │ │ └── IAR │ │ │ └── mb_bsp.c │ └── LPC2000 │ │ └── IAR │ │ └── mb_bsp.c ├── ARM9 │ ├── AT91SAM9261 │ │ ├── mb_bsp.c │ │ └── mb_bsp.h │ ├── AT91SAM9263 │ │ ├── mb_bsp.c │ │ └── mb_bsp.h │ └── AT91SAM9XE │ │ ├── mb_bsp.c │ │ └── mb_bsp.h ├── Atmel │ └── AVR32UC3A │ │ ├── mb_bsp.c │ │ └── mb_bsp.h └── Freescale │ └── MC9S12C32 │ └── Metrowerks │ └── mb_bsp.c ├── Source ├── mb.c ├── mb.h ├── mb_def.h ├── mb_util.c ├── mbm_core.c └── mbs_core.c └── readme.md /Cfg/Template/mb_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * MODBUS CONFIGURATION 20 | * 21 | * Filename : mb_cfg.h 22 | * Version : V2.14.00 23 | ********************************************************************************************************* 24 | * Note(s) : (1) This file contains configuration constants for uC/Modbus 25 | ********************************************************************************************************* 26 | */ 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * MODBUS MODULES CONFIGURATION 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #define MODBUS_CFG_SLAVE_EN DEF_ENABLED /* Enable or Disable Modbus Slave */ 35 | #define MODBUS_CFG_MASTER_EN DEF_DISABLED /* Enable or Disable Modbus Master */ 36 | 37 | /* 38 | ********************************************************************************************************* 39 | * MODBUS MODES CONFIGURATION 40 | ********************************************************************************************************* 41 | */ 42 | 43 | #define MODBUS_CFG_ASCII_EN DEF_ENABLED /* Modbus ASCII is supported when DEF_ENABLED */ 44 | #define MODBUS_CFG_RTU_EN DEF_ENABLED /* Modbus RTU is supported when DEF_ENABLED */ 45 | 46 | /* 47 | ********************************************************************************************************* 48 | * MODBUS COMMUNICATION CONFIGURATION 49 | ********************************************************************************************************* 50 | */ 51 | 52 | #define MODBUS_CFG_MAX_CH 10 /* Maximum number of Modbus channels. */ 53 | 54 | #define MODBUS_CFG_BUF_SIZE 255 /* Maximum outgoing message size. */ 55 | 56 | /* 57 | ********************************************************************************************************* 58 | * MODBUS FLOATING POINT SUPPORT 59 | ********************************************************************************************************* 60 | */ 61 | 62 | #define MODBUS_CFG_FP_EN DEF_ENABLED /* Enable Floating-Point support. */ 63 | 64 | #if (MODBUS_CFG_FP_EN == DEF_ENABLED) 65 | #define MODBUS_CFG_FP_START_IX 5000 /* Start address of Floating-Point registers */ 66 | #else 67 | #define MODBUS_CFG_FP_START_IX 65500 /* Floating point is disabled, set start of ... */ 68 | /* ...FP very high */ 69 | #endif 70 | 71 | 72 | /* 73 | ********************************************************************************************************* 74 | * MODBUS FUNCTIONS CONFIGURATION 75 | ********************************************************************************************************* 76 | */ 77 | 78 | #define MODBUS_CFG_FC01_EN DEF_ENABLED /* Enable or Disable support for Modbus functions */ 79 | #define MODBUS_CFG_FC02_EN DEF_ENABLED 80 | #define MODBUS_CFG_FC03_EN DEF_ENABLED 81 | #define MODBUS_CFG_FC04_EN DEF_ENABLED 82 | #define MODBUS_CFG_FC05_EN DEF_ENABLED 83 | #define MODBUS_CFG_FC06_EN DEF_ENABLED 84 | #define MODBUS_CFG_FC08_EN DEF_ENABLED 85 | #define MODBUS_CFG_FC15_EN DEF_ENABLED 86 | #define MODBUS_CFG_FC16_EN DEF_ENABLED 87 | #define MODBUS_CFG_FC20_EN DEF_DISABLED 88 | #define MODBUS_CFG_FC21_EN DEF_DISABLED -------------------------------------------------------------------------------- /Cfg/Template/mb_data.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * uC/MODBUS TARGET SPECIFIC DATA ACCESS FUNCTIONS (Template) 20 | * 21 | * Filename : mb_data.c 22 | * Version : V2.14.00 23 | ********************************************************************************************************* 24 | * Note(s) : 25 | ********************************************************************************************************* 26 | */ 27 | 28 | 29 | #include 30 | 31 | /* 32 | ********************************************************************************************************* 33 | * GET THE VALUE OF A SINGLE COIL 34 | * 35 | * Description: This function returns the value of a single coil. 36 | * It is called by 'MBS_FC01_CoilRd()'. 37 | * You must 'map' the 'coil' to the actual application's coil. 38 | * 39 | * Arguments : coil is the coil number that is being requested. 40 | * 41 | * perr is a pointer to an error code variable. You must either return: 42 | * 43 | * MODBUS_ERR_NONE the specified coil is valid and you are returning its value. 44 | * MODBUS_ERR_RANGE the specified coil is an invalid coil number in your 45 | * application (i.e. product). YOUR product defines what the 46 | * valid range of values is for the 'coil' argument. 47 | * 48 | * Note(s) : 1) You can perform the mapping of coil number to application coils directly in this 49 | * function or via a table lookup. A table lookup would make sense if you had a lot of 50 | * coils in your product. 51 | ********************************************************************************************************* 52 | */ 53 | 54 | #if (MODBUS_CFG_FC01_EN == DEF_ENABLED) 55 | CPU_BOOLEAN MB_CoilRd (CPU_INT16U coil, 56 | CPU_INT16U *perr) 57 | { 58 | CPU_BOOLEAN coil_val; 59 | 60 | switch (coil) { 61 | case 0: 62 | coil_val = DEF_TRUE; 63 | break; 64 | 65 | case 1: 66 | coil_val = DEF_FALSE; 67 | break; 68 | 69 | case 2: 70 | coil_val = DEF_TRUE; 71 | break; 72 | 73 | default: 74 | case 3: 75 | coil_val = DEF_FALSE; 76 | break; 77 | } 78 | 79 | *perr = MODBUS_ERR_NONE; 80 | return (coil_val); 81 | } 82 | #endif 83 | 84 | /* 85 | ********************************************************************************************************* 86 | * SET THE VALUE OF A SINGLE COIL 87 | * 88 | * Description: This function changes the value of a single coil. 89 | * It is called by 'MBS_FC05_CoilWr()' and 'MBS_FC15_CoilWrMultiple()'. 90 | * You must 'map' the 'coil' to the actual application's coil. 91 | * 92 | * Arguments : coil is the coil number that needs to be changed. 93 | * 94 | * coil_val is the desired value of the coil. This value can be either DEF_TRUE or DEF_FALSE with 95 | * DEF_TRUE indicating an energized coil. 96 | * 97 | * perr is a pointer to an error code variable. You must either return: 98 | * 99 | * MODBUS_ERR_NONE the specified coil is valid and your code changed the value 100 | * of the coil. 101 | * MODBUS_ERR_RANGE the specified coil is an invalid coil number in your 102 | * application (i.e. product). YOUR product defines what the 103 | * valid range of values is for the 'coil' argument. 104 | * MODBUS_ERR_WR if the device is not able to write or accept the value 105 | * 106 | * Note(s) : 1) You can perform the mapping of coil number to application coils directly in this 107 | * function or via a table lookup. A table lookup would make sense if you had a lot of 108 | * coils in your product. 109 | ********************************************************************************************************* 110 | */ 111 | 112 | #if (MODBUS_CFG_FC05_EN == DEF_ENABLED) || \ 113 | (MODBUS_CFG_FC15_EN == DEF_ENABLED) 114 | void MB_CoilWr (CPU_INT16U coil, 115 | CPU_BOOLEAN coil_val, 116 | CPU_INT16U *perr) 117 | { 118 | (void)coil; 119 | (void)coil_val; 120 | *perr = MODBUS_ERR_NONE; 121 | } 122 | #endif 123 | 124 | /* 125 | ********************************************************************************************************* 126 | * GET THE VALUE OF A SINGLE DISCRETE INPUT 127 | * 128 | * Description: This function reads the value of a single DI (DI means Discrete Input). 129 | * It is called by 'MBS_FC02_DIRd()'. 130 | * You must 'map' the 'di' to the actual application's DI. 131 | * 132 | * Arguments : di is the Discrete Input number that needs to be read. 133 | * 134 | * perr is a pointer to an error code variable. You must either return: 135 | * 136 | * MODBUS_ERR_NONE the specified DI is valid and your code is returning its 137 | * current value. 138 | * MODBUS_ERR_RANGE the specified DI is an invalid Discrete Input number in your 139 | * application (i.e. product). YOUR product defines what the 140 | * valid range of values is for the 'di' argument. 141 | * 142 | * Note(s) : 1) You can perform the mapping of DI number to the application DIs directly in this function 143 | * or via a table lookup. A table lookup would make sense if you had a lot of Discrete 144 | * Inputs in your product. 145 | ********************************************************************************************************* 146 | */ 147 | 148 | #if (MODBUS_CFG_FC02_EN == DEF_ENABLED) 149 | CPU_BOOLEAN MB_DIRd (CPU_INT16U di, 150 | CPU_INT16U *perr) 151 | { 152 | (void)di; 153 | *perr = MODBUS_ERR_NONE; 154 | return (DEF_FALSE); 155 | } 156 | #endif 157 | 158 | /* 159 | ********************************************************************************************************* 160 | * GET THE VALUE OF A SINGLE INPUT REGISTER 161 | * 162 | * Description: This function reads the value of a single Input Register. 163 | * It is called by 'MBS_FC04_InRegRd()' when the argument 'reg' is BELOW the value set by 164 | * the configuration constant MODBUS_CFG_FP_START_IX (see MB_CFG.H). 165 | * You must 'map' the Input Register to the actual application's corresponding integer register. 166 | * 167 | * Arguments : reg is the Input Register number that needs to be read. 168 | * 169 | * perr is a pointer to an error code variable. You must either return: 170 | * 171 | * MODBUS_ERR_NONE the specified input register is valid and your code is 172 | * returning its current value. 173 | * MODBUS_ERR_RANGE the specified input register is an invalid number in your 174 | * application (i.e. product). YOUR product defines what the 175 | * valid range of values is for the 'reg' argument. 176 | * 177 | * Note(s) : 1) You can perform the mapping of input register number to the application's input registers 178 | * directly in this function or via a table lookup. A table lookup would make sense if you 179 | * had a lot of Input Registers in your product. 180 | * 2) If your product doesn't have input registers, you could simply set '*err' to 181 | * MODBUS_ERR_NONE and return 0. 182 | ********************************************************************************************************* 183 | */ 184 | 185 | #if (MODBUS_CFG_FC04_EN == DEF_ENABLED) 186 | CPU_INT16U MB_InRegRd (CPU_INT16U reg, 187 | CPU_INT16U *perr) 188 | { 189 | CPU_INT16U val; 190 | CPU_SR cpu_sr; 191 | 192 | 193 | switch (reg) { 194 | case 10: 195 | CPU_CRITICAL_ENTER(); 196 | val = (CPU_INT16U)OSCPUUsage; 197 | CPU_CRITICAL_EXIT(); 198 | break; 199 | 200 | case 11: 201 | CPU_CRITICAL_ENTER(); 202 | val = (CPU_INT16U)OSCtxSwCtr; 203 | CPU_CRITICAL_EXIT(); 204 | break; 205 | 206 | case 12: 207 | CPU_CRITICAL_ENTER(); 208 | val = (CPU_INT16U)(OSTime >> 16); 209 | CPU_CRITICAL_EXIT(); 210 | break; 211 | 212 | case 13: 213 | CPU_CRITICAL_ENTER(); 214 | val = (CPU_INT16U)(OSTime & 0x0000FFFF); 215 | CPU_CRITICAL_EXIT(); 216 | break; 217 | 218 | case 14: 219 | CPU_CRITICAL_ENTER(); 220 | val = (CPU_INT16U)MB_ChSize; 221 | CPU_CRITICAL_EXIT(); 222 | break; 223 | 224 | case 15: 225 | CPU_CRITICAL_ENTER(); 226 | val = (CPU_INT16U)(MB_TotalRAMSize & 0x0000FFFF); 227 | CPU_CRITICAL_EXIT(); 228 | break; 229 | 230 | default: 231 | val = 0; 232 | break; 233 | } 234 | *perr = MODBUS_ERR_NONE; 235 | return (val); 236 | } 237 | #endif 238 | 239 | /* 240 | ********************************************************************************************************* 241 | * GET THE VALUE OF A SINGLE 'FLOATING-POINT' INPUT REGISTER 242 | * 243 | * Description: This function reads the value of a single Input Register. 244 | * It is called by 'MBS_FC04_InRegRd()' when the argument 'reg' is ABOVE or equal to the 245 | * value set the configuration constant MODBUS_CFG_FP_START_IX (see MB_CFG.H). 246 | * You must 'map' the Input Register to the actual application's corresponding floating-point 247 | * register. 248 | * 249 | * Arguments : reg is the Input Register number that needs to be read. 250 | * 251 | * perr is a pointer to an error code variable. You must either return: 252 | * 253 | * MODBUS_ERR_NONE the specified input register is valid and your code is 254 | * returning its current value. 255 | * MODBUS_ERR_RANGE the specified input register is an invalid number in your 256 | * application (i.e. product). YOUR product defines what the 257 | * valid range of values is for the 'reg' argument. 258 | * 259 | * Note(s) : 1) You can perform the mapping of input register number to the application's input registers 260 | * directly in this function or via a table lookup. A table lookup would make sense if you 261 | * had a lot of Input Registers in your product. 262 | * 2) If your product doesn't have input registers, you could simply set '*err' to 263 | * MODBUS_ERR_NONE and return (CPU_FP32)0. 264 | ********************************************************************************************************* 265 | */ 266 | 267 | #if (MODBUS_CFG_FP_EN == DEF_ENABLED) 268 | #if (MODBUS_CFG_FC04_EN == DEF_ENABLED) 269 | CPU_FP32 MB_InRegRdFP (CPU_INT16U reg, 270 | CPU_INT16U *perr) 271 | { 272 | (void)reg; 273 | *perr = MODBUS_ERR_NONE; 274 | return ((CPU_FP32)0); 275 | } 276 | #endif 277 | #endif 278 | 279 | /* 280 | ********************************************************************************************************* 281 | * GET THE VALUE OF A SINGLE HOLDING REGISTER 282 | * 283 | * Description: This function reads the value of a single Holding Register. 284 | * It is called by 'MBS_FC03_HoldingRegRd()' when the argument 'reg' is BELOW the value set 285 | * by the configuration constant MODBUS_CFG_FP_START_IX (see MB_CFG.H). 286 | * You must 'map' the Holding Register to the actual application's corresponding integer register. 287 | * 288 | * Arguments : reg is the Holding Register number that needs to be read. 289 | * 290 | * perr is a pointer to an error code variable. You must either return: 291 | * 292 | * MODBUS_ERR_NONE the specified holding register is valid and your code is 293 | * returning its current value. 294 | * MODBUS_ERR_RANGE the specified holding register is an invalid number in your 295 | * application (i.e. product). YOUR product defines what the 296 | * valid range of values is for the 'reg' argument. 297 | * 298 | * Note(s) : 1) You can perform the mapping of holding register number to the application's holding 299 | * registers directly in this function or via a table lookup. A table lookup would make 300 | * sense if you had a lot of Holding Registers in your product. 301 | * 2) If your product doesn't have holding registers, you could simply set '*err' to 302 | * MODBUS_ERR_NONE and return 0. 303 | ********************************************************************************************************* 304 | */ 305 | 306 | #if (MODBUS_CFG_FC03_EN == DEF_ENABLED) 307 | CPU_INT16U MB_HoldingRegRd (CPU_INT16U reg, 308 | CPU_INT16U *perr) 309 | { 310 | CPU_INT16U val; 311 | CPU_SR cpu_sr; 312 | 313 | 314 | switch (reg) { 315 | case 0: 316 | CPU_CRITICAL_ENTER(); 317 | val = (CPU_INT16U)OSCPUUsage; 318 | CPU_CRITICAL_EXIT(); 319 | break; 320 | 321 | case 1: 322 | CPU_CRITICAL_ENTER(); 323 | val = (CPU_INT16U)OSCtxSwCtr; 324 | CPU_CRITICAL_EXIT(); 325 | break; 326 | 327 | case 2: 328 | CPU_CRITICAL_ENTER(); 329 | val = (CPU_INT16U)(OSTime >> 16); 330 | CPU_CRITICAL_EXIT(); 331 | break; 332 | 333 | case 3: 334 | CPU_CRITICAL_ENTER(); 335 | val = (CPU_INT16U)(OSTime & 0x0000FFFF); 336 | CPU_CRITICAL_EXIT(); 337 | break; 338 | 339 | case 4: 340 | CPU_CRITICAL_ENTER(); 341 | val = (CPU_INT16U)MB_ChSize; 342 | CPU_CRITICAL_EXIT(); 343 | break; 344 | 345 | case 5: 346 | CPU_CRITICAL_ENTER(); 347 | val = (CPU_INT16U)(MB_TotalRAMSize & 0x0000FFFF); 348 | CPU_CRITICAL_EXIT(); 349 | break; 350 | 351 | case 6: 352 | CPU_CRITICAL_ENTER(); 353 | val = (CPU_INT16U)((MB_ChTbl[0].RxCtr / 1000) & 0x0000FFFF); 354 | CPU_CRITICAL_EXIT(); 355 | break; 356 | 357 | case 7: 358 | CPU_CRITICAL_ENTER(); 359 | val = (CPU_INT16U)((MB_ChTbl[0].RxCtr % 1000) & 0x0000FFFF); 360 | CPU_CRITICAL_EXIT(); 361 | break; 362 | 363 | case 8: 364 | CPU_CRITICAL_ENTER(); 365 | val = (CPU_INT16U)((MB_ChTbl[0].TxCtr / 1000) & 0x0000FFFF); 366 | CPU_CRITICAL_EXIT(); 367 | break; 368 | 369 | case 9: 370 | CPU_CRITICAL_ENTER(); 371 | val = (CPU_INT16U)((MB_ChTbl[0].TxCtr % 1000) & 0x0000FFFF); 372 | CPU_CRITICAL_EXIT(); 373 | break; 374 | 375 | default: 376 | val = 0; 377 | break; 378 | } 379 | *perr = MODBUS_ERR_NONE; 380 | return (val); 381 | } 382 | #endif 383 | 384 | /* 385 | ********************************************************************************************************* 386 | * GET THE VALUE OF A SINGLE 'FLOATING-POINT' HOLDING REGISTER 387 | * 388 | * Description: This function reads the value of a single Floating-Point Holding Register. 389 | * It is called by 'MBS_FC03_HoldingRegRd()' when the argument 'reg' is ABOVE or equal to the 390 | * value set by the configuration constant MODBUS_CFG_FP_START_IX (see MB_CFG.H). 391 | * You must 'map' the Holding Register to the actual application's corresponding floating-point 392 | * register. 393 | * 394 | * Arguments : reg is the Holding Register number that needs to be read. 395 | * 396 | * perr is a pointer to an error code variable. You must either return: 397 | * 398 | * MODBUS_ERR_NONE the specified holding register is valid and your code is 399 | * returning its current value. 400 | * MODBUS_ERR_RANGE the specified holding register is an invalid number in your 401 | * application (i.e. product). YOUR product defines what the 402 | * valid range of values is for the 'reg' argument. 403 | * 404 | * Note(s) : 1) You can perform the mapping of holding register number to the application's holding 405 | * registers directly in this function or via a table lookup. A table lookup would make 406 | * sense if you had a lot of Holding Registers in your product. 407 | * 2) If your product doesn't have holding registers, you could simply set '*err' to 408 | * MODBUS_ERR_NONE and return 0. 409 | ********************************************************************************************************* 410 | */ 411 | 412 | #if (MODBUS_CFG_FP_EN == DEF_ENABLED) 413 | #if (MODBUS_CFG_FC03_EN == DEF_ENABLED) 414 | CPU_FP32 MB_HoldingRegRdFP (CPU_INT16U reg, 415 | CPU_INT16U *perr) 416 | { 417 | (void)reg; 418 | *perr = MODBUS_ERR_NONE; 419 | return ((CPU_FP32)0); 420 | } 421 | #endif 422 | #endif 423 | 424 | /* 425 | ********************************************************************************************************* 426 | * SET THE VALUE OF A SINGLE HOLDING REGISTER 427 | * 428 | * Description: This function is called to change the value of a single Integer Holding Register. 429 | * It is called by 'MBS_FC06_HoldingRegWr()' and 'MBS_FC16_HoldingRegWrMultiple()' when the argument 430 | * 'reg' is BELOW to the value set by the configuration constant MODBUS_CFG_FP_START_IX (see MB_CFG.H). 431 | * You must 'map' the Holding Register to the actual application's corresponding integer register. 432 | * 433 | * Arguments : reg is the Holding Register number that needs to be read. 434 | * 435 | * reg_val is the desired value of the holding register. 436 | * The value is specified as an unsigned integer even though it could actually be 437 | * represented by a signed integer. 438 | * 439 | * perr is a pointer to an error code variable. You must either return: 440 | * 441 | * MODBUS_ERR_NONE the specified holding register is valid and your code is 442 | * returning its current value. 443 | * MODBUS_ERR_RANGE the specified holding register is an invalid number in your 444 | * application (i.e. product). YOUR product defines what the 445 | * valid range of values is for the 'reg' argument. 446 | * MODBUS_ERR_WR if the device is not able to write or accept the value 447 | * 448 | * Note(s) : 1) You can perform the mapping of holding register number to the application's holding 449 | * registers directly in this function or via a table lookup. A table lookup would make 450 | * sense if you had a lot of Holding Registers in your product. 451 | * 2) If your product doesn't have holding registers, you could simply set '*err' to 452 | * MODBUS_ERR_NONE and return 0. 453 | ********************************************************************************************************* 454 | */ 455 | 456 | #if (MODBUS_CFG_FC06_EN == DEF_ENABLED) || \ 457 | (MODBUS_CFG_FC16_EN == DEF_ENABLED) 458 | void MB_HoldingRegWr (CPU_INT16U reg, 459 | CPU_INT16U reg_val_16, 460 | CPU_INT16U *perr) 461 | { 462 | /* Access to your variable here! */ 463 | (void)reg; 464 | (void)reg_val_16; 465 | *perr = MODBUS_ERR_NONE; 466 | } 467 | #endif 468 | 469 | /* 470 | ********************************************************************************************************* 471 | * SET THE VALUE OF A SINGLE 'FLOATING-POINT' HOLDING REGISTER 472 | * 473 | * Description: This function is called to change the value of a single Floating-Point Holding Register. 474 | * It is called by 'MBS_FC06_HoldingRegWr()' and 'MBS_FC16_HoldingRegWrMultiple()' when the argument 475 | * 'reg' is ABOVE or equal to the value set by the configuration constant MODBUS_CFG_FP_START_IX 476 | * (see MB_CFG.H). 477 | * You must 'map' the Holding Register to the actual application's corresponding floating-point 478 | * register. 479 | * 480 | * Arguments : reg is the Holding Register number that needs to be read. 481 | * 482 | * reg_val is the desired value of the holding register. 483 | * The value is specified as an unsigned integer even though it could actually be 484 | * represented by a signed integer. 485 | * 486 | * perr is a pointer to an error code variable. You must either return: 487 | * 488 | * MODBUS_ERR_NONE the specified holding register is valid and your code is 489 | * returning its current value. 490 | * MODBUS_ERR_RANGE the specified holding register is an invalid number in your 491 | * application (i.e. product). YOUR product defines what the 492 | * valid range of values is for the 'reg' argument. 493 | * MODBUS_ERR_WR if the device is not able to write or accept the value 494 | * 495 | * Note(s) : 1) You can perform the mapping of holding register number to the application's holding 496 | * registers directly in this function or via a table lookup. A table lookup would make 497 | * sense if you had a lot of Holding Registers in your product. 498 | * 2) If your product doesn't have holding registers, you could simply set '*err' to 499 | * MODBUS_ERR_NONE and return 0. 500 | ********************************************************************************************************* 501 | */ 502 | 503 | #if (MODBUS_CFG_FP_EN == DEF_ENABLED) 504 | #if (MODBUS_CFG_FC06_EN == DEF_ENABLED) || \ 505 | (MODBUS_CFG_FC16_EN == DEF_ENABLED) 506 | void MB_HoldingRegWrFP (CPU_INT16U reg, 507 | CPU_FP32 reg_val_fp, 508 | CPU_INT16U *perr) 509 | { 510 | (void)reg; 511 | (void)reg_val_fp; 512 | *perr = MODBUS_ERR_RANGE; 513 | } 514 | #endif 515 | #endif 516 | 517 | /* 518 | ********************************************************************************************************* 519 | * GET A SINGLE ENTRY FROM A RECORD IN A FILE 520 | * 521 | * Description: This function is called to read a single integer from a file. 522 | * As mentionned in the Modbus specifications, a file is an organization of records. 523 | * Each file can contain up to 10,000 records (addressed from 0 to 9999). 524 | * You must 'map' the File/Record/Ix to the actual application's corresponding data. 525 | * 526 | * Arguments : file_nbr is the number of the desired file. 527 | * 528 | * record_nbr is the desired record within the file 529 | * 530 | * ix is the desired entry in the specified record. 531 | * 532 | * record_len is the desired length of the record. Note that this parameter is passed to 533 | * this function to provide the 'requested' requested length from the MODBUS command. 534 | * 535 | * perr is a pointer to an error code variable. You must either return: 536 | * 537 | * MODBUS_ERR_NONE the specified file/record/entry is valid and your code is 538 | * returning its current value. 539 | * MODBUS_ERR_FILE if the specified 'file_nbr' is not a valid file number in 540 | * your product. 541 | * MODBUS_ERR_RECORD if the specified 'record_nbr' is not a valid record in the 542 | * specified file. 543 | * MODBUS_ERR_IX if the specified 'ix' is not a valid index into the specified 544 | * record. 545 | * 546 | * Note(s) : 1) You can perform the mapping of file/record/ix to the application's data directly in 547 | * this function or via a table lookup. A table lookup would make sense if you had a lot 548 | * data in your files. 549 | ********************************************************************************************************* 550 | */ 551 | 552 | #if (MODBUS_CFG_FC20_EN == DEF_ENABLED) 553 | CPU_INT16U MB_FileRd (CPU_INT16U file_nbr, 554 | CPU_INT16U record_nbr, 555 | CPU_INT16U ix, 556 | CPU_INT08U record_len, 557 | CPU_INT16U *perr) 558 | { 559 | (void)file_nbr; 560 | (void)record_nbr; 561 | (void)ix; 562 | (void)record_len; 563 | *perr = MODBUS_ERR_NONE; 564 | return (0); 565 | } 566 | #endif 567 | 568 | /* 569 | ********************************************************************************************************* 570 | * SET A SINGLE ENTRY OF A RECORD IN A FILE 571 | * 572 | * Description: This function is called to change a single integer value in a file. 573 | * As mentionned in the Modbus specifications, a file is an organization of records. 574 | * Each file can contain up to 10,000 records (addressed from 0 to 9999). 575 | * You must 'map' the File/Record/Ix to the actual application's corresponding data. 576 | * 577 | * Arguments : file_nbr is the number of the desired file. 578 | * 579 | * record_nbr is the desired record within the file 580 | * 581 | * ix is the desired entry in the specified record. 582 | * 583 | * record_len is the desired length of the record. Note that this parameter is passed to 584 | * this function to provide the 'requested' requested length from the MODBUS command. 585 | * 586 | * val is the new value to place in the file. 587 | * 588 | * perr is a pointer to an error code variable. You must either return: 589 | * 590 | * MODBUS_ERR_NONE the specified file/record/entry is valid and your code is 591 | * returning its current value. 592 | * MODBUS_ERR_FILE if the specified 'file_nbr' is not a valid file number in 593 | * your product. 594 | * MODBUS_ERR_RECORD if the specified 'record_nbr' is not a valid record in the 595 | * specified file. 596 | * MODBUS_ERR_IX if the specified 'ix' is not a valid index into the specified 597 | * record. 598 | * 599 | * Note(s) : 1) You can perform the mapping of file/record/ix to the application's data directly in 600 | * this function or via a table lookup. A table lookup would make sense if you had a lot 601 | * data in your files. 602 | ********************************************************************************************************* 603 | */ 604 | 605 | #if (MODBUS_CFG_FC21_EN == DEF_ENABLED) 606 | void MB_FileWr (CPU_INT16U file_nbr, 607 | CPU_INT16U record_nbr, 608 | CPU_INT16U ix, 609 | CPU_INT08U record_len, 610 | CPU_INT16U val, 611 | CPU_INT16U *perr) 612 | { 613 | (void)file_nbr; 614 | (void)record_nbr; 615 | (void)ix; 616 | (void)record_len; 617 | (void)val; 618 | *perr = MODBUS_ERR_NONE; 619 | } 620 | #endif 621 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | ATTENTION ALL USERS OF THIS REPOSITORY: 2 | 3 | The original work found in this repository is provided by Silicon Labs under the 4 | Apache License, Version 2.0. 5 | 6 | Any third party may contribute derivative works to the original work in which 7 | modifications are clearly identified as being licensed under: 8 | 9 | (1) the Apache License, Version 2.0 or a compatible open source license; or 10 | (2) under a proprietary license with a copy of such license deposited. 11 | 12 | All posted derivative works must clearly identify which license choice has been 13 | elected. 14 | 15 | No such posted derivative works will be considered to be a “Contribution” under 16 | the Apache License, Version 2.0. 17 | 18 | SILICON LABS MAKES NO WARRANTY WITH RESPECT TO ALL POSTED THIRD PARTY CONTENT 19 | AND DISCLAIMS ALL OTHER WARRANTIES OR LIABILITIES, INCLUDING ALL WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OWNERSHIP, 21 | NON-INFRINGEMENT, AND NON-MISAPPROPRIATION. 22 | 23 | In the event a derivative work is desired to be submitted to Silicon Labs as a 24 | “Contribution” under the Apache License, Version 2.0, a “Contributor” must give 25 | written email notice to micrium@weston-embedded.com. Unless an email response in 26 | the affirmative to accept the derivative work as a “Contribution”, such email 27 | submission should be considered to have not been incorporated into the original 28 | work. 29 | -------------------------------------------------------------------------------- /OS/None/mb_os.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * MODBUS NO-OS LAYER INTERFACE 21 | * 22 | * Filename : mb_os.c 23 | * Version : V2.14.00 24 | ********************************************************************************************************* 25 | */ 26 | 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * INCLUDE FILES 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #define MB_OS_MODULE 35 | #include 36 | 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * LOCAL DEFINES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | #define MB_OS_ERR_NONE 0x00u 45 | #define MB_OS_ERR_Q_FULL 0x01u 46 | #define MB_OS_ERR_Q_EMPTY 0x03u 47 | #define MB_OS_ERR_TIMEOUT 0x02u 48 | 49 | 50 | /* 51 | ********************************************************************************************************* 52 | * LOCAL CONSTANTS 53 | ********************************************************************************************************* 54 | */ 55 | 56 | 57 | /* 58 | ********************************************************************************************************* 59 | * LOCAL DATA TYPES 60 | ********************************************************************************************************* 61 | */ 62 | 63 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 64 | typedef struct mb_os_q { 65 | MODBUS_CH **OS_Q_StoPtr; /* Queue storage pointer */ 66 | CPU_INT08U OS_Q_Entries; /* Queue current number of entries */ 67 | CPU_INT08U OS_Q_MaxEntries; /* Queue max number of entries */ 68 | CPU_INT08U OS_Q_FirstEntry; /* Queue first entry index */ 69 | CPU_INT08U OS_Q_LastEntry; /* Queue last entry index */ 70 | } MB_OS_Q; 71 | #endif 72 | 73 | 74 | /* 75 | ********************************************************************************************************* 76 | * LOCAL TABLES 77 | ********************************************************************************************************* 78 | */ 79 | 80 | 81 | /* 82 | ********************************************************************************************************* 83 | * LOCAL GLOBAL VARIABLES 84 | ********************************************************************************************************* 85 | */ 86 | 87 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 88 | static MB_OS_Q MB_OS_RxQ; 89 | static MODBUS_CH *MB_OS_RxQ_Tbl[MODBUS_CFG_MAX_CH]; 90 | #endif 91 | 92 | 93 | /* 94 | ********************************************************************************************************* 95 | * LOCAL FUNCTION PROTOTYPES 96 | ********************************************************************************************************* 97 | */ 98 | 99 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 100 | /* Queue functions */ 101 | static void MB_OS_Q_Create (MB_OS_Q *p_q, 102 | MODBUS_CH **p_sto, 103 | CPU_INT08U max_entries); 104 | 105 | static MODBUS_CH *MB_OS_Q_Pend (MB_OS_Q *p_q); 106 | 107 | static CPU_INT08U MB_OS_Q_Post (MB_OS_Q *p_q, 108 | MODBUS_CH *p_msg); 109 | 110 | static void MB_OS_InitSlave(void); 111 | #endif 112 | 113 | 114 | /* 115 | ********************************************************************************************************* 116 | * LOCAL CONFIGURATION ERRORS 117 | ********************************************************************************************************* 118 | */ 119 | 120 | 121 | /* 122 | ********************************************************************************************************* 123 | * MB_OS_Init() 124 | * 125 | * Description : This function initializes the NON OS interface. This function creates the following: 126 | * 127 | * (1) A queue structure that contains the pointer to the channel(s) wher a message needs to be processed. (Modbus Slave) 128 | * 129 | * Argument(s) : none. 130 | * 131 | * Return(s) : none. 132 | * 133 | * Caller(s) : MB_Init() 134 | * 135 | * Note(s) : none. 136 | ********************************************************************************************************* 137 | */ 138 | 139 | void MB_OS_Init (void) 140 | { 141 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 142 | MB_OS_InitSlave(); 143 | #endif 144 | } 145 | 146 | 147 | /* 148 | ********************************************************************************************************* 149 | * MB_OS_InitSlave() 150 | * 151 | * Description : This function create a queue structure for income Rx messages. (Modbus Slave) 152 | * 153 | * Argument(s) : none. 154 | * 155 | * Return(s) : none. 156 | * 157 | * Caller(s) : MB_OS_Init() 158 | * 159 | * Note(s) : none. 160 | ********************************************************************************************************* 161 | */ 162 | 163 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 164 | static void MB_OS_InitSlave (void) 165 | { 166 | MB_OS_Q_Create(&MB_OS_RxQ, &MB_OS_RxQ_Tbl[0], MODBUS_CFG_MAX_CH); 167 | } 168 | #endif 169 | 170 | 171 | /* 172 | ********************************************************************************************************* 173 | * MB_OS_Exit() 174 | * 175 | * Description : This function is called to terminate the RTOS interface for Modbus channels. 176 | * 177 | * No action is performed for the no-OS layer. 178 | * 179 | * Argument(s) : none. 180 | * 181 | * Return(s) : none. 182 | * 183 | * Caller(s) : MB_Exit(). 184 | * 185 | * Note(s) : none. 186 | ********************************************************************************************************* 187 | */ 188 | 189 | void MB_OS_Exit (void) 190 | { 191 | 192 | } 193 | 194 | 195 | /* 196 | ********************************************************************************************************* 197 | * MB_OS_RxSignal() 198 | * 199 | * Description : This function signals the reception of a packet either from the Rx ISR(s) or the RTU timeout 200 | * timer(s) to indicate that a received packet needs to be processed. 201 | * 202 | * Argument(s) : pch specifies the Modbus channel data structure in which a packet was received. 203 | * 204 | * Return(s) : none. 205 | * 206 | * Caller(s) : MB_ASCII_RxByte(), 207 | * MB_RTU_TmrUpdate(). 208 | * 209 | * Note(s) : none. 210 | ********************************************************************************************************* 211 | */ 212 | 213 | void MB_OS_RxSignal (MODBUS_CH *pch) 214 | { 215 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 216 | if (pch != (MODBUS_CH *)0) { 217 | MB_OS_Q_Post(&MB_OS_RxQ, 218 | pch); 219 | } 220 | #endif 221 | } 222 | 223 | /* 224 | ********************************************************************************************************* 225 | * MB_OS_RxTask() 226 | * 227 | * Description : This functions needs to be called frequently by the application to poll if a Rx has been 228 | * received. 229 | * 230 | * Argument(s) : none. 231 | * 232 | * Return(s) : none. 233 | * 234 | * Caller(s) : Application. 235 | * 236 | * Note(s) : (1) MB_OS_RxTask() checks whether there is an Rx message in the queue; if there is not, 237 | this function will return immediately. 238 | ********************************************************************************************************* 239 | */ 240 | 241 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 242 | void MB_OS_RxTask (void) 243 | { 244 | MODBUS_CH *p_ch; 245 | 246 | 247 | p_ch = (MODBUS_CH *)MB_OS_Q_Pend(&MB_OS_RxQ); /* Wait for a Rx packet */ 248 | 249 | if (p_ch == (MODBUS_CH *)0) { 250 | return; 251 | } 252 | 253 | MB_RxTask(p_ch); /* Process the packet received */ 254 | 255 | } 256 | #endif 257 | 258 | /* 259 | ********************************************************************************************************* 260 | * MB_OS_SemCreate() 261 | * 262 | * Description : This function creates a semaphore. 263 | * 264 | * Argument(s) : p_sem Pointer to the semaphore. 265 | * 266 | * cnt Initial value of the semaphore 267 | * 268 | * Return(s) : none. 269 | * 270 | * Caller(s) : MB_OS_InitMaster() 271 | * 272 | * Return(s) : none. 273 | ********************************************************************************************************* 274 | */ 275 | 276 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 277 | static void MB_OS_SemCreate (MB_OS_SEM *p_sem, 278 | CPU_INT32U cnt) 279 | { 280 | p_sem->OS_SemCnt = cnt; 281 | } 282 | #endif 283 | 284 | 285 | /* 286 | ********************************************************************************************************* 287 | * MB_OS_SemPost() 288 | * 289 | * Description : This function signals a semaphore 290 | * 291 | * Argument(s) : p_sem Pointer to the semaphore. 292 | * 293 | * Return(s) : none. 294 | * 295 | * Caller(s) : MB_OS_InitMaster() 296 | * 297 | * Return(s) : none. 298 | ********************************************************************************************************* 299 | */ 300 | 301 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 302 | static void MB_OS_SemPost (MB_OS_SEM *p_sem) 303 | { 304 | CPU_SR_ALLOC(); 305 | 306 | 307 | CPU_CRITICAL_ENTER(); /* Increment the semaphore counts value */ 308 | p_sem->OS_SemCnt++; 309 | CPU_CRITICAL_EXIT(); 310 | } 311 | #endif 312 | 313 | 314 | /* 315 | ********************************************************************************************************* 316 | * MB_OS_Q_Create() 317 | * 318 | * Description : This function creates a message queue. 319 | * 320 | * Argument(s) : p_sem Pointer to the message queue. 321 | * 322 | * p_sto Pointer to the base address of the message queue storage area. 323 | * 324 | * max_entries Number of elements in the storage area. 325 | * 326 | * Return(s) : none. 327 | * 328 | * Caller(s) : MB_OS_InitMaster() 329 | * 330 | * Return(s) : none. 331 | ********************************************************************************************************* 332 | */ 333 | 334 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 335 | static void MB_OS_Q_Create (MB_OS_Q *p_q, 336 | MODBUS_CH **p_sto, 337 | CPU_INT08U max_entries) 338 | { 339 | p_q->OS_Q_StoPtr = p_sto; 340 | p_q->OS_Q_Entries = 0; 341 | p_q->OS_Q_MaxEntries = max_entries; 342 | p_q->OS_Q_FirstEntry = 0; 343 | p_q->OS_Q_LastEntry = 0; 344 | } 345 | #endif 346 | 347 | 348 | /* 349 | ********************************************************************************************************* 350 | * MB_OS_Q_Post() 351 | * 352 | * Description : This function posts to a message queue. 353 | * 354 | * Argument(s) : p_sem Pointer to the message queue. 355 | * 356 | * p_msg Message to post. 357 | * 358 | * Return(s) : MB_OS_ERR_NONE, is message put in queue. 359 | * MB_OS_ERR_Q_FULL, if queue full. 360 | * 361 | * Caller(s) : MB_OS_InitMaster() 362 | * 363 | * Return(s) : none. 364 | ********************************************************************************************************* 365 | */ 366 | 367 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 368 | static CPU_INT08U MB_OS_Q_Post (MB_OS_Q *p_q, 369 | MODBUS_CH *p_msg) 370 | { 371 | MODBUS_CH **p_sto; 372 | CPU_INT08U err; 373 | CPU_SR_ALLOC(); 374 | 375 | 376 | p_sto = p_q->OS_Q_StoPtr; 377 | err = MB_OS_ERR_NONE; 378 | 379 | CPU_CRITICAL_ENTER(); 380 | if ((p_q->OS_Q_MaxEntries) > (p_q->OS_Q_Entries)) { 381 | p_q->OS_Q_Entries++; 382 | 383 | if (p_q->OS_Q_LastEntry == (p_q->OS_Q_MaxEntries - 1)) { 384 | p_q->OS_Q_LastEntry = 0; 385 | } else { 386 | p_q->OS_Q_LastEntry++; 387 | } 388 | 389 | p_sto[p_q->OS_Q_LastEntry] = p_msg; 390 | 391 | } else { 392 | err = MB_OS_ERR_Q_FULL; 393 | } 394 | CPU_CRITICAL_EXIT(); 395 | 396 | return (err); 397 | } 398 | #endif 399 | 400 | 401 | /* 402 | ********************************************************************************************************* 403 | * MB_OS_Q_Pend() 404 | * 405 | * Description : This function wait until at least on message receive in the queue or a timeout ocurrs. 406 | * 407 | * Argument(s) : p_q Pointer to the message queue. 408 | * 409 | * Return(s) : A pointer to the message received. 410 | * 411 | * Caller(s) : MB_OS_RxTask(). 412 | * 413 | * Return(s) : none. 414 | ********************************************************************************************************* 415 | */ 416 | 417 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 418 | static MODBUS_CH *MB_OS_Q_Pend (MB_OS_Q *p_q) 419 | { 420 | MODBUS_CH **p_sto; 421 | MODBUS_CH *p_msg; 422 | CPU_SR_ALLOC(); 423 | 424 | 425 | p_sto = p_q->OS_Q_StoPtr; 426 | p_msg = (MODBUS_CH *)0; 427 | 428 | CPU_CRITICAL_ENTER(); 429 | if (p_q->OS_Q_Entries > 0) { 430 | p_msg = (p_sto[p_q->OS_Q_FirstEntry]); 431 | 432 | if (p_q->OS_Q_FirstEntry == (p_q->OS_Q_MaxEntries - 1)) { 433 | p_q->OS_Q_FirstEntry = 0; 434 | } else { 435 | p_q->OS_Q_FirstEntry++; 436 | } 437 | 438 | p_q->OS_Q_Entries--; 439 | } 440 | CPU_CRITICAL_EXIT(); 441 | 442 | return (p_msg); 443 | } 444 | #endif 445 | 446 | -------------------------------------------------------------------------------- /OS/None/mb_os.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * MODBUS NO-OS LAYER INTERFACE 21 | * 22 | * Filename : mb_os.h 23 | * Version : V2.14.00 24 | ********************************************************************************************************* 25 | */ 26 | 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * MODULE 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #ifndef MB_OS_MODULE_PRESENT 35 | #define MB_OS_MODULE_PRESENT 36 | 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * INCLUDE FILES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | 45 | /* 46 | ********************************************************************************************************* 47 | * EXTERNS 48 | ********************************************************************************************************* 49 | */ 50 | 51 | #ifdef MB_OS_MODULE 52 | #define MB_OS_EXT 53 | #else 54 | #define MB_OS_EXT extern 55 | #endif 56 | 57 | 58 | /* 59 | ********************************************************************************************************* 60 | * DEFINES 61 | ********************************************************************************************************* 62 | */ 63 | 64 | 65 | /* 66 | ********************************************************************************************************* 67 | * DATA TYPES 68 | ********************************************************************************************************* 69 | */ 70 | 71 | 72 | /* 73 | ********************************************************************************************************* 74 | * GLOBAL VARIABLES 75 | ********************************************************************************************************* 76 | */ 77 | 78 | 79 | /* 80 | ********************************************************************************************************* 81 | * MACRO'S 82 | ********************************************************************************************************* 83 | */ 84 | 85 | 86 | /* 87 | ********************************************************************************************************* 88 | * FUNCTION PROTOTYPES 89 | ********************************************************************************************************* 90 | */ 91 | 92 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 93 | void MB_OS_RxTask(void); 94 | #endif 95 | 96 | 97 | 98 | /* 99 | ********************************************************************************************************* 100 | * CONFIGURATION ERRORS 101 | ********************************************************************************************************* 102 | */ 103 | 104 | #ifdef MODBUS_CFG_MASTER_EN 105 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 106 | #error "MODBUS Master cannot be used in a single-threaded scheme." 107 | #endif 108 | #endif 109 | 110 | 111 | /* 112 | ********************************************************************************************************* 113 | * MODULE END 114 | ********************************************************************************************************* 115 | */ 116 | 117 | #endif /* End of MB_OS module */ 118 | 119 | -------------------------------------------------------------------------------- /OS/uCOS-II/mb_os.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * MODBUS uC/OS-II LAYER INTERFACE 21 | * 22 | * Filename : mb_os.c 23 | * Version : V2.14.00 24 | ********************************************************************************************************* 25 | */ 26 | 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * INCLUDE FILES 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #define MB_OS_MODULE 35 | #include 36 | 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * LOCAL DEFINES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | 45 | /* 46 | ********************************************************************************************************* 47 | * LOCAL CONSTANTS 48 | ********************************************************************************************************* 49 | */ 50 | 51 | 52 | /* 53 | ********************************************************************************************************* 54 | * LOCAL DATA TYPES 55 | ********************************************************************************************************* 56 | */ 57 | 58 | 59 | /* 60 | ********************************************************************************************************* 61 | * LOCAL TABLES 62 | ********************************************************************************************************* 63 | */ 64 | 65 | 66 | /* 67 | ********************************************************************************************************* 68 | * LOCAL GLOBAL VARIABLES 69 | ********************************************************************************************************* 70 | */ 71 | 72 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 73 | static OS_EVENT *MB_OS_RxSemTbl[MODBUS_CFG_MAX_CH]; 74 | #endif 75 | 76 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 77 | static OS_STK MB_OS_RxTaskStk[MB_OS_CFG_RX_TASK_STK_SIZE]; 78 | 79 | static OS_EVENT *MB_OS_RxQ; 80 | static void *MB_OS_RxQTbl[MODBUS_CFG_MAX_CH]; 81 | #endif 82 | 83 | 84 | /* 85 | ********************************************************************************************************* 86 | * LOCAL FUNCTION PROTOTYPES 87 | ********************************************************************************************************* 88 | */ 89 | 90 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 91 | static void MB_OS_InitMaster(void); 92 | static void MB_OS_ExitMaster(void); 93 | #endif 94 | 95 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 96 | static void MB_OS_InitSlave (void); 97 | static void MB_OS_ExitSlave (void); 98 | static void MB_OS_RxTask (void *p_arg); 99 | #endif 100 | 101 | 102 | /* 103 | ********************************************************************************************************* 104 | * LOCAL CONFIGURATION ERRORS 105 | ********************************************************************************************************* 106 | */ 107 | 108 | 109 | /* 110 | ********************************************************************************************************* 111 | * MB_OS_Init() 112 | * 113 | * Description : This function initializes the RTOS interface. This function creates the following: 114 | * 115 | * (1) A message queue to signal the reception of a packet. 116 | * 117 | * (2) A task that waits for packets to be received. 118 | * 119 | * Argument(s) : none 120 | * 121 | * Return(s) : none. 122 | * 123 | * Caller(s) : MB_Init(). 124 | * 125 | * Note(s) : none. 126 | ********************************************************************************************************* 127 | */ 128 | 129 | void MB_OS_Init (void) 130 | { 131 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 132 | MB_OS_InitMaster(); 133 | #endif 134 | 135 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 136 | MB_OS_InitSlave(); 137 | #endif 138 | } 139 | 140 | 141 | /* 142 | ********************************************************************************************************* 143 | * MB_OS_InitMaster() 144 | * 145 | * Description : This function initializes and creates the kernel objectes needed for Modbus Master 146 | * 147 | * Argument(s) : none. 148 | * 149 | * Return(s) : none. 150 | * 151 | * Caller(s) : MB_OS_Init(). 152 | * 153 | * Note(s) : none. 154 | ********************************************************************************************************* 155 | */ 156 | 157 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 158 | static void MB_OS_InitMaster (void) 159 | { 160 | OS_EVENT *pevent; 161 | CPU_INT08U i; 162 | CPU_INT08U err; 163 | 164 | 165 | for (i = 0; i < MODBUS_CFG_MAX_CH; i++) { /* Create a semaphore for each channel */ 166 | pevent = OSSemCreate(0); 167 | if (pevent != (OS_EVENT *)0) { /* Assign a name to the semaphore */ 168 | MB_OS_RxSemTbl[i] = pevent; 169 | 170 | #if (OS_VERSION < 287) 171 | #if (OS_EVENT_NAME_SIZE > 16) 172 | 173 | OSEventNameSet(pevent, 174 | (INT8U *)"uC/Modbus Rx Sem", 175 | &err); 176 | (void)&err; 177 | #endif 178 | #else 179 | #if (OS_EVENT_NAME_EN > 0) 180 | 181 | OSEventNameSet(pevent, 182 | (INT8U *)"uC/Modbus Rx Sem", 183 | &err); 184 | (void)&err; 185 | #endif 186 | #endif 187 | } 188 | } 189 | } 190 | #endif 191 | 192 | 193 | /* 194 | ********************************************************************************************************* 195 | * MB_OS_InitSlave() 196 | * 197 | * Description : This function initializes and creates the kernel objectes needed for Modbus Salve 198 | * 199 | * Argument(s) : none. 200 | * 201 | * Return(s) : none. 202 | * 203 | * Caller(s) : MB_OS_Init(). 204 | * 205 | * Note(s) : none. 206 | ********************************************************************************************************* 207 | */ 208 | 209 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 210 | static void MB_OS_InitSlave (void) 211 | { 212 | INT8U err; 213 | 214 | 215 | MB_OS_RxQ = OSQCreate(&MB_OS_RxQTbl[0], /* Create Rx Task message queue */ 216 | MODBUS_CFG_MAX_CH); 217 | 218 | #if (OS_VERSION < 287) 219 | #if (OS_EVENT_NAME_SIZE > 14) 220 | if (MB_OS_RxQ != (OS_EVENT *)0) { /* Assign a name to the message queue */ 221 | OSEventNameSet(MB_OS_RxQ, 222 | (INT8U *)"uC/Modbus Rx Q", 223 | &err); 224 | (void)&err; 225 | } 226 | #endif 227 | #else 228 | #if (OS_EVENT_NAME_EN > 0) 229 | if (MB_OS_RxQ != (OS_EVENT *)0) { 230 | OSEventNameSet(MB_OS_RxQ, 231 | (INT8U *)"uC/Modbus Rx Q", 232 | &err); 233 | (void)&err; 234 | } 235 | #endif 236 | #endif 237 | 238 | #if (OS_TASK_CREATE_EXT_EN > 0) 239 | #if (OS_STK_GROWTH == 1) 240 | (void)OSTaskCreateExt((void (*)(void *)) MB_OS_RxTask, 241 | (void *) 0, 242 | &MB_OS_RxTaskStk[MB_OS_CFG_RX_TASK_STK_SIZE - 1], 243 | MB_OS_CFG_RX_TASK_PRIO, 244 | MB_OS_CFG_RX_TASK_ID, 245 | &MB_OS_RxTaskStk[0], 246 | MB_OS_CFG_RX_TASK_STK_SIZE, 247 | (void *) 0, 248 | (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); 249 | #else 250 | (void)OSTaskCreateExt((void (*)(void *)) MB_OS_RxTask, 251 | (void *) 0, 252 | &MB_OS_RxTaskStk[0], 253 | MB_OS_CFG_RX_TASK_PRIO, 254 | MB_OS_CFG_RX_TASK_ID, 255 | &MB_OS_RxTaskStk[MB_OS_CFG_RX_TASK_STK_SIZE - 1], 256 | MB_OS_CFG_RX_TASK_STK_SIZE, 257 | (void *) 0, 258 | (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); 259 | #endif 260 | #else 261 | #if OS_STK_GROWTH == 1 262 | (void)OSTaskCreate((void (*)(void *)) MB_OS_RxTask, 263 | (void *) 0, 264 | &MB_OS_RxTaskStk[MB_OS_CFG_RX_TASK_STK_SIZE - 1], 265 | MB_OS_CFG_RX_TASK_PRIO); 266 | #else 267 | (void)OSTaskCreate((void (*)(void *)) MB_OS_RxTask, 268 | (void *) 0, 269 | &MB_OS_RxTaskStk[0], 270 | MB_OS_CFG_RX_TASK_PRIO); 271 | #endif 272 | #endif 273 | 274 | #if (OS_VERSION < 287) 275 | #if (OS_EVENT_NAME_SIZE > 12) 276 | 277 | OSTaskNameSet( MB_OS_CFG_RX_TASK_PRIO, /* Assign a name to the event flag group */ 278 | (INT8U *)"uC/Modbus Rx", 279 | &err); 280 | #endif 281 | #else 282 | #if (OS_EVENT_NAME_EN > 0) 283 | OSTaskNameSet( MB_OS_CFG_RX_TASK_PRIO, 284 | (INT8U *)"uC/Modbus Rx", 285 | &err); 286 | 287 | #endif 288 | #endif 289 | 290 | 291 | } 292 | #endif 293 | 294 | 295 | /* 296 | ********************************************************************************************************* 297 | * MB_OS_Exit() 298 | * 299 | * Description : This function is called to terminate the RTOS interface for Modbus channels. We delete 300 | * the following uC/OS-II objects: 301 | * 302 | * (1) An event flag group to signal the reception of a packet. 303 | * (2) A task that waits for packets to be received. 304 | * 305 | * Argument(s) : none. 306 | * 307 | * Return(s) : none. 308 | * 309 | * Caller(s) : MB_Exit(). 310 | * 311 | * Note(s) : none. 312 | ********************************************************************************************************* 313 | */ 314 | 315 | void MB_OS_Exit (void) 316 | { 317 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 318 | MB_OS_ExitMaster(); 319 | #endif 320 | 321 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 322 | MB_OS_ExitSlave(); 323 | #endif 324 | } 325 | 326 | 327 | /* 328 | ********************************************************************************************************* 329 | * MB_OS_ExitMaster() 330 | * 331 | * Description : This function is called to terminate the RTOS interface for Modbus Master channels. The 332 | * following objects are deleted. 333 | * 334 | * (1) An event flag group to signal the reception of a packet. 335 | * 336 | * Argument(s) : none. 337 | * 338 | * Return(s) : none. 339 | * 340 | * Caller(s) : MB_OS_Exit(). 341 | * 342 | * Note(s) : none. 343 | ********************************************************************************************************* 344 | */ 345 | 346 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 347 | static void MB_OS_ExitMaster (void) 348 | { 349 | CPU_INT08U i; 350 | INT8U err; 351 | 352 | 353 | for (i = 0; i < MODBUS_CFG_MAX_CH; i++) { /* Delete semaphore for each channel */ 354 | OSSemDel(MB_OS_RxSemTbl[i], 355 | OS_DEL_ALWAYS, 356 | &err); 357 | } 358 | } 359 | #endif 360 | 361 | 362 | /* 363 | ********************************************************************************************************* 364 | * MB_OS_ExitSlave() 365 | * 366 | * Description : This function is called to terminate the RTOS interface for Modbus Salve channels. 367 | * The following objects are deleted. 368 | * 369 | * (1) A task that waits for packets to be received. 370 | * (2) A message queue to signal the reception of a packet. 371 | * 372 | * Argument(s) : none 373 | * 374 | * Return(s) : none. 375 | * 376 | * Caller(s) : MB_OS_Exit(). 377 | * 378 | * Note(s) : none. 379 | ********************************************************************************************************* 380 | */ 381 | 382 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 383 | void MB_OS_ExitSlave (void) 384 | { 385 | INT8U err; 386 | 387 | 388 | OSTaskDel(MB_OS_CFG_RX_TASK_PRIO); /* Delete Modbus Rx Task */ 389 | OSQDel(MB_OS_RxQ, /* Delete the Queue */ 390 | OS_DEL_ALWAYS, 391 | &err); 392 | } 393 | #endif 394 | 395 | 396 | /* 397 | ********************************************************************************************************* 398 | * MB_OS_RxSignal() 399 | * 400 | * Description : This function signals the reception of a packet either from the Rx ISR(s) or the RTU timeout 401 | * timer(s) to indicate that a received packet needs to be processed. 402 | * 403 | * Argument(s) : pch specifies the Modbus channel data structure in which a packet was received. 404 | * 405 | * Return(s) : none. 406 | * 407 | * Caller(s) : MB_ASCII_RxByte(), 408 | * MB_RTU_TmrUpdate(). 409 | * 410 | * Note(s) : none. 411 | ********************************************************************************************************* 412 | */ 413 | 414 | void MB_OS_RxSignal (MODBUS_CH *pch) 415 | { 416 | if (pch != (MODBUS_CH *)0) { 417 | switch (pch->MasterSlave) { 418 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 419 | case MODBUS_MASTER: 420 | (void)OSSemPost(MB_OS_RxSemTbl[pch->Ch]); 421 | break; 422 | #endif 423 | 424 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 425 | case MODBUS_SLAVE: 426 | default: 427 | (void)OSQPost(MB_OS_RxQ, 428 | (void *)pch); 429 | break; 430 | #endif 431 | } 432 | } 433 | } 434 | 435 | 436 | /* 437 | ********************************************************************************************************* 438 | * MB_OS_RxWait() 439 | * 440 | * Description : This function waits for a response from a slave. 441 | * 442 | * Argument(s) : pch specifies the Modbus channel data structure to wait on. 443 | * 444 | * perr is a pointer to a variable that will receive an error code. Possible errors are: 445 | * 446 | * MODBUS_ERR_NONE the call was successful and a packet was received 447 | * MODBUS_ERR_TIMED_OUT a packet was not received within the specified timeout 448 | * MODBUS_ERR_NOT_MASTER the channel is not a Master 449 | * MODBUS_ERR_INVALID an invalid error was detected 450 | * 451 | * Return(s) : none. 452 | * 453 | * Caller(s) : MBM_FCxx() Modbus Master Functions 454 | * 455 | * Return(s) : none. 456 | ********************************************************************************************************* 457 | */ 458 | 459 | void MB_OS_RxWait (MODBUS_CH *pch, 460 | CPU_INT16U *perr) 461 | { 462 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 463 | INT8U err; 464 | 465 | 466 | if (pch != (MODBUS_CH *)0) { 467 | if (pch->MasterSlave == MODBUS_MASTER) { 468 | OSSemPend(MB_OS_RxSemTbl[pch->Ch], 469 | pch->RxTimeout, 470 | &err); 471 | switch (err) { 472 | case OS_ERR_EVENT_TYPE: 473 | case OS_ERR_PEND_ISR: 474 | case OS_ERR_PEND_LOCKED: 475 | *perr = MODBUS_ERR_INVALID; 476 | break; 477 | 478 | case OS_ERR_TIMEOUT: 479 | *perr = MODBUS_ERR_TIMED_OUT; 480 | break; 481 | 482 | case OS_ERR_NONE: 483 | *perr = MODBUS_ERR_NONE; 484 | break; 485 | } 486 | } else { 487 | *perr = MODBUS_ERR_NOT_MASTER; 488 | } 489 | } else { 490 | *perr = MODBUS_ERR_NULLPTR; 491 | } 492 | #else 493 | *perr = MODBUS_ERR_INVALID; 494 | #endif 495 | } 496 | 497 | 498 | /* 499 | ********************************************************************************************************* 500 | * MB_OS_RxTask() 501 | * 502 | * Description : This task is created by MB_OS_Init() and waits for signals from either the Rx ISR(s) or 503 | * the RTU timeout timer(s) to indicate that a packet needs to be processed. 504 | * 505 | * Argument(s) : p_arg is a pointer to an optional argument that is passed by uC/OS-II to the task. 506 | * This argument is not used. 507 | * 508 | * Return(s) : none. 509 | * 510 | * Caller(s) : This is a Task. 511 | * 512 | * Return(s) : none. 513 | ********************************************************************************************************* 514 | */ 515 | 516 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 517 | static void MB_OS_RxTask (void *p_arg) 518 | { 519 | INT8U err; 520 | MODBUS_CH *pch; 521 | 522 | 523 | (void)p_arg; 524 | 525 | while (DEF_TRUE) { 526 | pch = (MODBUS_CH *)OSQPend(MB_OS_RxQ, /* Wait for a packet to be received */ 527 | 0, 528 | &err); 529 | MB_RxTask(pch); /* Process the packet received */ 530 | } 531 | } 532 | #endif 533 | 534 | -------------------------------------------------------------------------------- /OS/uCOS-II/mb_os.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * MODBUS uC/OS-II LAYER INTERFACE 21 | * 22 | * Filename : mb_os.h 23 | * Version : V2.14.00 24 | ********************************************************************************************************* 25 | */ 26 | 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * MODULE 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #ifndef MB_OS_MODULE_PRESENT 35 | #define MB_OS_MODULE_PRESENT 36 | 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * INCLUDE FILES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | #include 45 | 46 | 47 | /* 48 | ********************************************************************************************************* 49 | * EXTERNS 50 | ********************************************************************************************************* 51 | */ 52 | 53 | #ifdef MB_OS_MODULE 54 | #define MB_OS_EXT 55 | #else 56 | #define MB_OS_EXT extern 57 | #endif 58 | 59 | 60 | /* 61 | ********************************************************************************************************* 62 | * DEFINES 63 | ********************************************************************************************************* 64 | */ 65 | 66 | 67 | /* 68 | ********************************************************************************************************* 69 | * DATA TYPES 70 | ********************************************************************************************************* 71 | */ 72 | 73 | 74 | /* 75 | ********************************************************************************************************* 76 | * GLOBAL VARIABLES 77 | ********************************************************************************************************* 78 | */ 79 | 80 | 81 | /* 82 | ********************************************************************************************************* 83 | * MACRO'S 84 | ********************************************************************************************************* 85 | */ 86 | 87 | 88 | /* 89 | ********************************************************************************************************* 90 | * FUNCTION PROTOTYPES 91 | ********************************************************************************************************* 92 | */ 93 | 94 | 95 | /* 96 | ********************************************************************************************************* 97 | * CONFIGURATION ERRORS 98 | ********************************************************************************************************* 99 | */ 100 | 101 | #if (OS_Q_EN == 0) 102 | #error "MODBUS Slave requires uC/OS-II Message Queue Services." 103 | #endif 104 | 105 | #ifndef MB_OS_CFG_RX_TASK_ID 106 | #error "MODBUS Missing Rx Task's MB_OS_CFG_RX_TASK_ID." 107 | #endif 108 | 109 | 110 | #ifndef MB_OS_CFG_RX_TASK_PRIO 111 | #error "MODBUS Missing Rx Task's MB_OS_CFG_RX_TASK_PRIO." 112 | #endif 113 | 114 | 115 | #ifndef MB_OS_CFG_RX_TASK_STK_SIZE 116 | #error "MODBUS Missing Rx Task's MB_OS_CFG_RX_TASK_STK_SIZE." 117 | #endif 118 | 119 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 120 | #if (OS_SEM_EN == 0 ) 121 | #error "MODBUS Master requires uC/OS-II Semaphore Services." 122 | #error "... It needs MODBUS_CFG_MAX_CH semaphores." 123 | #endif 124 | #endif 125 | 126 | 127 | /* 128 | ********************************************************************************************************* 129 | * MODULE END 130 | ********************************************************************************************************* 131 | */ 132 | 133 | #endif /* End of MB_OS module */ 134 | 135 | -------------------------------------------------------------------------------- /OS/uCOS-III/mb_os.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * MODBUS uC/OS-III LAYER INTERFACE 21 | * 22 | * Filename : mb_os.c 23 | * Version : V2.14.00 24 | ********************************************************************************************************* 25 | */ 26 | 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * INCLUDE FILES 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #define MB_OS_MODULE 35 | #include 36 | 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * LOCAL DEFINES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | 45 | /* 46 | ********************************************************************************************************* 47 | * LOCAL CONSTANTS 48 | ********************************************************************************************************* 49 | */ 50 | 51 | 52 | /* 53 | ********************************************************************************************************* 54 | * LOCAL DATA TYPES 55 | ********************************************************************************************************* 56 | */ 57 | 58 | 59 | /* 60 | ********************************************************************************************************* 61 | * LOCAL TABLES 62 | ********************************************************************************************************* 63 | */ 64 | 65 | 66 | /* 67 | ********************************************************************************************************* 68 | * LOCAL GLOBAL VARIABLES 69 | ********************************************************************************************************* 70 | */ 71 | 72 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 73 | static OS_SEM MB_OS_RxSemTbl[MODBUS_CFG_MAX_CH]; 74 | #endif 75 | 76 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 77 | static OS_TCB MB_OS_RxTaskTCB; 78 | static CPU_STK MB_OS_RxTaskStk[MB_OS_CFG_RX_TASK_STK_SIZE]; 79 | #endif 80 | 81 | 82 | /* 83 | ********************************************************************************************************* 84 | * LOCAL FUNCTION PROTOTYPES 85 | ********************************************************************************************************* 86 | */ 87 | 88 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 89 | static void MB_OS_InitMaster(void); 90 | static void MB_OS_ExitMaster(void); 91 | #endif 92 | 93 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 94 | static void MB_OS_InitSlave (void); 95 | static void MB_OS_ExitSlave (void); 96 | static void MB_OS_RxTask (void *p_arg); 97 | #endif 98 | 99 | 100 | /* 101 | ********************************************************************************************************* 102 | * LOCAL CONFIGURATION ERRORS 103 | ********************************************************************************************************* 104 | */ 105 | 106 | 107 | /* 108 | ********************************************************************************************************* 109 | * MB_OS_Init() 110 | * 111 | * Description : This function initializes the RTOS interface. This function creates the following: 112 | * 113 | * (1) A message queue to signal the reception of a packet. 114 | * 115 | * (2) A task that waits for packets to be received. 116 | * 117 | * Argument(s) : none 118 | * 119 | * Return(s) : none. 120 | * 121 | * Caller(s) : MB_Init(). 122 | * 123 | * Note(s) : none. 124 | ********************************************************************************************************* 125 | */ 126 | 127 | void MB_OS_Init (void) 128 | { 129 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 130 | MB_OS_InitMaster(); 131 | #endif 132 | 133 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 134 | MB_OS_InitSlave(); 135 | #endif 136 | } 137 | 138 | 139 | /* 140 | ********************************************************************************************************* 141 | * MB_OS_InitMaster() 142 | * 143 | * Description : This function initializes and creates the kernel objectes needed for Modbus Master 144 | * 145 | * Argument(s) : none. 146 | * 147 | * Return(s) : none. 148 | * 149 | * Caller(s) : MB_OS_Init(). 150 | * 151 | * Note(s) : none. 152 | ********************************************************************************************************* 153 | */ 154 | 155 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 156 | static void MB_OS_InitMaster (void) 157 | { 158 | CPU_INT08U i; 159 | OS_ERR err; 160 | 161 | 162 | for (i = 0; i < MODBUS_CFG_MAX_CH; i++) { /* Create a semaphore for each channel */ 163 | OSSemCreate(&MB_OS_RxSemTbl[i], 164 | (CPU_CHAR *)"uC/Modbus Rx Sem", 165 | 0, 166 | &err); 167 | } 168 | } 169 | #endif 170 | 171 | 172 | /* 173 | ********************************************************************************************************* 174 | * MB_OS_InitSlave() 175 | * 176 | * Description : This function initializes and creates the kernel objectes needed for Modbus Salve 177 | * 178 | * Argument(s) : none. 179 | * 180 | * Return(s) : none. 181 | * 182 | * Caller(s) : MB_OS_Init(). 183 | * 184 | * Note(s) : none. 185 | ********************************************************************************************************* 186 | */ 187 | 188 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 189 | static void MB_OS_InitSlave (void) 190 | { 191 | OS_ERR err; 192 | 193 | 194 | OSTaskCreate(&MB_OS_RxTaskTCB, 195 | (CPU_CHAR *)"Modbus Rx Task", 196 | MB_OS_RxTask, 197 | (void *)0, 198 | MB_OS_CFG_RX_TASK_PRIO, 199 | &MB_OS_RxTaskStk[0], 200 | MB_OS_CFG_RX_TASK_STK_SIZE / 10, 201 | MB_OS_CFG_RX_TASK_STK_SIZE, 202 | MODBUS_CFG_MAX_CH, 203 | 0, 204 | (void *)0, 205 | (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 206 | &err); 207 | } 208 | #endif 209 | 210 | 211 | /* 212 | ********************************************************************************************************* 213 | * MB_OS_Exit() 214 | * 215 | * Description : This function is called to terminate the RTOS interface for Modbus channels. We delete 216 | * the following uC/OS-II objects: 217 | * 218 | * (1) An event flag group to signal the reception of a packet. 219 | * (2) A task that waits for packets to be received. 220 | * 221 | * Argument(s) : none. 222 | * 223 | * Return(s) : none. 224 | * 225 | * Caller(s) : MB_Exit(). 226 | * 227 | * Note(s) : none. 228 | ********************************************************************************************************* 229 | */ 230 | 231 | void MB_OS_Exit (void) 232 | { 233 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 234 | MB_OS_ExitMaster(); 235 | #endif 236 | 237 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 238 | MB_OS_ExitSlave(); 239 | #endif 240 | } 241 | 242 | 243 | /* 244 | ********************************************************************************************************* 245 | * MB_OS_ExitMaster() 246 | * 247 | * Description : This function is called to terminate the RTOS interface for Modbus Master channels. The 248 | * following objects are deleted. 249 | * 250 | * (1) An event flag group to signal the reception of a packet. 251 | * 252 | * Argument(s) : none. 253 | * 254 | * Return(s) : none. 255 | * 256 | * Caller(s) : MB_OS_Exit(). 257 | * 258 | * Note(s) : none. 259 | ********************************************************************************************************* 260 | */ 261 | 262 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 263 | static void MB_OS_ExitMaster (void) 264 | { 265 | CPU_INT08U i; 266 | OS_ERR err; 267 | 268 | 269 | for (i = 0; i < MODBUS_CFG_MAX_CH; i++) { /* Delete semaphore for each channel */ 270 | OSSemDel(&MB_OS_RxSemTbl[i], 271 | OS_OPT_DEL_ALWAYS, 272 | &err); 273 | } 274 | } 275 | #endif 276 | 277 | 278 | /* 279 | ********************************************************************************************************* 280 | * MB_OS_ExitSlave() 281 | * 282 | * Description : This function is called to terminate the RTOS interface for Modbus Salve channels. 283 | * The following objects are deleted. 284 | * 285 | * (1) A task that waits for packets to be received. 286 | * (2) A message queue to signal the reception of a packet. 287 | * 288 | * Argument(s) : none 289 | * 290 | * Return(s) : none. 291 | * 292 | * Caller(s) : MB_OS_Exit(). 293 | * 294 | * Note(s) : none. 295 | ********************************************************************************************************* 296 | */ 297 | 298 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 299 | void MB_OS_ExitSlave (void) 300 | { 301 | OS_ERR err; 302 | 303 | 304 | OSTaskDel(&MB_OS_RxTaskTCB, /* Delete Modbus Rx Task */ 305 | &err); 306 | (void)err; 307 | } 308 | #endif 309 | 310 | 311 | /* 312 | ********************************************************************************************************* 313 | * MB_OS_RxSignal() 314 | * 315 | * Description : This function signals the reception of a packet either from the Rx ISR(s) or the RTU timeout 316 | * timer(s) to indicate that a received packet needs to be processed. 317 | * 318 | * Argument(s) : pch specifies the Modbus channel data structure in which a packet was received. 319 | * 320 | * Return(s) : none. 321 | * 322 | * Caller(s) : MB_ASCII_RxByte(), 323 | * MB_RTU_TmrUpdate(). 324 | * 325 | * Note(s) : none. 326 | ********************************************************************************************************* 327 | */ 328 | 329 | void MB_OS_RxSignal (MODBUS_CH *pch) 330 | { 331 | OS_ERR err; 332 | 333 | 334 | if (pch != (MODBUS_CH *)0) { 335 | switch (pch->MasterSlave) { 336 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 337 | case MODBUS_MASTER: 338 | (void)OSSemPost(&MB_OS_RxSemTbl[pch->Ch], 339 | OS_OPT_POST_1, 340 | &err); 341 | break; 342 | #endif 343 | 344 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 345 | case MODBUS_SLAVE: 346 | default: 347 | (void)OSTaskQPost(&MB_OS_RxTaskTCB, 348 | pch, 349 | sizeof(void *), 350 | OS_OPT_POST_FIFO, 351 | &err); 352 | break; 353 | #endif 354 | } 355 | } 356 | } 357 | 358 | 359 | /* 360 | ********************************************************************************************************* 361 | * MB_OS_RxWait() 362 | * 363 | * Description : This function waits for a response from a slave. 364 | * 365 | * Argument(s) : pch specifies the Modbus channel data structure to wait on. 366 | * 367 | * perr is a pointer to a variable that will receive an error code. Possible errors are: 368 | * 369 | * MODBUS_ERR_NONE the call was successful and a packet was received 370 | * MODBUS_ERR_TIMED_OUT a packet was not received within the specified timeout 371 | * MODBUS_ERR_NOT_MASTER the channel is not a Master 372 | * MODBUS_ERR_INVALID an invalid error was detected 373 | * 374 | * Return(s) : none. 375 | * 376 | * Caller(s) : MBM_FCxx() Modbus Master Functions 377 | * 378 | * Return(s) : none. 379 | ********************************************************************************************************* 380 | */ 381 | 382 | void MB_OS_RxWait (MODBUS_CH *pch, 383 | CPU_INT16U *perr) 384 | { 385 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 386 | OS_ERR err; 387 | CPU_TS ts; 388 | 389 | 390 | if (pch != (MODBUS_CH *)0) { 391 | if (pch->MasterSlave == MODBUS_MASTER) { 392 | OSSemPend(&MB_OS_RxSemTbl[pch->Ch], 393 | pch->RxTimeout, 394 | OS_OPT_PEND_BLOCKING, 395 | &ts, 396 | &err); 397 | switch (err) { 398 | case OS_ERR_OBJ_DEL: 399 | case OS_ERR_OBJ_PTR_NULL: 400 | case OS_ERR_OBJ_TYPE: 401 | case OS_ERR_PEND_ABORT: 402 | case OS_ERR_PEND_ISR: 403 | case OS_ERR_PEND_WOULD_BLOCK: 404 | case OS_ERR_SCHED_LOCKED: 405 | case OS_ERR_STATUS_INVALID: 406 | *perr = MODBUS_ERR_INVALID; 407 | break; 408 | 409 | case OS_ERR_TIMEOUT: 410 | *perr = MODBUS_ERR_TIMED_OUT; 411 | break; 412 | 413 | case OS_ERR_NONE: 414 | *perr = MODBUS_ERR_NONE; 415 | break; 416 | } 417 | } else { 418 | *perr = MODBUS_ERR_NOT_MASTER; 419 | } 420 | } else { 421 | *perr = MODBUS_ERR_NULLPTR; 422 | } 423 | #else 424 | *perr = MODBUS_ERR_INVALID; 425 | #endif 426 | } 427 | 428 | /* 429 | ********************************************************************************************************* 430 | * MB_OS_RxTask() 431 | * 432 | * Description : This task is created by MB_OS_Init() and waits for signals from either the Rx ISR(s) or 433 | * the RTU timeout timer(s) to indicate that a packet needs to be processed. 434 | * 435 | * Argument(s) : p_arg is a pointer to an optional argument that is passed by uC/OS-II to the task. 436 | * This argument is not used. 437 | * 438 | * Return(s) : none. 439 | * 440 | * Caller(s) : This is a Task. 441 | * 442 | * Return(s) : none. 443 | ********************************************************************************************************* 444 | */ 445 | 446 | #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) 447 | static void MB_OS_RxTask (void *p_arg) 448 | { 449 | OS_ERR err; 450 | OS_MSG_SIZE msg_size; 451 | CPU_TS ts; 452 | MODBUS_CH *pch; 453 | 454 | 455 | (void)p_arg; 456 | 457 | while (DEF_TRUE) { 458 | pch = (MODBUS_CH *)OSTaskQPend(0, /* Wait for a packet to be received */ 459 | OS_OPT_PEND_BLOCKING, 460 | &msg_size, 461 | &ts, 462 | &err); 463 | MB_RxTask(pch); /* Process the packet received */ 464 | } 465 | } 466 | #endif 467 | 468 | -------------------------------------------------------------------------------- /OS/uCOS-III/mb_os.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * MODBUS uC/OS-III LAYER INTERFACE 21 | * 22 | * Filename : mb_os.h 23 | * Version : V2.14.00 24 | ********************************************************************************************************* 25 | */ 26 | 27 | 28 | /* 29 | ********************************************************************************************************* 30 | * MODULE 31 | ********************************************************************************************************* 32 | */ 33 | 34 | #ifndef MB_OS_MODULE_PRESENT 35 | #define MB_OS_MODULE_PRESENT 36 | 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * INCLUDE FILES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | #include 45 | 46 | 47 | /* 48 | ********************************************************************************************************* 49 | * EXTERNS 50 | ********************************************************************************************************* 51 | */ 52 | 53 | #ifdef MB_OS_MODULE 54 | #define MB_OS_EXT 55 | #else 56 | #define MB_OS_EXT extern 57 | #endif 58 | 59 | 60 | /* 61 | ********************************************************************************************************* 62 | * DEFINES 63 | ********************************************************************************************************* 64 | */ 65 | 66 | 67 | /* 68 | ********************************************************************************************************* 69 | * DATA TYPES 70 | ********************************************************************************************************* 71 | */ 72 | 73 | 74 | /* 75 | ********************************************************************************************************* 76 | * GLOBAL VARIABLES 77 | ********************************************************************************************************* 78 | */ 79 | 80 | 81 | /* 82 | ********************************************************************************************************* 83 | * MACRO'S 84 | ********************************************************************************************************* 85 | */ 86 | 87 | 88 | /* 89 | ********************************************************************************************************* 90 | * FUNCTION PROTOTYPES 91 | ********************************************************************************************************* 92 | */ 93 | 94 | 95 | /* 96 | ********************************************************************************************************* 97 | * CONFIGURATION ERRORS 98 | ********************************************************************************************************* 99 | */ 100 | 101 | #if (OS_CFG_Q_EN == 0) 102 | #error "MODBUS Slave requires uC/OS-III Message Queue Services." 103 | #endif 104 | 105 | 106 | #ifndef MB_OS_CFG_RX_TASK_PRIO 107 | #error "MODBUS Missing Rx Task's MB_OS_CFG_RX_TASK_PRIO." 108 | #endif 109 | 110 | 111 | #ifndef MB_OS_CFG_RX_TASK_STK_SIZE 112 | #error "MODBUS Missing Rx Task's MB_OS_CFG_RX_TASK_STK_SIZE." 113 | #endif 114 | 115 | 116 | #if (MODBUS_CFG_MASTER_EN == DEF_ENABLED) 117 | #if (OS_CFG_SEM_EN == 0 ) 118 | #error "MODBUS Master requires uC/OS-III Semaphore Services." 119 | #error "... It needs at least MODBUS_CFG_MAX_CH semaphores." 120 | #endif 121 | #endif 122 | 123 | 124 | /* 125 | ********************************************************************************************************* 126 | * MODULE END 127 | ********************************************************************************************************* 128 | */ 129 | 130 | #endif /* End of MB_OS module */ 131 | 132 | -------------------------------------------------------------------------------- /Ports/ARM7/LH79520/IAR/mb_bsp.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * MODBUS BOARD SUPPORT PACKAGE 23 | * Sharp LH79520 (ARM7) 24 | * 25 | * Filename : mb_bsp.c 26 | * Version : V2.14.00 27 | ********************************************************************************************************* 28 | */ 29 | 30 | /* 31 | ********************************************************************************************************* 32 | * INCLUDE FILES 33 | ********************************************************************************************************* 34 | */ 35 | 36 | #include 37 | 38 | 39 | /* 40 | ********************************************************************************************************* 41 | * MB_CommExit() 42 | * 43 | * Description : This function is called to terminate Modbus communications. All Modbus channels are close. 44 | * 45 | * Argument(s) : none 46 | * 47 | * Return(s) : none. 48 | * 49 | * Caller(s) : MB_Exit() 50 | * 51 | * Note(s) : none. 52 | ********************************************************************************************************* 53 | */ 54 | 55 | void MB_CommExit (void) 56 | { 57 | CPU_INT08U ch; 58 | MODBUS_CH *pch; 59 | 60 | 61 | pch = &MB_ChTbl[0]; 62 | for (ch = 0; ch < MODBUS_CFG_MAX_CH; ch++) { 63 | MB_CommTxIntDis(pch); 64 | MB_CommRxIntDis(pch); 65 | pch++; 66 | } 67 | } 68 | 69 | 70 | /* 71 | ********************************************************************************************************* 72 | * MB_CommPortCfg() 73 | * 74 | * Description : This function initializes the serial port to the desired baud rate and the UART will be 75 | * configured for N, 8, 1 (No parity, 8 bits, 1 stop). 76 | * 77 | * Argument(s) : pch is a pointer to the Modbus channel 78 | * port_nbr is the desired serial port number. This argument allows you to assign a 79 | * specific serial port to a sepcific Modbus channel. 80 | * baud is the desired baud rate for the serial port. 81 | * parity is the desired parity and can be either: 82 | * 83 | * MODBUS_PARITY_NONE 84 | * MODBUS_PARITY_ODD 85 | * MODBUS_PARITY_EVEN 86 | * 87 | * bits specifies the number of bit and can be either 7 or 8. 88 | * stops specifies the number of stop bits and can either be 1 or 2 89 | * 90 | * Return(s) : none. 91 | * 92 | * Caller(s) : MB_CfgCh() 93 | * 94 | * Note(s) : none. 95 | ********************************************************************************************************* 96 | */ 97 | 98 | void MB_CommPortCfg (MODBUS_CH *pch, 99 | CPU_INT08U port_nbr, 100 | CPU_INT32U baud, 101 | CPU_INT08U bits, 102 | CPU_INT08U parity, 103 | CPU_INT08U stops) 104 | { 105 | UARTREGS *pUART; 106 | CPU_INT32U lcr; 107 | 108 | 109 | if (pch != (MODBUS_CH *)0) { 110 | pch->PortNbr = port_nbr; 111 | pch->BaudRate = baud; 112 | pch->Parity = parity; 113 | pch->Bits = bits; 114 | pch->Stops = stops; 115 | switch (port_nbr) { /* Determine which serial port is assigned */ 116 | case 0: 117 | pUART = UART0; /* Point to UART0 */ 118 | RCPC->periphclkctrl &= ~(1 << 0); /* Enable the UART clock */ 119 | RCPC->periphclksel &= ~(1 << 0); /* Select the internal crystal oscillator */ 120 | IOCON->uartmux |= UARTMUX_U0RXD | UARTMUX_U0TXD; /* Enable UART pins */ 121 | VIC->vectcntl[VIC_VECT_PORT_0] = VIC_VECTCNTL_ENABLE | VIC_UARTINT0; 122 | VIC->vectaddr[VIC_VECT_PORT_0] = (CPU_INT32U)MB_CommRxTxISR_0_Handler; 123 | VIC->intenable = _BIT(VIC_UARTINT0); 124 | break; 125 | 126 | case 1: 127 | pUART = UART1; /* Point to UART1 */ 128 | RCPC->periphclkctrl &= ~(1 << 1); /* Enable the UART clock */ 129 | RCPC->periphclksel &= ~(1 << 1); /* Select the internal crystal oscillator */ 130 | IOCON->uartmux |= UARTMUX_U1RXD | UARTMUX_U1TXD; /* Enable UART pins */ 131 | VIC->vectcntl[VIC_VECT_PORT_1] = VIC_VECTCNTL_ENABLE | VIC_UARTINT1; 132 | VIC->vectaddr[VIC_VECT_PORT_1] = (CPU_INT32U)MB_CommRxTxISR_1_Handler; 133 | VIC->intenable = _BIT(VIC_UARTINT1); 134 | break; 135 | 136 | case 2: 137 | pUART = UART2; /* Point to UART2 */ 138 | RCPC->periphclkctrl &= ~(1 << 2); /* Enable the UART clock */ 139 | RCPC->periphclksel &= ~(1 << 2); /* Select the internal crystal oscillator */ 140 | IOCON->ssimux |= SSIMUX_UT2RXD | SSIMUX_UT2TXD; /* Enable UART pins */ 141 | VIC->vectcntl[VIC_VECT_PORT_2] = VIC_VECTCNTL_ENABLE | VIC_UARTINT2; 142 | VIC->vectaddr[VIC_VECT_PORT_2] = (CPU_INT32U)MB_CommRxTxISR_2_Handler; 143 | VIC->intenable = _BIT(VIC_UARTINT2); 144 | break; 145 | } 146 | pUART->cr = 0x0000; /* DISABLE the UART to reprogram it! */ 147 | 148 | pUART->icr = UARTINT_RX /* Clear pending interrupts */ 149 | | UARTINT_TX 150 | | UARTINT_RT 151 | | UARTINT_FE 152 | | UARTINT_PE 153 | | UARTINT_BE 154 | | UARTINT_OE; 155 | 156 | pUART->ifls = UARTIFLS_RX_1_8 /* Set FIFO interrupt levels */ 157 | | UARTIFLS_TX_1_8; 158 | 159 | switch (baud) { /* Setup Baud Rate */ 160 | case 9600: 161 | pUART->ibrd = UARTBRINT_9600; 162 | pUART->fbrd = UARTBRFRAC_9600; 163 | break; 164 | 165 | case 19200: 166 | pUART->ibrd = UARTBRINT_19200; 167 | pUART->fbrd = UARTBRFRAC_19200; 168 | break; 169 | 170 | case 38400: 171 | pUART->ibrd = UARTBRINT_38400; 172 | pUART->fbrd = UARTBRFRAC_38400; 173 | break; 174 | 175 | case 57600: 176 | pUART->ibrd = UARTBRINT_57600; 177 | pUART->fbrd = UARTBRFRAC_57600; 178 | break; 179 | 180 | case 115200: 181 | pUART->ibrd = UARTBRINT_115200; 182 | pUART->fbrd = UARTBRFRAC_115200; 183 | break; 184 | 185 | default: /* Assume 38,400 by default */ 186 | pUART->ibrd = UARTBRINT_38400; 187 | pUART->fbrd = UARTBRFRAC_38400; 188 | break; 189 | } 190 | 191 | lcr = 0; /* Setup #bits, parity and stop bits */ 192 | switch (bits) { 193 | case 7: 194 | lcr |= UARTLCR_WLEN7; 195 | break; 196 | 197 | case 8: 198 | default: 199 | lcr |= UARTLCR_WLEN8; 200 | break; 201 | } 202 | 203 | switch (parity) { 204 | case MODBUS_PARITY_ODD: 205 | lcr |= UARTLCR_PARITY_ODD; 206 | break; 207 | 208 | case MODBUS_PARITY_EVEN: 209 | lcr |= UARTLCR_PARITY_EVEN; 210 | break; 211 | 212 | case MODBUS_PARITY_NONE: 213 | default: 214 | lcr |= UARTLCR_PARITY_NONE; 215 | } 216 | 217 | switch (stops) { 218 | case 1: 219 | lcr |= UARTLCR_STP1; 220 | break; 221 | 222 | case 2: 223 | default: 224 | lcr |= UARTLCR_STP2; 225 | break; 226 | } 227 | 228 | pUART->lcr_h = lcr; 229 | 230 | pUART->imsc = UARTINT_RX; /* Enable Rx interrupts ONLY */ 231 | 232 | pUART->cr = UARTCR_RXE /* Enable Rx, Tx and UART */ 233 | | UARTCR_TXE 234 | | UARTCR_ENABLE; 235 | } 236 | } 237 | 238 | 239 | /* 240 | ********************************************************************************************************* 241 | * MB_CommRxIntDis() 242 | * 243 | * Description : This function disables Rx interrupts. 244 | * 245 | * Argument(s) : pch is a pointer to the Modbus channel 246 | * 247 | * Return(s) : none. 248 | * 249 | * Caller(s) : MB_CommExit() 250 | * 251 | * Note(s) : none. 252 | ********************************************************************************************************* 253 | */ 254 | 255 | void MB_CommRxIntDis (MODBUS_CH *pch) 256 | { 257 | CPU_SR cpu_sr = 0; 258 | 259 | 260 | CPU_CRITICAL_ENTER(); 261 | switch (pch->PortNbr) { 262 | case 0: 263 | UART0->imsc &= ~UARTINT_RX; 264 | break; 265 | 266 | case 1: 267 | UART1->imsc &= ~UARTINT_RX; 268 | break; 269 | 270 | case 2: 271 | UART2->imsc &= ~UARTINT_RX; 272 | break; 273 | } 274 | CPU_CRITICAL_EXIT(); 275 | } 276 | 277 | 278 | /* 279 | ********************************************************************************************************* 280 | * MB_CommRxIntEn() 281 | * 282 | * Description : This function enables Rx interrupts. 283 | * 284 | * Argument(s) : pch is a pointer to the Modbus channel 285 | * 286 | * Return(s) : none. 287 | * 288 | * Caller(s) : MB_TxByte() 289 | * 290 | * Note(s) : none. 291 | ********************************************************************************************************* 292 | */ 293 | 294 | void MB_CommRxIntEn (MODBUS_CH *pch) 295 | { 296 | CPU_SR cpu_sr = 0; 297 | 298 | 299 | CPU_CRITICAL_ENTER(); 300 | switch (pch->PortNbr) { 301 | case 0: 302 | UART0->imsc |= UARTINT_RX; 303 | break; 304 | 305 | case 1: 306 | UART1->imsc |= UARTINT_RX; 307 | break; 308 | 309 | case 2: 310 | UART2->imsc |= UARTINT_RX; 311 | break; 312 | } 313 | CPU_CRITICAL_EXIT(); 314 | } 315 | 316 | 317 | /* 318 | ********************************************************************************************************* 319 | * MB_CommRxTxISR_Handler() 320 | * 321 | * Description : This function is the ISR for either a received or transmitted character. 322 | * 323 | * Argument(s) : none. 324 | * 325 | * Return(s) : none. 326 | * 327 | * Caller(s) : This is a ISR 328 | * 329 | * Note(s) : (1) The pseudo-code for this function should be: 330 | * 331 | * if (Rx Byte has been received) { 332 | * c = get byte from serial port; 333 | * Clear receive interrupt; 334 | * pch->RxCtr++; Increment the number of bytes received 335 | * MB_RxByte(pch, c); Pass character to Modbus to process 336 | * } 337 | * 338 | * if (Byte has been transmitted) { 339 | * pch->TxCtr++; Increment the number of bytes transmitted 340 | * MB_TxByte(pch); Send next byte in response 341 | * Clear transmit interrupt Clear Transmit Interrupt flag 342 | * } 343 | ********************************************************************************************************* 344 | */ 345 | 346 | void MB_CommRxTxISR_Handler (CPU_INT08U port_nbr) 347 | { 348 | CPU_INT08U c; 349 | CPU_INT08U ch; 350 | MODBUS_CH *pch; 351 | CPU_INT32U mis; 352 | UARTREGS *pUART; 353 | 354 | 355 | switch (port_nbr) { /* Point to UART port data structure */ 356 | case 0: 357 | pUART = UART0; 358 | break; 359 | 360 | case 1: 361 | pUART = UART1; 362 | break; 363 | 364 | case 2: 365 | pUART = UART2; 366 | break; 367 | } 368 | pch = &MB_ChTbl[0]; 369 | for (ch = 0; ch < MODBUS_CFG_MAX_CH; ch++) { /* Find the channel assigned to this port */ 370 | if (pch->PortNbr == port_nbr) { 371 | mis = pUART->mis; 372 | if (mis & UARTINT_RX) { 373 | c = (CPU_INT08U)(pUART->dr & 0x00FF); /* Read the character from the UART */ 374 | pUART->icr = UARTINT_RX; /* Clear receive interrupt */ 375 | pch->RxCtr++; 376 | MB_RxByte(pch, c); /* Pass character to Modbus to process */ 377 | } 378 | if (mis & UARTINT_TX) { 379 | pch->TxCtr++; 380 | MB_TxByte(pch); /* Send next byte */ 381 | pUART->icr = UARTINT_TX; /* Clear transmit interrupt */ 382 | } 383 | break; 384 | } else { 385 | pch++; 386 | } 387 | } 388 | pUART->icr = UARTINT_RT /* Clear other 'spurious' interrupts */ 389 | | UARTINT_FE 390 | | UARTINT_PE 391 | | UARTINT_BE 392 | | UARTINT_OE; 393 | VIC->vectoraddr = 0x00000000L; /* Clear the vector address register */ 394 | } 395 | 396 | 397 | /* 398 | ********************************************************************************************************* 399 | * UART #0 Rx/Tx Communication handler for Modbus 400 | ********************************************************************************************************* 401 | */ 402 | 403 | void MB_CommRxTxISR_0_Handler (void) 404 | { 405 | MB_CommRxTxISR_Handler(0); 406 | } 407 | 408 | 409 | /* 410 | ********************************************************************************************************* 411 | * UART #1 Rx/Tx Communication handler for Modbus 412 | ********************************************************************************************************* 413 | */ 414 | 415 | void MB_CommRxTxISR_1_Handler (void) 416 | { 417 | MB_CommRxTxISR_Handler(1); 418 | } 419 | 420 | 421 | /* 422 | ********************************************************************************************************* 423 | * UART #1 Rx/Tx Communication handler for Modbus 424 | ********************************************************************************************************* 425 | */ 426 | 427 | void MB_CommRxTxISR_2_Handler (void) 428 | { 429 | MB_CommRxTxISR_Handler(2); 430 | } 431 | 432 | 433 | /* 434 | ********************************************************************************************************* 435 | * MB_CommTx1() 436 | * 437 | * Description : This function is called to obtain the next byte to send from the transmit buffer. When 438 | * all bytes in the reply have been sent, transmit interrupts are disabled and the receiver 439 | * is enabled to accept the next Modbus request. 440 | * 441 | * Argument(s) : c is the byte to send to the serial port 442 | * 443 | * Return(s) : none. 444 | * 445 | * Caller(s) : MB_TxByte() 446 | * 447 | * Note(s) : none. 448 | ********************************************************************************************************* 449 | */ 450 | 451 | void MB_CommTx1 (MODBUS_CH *pch, 452 | CPU_INT08U c) 453 | { 454 | switch (pch->PortNbr) { 455 | case 0: 456 | UART0->dr = (CPU_INT32U)c; 457 | break; 458 | 459 | case 1: 460 | UART1->dr = (CPU_INT32U)c; 461 | break; 462 | 463 | case 2: 464 | UART2->dr = (CPU_INT32U)c; 465 | break; 466 | } 467 | } 468 | 469 | 470 | /* 471 | ********************************************************************************************************* 472 | * MB_CommTxIntDis() 473 | * 474 | * Description : This function disables Tx interrupts. 475 | * 476 | * Argument(s) : pch is a pointer to the Modbus channel 477 | * 478 | * Return(s) : none. 479 | * 480 | * Caller(s) : MB_CommExit() 481 | * MB_TxByte() 482 | * 483 | * Note(s) : none. 484 | ********************************************************************************************************* 485 | */ 486 | 487 | void MB_CommTxIntDis (MODBUS_CH *pch) 488 | { 489 | CPU_SR cpu_sr = 0; 490 | 491 | 492 | CPU_CRITICAL_ENTER(); 493 | switch (pch->PortNbr) { /* Just enable the receiver interrupt */ 494 | case 0: 495 | UART0->imsc = UARTINT_RX; 496 | break; 497 | 498 | case 1: 499 | UART1->imsc = UARTINT_RX; 500 | break; 501 | 502 | case 2: 503 | UART2->imsc = UARTINT_RX; 504 | break; 505 | } 506 | CPU_CRITICAL_EXIT(); 507 | } 508 | 509 | 510 | /* 511 | ********************************************************************************************************* 512 | * MB_CommTxIntEn() 513 | * 514 | * Description : This function enables Tx interrupts. 515 | * 516 | * Argument(s) : pch is a pointer to the Modbus channel 517 | * 518 | * Return(s) : none. 519 | * 520 | * Caller(s) : MB_Tx() 521 | * 522 | * Note(s) : none. 523 | ********************************************************************************************************* 524 | */ 525 | 526 | void MB_CommTxIntEn (MODBUS_CH *pch) 527 | { 528 | CPU_SR cpu_sr = 0; 529 | 530 | 531 | CPU_CRITICAL_ENTER(); 532 | switch (pch->PortNbr) { /* Just enable the receiver interrupt */ 533 | case 0: 534 | UART0->imsc = UARTINT_RX | UARTINT_TX; 535 | break; 536 | 537 | case 1: 538 | UART1->imsc = UARTINT_RX | UARTINT_TX; 539 | break; 540 | 541 | case 2: 542 | UART2->imsc = UARTINT_RX | UARTINT_TX; 543 | break; 544 | } 545 | CPU_CRITICAL_EXIT(); 546 | } 547 | 548 | 549 | /* 550 | ********************************************************************************************************* 551 | * MB_RTU_TmrInit() 552 | * 553 | * Description : This function is called to initialize the RTU timeout timer. 554 | * 555 | * Argument(s) : freq Is the frequency of the modbus RTU timer interrupt. 556 | * 557 | * Return(s) : none. 558 | * 559 | * Caller(s) : MB_Init(). 560 | * 561 | * Note(s) : none. 562 | ********************************************************************************************************* 563 | */ 564 | 565 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 566 | void MB_RTU_TmrInit (void) 567 | { 568 | TIMER3->clear = 0; /* Enable Timer #3 for Modbus RTU Timer */ 569 | TIMER3->load = BSP_LH79520_CLK / 16 / MB_RTU_Freq; 570 | TIMER3->control = TMRCTRL_ENABLE | TMRCTRL_MODE_PERIODIC | TMRCTRL_PRESCALE16; 571 | 572 | /* Setup the interrupt vector for the tick ISR */ 573 | /* Timer interrupt is a medium priority */ 574 | VIC->vectcntl[VIC_VECT_MODBUS_RTU_TMR] = VIC_VECTCNTL_ENABLE | VIC_TIMER3; 575 | VIC->vectaddr[VIC_VECT_MODBUS_RTU_TMR] = (CPU_INT32U)MB_RTU_TmrISR_Handler; 576 | VIC->intenable = _BIT(VIC_TIMER3); 577 | 578 | MB_RTU_TmrResetAll(); /* Reset all the RTU timers, we changed freq. */ 579 | } 580 | #endif 581 | 582 | 583 | /* 584 | ********************************************************************************************************* 585 | * MB_RTU_TmrExit() 586 | * 587 | * Description : This function is called to disable the RTU timeout timer. 588 | * 589 | * Argument(s) : none. 590 | * 591 | * Return(s) : none. 592 | * 593 | * Caller(s) : MB_Exit() 594 | * 595 | * Note(s) : none. 596 | ********************************************************************************************************* 597 | */ 598 | 599 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 600 | void MB_RTU_TmrExit (void) 601 | { 602 | TIMER3->control = TMRCTRL_DISABLE | TMRCTRL_MODE_PERIODIC | TMRCTRL_PRESCALE16; 603 | } 604 | #endif 605 | 606 | 607 | /* 608 | ********************************************************************************************************* 609 | * MB_RTU_TmrISR_Handler() 610 | * 611 | * Description : This function handles the case when the RTU timeout timer expires. 612 | * 613 | * Arguments : none. 614 | * 615 | * Returns : none. 616 | * 617 | * Caller(s) : This is a ISR. 618 | * 619 | * Note(s) : none. 620 | ********************************************************************************************************* 621 | */ 622 | 623 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 624 | void MB_RTU_TmrISR_Handler (void) 625 | { 626 | TIMER3->clear = 0x00000000L; /* Clear the RTU interrupt source */ 627 | VIC->vectoraddr = 0x00000000L; /* Clear the vector address register */ 628 | 629 | MB_RTU_TmrCtr++; /* Indicate that we had activities on this interrupt. */ 630 | MB_RTU_TmrUpdate(); /* Check for RTU timers that have expired */ 631 | } 632 | #endif 633 | -------------------------------------------------------------------------------- /Ports/ARM7/LPC2000/IAR/mb_bsp.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * MODBUS BOARD SUPPORT PACKAGE 23 | * Philips LPC2000 (ARM7) 24 | * 25 | * Filename : mb_bsp.c 26 | * Version : V2.14.00 27 | ********************************************************************************************************* 28 | */ 29 | 30 | /* 31 | ********************************************************************************************************* 32 | * INCLUDE FILES 33 | ********************************************************************************************************* 34 | */ 35 | 36 | #include 37 | 38 | /* 39 | ********************************************************************************************************* 40 | * LOCAL DEFINES 41 | ********************************************************************************************************* 42 | */ 43 | 44 | #define BIT0 0x01 45 | #define BIT1 0x02 46 | #define BIT2 0x04 47 | #define BIT3 0x08 48 | #define BIT4 0x10 49 | #define BIT5 0x20 50 | #define BIT6 0x40 51 | #define BIT7 0x80 52 | 53 | /* 54 | ********************************************************************************************************* 55 | * LOCAL VARIABLES 56 | ********************************************************************************************************* 57 | */ 58 | 59 | static CPU_INT32U MB_Tmr_ReloadCnts; 60 | 61 | 62 | /* 63 | ********************************************************************************************************* 64 | * MB_CommExit() 65 | * 66 | * Description : This function is called to terminate Modbus communications. All Modbus channels are close. 67 | * 68 | * Argument(s) : none 69 | * 70 | * Return(s) : none. 71 | * 72 | * Caller(s) : MB_Exit() 73 | * 74 | * Note(s) : none. 75 | ********************************************************************************************************* 76 | */ 77 | 78 | void MB_CommExit (void) 79 | { 80 | CPU_INT08U ch; 81 | MODBUS_CH *pch; 82 | 83 | 84 | pch = &MB_ChTbl[0]; 85 | for (ch = 0; ch < MODBUS_CFG_MAX_CH; ch++) { 86 | MB_CommTxIntDis(pch); 87 | MB_CommRxIntDis(pch); 88 | pch++; 89 | } 90 | } 91 | 92 | 93 | /* 94 | ********************************************************************************************************* 95 | * MB_CommPortCfg() 96 | * 97 | * Description : This function initializes the serial port to the desired baud rate and the UART will be 98 | * configured for N, 8, 1 (No parity, 8 bits, 1 stop). 99 | * 100 | * Argument(s) : pch is a pointer to the Modbus channel 101 | * port_nbr is the desired serial port number. This argument allows you to assign a 102 | * specific serial port to a sepcific Modbus channel. 103 | * baud is the desired baud rate for the serial port. 104 | * parity is the desired parity and can be either: 105 | * 106 | * MODBUS_PARITY_NONE 107 | * MODBUS_PARITY_ODD 108 | * MODBUS_PARITY_EVEN 109 | * 110 | * bits specifies the number of bit and can be either 7 or 8. 111 | * stops specifies the number of stop bits and can either be 1 or 2 112 | * 113 | * Return(s) : none. 114 | * 115 | * Caller(s) : MB_CfgCh() 116 | * 117 | * Note(s) : none. 118 | ********************************************************************************************************* 119 | */ 120 | 121 | void MB_CommPortCfg (MODBUS_CH *pch, 122 | CPU_INT08U port_nbr, 123 | CPU_INT32U baud, 124 | CPU_INT08U bits, 125 | CPU_INT08U parity, 126 | CPU_INT08U stops) 127 | { 128 | CPU_INT32U pinsel; 129 | CPU_INT32U peripheral_clk_freq; 130 | CPU_INT16U div; /* Baud rate divisor */ 131 | CPU_INT08U divlo; 132 | CPU_INT08U divhi; 133 | CPU_INT08U lcr; /* Line Control Register */ 134 | CPU_SR cpu_sr = 0; 135 | 136 | 137 | if (pch != (MODBUS_CH *)0) { 138 | pch->PortNbr = port_nbr; /* Store configuration in channel */ 139 | pch->BaudRate = baud; 140 | pch->Parity = parity; 141 | pch->Bits = bits; 142 | pch->Stops = stops; 143 | /* Compute divisor for desired baud rate */ 144 | peripheral_clk_freq = BSP_CPU_ClkFreqPeripheral(); 145 | div = (CPU_INT16U)(((2 * peripheral_clk_freq / 16 / baud) + 1) / 2); 146 | divlo = div & 0x00FF; /* Split divisor into LOW and HIGH bytes */ 147 | divhi = (div >> 8) & 0x00FF; 148 | lcr = 0; /* Setup #bits, parity and stop bits */ 149 | switch (bits) { 150 | case 7: 151 | lcr |= 2 << 0; 152 | break; 153 | 154 | case 8: 155 | default: 156 | lcr |= 3 << 0; 157 | break; 158 | } 159 | 160 | switch (parity) { 161 | case MODBUS_PARITY_ODD: 162 | lcr |= BIT3; 163 | break; 164 | 165 | case MODBUS_PARITY_EVEN: 166 | lcr |= BIT4 | BIT3; 167 | break; 168 | 169 | case MODBUS_PARITY_NONE: 170 | default: 171 | break; 172 | } 173 | 174 | switch (stops) { 175 | case 1: 176 | break; 177 | 178 | case 2: 179 | default: 180 | lcr |= BIT2; 181 | break; 182 | } 183 | 184 | switch (port_nbr) { /* Determine which serial port is assigned */ 185 | case 0: 186 | CPU_CRITICAL_ENTER(); 187 | pinsel = PINSEL0; /* Enable UART0 I/Os */ 188 | pinsel &= 0xFFFFFFF0; 189 | pinsel |= 0x00000005; 190 | PINSEL0 = pinsel; 191 | U0LCR = BIT7; /* Set divisor access bit */ 192 | U0DLL = divlo; /* Load divisor */ 193 | U0DLM = divhi; 194 | U0LCR = lcr; /* Set line control register (Bit 8 is 0) */ 195 | U0IER = BIT0; /* Enable Rx interrupts only */ 196 | U0FCR = 0x07; /* Enable FIFO, flush Rx & Tx */ 197 | CPU_CRITICAL_EXIT(); 198 | /* VIC UART #0 Initialization */ 199 | VICIntSelect &= ~(1 << VIC_UART0); /* Enable interrupts */ 200 | VICVectAddr14 = (CPU_INT32U)MB_CommRxTxISR_0_Handler; /* Set the vector address */ 201 | VICVectCntl14 = 0x20 | VIC_UART0; /* Enable vectored interrupts */ 202 | VICIntEnable = (1 << VIC_UART0); /* Enable Interrupts */ 203 | break; 204 | 205 | case 1: 206 | CPU_CRITICAL_ENTER(); 207 | pinsel = PINSEL0; /* Enable UART1 I/Os */ 208 | pinsel &= 0xFFF0FFFF; 209 | pinsel |= 0x00050000; 210 | PINSEL0 = pinsel; 211 | U1LCR = BIT7; /* Set divisor access bit */ 212 | U1DLL = divlo; /* Load divisor */ 213 | U1DLM = divhi; 214 | U1LCR = lcr; /* Set line control register (Bit 8 is 0) */ 215 | U1IER = BIT0; /* Enable Rx interrupts only */ 216 | U1FCR = 0x07; /* Enable FIFO, flush Rx & Tx */ 217 | CPU_CRITICAL_EXIT(); 218 | /* VIC UART #1 Initialization */ 219 | VICIntSelect &= ~(1 << VIC_UART1); /* Enable interrupts */ 220 | VICVectAddr14 = (CPU_INT32U)MB_CommRxTxISR_1_Handler; /* Set the vector address */ 221 | VICVectCntl14 = 0x20 | VIC_UART1; /* Enable vectored interrupts */ 222 | VICIntEnable = (1 << VIC_UART1); /* Enable Interrupts */ 223 | } 224 | } 225 | } 226 | 227 | 228 | /* 229 | ********************************************************************************************************* 230 | * MB_CommRxIntDis() 231 | * 232 | * Description : This function disables Rx interrupts. 233 | * 234 | * Argument(s) : pch is a pointer to the Modbus channel 235 | * 236 | * Return(s) : none. 237 | * 238 | * Caller(s) : MB_CommExit() 239 | * 240 | * Note(s) : none. 241 | ********************************************************************************************************* 242 | */ 243 | 244 | void MB_CommRxIntDis (MODBUS_CH *pch) 245 | { 246 | CPU_SR cpu_sr = 0; 247 | 248 | 249 | CPU_CRITICAL_ENTER(); 250 | switch (pch->PortNbr) { 251 | case 0: 252 | U0IER = 0; 253 | break; 254 | 255 | case 1: 256 | U1IER = 0; 257 | break; 258 | } 259 | CPU_CRITICAL_EXIT(); 260 | } 261 | 262 | 263 | /* 264 | ********************************************************************************************************* 265 | * MB_CommRxIntEn() 266 | * 267 | * Description : This function enables Rx interrupts. 268 | * 269 | * Argument(s) : pch is a pointer to the Modbus channel 270 | * 271 | * Return(s) : none. 272 | * 273 | * Caller(s) : MB_TxByte() 274 | * 275 | * Note(s) : none. 276 | ********************************************************************************************************* 277 | */ 278 | 279 | void MB_CommRxIntEn (MODBUS_CH *pch) 280 | { 281 | CPU_SR cpu_sr = 0; 282 | 283 | 284 | CPU_CRITICAL_ENTER(); 285 | switch (pch->PortNbr) { 286 | case 0: 287 | U0IER = BIT0; 288 | break; 289 | 290 | case 1: 291 | U1IER = BIT0; 292 | break; 293 | } 294 | CPU_CRITICAL_EXIT(); 295 | } 296 | 297 | 298 | /* 299 | ********************************************************************************************************* 300 | * MB_CommRxTxISR_Handler() 301 | * 302 | * Description : This function is the ISR for either a received or transmitted character. 303 | * 304 | * Argument(s) : none. 305 | * 306 | * Return(s) : none. 307 | * 308 | * Caller(s) : This is a ISR 309 | * 310 | * Note(s) : (1) The pseudo-code for this function should be: 311 | * 312 | * if (Rx Byte has been received) { 313 | * c = get byte from serial port; 314 | * Clear receive interrupt; 315 | * pch->RxCtr++; Increment the number of bytes received 316 | * MB_RxByte(pch, c); Pass character to Modbus to process 317 | * } 318 | * 319 | * if (Byte has been transmitted) { 320 | * pch->TxCtr++; Increment the number of bytes transmitted 321 | * MB_TxByte(pch); Send next byte in response 322 | * Clear transmit interrupt Clear Transmit Interrupt flag 323 | * } 324 | ********************************************************************************************************* 325 | */ 326 | 327 | void MB_CommRxTxISR_Handler (CPU_INT08U port_nbr) 328 | { 329 | CPU_INT08U ch; 330 | MODBUS_CH *pch; 331 | volatile CPU_INT08U rx_data; 332 | volatile CPU_INT08U lsr; 333 | volatile CPU_INT08U iir; 334 | 335 | 336 | pch = &MB_ChTbl[0]; 337 | for (ch = 0; ch < MODBUS_CFG_MAX_CH; ch++) { /* Find the channel assigned to this port */ 338 | if (pch->PortNbr == port_nbr) { 339 | break; 340 | } else { 341 | pch++; 342 | } 343 | } 344 | 345 | switch (port_nbr) { /* Point to UART port data structure */ 346 | case 0: 347 | iir = U0IIR & 0x0F; 348 | while (iir != 1) { 349 | switch (iir) { 350 | case 0: /* Modem interrupt? */ 351 | break; 352 | 353 | case 2: /* Transmitted character? */ 354 | pch->TxCtr++; 355 | MB_TxByte(pch); /* Send next byte */ 356 | break; 357 | 358 | case 4: /* Received a character? */ 359 | lsr = U0LSR; 360 | rx_data = U0RBR; 361 | pch->RxCtr++; 362 | MB_RxByte(pch, rx_data); /* Pass character to Modbus to process */ 363 | break; 364 | 365 | case 6: /* Receive Line Status interrupt? */ 366 | break; 367 | 368 | case 12: /* CTI interrupt? */ 369 | break; 370 | } 371 | iir = U0IIR & 0x0F; 372 | } 373 | break; 374 | 375 | case 1: 376 | iir = U1IIR & 0x0F; 377 | while (iir != 1) { 378 | switch (iir) { 379 | case 0: /* Modem interrupt? */ 380 | break; 381 | 382 | case 2: /* Transmitted character? */ 383 | pch->TxCtr++; 384 | MB_TxByte(pch); /* Send next byte */ 385 | break; 386 | 387 | case 4: /* Received a character? */ 388 | lsr = U1LSR; 389 | rx_data = U1RBR; 390 | pch->RxCtr++; 391 | MB_RxByte(pch, rx_data); /* Pass character to Modbus to process */ 392 | break; 393 | 394 | case 6: /* Receive Line Status interrupt? */ 395 | break; 396 | 397 | case 12: /* CTI interrupt? */ 398 | break; 399 | } 400 | iir = U1IIR & 0x0F; 401 | } 402 | break; 403 | } 404 | 405 | VICVectAddr = 0x00000000L; /* Clear the vector address register */ 406 | } 407 | 408 | 409 | /* 410 | ********************************************************************************************************* 411 | * UART #0 Rx/Tx Communication handler for Modbus 412 | ********************************************************************************************************* 413 | */ 414 | 415 | void MB_CommRxTxISR_0_Handler (void) 416 | { 417 | MB_CommRxTxISR_Handler(0); 418 | } 419 | 420 | 421 | /* 422 | ********************************************************************************************************* 423 | * UART #1 Rx/Tx Communication handler for Modbus 424 | ********************************************************************************************************* 425 | */ 426 | 427 | void MB_CommRxTxISR_1_Handler (void) 428 | { 429 | MB_CommRxTxISR_Handler(1); 430 | } 431 | 432 | 433 | /* 434 | ********************************************************************************************************* 435 | * MB_CommTx1() 436 | * 437 | * Description : This function is called to obtain the next byte to send from the transmit buffer. When 438 | * all bytes in the reply have been sent, transmit interrupts are disabled and the receiver 439 | * is enabled to accept the next Modbus request. 440 | * 441 | * Argument(s) : c is the byte to send to the serial port 442 | * 443 | * Return(s) : none. 444 | * 445 | * Caller(s) : MB_TxByte() 446 | * 447 | * Note(s) : none. 448 | ********************************************************************************************************* 449 | */ 450 | 451 | void MB_CommTx1 (MODBUS_CH *pch, 452 | CPU_INT08U c) 453 | { 454 | switch (pch->PortNbr) { 455 | case 0: 456 | U0THR = c; 457 | break; 458 | 459 | case 1: 460 | U1THR = c; 461 | break; 462 | } 463 | } 464 | 465 | 466 | /* 467 | ********************************************************************************************************* 468 | * MB_CommTxIntDis() 469 | * 470 | * Description : This function disables Tx interrupts. 471 | * 472 | * Argument(s) : pch is a pointer to the Modbus channel 473 | * 474 | * Return(s) : none. 475 | * 476 | * Caller(s) : MB_CommExit() 477 | * MB_TxByte() 478 | * 479 | * Note(s) : none. 480 | ********************************************************************************************************* 481 | */ 482 | 483 | void MB_CommTxIntDis (MODBUS_CH *pch) 484 | { 485 | CPU_SR cpu_sr = 0; 486 | 487 | 488 | CPU_CRITICAL_ENTER(); 489 | switch (pch->PortNbr) { /* Just enable the receiver interrupt */ 490 | case 0: 491 | U0IER = BIT0; 492 | break; 493 | 494 | case 1: 495 | U1IER = BIT0; 496 | break; 497 | } 498 | CPU_CRITICAL_EXIT(); 499 | } 500 | 501 | 502 | /* 503 | ********************************************************************************************************* 504 | * MB_CommTxIntEn() 505 | * 506 | * Description : This function enables Tx interrupts. 507 | * 508 | * Argument(s) : pch is a pointer to the Modbus channel 509 | * 510 | * Return(s) : none. 511 | * 512 | * Caller(s) : MB_Tx() 513 | * 514 | * Note(s) : none. 515 | ********************************************************************************************************* 516 | */ 517 | 518 | void MB_CommTxIntEn (MODBUS_CH *pch) 519 | { 520 | CPU_SR cpu_sr = 0; 521 | 522 | 523 | CPU_CRITICAL_ENTER(); 524 | switch (pch->PortNbr) { /* Just enable the receiver interrupt */ 525 | case 0: 526 | U0IER = BIT1 | BIT0; 527 | break; 528 | 529 | case 1: 530 | U1IER = BIT1 | BIT0; 531 | break; 532 | } 533 | CPU_CRITICAL_EXIT(); 534 | } 535 | 536 | 537 | /* 538 | ********************************************************************************************************* 539 | * MB_RTU_TmrInit() 540 | * 541 | * Description : This function is called to initialize the RTU timeout timer. 542 | * 543 | * Argument(s) : freq Is the frequency of the modbus RTU timer interrupt. 544 | * 545 | * Return(s) : none. 546 | * 547 | * Caller(s) : MB_Init(). 548 | * 549 | * Note(s) : none. 550 | ********************************************************************************************************* 551 | */ 552 | 553 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 554 | void MB_RTU_TmrInit (void) 555 | { 556 | CPU_INT32U peripheral_clk_freq; 557 | 558 | 559 | peripheral_clk_freq = BSP_CPU_ClkFreqPeripheral(); 560 | MB_Tmr_ReloadCnts = peripheral_clk_freq / MB_RTU_Freq; 561 | T1TCR = 0; /* Disable timer 1. */ 562 | T1PC = 0; /* Prescaler is set to no division. */ 563 | T1MR0 = T1TC + MB_Tmr_ReloadCnts; 564 | T1MCR = 1; /* Interrupt on MR0 (match register 0). */ 565 | T1CCR = 0; /* Capture is disabled. */ 566 | T1EMR = 0; /* No external match output. */ 567 | T1TCR = 1; /* Enable timer 1 */ 568 | 569 | VICIntSelect &= ~(1 << VIC_TIMER1); /* Enable interrupts */ 570 | VICVectAddr13 = (CPU_INT32U)MB_RTU_TmrISR_Handler; /* Set the vector address */ 571 | VICVectCntl13 = 0x20 | VIC_TIMER1; /* Enable vectored interrupts */ 572 | VICIntEnable = (1 << VIC_TIMER1); /* Enable Interrupts */ 573 | 574 | MB_RTU_TmrResetAll(); /* Reset all the RTU timers, we changed freq. */ 575 | } 576 | #endif 577 | 578 | 579 | /* 580 | ********************************************************************************************************* 581 | * MB_RTU_TmrExit() 582 | * 583 | * Description : This function is called to disable the RTU timeout timer. 584 | * 585 | * Argument(s) : none. 586 | * 587 | * Return(s) : none. 588 | * 589 | * Caller(s) : MB_Exit() 590 | * 591 | * Note(s) : none. 592 | ********************************************************************************************************* 593 | */ 594 | 595 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 596 | void MB_RTU_TmrExit (void) 597 | { 598 | T1TCR = 0; /* Disable timer 1 */ 599 | } 600 | #endif 601 | 602 | 603 | /* 604 | ********************************************************************************************************* 605 | * MB_RTU_TmrISR_Handler() 606 | * 607 | * Description : This function handles the case when the RTU timeout timer expires. 608 | * 609 | * Arguments : none. 610 | * 611 | * Returns : none. 612 | * 613 | * Caller(s) : This is a ISR. 614 | * 615 | * Note(s) : none. 616 | ********************************************************************************************************* 617 | */ 618 | 619 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 620 | void MB_RTU_TmrISR_Handler (void) 621 | { 622 | T1IR = 0xFF; /* Clear timer #1 interrupt */ 623 | /* Reload 'relative' to current interrupt time */ 624 | T1MR0 = T1TC + MB_Tmr_ReloadCnts; 625 | VICVectAddr = 0; 626 | 627 | MB_RTU_TmrCtr++; /* Indicate that we had activities on this interrupt. */ 628 | MB_RTU_TmrUpdate(); /* Check for RTU timers that have expired */ 629 | } 630 | #endif 631 | -------------------------------------------------------------------------------- /Ports/ARM9/AT91SAM9261/mb_bsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * Board Support Package 23 | * Atmel AT91SAM9261 (ARM9) 24 | * 25 | * Filename : mb_bsp.h 26 | * Version : V2.14.00 27 | ********************************************************************************************************* 28 | */ 29 | 30 | #ifndef __MB_BSP_H__ 31 | #define __MB_BSP_H__ 32 | 33 | 34 | /* 35 | ********************************************************************************************************* 36 | * DEFINES 37 | ********************************************************************************************************* 38 | */ 39 | /* ------------------ UART PORT NUMBERS DEFINES ------------ */ 40 | #define MB_BSP_UART_00 1 41 | #define MB_BSP_UART_01 2 42 | #define MB_BSP_UART_02 3 43 | #define MB_BSP_UART_DBG 4 44 | /* ------------------- UART COMMUNICATION MODE ------------- */ 45 | #define MB_BSP_UART_RS232_MODE 1 46 | #define MB_BSP_UART_RS485_MODE 2 47 | /* ----------------- TIMER CONFIGURATION. RTU MODE -------- */ 48 | #define MB_BSP_TMR_0 1 49 | #define MB_BSP_TMR_1 2 50 | #define MB_BSP_TMR_2 3 51 | 52 | 53 | 54 | /* 55 | ********************************************************************************************************* 56 | * CONFIGURATION ERRORS 57 | ********************************************************************************************************* 58 | */ 59 | 60 | void MB_CommRxTxISR_3_Handler (void); 61 | 62 | /* 63 | ********************************************************************************************************* 64 | * CONFIGURATION ERRORS 65 | ********************************************************************************************************* 66 | */ 67 | /*-------------- UART MODE CONFIGURATION ERRORS ------------ */ 68 | #ifndef MB_BSP_CFG_UART_00_MODE 69 | #error "MB_BSP_CFG_UART_00_MODE not #define'd in 'app_cfg.h' " 70 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 71 | #error " [ || MB_BSP_UART_RS485_MODE ] " 72 | 73 | #elif (MB_BSP_CFG_UART_00_MODE != MB_BSP_UART_RS232_MODE ) && \ 74 | (MB_BSP_CFG_UART_00_MODE != MB_BSP_UART_RS485_MODE ) 75 | #error "MB_BSP_CFG_UART_00_MODE illegally #define'd in 'app_cfg.h' " 76 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 77 | #error " [ || MB_BSP_UART_RS485_MODE ] " 78 | #endif 79 | 80 | #ifndef MB_BSP_CFG_UART_01_MODE 81 | #error "MB_BSP_CFG_UART_01_MODE not #define'd in 'app_cfg.h' " 82 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 83 | #error " [ || MB_BSP_UART_RS485_MODE ] " 84 | 85 | #elif (MB_BSP_CFG_UART_01_MODE != MB_BSP_UART_RS232_MODE ) && \ 86 | (MB_BSP_CFG_UART_01_MODE != MB_BSP_UART_RS485_MODE ) 87 | #error "MB_BSP_CFG_UART_01_MODE illegally #define'd in 'app_cfg.h' 88 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 89 | #error " [ || MB_BSP_UART_RS485_MODE ] " 90 | #endif 91 | 92 | #ifndef MB_BSP_CFG_UART_01_MODE 93 | #error "MB_BSP_CFG_UART_01_MODE not #define'd in 'app_cfg.h' " 94 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 95 | #error " [ || MB_BSP_UART_RS485_MODE ] " 96 | 97 | #elif (MB_BSP_CFG_UART_02_MODE != MB_BSP_UART_RS232_MODE ) && \ 98 | (MB_BSP_CFG_UART_02_MODE != MB_BSP_UART_RS485_MODE ) 99 | #error "MB_BSP_CFG_UART_01_MODE illegally #define'd in 'app_cfg.h' " 100 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 101 | #error " [ || MB_BSP_UART_RS485_MODE ] " 102 | #endif 103 | 104 | /*-------------- TIMER SEL CONFIGURATION ------------ */ 105 | #ifndef MS_BSP_CFG_TMR 106 | #error "MS_BSP_CFG_TMR not #define'd in 'app_cfg.h' " 107 | #error " [MUST be MB_BSP_TMR_0 ] " 108 | #error " [ || MB_BSP_TMR_1 ] " 109 | #error " [ || MB_BSP_TMR_2 ] " 110 | 111 | #elif (MS_BSP_CFG_TMR != MB_BSP_TMR_0 ) && \ 112 | (MS_BSP_CFG_TMR != MB_BSP_TMR_1 ) && \ 113 | (MS_BSP_CFG_TMR != MB_BSP_TMR_2 ) 114 | #error "MS_BSP_CFG_TMR illegally #define'd in 'app_cfg.h' " 115 | #error " [MUST be MB_BSP_TMR_0 ] " 116 | #error " [ || MB_BSP_TMR_1 ] " 117 | #error " [ || MB_BSP_TMR_2 ] " 118 | 119 | #endif 120 | 121 | 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /Ports/ARM9/AT91SAM9263/mb_bsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * Board Support Package 23 | * Atmel AT91SAM9263 (ARM9) 24 | * 25 | * Filename : mb_bsp.h 26 | * Version : V2.14.00 27 | ********************************************************************************************************* 28 | */ 29 | 30 | #ifndef __MB_BSP_H__ 31 | #define __MB_BSP_H__ 32 | 33 | 34 | /* 35 | ********************************************************************************************************* 36 | * DEFINES 37 | ********************************************************************************************************* 38 | */ 39 | /* ------------------ UART PORT NUMBERS DEFINES ------------ */ 40 | #define MB_BSP_UART_00 1 41 | #define MB_BSP_UART_01 2 42 | #define MB_BSP_UART_02 3 43 | #define MB_BSP_UART_DBG 4 44 | /* ------------------- UART COMMUNICATION MODE ------------- */ 45 | #define MB_BSP_UART_RS232_MODE 1 46 | #define MB_BSP_UART_RS485_MODE 2 47 | /* ----------------- TIMER CONFIGURATION. RTU MODE -------- */ 48 | #define MB_BSP_TMR_0 1 49 | #define MB_BSP_TMR_1 2 50 | #define MB_BSP_TMR_2 3 51 | 52 | 53 | 54 | /* 55 | ********************************************************************************************************* 56 | * CONFIGURATION ERRORS 57 | ********************************************************************************************************* 58 | */ 59 | 60 | void MB_CommRxTxISR_3_Handler (void); 61 | 62 | /* 63 | ********************************************************************************************************* 64 | * CONFIGURATION ERRORS 65 | ********************************************************************************************************* 66 | */ 67 | /*-------------- UART MODE CONFIGURATION ERRORS ------------ */ 68 | #ifndef MB_BSP_CFG_UART_00_MODE 69 | #error "MB_BSP_CFG_UART_00_MODE not #define'd in 'app_cfg.h' " 70 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 71 | #error " [ || MB_BSP_UART_RS485_MODE ] " 72 | 73 | #elif (MB_BSP_CFG_UART_00_MODE != MB_BSP_UART_RS232_MODE ) && \ 74 | (MB_BSP_CFG_UART_00_MODE != MB_BSP_UART_RS485_MODE ) 75 | #error "MB_BSP_CFG_UART_00_MODE illegally #define'd in 'app_cfg.h' " 76 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 77 | #error " [ || MB_BSP_UART_RS485_MODE ] " 78 | #endif 79 | 80 | #ifndef MB_BSP_CFG_UART_01_MODE 81 | #error "MB_BSP_CFG_UART_01_MODE not #define'd in 'app_cfg.h' " 82 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 83 | #error " [ || MB_BSP_UART_RS485_MODE ] " 84 | 85 | #elif (MB_BSP_CFG_UART_01_MODE != MB_BSP_UART_RS232_MODE ) && \ 86 | (MB_BSP_CFG_UART_01_MODE != MB_BSP_UART_RS485_MODE ) 87 | #error "MB_BSP_CFG_UART_01_MODE illegally #define'd in 'app_cfg.h' 88 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 89 | #error " [ || MB_BSP_UART_RS485_MODE ] " 90 | #endif 91 | 92 | #ifndef MB_BSP_CFG_UART_01_MODE 93 | #error "MB_BSP_CFG_UART_01_MODE not #define'd in 'app_cfg.h' " 94 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 95 | #error " [ || MB_BSP_UART_RS485_MODE ] " 96 | 97 | #elif (MB_BSP_CFG_UART_02_MODE != MB_BSP_UART_RS232_MODE ) && \ 98 | (MB_BSP_CFG_UART_02_MODE != MB_BSP_UART_RS485_MODE ) 99 | #error "MB_BSP_CFG_UART_01_MODE illegally #define'd in 'app_cfg.h' " 100 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 101 | #error " [ || MB_BSP_UART_RS485_MODE ] " 102 | #endif 103 | 104 | /*-------------- TIMER SEL CONFIGURATION ------------ */ 105 | #ifndef MS_BSP_CFG_TMR 106 | #error "MS_BSP_CFG_TMR not #define'd in 'app_cfg.h' " 107 | #error " [MUST be MB_BSP_TMR_0 ] " 108 | #error " [ || MB_BSP_TMR_1 ] " 109 | #error " [ || MB_BSP_TMR_2 ] " 110 | 111 | #elif (MS_BSP_CFG_TMR != MB_BSP_TMR_0 ) && \ 112 | (MS_BSP_CFG_TMR != MB_BSP_TMR_1 ) && \ 113 | (MS_BSP_CFG_TMR != MB_BSP_TMR_2 ) 114 | #error "MS_BSP_CFG_TMR illegally #define'd in 'app_cfg.h' " 115 | #error " [MUST be MB_BSP_TMR_0 ] " 116 | #error " [ || MB_BSP_TMR_1 ] " 117 | #error " [ || MB_BSP_TMR_2 ] " 118 | 119 | #endif 120 | 121 | 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /Ports/ARM9/AT91SAM9XE/mb_bsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * Board Support Package 23 | * Atmel AT91SAM9XE (ARM9) 24 | * 25 | * Filename : mb_bsp.h 26 | * Version : V2.14.00 27 | ********************************************************************************************************* 28 | */ 29 | 30 | #ifndef __MB_BSP_H__ 31 | #define __MB_BSP_H__ 32 | 33 | 34 | /* 35 | ********************************************************************************************************* 36 | * DEFINES 37 | ********************************************************************************************************* 38 | */ 39 | /* ------------------ UART PORT NUMBERS DEFINES ------------ */ 40 | #define MB_BSP_UART_00 1 41 | #define MB_BSP_UART_01 2 42 | #define MB_BSP_UART_02 3 43 | #define MB_BSP_UART_03 4 44 | #define MB_BSP_UART_04 5 45 | #define MB_BSP_UART_DBG 6 46 | /* ------------------- UART COMMUNICATION MODE ------------- */ 47 | #define MB_BSP_UART_RS232_MODE 1 48 | #define MB_BSP_UART_RS485_MODE 2 49 | /* ----------------- TIMER CONFIGURATION. RTU MODE -------- */ 50 | #define MB_BSP_TMR_0 1 51 | #define MB_BSP_TMR_1 2 52 | #define MB_BSP_TMR_2 3 53 | #define MB_BSP_TMR_3 4 54 | #define MB_BSP_TMR_4 5 55 | #define MB_BSP_TMR_5 6 56 | 57 | 58 | void MB_CommRxTxISR_3_Handler (void); 59 | 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /Ports/Atmel/AVR32UC3A/mb_bsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * Board Support Package 23 | * Atmel AVR32UC3A 24 | * 25 | * Filename : mb_bsp.h 26 | * Version : V2.14.00 27 | ********************************************************************************************************* 28 | */ 29 | 30 | #ifndef __MB_BSP_H__ 31 | #define __MB_BSP_H__ 32 | 33 | 34 | /* 35 | ********************************************************************************************************* 36 | * DEFINES 37 | ********************************************************************************************************* 38 | */ 39 | /* ------------------ UART PORT NUMBERS DEFINES ------------ */ 40 | #define MB_BSP_UART_00 1 41 | #define MB_BSP_UART_01 2 42 | #define MB_BSP_UART_02 3 43 | #define MB_BSP_UART_03 4 44 | /* ------------------- UART COMMUNICATION MODE ------------- */ 45 | #define MB_BSP_UART_RS232_MODE 1 46 | #define MB_BSP_UART_RS485_MODE 2 47 | /* ----------------- TIMER CONFIGURATION. RTU MODE -------- */ 48 | #define MB_BSP_TMR_0 1 49 | 50 | 51 | /* 52 | ********************************************************************************************************* 53 | * CONFIGURATION ERRORS 54 | ********************************************************************************************************* 55 | */ 56 | /*-------------- UART MODE CONFIGURATION ERRORS ------------ */ 57 | #ifndef MB_BSP_CFG_UART_00_MODE 58 | #error "MB_BSP_CFG_UART_00_MODE not #define'd in 'app_cfg.h' " 59 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 60 | #error " [ || MB_BSP_UART_RS485_MODE ] " 61 | 62 | #elif (MB_BSP_CFG_UART_00_MODE != MB_BSP_UART_RS232_MODE ) && \ 63 | (MB_BSP_CFG_UART_00_MODE != MB_BSP_UART_RS485_MODE ) 64 | #error "MB_BSP_CFG_UART_00_MODE illegally #define'd in 'app_cfg.h' " 65 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 66 | #error " [ || MB_BSP_UART_RS485_MODE ] " 67 | #endif 68 | 69 | #ifndef MB_BSP_CFG_UART_01_MODE 70 | #error "MB_BSP_CFG_UART_01_MODE not #define'd in 'app_cfg.h' " 71 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 72 | #error " [ || MB_BSP_UART_RS485_MODE ] " 73 | 74 | #elif (MB_BSP_CFG_UART_01_MODE != MB_BSP_UART_RS232_MODE ) && \ 75 | (MB_BSP_CFG_UART_01_MODE != MB_BSP_UART_RS485_MODE ) 76 | #error "MB_BSP_CFG_UART_01_MODE illegally #define'd in 'app_cfg.h' 77 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 78 | #error " [ || MB_BSP_UART_RS485_MODE ] " 79 | #endif 80 | 81 | #ifndef MB_BSP_CFG_UART_02_MODE 82 | #error "MB_BSP_CFG_UART_02_MODE not #define'd in 'app_cfg.h' " 83 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 84 | #error " [ || MB_BSP_UART_RS485_MODE ] " 85 | 86 | #elif (MB_BSP_CFG_UART_02_MODE != MB_BSP_UART_RS232_MODE ) && \ 87 | (MB_BSP_CFG_UART_02_MODE != MB_BSP_UART_RS485_MODE ) 88 | #error "MB_BSP_CFG_UART_02_MODE illegally #define'd in 'app_cfg.h' " 89 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 90 | #error " [ || MB_BSP_UART_RS485_MODE ] " 91 | #endif 92 | 93 | #ifndef MB_BSP_CFG_UART_03_MODE 94 | #error "MB_BSP_CFG_UART_03_MODE not #define'd in 'app_cfg.h' " 95 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 96 | #error " [ || MB_BSP_UART_RS485_MODE ] " 97 | 98 | #elif (MB_BSP_CFG_UART_03_MODE != MB_BSP_UART_RS232_MODE ) && \ 99 | (MB_BSP_CFG_UART_03_MODE != MB_BSP_UART_RS485_MODE ) 100 | #error "MB_BSP_CFG_UART_03_MODE illegally #define'd in 'app_cfg.h' " 101 | #error " [MUST be MB_BSP_UART_RS232_MODE ] " 102 | #error " [ || MB_BSP_UART_RS485_MODE ] " 103 | #endif 104 | 105 | /*-------------- TIMER SEL CONFIGURATION ------------ */ 106 | #ifndef MS_BSP_CFG_TMR 107 | #error "MS_BSP_CFG_TMR not #define'd in 'app_cfg.h' " 108 | #error " [MUST be MB_BSP_TMR_0 ] " 109 | 110 | #elif (MS_BSP_CFG_TMR != MB_BSP_TMR_0 ) 111 | #error "MS_BSP_CFG_TMR illegally #define'd in 'app_cfg.h' " 112 | #error " [MUST be MB_BSP_TMR_0 ] " 113 | #endif 114 | 115 | 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /Ports/Freescale/MC9S12C32/Metrowerks/mb_bsp.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * 20 | * uC/Modbus 21 | * 22 | * MODBUS BOARD SUPPORT PACKAGE 23 | * Freescale MC9S12C32 24 | * 25 | * 26 | * Filename : mb_bsp.c 27 | * Version : V2.14.00 28 | ********************************************************************************************************* 29 | */ 30 | 31 | /* 32 | ********************************************************************************************************* 33 | * INCLUDE FILES 34 | ********************************************************************************************************* 35 | */ 36 | 37 | #include 38 | 39 | /* 40 | ********************************************************************************************************* 41 | * GLOBALS 42 | ********************************************************************************************************* 43 | */ 44 | 45 | 46 | 47 | /* 48 | ********************************************************************************************************* 49 | * MB_CommExit() 50 | * 51 | * Description : This function is called to terminate Modbus communications. All Modbus channels are close. 52 | * 53 | * Argument(s) : none 54 | * 55 | * Return(s) : none. 56 | * 57 | * Caller(s) : MB_Exit() 58 | * 59 | * Note(s) : none. 60 | ********************************************************************************************************* 61 | */ 62 | 63 | 64 | CPU_VOID MB_CommExit (CPU_VOID) 65 | { 66 | CPU_INT08U ch; 67 | MODBUS_CH *pch; 68 | 69 | 70 | pch = &MB_ChTbl[0]; 71 | for (ch = 0; ch < MODBUS_CFG_MAX_CH; ch++) { 72 | MBS_CommTxIntDis(pch); 73 | MBS_CommRxIntDis(pch); 74 | pch++; 75 | } 76 | } 77 | 78 | 79 | /* 80 | ********************************************************************************************************* 81 | * MB_CommPortCfg() 82 | * 83 | * Description : This function initializes the serial port to the desired baud rate and the UART will be 84 | * configured for N, 8, 1 (No parity, 8 bits, 1 stop). 85 | * 86 | * Argument(s) : pch is a pointer to the Modbus channel 87 | * port_nbr is the desired serial port number. This argument allows you to assign a 88 | * specific serial port to a sepcific Modbus channel. 89 | * baud is the desired baud rate for the serial port. 90 | * parity is the desired parity and can be either: 91 | * 92 | * MODBUS_PARITY_NONE 93 | * MODBUS_PARITY_ODD 94 | * MODBUS_PARITY_EVEN 95 | * 96 | * bits specifies the number of bit and can be either 7 or 8. 97 | * stops specifies the number of stop bits and can either be 1 or 2 98 | * 99 | * Return(s) : none. 100 | * 101 | * Caller(s) : MB_CfgCh() 102 | * 103 | * Note(s) : none. 104 | ********************************************************************************************************* 105 | */ 106 | 107 | CPU_VOID MB_CommPortCfg (CPU_INT08U ch, 108 | CPU_INT08U port_nbr, 109 | CPU_INT32U baud, 110 | CPU_INT08U bits, 111 | CPU_INT08U parity, 112 | CPU_INT08U stops) 113 | { 114 | MODBUS_CH *pch; 115 | CPU_INT08U reg_val; 116 | 117 | 118 | if (ch < MODBUS_CFG_MAX_CH) { 119 | pch = &MB_ChTbl[ch]; 120 | pch->PortNbr = port_nbr; 121 | pch->BaudRate = baud; 122 | pch->Parity = parity; 123 | pch->Bits = bits; 124 | pch->Stops = stops; 125 | 126 | SCI_RxDis(); /* Disable the SCI Receiver to reprogram it */ 127 | SCI_TxDis(); /* Disable the SCI Transmitter to reprogram it */ 128 | 129 | reg_val = SCISR1; /* Clear pending interrupts */ 130 | reg_val = SCIDRL; /* Clear pending interrupts */ 131 | (void)reg_val; /* Eliminate compiler warning: reg_val not used */ 132 | 133 | switch (baud) { /* Setup Baud Rate */ 134 | case 9600: 135 | SCI_SetBaud(9600); 136 | break; 137 | 138 | case 19200: 139 | SCI_SetBaud(19200); 140 | break; 141 | 142 | case 38400: 143 | SCI_SetBaud(38400); 144 | break; 145 | 146 | case 57600: 147 | SCI_SetBaud(57600); 148 | break; 149 | 150 | case 115200: 151 | SCI_SetBaud(115200); 152 | break; 153 | 154 | default: /* Assume 38,400 by default */ 155 | SCI_SetBaud(38400); 156 | break; 157 | } 158 | 159 | switch (bits) { 160 | case 8: 161 | SCI_SetDataBits(8); 162 | break; 163 | 164 | case 9: 165 | SCI_SetDataBits(9); 166 | 167 | default: 168 | SCI_SetDataBits(8); 169 | break; 170 | } 171 | 172 | switch (parity) { 173 | case MODBUS_PARITY_ODD: 174 | SCI_SetParity(SCI_PARITY_ODD); 175 | break; 176 | 177 | case MODBUS_PARITY_EVEN: 178 | SCI_SetParity(SCI_PARITY_EVEN); 179 | break; 180 | 181 | case MODBUS_PARITY_NONE: 182 | SCI_SetParity(SCI_PARITY_NONE); 183 | break; 184 | 185 | default: 186 | SCI_SetParity(SCI_PARITY_NONE); 187 | break; 188 | } 189 | 190 | SCI_RxIntEn(); /* Enable Rx interrupts ONLY */ 191 | 192 | SCI_RxEn(); /* Enable the SCI Receiver */ 193 | SCI_TxEn(); /* Enable the SCI Transmitter */ 194 | } 195 | } 196 | 197 | 198 | 199 | /* 200 | ********************************************************************************************************* 201 | * MB_CommRxIntDis() 202 | * 203 | * Description : This function disables Rx interrupts. 204 | * 205 | * Argument(s) : pch is a pointer to the Modbus channel 206 | * 207 | * Return(s) : none. 208 | * 209 | * Caller(s) : MB_CommExit() 210 | * 211 | * Note(s) : none. 212 | ********************************************************************************************************* 213 | */ 214 | 215 | CPU_VOID MBS_CommRxIntDis (MODBUS_CH *pch) 216 | { 217 | #if OS_CRITICAL_METHOD == 3 218 | OS_CPU_SR cpu_sr; 219 | 220 | 221 | cpu_sr = 0; 222 | #endif 223 | OS_ENTER_CRITICAL(); 224 | switch (pch->PortNbr) { 225 | case 0: 226 | SCI_RxIntDis(); 227 | break; 228 | 229 | default: 230 | break; 231 | } 232 | OS_EXIT_CRITICAL(); 233 | } 234 | 235 | 236 | /* 237 | ********************************************************************************************************* 238 | * MB_CommRxIntEn() 239 | * 240 | * Description : This function enables Rx interrupts. 241 | * 242 | * Argument(s) : pch is a pointer to the Modbus channel 243 | * 244 | * Return(s) : none. 245 | * 246 | * Caller(s) : MB_TxByte() 247 | * 248 | * Note(s) : none. 249 | ********************************************************************************************************* 250 | */ 251 | CPU_VOID MBS_CommRxIntEn (MODBUS_CH *pch) 252 | { 253 | #if OS_CRITICAL_METHOD == 3 254 | OS_CPU_SR cpu_sr; 255 | 256 | 257 | cpu_sr = 0; 258 | #endif 259 | OS_ENTER_CRITICAL(); 260 | switch (pch->PortNbr) { 261 | case 0: 262 | SCI_RxIntEn(); 263 | break; 264 | 265 | default: 266 | break; 267 | } 268 | OS_EXIT_CRITICAL(); 269 | } 270 | 271 | 272 | /* 273 | ********************************************************************************************************* 274 | * MB_CommRxTxISR_Handler() 275 | * 276 | * Description : This function is the ISR for either a received or transmitted character. 277 | * 278 | * Argument(s) : none. 279 | * 280 | * Return(s) : none. 281 | * 282 | * Caller(s) : This is a ISR 283 | * 284 | * Note(s) : (1) The pseudo-code for this function should be: 285 | * 286 | * if (Rx Byte has been received) { 287 | * c = get byte from serial port; 288 | * Clear receive interrupt; 289 | * pch->RxCtr++; Increment the number of bytes received 290 | * MB_RxByte(pch, c); Pass character to Modbus to process 291 | * } 292 | * 293 | * if (Byte has been transmitted) { 294 | * pch->TxCtr++; Increment the number of bytes transmitted 295 | * MB_TxByte(pch); Send next byte in response 296 | * Clear transmit interrupt Clear Transmit Interrupt flag 297 | * } 298 | ********************************************************************************************************* 299 | */ 300 | 301 | CPU_VOID MBS_CommRxTxISR_Handler (CPU_INT08U port_nbr) 302 | { 303 | CPU_INT08U c; 304 | CPU_INT08U ch; 305 | MODBUS_CH *pch; 306 | CPU_INT32U mis; 307 | CPU_INT08U SCI_Status; 308 | 309 | 310 | (CPU_VOID)port_nbr; 311 | (CPU_VOID)ch; 312 | (CPU_VOID)mis; 313 | 314 | SCI_Status = SCISR1; 315 | 316 | pch = &MB_ChTbl[0]; 317 | 318 | if (SCI_Status & SCI_RX_COMPLETE) { 319 | c = (CPU_INT08U)(SCIDRL); /* Read the character from the UART */ 320 | pch->RxCtr++; 321 | MBS_RxByte(pch, c); /* Pass character to Modbus to process */ 322 | } 323 | 324 | if (SCI_Status & SCI_TX_COMPLETE) { 325 | pch->TxCtr++; 326 | MBS_TxByte(pch); /* Send next byte in response */ 327 | } 328 | } 329 | 330 | 331 | /* 332 | ********************************************************************************************************* 333 | * UART #0 Rx/Tx Communication handler for Modbus 334 | * (THIS IS THE START OF THE ISR!) 335 | ********************************************************************************************************* 336 | */ 337 | 338 | interrupt CPU_VOID MBS_CommRxTxISR_0_Handler (CPU_VOID) 339 | { 340 | MBS_CommRxTxISR_Handler(0); 341 | } 342 | 343 | 344 | 345 | /* 346 | ********************************************************************************************************* 347 | * MB_CommTx1() 348 | * 349 | * Description : This function is called to obtain the next byte to send from the transmit buffer. When 350 | * all bytes in the reply have been sent, transmit interrupts are disabled and the receiver 351 | * is enabled to accept the next Modbus request. 352 | * 353 | * Argument(s) : c is the byte to send to the serial port 354 | * 355 | * Return(s) : none. 356 | * 357 | * Caller(s) : MB_TxByte() 358 | * 359 | * Note(s) : none. 360 | ********************************************************************************************************* 361 | */ 362 | 363 | CPU_VOID MBS_CommTx1 (MODBUS_CH *pch, 364 | CPU_INT08U c) 365 | { 366 | switch (pch->PortNbr) { 367 | case 0: 368 | SCI_Tx1(c); 369 | break; 370 | 371 | default: 372 | break; 373 | } 374 | } 375 | 376 | 377 | 378 | /* 379 | ********************************************************************************************************* 380 | * MB_CommTxIntDis() 381 | * 382 | * Description : This function disables Tx interrupts. 383 | * 384 | * Argument(s) : pch is a pointer to the Modbus channel 385 | * 386 | * Return(s) : none. 387 | * 388 | * Caller(s) : MB_CommExit() 389 | * MB_TxByte() 390 | * 391 | * Note(s) : none. 392 | ********************************************************************************************************* 393 | */ 394 | 395 | CPU_VOID MBS_CommTxIntDis (MODBUS_CH *pch) 396 | { 397 | #if OS_CRITICAL_METHOD == 3 398 | OS_CPU_SR cpu_sr; 399 | 400 | 401 | cpu_sr = 0; 402 | #endif 403 | 404 | (CPU_VOID)pch; 405 | 406 | OS_ENTER_CRITICAL(); 407 | SCI_TxIntDis(); /* Enable SCI Receive Interrupts */ 408 | OS_EXIT_CRITICAL(); 409 | } 410 | 411 | 412 | /* 413 | ********************************************************************************************************* 414 | * MB_CommTxIntEn() 415 | * 416 | * Description : This function enables Tx interrupts. 417 | * 418 | * Argument(s) : pch is a pointer to the Modbus channel 419 | * 420 | * Return(s) : none. 421 | * 422 | * Caller(s) : MB_Tx() 423 | * 424 | * Note(s) : none. 425 | ********************************************************************************************************* 426 | */ 427 | 428 | CPU_VOID MBS_CommTxIntEn (MODBUS_CH *pch) 429 | { 430 | #if OS_CRITICAL_METHOD == 3 431 | OS_CPU_SR cpu_sr; 432 | 433 | 434 | cpu_sr = 0; 435 | #endif 436 | 437 | (CPU_VOID)pch; 438 | 439 | OS_ENTER_CRITICAL(); 440 | SCI_TxIntEn(); /* Enable SCI Rx Interrupts */ 441 | OS_EXIT_CRITICAL(); 442 | } 443 | 444 | 445 | /* 446 | ********************************************************************************************************* 447 | * MB_RTU_TmrInit() 448 | * 449 | * Description : This function is called to initialize the RTU timeout timer. 450 | * 451 | * Argument(s) : freq Is the frequency of the modbus RTU timer interrupt. 452 | * 453 | * Return(s) : none. 454 | * 455 | * Caller(s) : MB_Init(). 456 | * 457 | * Note(s) : none. 458 | ********************************************************************************************************* 459 | */ 460 | 461 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 462 | CPU_VOID MB_RTU_TmrInit (void) 463 | { 464 | ECT_ChInt_Init(MB_ECT_CH, MB_RTU_Freq); /* Use ECT Channel selected in app.cfg at freq hz */ 465 | /* for the RTU timer */ 466 | 467 | MB_RTU_TmrResetAll(); /* Reset all the RTU timers, we changed freq. */ 468 | } 469 | #endif 470 | 471 | 472 | /* 473 | ********************************************************************************************************* 474 | * MB_RTU_TmrExit() 475 | * 476 | * Description : This function is called to disable the RTU timeout timer. 477 | * 478 | * Argument(s) : none. 479 | * 480 | * Return(s) : none. 481 | * 482 | * Caller(s) : MB_Exit() 483 | * 484 | * Note(s) : none. 485 | ********************************************************************************************************* 486 | */s 487 | 488 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 489 | CPU_VOID MB_RTU_TmrExit (CPU_VOID) 490 | { 491 | ECT_IntDis(MB_ECT_CH); /* Disable the MB ECT Timer Channel Interrupts */ 492 | } 493 | #endif 494 | 495 | 496 | 497 | /* 498 | ********************************************************************************************************* 499 | * MB_RTU_TmrISR_Handler() 500 | * 501 | * Description : This function handles the case when the RTU timeout timer expires. 502 | * 503 | * Arguments : none. 504 | * 505 | * Returns : none. 506 | * 507 | * Caller(s) : This is a ISR. 508 | * 509 | * Note(s) : none. 510 | ********************************************************************************************************* 511 | */ 512 | 513 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 514 | interrupt CPU_VOID MB_RTU_Tmr_Timeout (CPU_VOID) 515 | { 516 | TFLG1 |= (1 << MB_ECT_CH); /* Clear the ECT interrupt flag for the channel used */ 517 | MB_RTU_TmrCtr++; /* Indicate that we had activities on this interrupt. */ 518 | MB_RTU_TmrUpdate(); /* Check for RTU timers that have expired */ 519 | } 520 | #endif 521 | 522 | -------------------------------------------------------------------------------- /Source/mb_def.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * uC/MODBUS DEFINITIONS HEADER FILE 20 | * 21 | * Filename : mb_def.h 22 | * Version : V2.14.00 23 | ********************************************************************************************************* 24 | */ 25 | 26 | 27 | /* 28 | ********************************************************************************************************* 29 | * GLOBAL MODBUS CONSTANTS 30 | ********************************************************************************************************* 31 | */ 32 | 33 | #define MODBUS_MODE_ASCII 1 34 | #define MODBUS_MODE_RTU 0 35 | 36 | 37 | #define MODBUS_WR_EN 1 38 | #define MODBUS_WR_DIS 0 39 | 40 | 41 | #define MODBUS_PARITY_NONE 0 42 | #define MODBUS_PARITY_ODD 1 43 | #define MODBUS_PARITY_EVEN 2 44 | 45 | 46 | #define MODBUS_COIL_OFF 0 47 | #define MODBUS_COIL_ON 1 48 | 49 | #define MODBUS_SLAVE 0 50 | #define MODBUS_MASTER 1 51 | 52 | #define MODBUS_MASTER_STATE_RX 0 53 | #define MODBUS_MASTER_STATE_TX 1 54 | #define MODBUS_MASTER_STATE_WAITING 2 55 | 56 | #define MODBUS_FALSE 0 57 | #define MODBUS_TRUE 1 58 | 59 | 60 | /* 61 | ********************************************************************************************************* 62 | * CONSTANTS 63 | ********************************************************************************************************* 64 | */ 65 | 66 | #define MODBUS_FC01_COIL_RD 1 /* COIL Status. */ 67 | #define MODBUS_FC02_DI_RD 2 /* Read Discrete Input */ 68 | #define MODBUS_FC03_HOLDING_REG_RD 3 /* Holding registers. */ 69 | #define MODBUS_FC04_IN_REG_RD 4 /* Read Only registers. */ 70 | #define MODBUS_FC05_COIL_WR 5 /* Set a single COIL value. */ 71 | #define MODBUS_FC06_HOLDING_REG_WR 6 /* Holding registers. */ 72 | #define MODBUS_FC08_LOOPBACK 8 73 | #define MODBUS_FC15_COIL_WR_MULTIPLE 15 /* Set multiple COIL values. */ 74 | #define MODBUS_FC16_HOLDING_REG_WR_MULTIPLE 16 /* Holding registers */ 75 | #define MODBUS_FC20_FILE_RD 20 /* Read contents of a File/Record */ 76 | #define MODBUS_FC21_FILE_WR 21 /* Write data to a File/Record */ 77 | 78 | #define MODBUS_FC08_LOOPBACK_QUERY 0 /* Loopback sub-function codes */ 79 | #define MODBUS_FC08_LOOPBACK_CLR_CTR 10 80 | #define MODBUS_FC08_LOOPBACK_BUS_MSG_CTR 11 81 | #define MODBUS_FC08_LOOPBACK_BUS_CRC_CTR 12 82 | #define MODBUS_FC08_LOOPBACK_BUS_EXCEPT_CTR 13 83 | #define MODBUS_FC08_LOOPBACK_SLAVE_MSG_CTR 14 84 | #define MODBUS_FC08_LOOPBACK_SLAVE_NO_RESP_CTR 15 85 | 86 | 87 | #define MODBUS_COIL_OFF_CODE 0x0000 88 | #define MODBUS_COIL_ON_CODE 0xFF00 89 | /* 90 | ********************************************************************************************************* 91 | * ERROR CODES 92 | ********************************************************************************************************* 93 | */ 94 | 95 | #define MODBUS_ERR_NONE 0 96 | 97 | #define MODBUS_ERR_ILLEGAL_FC 1 98 | #define MODBUS_ERR_ILLEGAL_DATA_ADDR 2 99 | #define MODBUS_ERR_ILLEGAL_DATA_QTY 3 100 | #define MODBUS_ERR_ILLEGAL_DATA_VAL 4 101 | 102 | #define MODBUS_ERR_FC01_01 101 103 | #define MODBUS_ERR_FC01_02 102 104 | #define MODBUS_ERR_FC01_03 103 105 | 106 | #define MODBUS_ERR_FC02_01 201 107 | #define MODBUS_ERR_FC02_02 202 108 | 109 | #define MODBUS_ERR_FC03_01 301 110 | #define MODBUS_ERR_FC03_02 302 111 | #define MODBUS_ERR_FC03_03 303 112 | #define MODBUS_ERR_FC03_04 304 113 | 114 | #define MODBUS_ERR_FC04_01 401 115 | #define MODBUS_ERR_FC04_02 402 116 | #define MODBUS_ERR_FC04_03 403 117 | #define MODBUS_ERR_FC04_04 404 118 | 119 | #define MODBUS_ERR_FC05_01 501 120 | #define MODBUS_ERR_FC05_02 502 121 | 122 | #define MODBUS_ERR_FC06_01 601 123 | 124 | #define MODBUS_ERR_FC08_01 801 125 | 126 | #define MODBUS_ERR_FC15_01 1501 127 | #define MODBUS_ERR_FC15_02 1502 128 | #define MODBUS_ERR_FC15_03 1503 129 | 130 | #define MODBUS_ERR_FC16_01 1601 131 | #define MODBUS_ERR_FC16_02 1602 132 | #define MODBUS_ERR_FC16_03 1603 133 | #define MODBUS_ERR_FC16_04 1604 134 | #define MODBUS_ERR_FC16_05 1605 135 | 136 | #define MODBUS_ERR_FC20_01 2001 137 | #define MODBUS_ERR_FC20_02 2002 138 | #define MODBUS_ERR_FC20_03 2003 139 | #define MODBUS_ERR_FC20_04 2004 140 | #define MODBUS_ERR_FC20_05 2005 141 | 142 | #define MODBUS_ERR_FC21_01 2101 143 | #define MODBUS_ERR_FC21_02 2102 144 | #define MODBUS_ERR_FC21_03 2103 145 | #define MODBUS_ERR_FC21_04 2104 146 | #define MODBUS_ERR_FC21_05 2105 147 | 148 | #define MODBUS_ERR_TIMED_OUT 3000 149 | #define MODBUS_ERR_NOT_MASTER 3001 150 | #define MODBUS_ERR_INVALID 3002 151 | #define MODBUS_ERR_NULLPTR 3003 152 | 153 | #define MODBUS_ERR_RANGE 4000 154 | #define MODBUS_ERR_FILE 4001 155 | #define MODBUS_ERR_RECORD 4002 156 | #define MODBUS_ERR_IX 4003 157 | #define MODBUS_ERR_VALUE 4004 158 | 159 | #define MODBUS_ERR_COIL_ADDR 5000 160 | #define MODBUS_ERR_COIL_WR 5001 161 | #define MODBUS_ERR_SLAVE_ADDR 5002 162 | #define MODBUS_ERR_FC 5003 163 | #define MODBUS_ERR_BYTE_COUNT 5004 164 | #define MODBUS_ERR_COIL_QTY 5005 165 | #define MODBUS_ERR_REG_ADDR 5006 166 | #define MODBUS_ERR_NBR_REG 5007 167 | #define MODBUS_ERR_SUB_FNCT 5008 168 | #define MODBUS_ERR_DIAG 5009 169 | #define MODBUS_ERR_WR 5010 170 | 171 | #define MODBUS_ERR_RX 6000 172 | 173 | /* 174 | ********************************************************************************************************* 175 | * MODBUS ASCII CONSTANTS 176 | ********************************************************************************************************* 177 | */ 178 | 179 | #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED) 180 | #define MODBUS_ASCII_START_FRAME_CHAR ':' /* Start of frame delimiter */ 181 | #define MODBUS_ASCII_END_FRAME_CHAR1 0x0D /* ASCII character: Carriage return */ 182 | #define MODBUS_ASCII_END_FRAME_CHAR2 0x0A /* ASCII character: Line Feed */ 183 | #define MODBUS_ASCII_MIN_MSG_SIZE 11 184 | #endif 185 | 186 | /* 187 | ********************************************************************************************************* 188 | * MODBUS RTU CONSTANTS 189 | ********************************************************************************************************* 190 | */ 191 | 192 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 193 | #define MODBUS_RTU_MIN_MSG_SIZE 4 194 | #endif 195 | 196 | #define MODBUS_CRC16_POLY 0xA001 /* CRC-16 Generation Polynomial value. */ 197 | 198 | -------------------------------------------------------------------------------- /Source/mb_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************************************************* 3 | * uC/Modbus 4 | * The Embedded Modbus Stack 5 | * 6 | * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 7 | * 8 | * SPDX-License-Identifier: APACHE-2.0 9 | * 10 | * This software is subject to an open source license and is distributed by 11 | * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 12 | * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 13 | * 14 | ********************************************************************************************************* 15 | */ 16 | 17 | /* 18 | ********************************************************************************************************* 19 | * uC/MODBUS Utilities 20 | * 21 | * Filename : mb_util.h 22 | * Version : V2.14.00 23 | ********************************************************************************************************* 24 | */ 25 | 26 | 27 | /* 28 | ********************************************************************************************************* 29 | * INCLUDE FILES 30 | ********************************************************************************************************* 31 | */ 32 | 33 | #define MB_UTIL_MODULE 34 | #include 35 | 36 | 37 | /* 38 | ********************************************************************************************************* 39 | * LOCAL DEFINES 40 | ********************************************************************************************************* 41 | */ 42 | 43 | 44 | /* 45 | ********************************************************************************************************* 46 | * LOCAL CONSTANTS 47 | ********************************************************************************************************* 48 | */ 49 | 50 | 51 | /* 52 | ********************************************************************************************************* 53 | * LOCAL DATA TYPES 54 | ********************************************************************************************************* 55 | */ 56 | 57 | 58 | /* 59 | ********************************************************************************************************* 60 | * LOCAL TABLES 61 | ********************************************************************************************************* 62 | */ 63 | 64 | 65 | /* 66 | ********************************************************************************************************* 67 | * LOCAL GLOBAL VARIABLES 68 | ********************************************************************************************************* 69 | */ 70 | 71 | 72 | /* 73 | ********************************************************************************************************* 74 | * LOCAL FUNCTION PROTOTYPES 75 | ********************************************************************************************************* 76 | */ 77 | 78 | 79 | /* 80 | ********************************************************************************************************* 81 | * LOCAL CONFIGURATION ERRORS 82 | ********************************************************************************************************* 83 | */ 84 | 85 | 86 | 87 | /* 88 | ********************************************************************************************************* 89 | * MB_ASCII_BinToHex() 90 | * 91 | * Description : Converts a byte into two ASCII characters into the given buffer. 92 | * 93 | * Argument(s) : value The byte of data to be converted. 94 | * pbuf A pointer to the buffer to store the ASCII chars. 95 | * 96 | * Return(s) : The buffer pointer which has been updated to point to the next char in the buffer. 97 | * 98 | * Caller(s) : MB_ASCII_Tx(). 99 | * 100 | * Note(s) : (1) The function ONLY converts the byte to ASCII and DOES NOT null terminate the string. 101 | ********************************************************************************************************* 102 | */ 103 | 104 | #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED) 105 | CPU_INT08U *MB_ASCII_BinToHex (CPU_INT08U value, 106 | CPU_INT08U *pbuf) 107 | { 108 | CPU_INT08U nibble; 109 | 110 | 111 | nibble = (value >> 4) & 0x0F; /* Upper Nibble */ 112 | if (nibble <= 9) { 113 | *pbuf++ = (CPU_INT08U)(nibble + '0'); 114 | } else { 115 | *pbuf++ = (CPU_INT08U)(nibble - 10 + 'A'); 116 | } 117 | 118 | nibble = value & 0x0F; /* Lower Nibble */ 119 | if (nibble <= 9) { 120 | *pbuf++ = (CPU_INT08U)(nibble + '0'); 121 | } else { 122 | *pbuf++ = (CPU_INT08U)(nibble - 10 + 'A'); 123 | } 124 | return (pbuf); 125 | } 126 | #endif 127 | 128 | 129 | /* 130 | ********************************************************************************************************* 131 | * MB_ASCII_HexToBin() 132 | * 133 | * Description : Converts the first two ASCII hex characters in the buffer into one byte. 134 | * 135 | * Argument(s) : phex Pointer to the buffer that contains the two ascii chars. 136 | * 137 | * Return(s) : value of the two ASCII HEX digits pointed to by 'phex'. 138 | * 139 | * Caller(s) : MB_ASCII_RxByte(), 140 | * MB_ASCII_Rx(), 141 | * MB_ASCII_RxCalcLRC(), 142 | * MB_ASCII_TxCalcLRC(). 143 | * 144 | * Note(s) : none. 145 | ********************************************************************************************************* 146 | */ 147 | 148 | #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED) 149 | CPU_INT08U MB_ASCII_HexToBin (CPU_INT08U *phex) 150 | { 151 | CPU_INT08U value; 152 | CPU_INT08U high; 153 | CPU_INT08U low; 154 | 155 | 156 | high = *phex; /* Get upper nibble */ 157 | phex++; 158 | low = *phex; /* Get lower nibble */ 159 | if (high <= '9') { /* Upper Nibble */ 160 | value = (CPU_INT08U)(high - '0'); 161 | } else if (high <= 'F') { 162 | value = (CPU_INT08U)(high - 'A' + 10); 163 | } else { 164 | value = (CPU_INT08U)(high - 'a' + 10); 165 | } 166 | value <<= 4; 167 | 168 | if (low <= '9') { /* Lower Nibble */ 169 | value += (CPU_INT08U)(low - '0'); 170 | } else if (low <= 'F') { 171 | value += (CPU_INT08U)(low - 'A' + 10); 172 | } else { 173 | value += (CPU_INT08U)(low - 'a' + 10); 174 | } 175 | return (value); 176 | } 177 | #endif 178 | 179 | 180 | /* 181 | ********************************************************************************************************* 182 | * MB_ASCII_RxCalcLRC() 183 | * 184 | * Description : The function calculates an 8-bit Longitudinal Redundancy Check on a MODBUS_FRAME 185 | * structure. 186 | * 187 | * Argument(s) : none. 188 | * 189 | * Return(s) : The calculated LRC value. 190 | * 191 | * Caller(s) : MBS_ASCII_Task(). 192 | * 193 | * Note(s) : (1) The LRC is calculated on the ADDR, FC and Data fields, not the ':', CR/LF and LRC 194 | * placed in the message by the sender. We thus need to subtract 5 'ASCII' characters 195 | * from the received message to exclude these. 196 | ********************************************************************************************************* 197 | */ 198 | 199 | #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED) 200 | CPU_INT08U MB_ASCII_RxCalcLRC (MODBUS_CH *pch) 201 | { 202 | CPU_INT08U lrc; 203 | CPU_INT16U len; 204 | CPU_INT08U *pblock; 205 | 206 | 207 | len = (pch->RxBufByteCtr - 5) / 2 ; /* LRC to include Addr + FC + Data */ 208 | pblock = (CPU_INT08U *)&pch->RxBuf[1]; 209 | lrc = 0; 210 | while (len-- > 0) { /* For each byte of data in the data block... */ 211 | lrc += MB_ASCII_HexToBin(pblock); /* Add the data byte to LRC, increment data pointer. */ 212 | pblock += 2; 213 | } 214 | 215 | lrc = ~lrc + 1; /* Two complement the binary sum */ 216 | return (lrc); /* Return LRC for all data in block. */ 217 | } 218 | #endif 219 | 220 | 221 | /* 222 | ********************************************************************************************************* 223 | * MB_ASCII_TxCalcLRC() 224 | * 225 | * Description : The function calculates an 8-bit Longitudinal Redundancy Check on a MODBUS_FRAME 226 | * structure. 227 | * 228 | * Argument(s) : none. 229 | * 230 | * Return(s) : The calculated LRC value. 231 | * 232 | * Caller(s) : MB_ASCII_Tx(). 233 | * 234 | * Note(s) : (1) The LRC is calculated on the ADDR, FC and Data fields, not the ':' which was inserted 235 | * in the TxBuf[]. Thus we subtract 1 ASCII character from the LRC. 236 | * 237 | * (2) The LRC and CR/LF bytes are not YET in the .RxBuf[]. 238 | ********************************************************************************************************* 239 | */ 240 | 241 | #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED) 242 | CPU_INT08U MB_ASCII_TxCalcLRC (MODBUS_CH *pch, CPU_INT16U tx_bytes) 243 | { 244 | CPU_INT08U lrc; 245 | CPU_INT16U len; 246 | CPU_INT08U *pblock; 247 | 248 | 249 | len = (tx_bytes - 1) / 2; /* LRC to include Addr + FC + Data (exclude ':') */ 250 | pblock = (CPU_INT08U *)&pch->TxBuf[1]; 251 | lrc = 0; 252 | while (len-- > 0) { /* For each byte of data in the data block... */ 253 | lrc += MB_ASCII_HexToBin(pblock); /* Add the data byte to LRC, increment data pointer. */ 254 | pblock += 2; 255 | } 256 | lrc = ~lrc + 1; /* Two complement the binary sum */ 257 | return (lrc); /* Return LRC for all data in block. */ 258 | } 259 | #endif 260 | 261 | 262 | /* 263 | ********************************************************************************************************* 264 | * MB_RTU_RxCalcCRC() 265 | * 266 | * Description : The polynomial is a CRC-16 found for 'MBS_RxFrameNDataBytes' number of characters 267 | * starting at 'MBS_RxFrameAddr'. 268 | * 269 | * Argument(s) : none. 270 | * 271 | * Return(s) : An unsigned 16-bit value representing the CRC-16 of the data. 272 | * 273 | * Caller(s) : MBS_RTU_Task(). 274 | * 275 | * Note(s) : none. 276 | ********************************************************************************************************* 277 | */ 278 | 279 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 280 | CPU_INT16U MB_RTU_RxCalcCRC (MODBUS_CH *pch) 281 | { 282 | CPU_INT16U crc; 283 | CPU_INT08U shiftctr; 284 | CPU_BOOLEAN flag; 285 | CPU_INT16U length; 286 | CPU_INT08U *pblock; 287 | 288 | 289 | pblock = (CPU_INT08U *)&pch->RxFrameData[0]; /* Starting address of where the CRC data starts */ 290 | length = pch->RxFrameNDataBytes + 2; /* Include the address and function code in the CRC */ 291 | crc = 0xFFFF; /* Initialize CRC to all ones. */ 292 | while (length > 0) { /* Account for each byte of data */ 293 | length--; 294 | crc ^= (CPU_INT16U)*pblock++; 295 | shiftctr = 8; 296 | do { 297 | flag = (crc & 0x0001) ? DEF_TRUE : DEF_FALSE; /* Determine if the shift out of rightmost bit is 1 */ 298 | crc >>= 1; /* Shift CRC to the right one bit. */ 299 | if (flag == DEF_TRUE) { /* If (bit shifted out of rightmost bit was a 1) */ 300 | crc ^= MODBUS_CRC16_POLY; /* Exclusive OR the CRC with the generating polynomial. */ 301 | } 302 | shiftctr--; 303 | } while (shiftctr > 0); 304 | } 305 | pch->RxFrameCRC_Calc = crc; 306 | return (crc); 307 | } 308 | #endif 309 | 310 | 311 | /* 312 | ********************************************************************************************************* 313 | * MB_RTU_TxCalcCRC() 314 | * 315 | * Description : The polynomial is a CRC-16 found for 'MBS_TxFrameNDataBytes' number of characters 316 | * starting at 'MBS_TxFrameAddr'. 317 | * 318 | * Argument(s) : none. 319 | * 320 | * Return(s) : An unsigned 16-bit value representing the CRC-16 of the data. 321 | * 322 | * Caller(s) : MB_RTU_Tx(). 323 | * 324 | * Note*(s) : none. 325 | ********************************************************************************************************* 326 | */ 327 | 328 | #if (MODBUS_CFG_RTU_EN == DEF_ENABLED) 329 | CPU_INT16U MB_RTU_TxCalcCRC (MODBUS_CH *pch) 330 | { 331 | CPU_INT16U crc; 332 | CPU_INT08U shiftctr; 333 | CPU_BOOLEAN flag; 334 | CPU_INT16U length; 335 | CPU_INT08U *pblock; 336 | 337 | 338 | pblock = (CPU_INT08U *)&pch->TxFrameData[0]; /* Starting address of where the CRC data starts */ 339 | length = pch->TxFrameNDataBytes + 2; /* Include the address and function code in the CRC */ 340 | crc = 0xFFFF; /* Initialize CRC to all ones. */ 341 | while (length > 0) { /* Account for each byte of data */ 342 | length--; 343 | crc ^= (CPU_INT16U)*pblock++; 344 | shiftctr = 8; 345 | do { 346 | flag = (crc & 0x0001) ? DEF_TRUE : DEF_FALSE; /* Determine if the shift out of rightmost bit is 1. */ 347 | crc >>= 1; /* Shift CRC to the right one bit. */ 348 | if (flag == DEF_TRUE) { /* If (bit shifted out of rightmost bit was a 1) */ 349 | crc ^= MODBUS_CRC16_POLY; /* Exclusive OR the CRC with the generating polynomial */ 350 | } 351 | shiftctr--; 352 | } while (shiftctr > 0); 353 | } 354 | return (crc); /* Return CRC for all data in block. */ 355 | } 356 | #endif 357 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # uC/Modbus 2 | 3 | µC/Modbus provides an embedded solution for implementing Modbus, an industrial communications protocol used for connecting industrial electronic devices. 4 | 5 | ## For the complete documentation, visit https://doc.micrium.com/display/ucos/ --------------------------------------------------------------------------------