├── CHANGELOG.md ├── projects ├── msvs │ ├── msvs.sln │ └── msvs │ │ ├── msvs.cpp │ │ ├── sample.c │ │ └── msvs.vcxproj ├── qt │ └── stModbus.pro └── keil │ └── stModbus.uvprojx ├── LICENSE.md ├── include ├── mbutils.h ├── mbdevice.h ├── dev │ └── sample.h ├── modbus_conf.h └── modbus.h ├── README.md └── src ├── rtu └── mbutils.c ├── dev └── sample.c └── modbus.c /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | - 13.09.2017 Initialize stModbus project 2 | - 11.02.2021 Add easy start with library 3 | -------------------------------------------------------------------------------- /projects/msvs/msvs.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30611.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvs", "msvs\msvs.vcxproj", "{6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Debug|x64.ActiveCfg = Debug|x64 17 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Debug|x64.Build.0 = Debug|x64 18 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Debug|x86.ActiveCfg = Debug|Win32 19 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Debug|x86.Build.0 = Debug|Win32 20 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Release|x64.ActiveCfg = Release|x64 21 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Release|x64.Build.0 = Release|x64 22 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Release|x86.ActiveCfg = Release|Win32 23 | {6A2DA4D7-5814-4262-A5F0-4AC3DD4F8413}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {30BA136F-FEF2-4EA1-B33D-F63F0115A677} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | -------------------------------------------------------------------------------- /projects/qt/stModbus.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-09-13T14:56:41 4 | # 5 | #------------------------------------------------- 6 | 7 | QT -= core gui qt 8 | 9 | TARGET = stModbus 10 | TEMPLATE = lib 11 | CONFIG += static 12 | 13 | QMAKE_LFLAGS+= -static 14 | 15 | # The following define makes your compiler emit warnings if you use 16 | # any feature of Qt which has been marked as deprecated (the exact warnings 17 | # depend on your compiler). Please consult the documentation of the 18 | # deprecated API in order to know how to port your code away from it. 19 | DEFINES += QT_DEPRECATED_WARNINGS 20 | 21 | # You can also make your code fail to compile if you use deprecated APIs. 22 | # In order to do so, uncomment the following line. 23 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 24 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 25 | 26 | INCLUDEPATH += $$PWD/../../include 27 | 28 | 29 | SOURCES += \ 30 | ../../src/modbus.c \ 31 | ../../src/rtu/mbutils.c \ 32 | 33 | 34 | 35 | HEADERS += \ 36 | ../../include/modbus.h \ 37 | ../../include/modbus_conf.h \ 38 | ../../include/mbutils.h \ 39 | 40 | 41 | CONFIG(release, debug|release) { 42 | BUILD_TYPE = release 43 | 44 | } 45 | CONFIG(debug, debug|release) { 46 | BUILD_TYPE = debug 47 | CONFIG += debug 48 | CONFIG -= qml_debug 49 | } 50 | 51 | LICENSE_TEMPLATE = $$PWD/../../LICENSE.md 52 | 53 | OBJECTS_DIR = $$PWD/../../build/$${TARGET}_$${BUILD_TYPE}/obj 54 | 55 | DESTDIR = $$PWD/../../lib/ 56 | -------------------------------------------------------------------------------- /include/mbutils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #ifndef _STMODBUS_UTILS_H_ 33 | #define _STMODBUS_UTILS_H_ 34 | 35 | #include 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | uint16_t usModbusCRC16(uint8_t *pucFrame, uint16_t usLen); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif // _STMODBUS_UTILS_H_ 48 | -------------------------------------------------------------------------------- /include/mbdevice.h: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2021+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2021+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #ifndef _STMODBUS_MBDEVICE_H_ 33 | #define _STMODBUS_MBDEVICE_H_ 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) || \ 40 | defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \ 41 | defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F469xx) || \ 42 | defined(STM32F479xx) || defined(STM32F4) 43 | #include 44 | void modbus_usart_it(UART_HandleTypeDef *huart); 45 | #endif 46 | 47 | 48 | 49 | 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif // _STMODBUS_MBDEVICE_H_ 56 | -------------------------------------------------------------------------------- /include/dev/sample.h: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #ifndef _STMODBUS_SAMPLE_H_ 33 | #define _STMODBUS_SAMPLE_H_ 34 | 35 | #ifdef __cplusplus 36 | extern "C" 37 | { 38 | #endif 39 | 40 | #include "modbus.h" 41 | 42 | /* 43 | * function mbus_isma_open() 44 | * open new modbus context for new port 45 | * return: MODBUS_ERROR - if can't open context 46 | */ 47 | 48 | mbus_status_t mbus_somedev_read_3xxxx(mbus_t mb_context); 49 | 50 | mbus_status_t mbus_somedev_read_4xxxx(mbus_t mb_context); 51 | 52 | uint16_t mbus_somedev_read(uint32_t la); 53 | 54 | uint16_t mbus_somedev_write(uint32_t la, uint16_t value); 55 | 56 | 57 | mbus_t mbus_somedev_open(Modbus_Conf_t* pconf); 58 | 59 | mbus_t mbus_somedevice_open(Modbus_Conf_t *pconf); 60 | 61 | 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif // _STMODBUS_SAMPLE_H_ 68 | -------------------------------------------------------------------------------- /projects/msvs/msvs/msvs.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2021+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2021+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | int main() 36 | { 37 | std::cout << "Hello World!\n"; 38 | } 39 | 40 | // Запуск программы: CTRL+F5 или меню "Отладка" > "Запуск без отладки" 41 | // Отладка программы: F5 или меню "Отладка" > "Запустить отладку" 42 | 43 | // Советы по началу работы 44 | // 1. В окне обозревателя решений можно добавлять файлы и управлять ими. 45 | // 2. В окне Team Explorer можно подключиться к системе управления версиями. 46 | // 3. В окне "Выходные данные" можно просматривать выходные данные сборки и другие сообщения. 47 | // 4. В окне "Список ошибок" можно просматривать ошибки. 48 | // 5. Последовательно выберите пункты меню "Проект" > "Добавить новый элемент", чтобы создать файлы кода, или "Проект" > "Добавить существующий элемент", чтобы добавить в проект существующие файлы кода. 49 | // 6. Чтобы снова открыть этот проект позже, выберите пункты меню "Файл" > "Открыть" > "Проект" и выберите SLN-файл. 50 | -------------------------------------------------------------------------------- /include/modbus_conf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #ifndef _STMODBUS_CONF_H_ 33 | #define _STMODBUS_CONF_H_ 34 | 35 | #ifdef _cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | //-------- <<< Use Configuration Wizard in Context Menu >>> -------------------- 40 | 41 | // Use Modbus-RTU 42 | #define STMODBUS_USE_RTU 1 43 | // Use Modbus-ASCII 44 | #define STMODBUS_USE_ASCII 0 45 | // Use critical sections (recommended) 46 | #define STMODBUS_USE_CRITICAL_SECTIONS 0 47 | // Count modbus context 48 | // Don't set a lot of count for memory saving 49 | #define STMODBUS_COUNT_CONTEXT 1 50 | 51 | // Count modbus func 52 | // Don't set a lot of count for memory saving 53 | #define STMODBUS_COUNT_FUNC 0 54 | 55 | // Count modbus coils (discrete output) 56 | // Don't set a lot of count for memory saving 57 | #define STMODBUS_COUNT_COILS 10 58 | 59 | // Count modbus discrete (discrete inputs) 60 | // Don't set a lot of count for memory saving 61 | #define STMODBUS_COUNT_DISCRETE 8 62 | 63 | // Response buffer size 64 | // Don't set a lot of count for memory saving 65 | #define STMODBUS_MAX_RESPONSE_SIZE 255 66 | 67 | // Debug information messages level <0=>Off <1=>Low <2=>Medium <3=>High 68 | // Debug information messages sending or stop on warnings 69 | #define STACKOS_DEBUG 3 70 | #if (STACKOS_DEBUG > 3) 71 | #error "Invalid debug information messages level!" 72 | #endif 73 | 74 | // Default Stack OS module parameters 75 | // Debug information messages level <4=>idle (lowest) <5=>low <6=>below 76 | //normal <0=>normal (default) <1=>above normal <2=>high <3=>realtime (highest) 77 | // Thread priority 78 | #define STACKOS_MODULE_THREAD_LEVEL 0 79 | // Thread stack size 80 | // Thread 81 | #define STACKOS_MODULE_THREAD_STACK 0 82 | // 83 | 84 | // Enable test unit (Benchmark) 85 | #define STOS_TESTUNIT 1 86 | // Enable exclusive test unit 87 | #define STOS_TESTUNIT_EXCLUSIVE 0 88 | // 89 | 90 | //-------- <<< end of configuration section >>> -------------------- 91 | 92 | #include "mbutils.h" 93 | 94 | #ifdef _cplusplus 95 | } 96 | #endif 97 | 98 | #endif // _STMODBUS_CONF_H_ 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stModbus (beta 0.1b10) 2 | Modbus RTU implementation for Cortex-M (STM32 series: F1/F3/F4) 3 | 4 | This is free tiny library for Desktop and MCU application. 5 | The main purpose of this library usage on STM32 controllers together with CMSIS library 6 | 7 | The library allows you to create multiple modbus contexts for devices. You will be able to implement several modbus ports on single MCU. 8 | 9 | ## Requirements 10 | 11 | 12 | ## How usage 13 | 14 | An example of implementing a device with some registers can be viewed in the example folder. You can also use these examples as a template for your own implementations. 15 | 16 | It's library easy for usage. you need to take a few steps: 17 | 18 | 1. Define address space for you device: 19 | 20 | Usually protocol address split like that: 21 | - 1-9999 Discrete Output Coils (DO) r/w 22 | - 10001-19999 Discrete Input Contacts (DI) r 23 | - 30001-39999 Analog Input Registers (AI) r 24 | - 40001-49999 Analog Output Holding Registers(AO) r/w 25 | 26 | You may not follow these guidelines but some apps may not work correctly with your device. 27 | 28 | 2. Define read and write callback function for you device registers as you need 29 | 30 | ```c 31 | /* It's modbus request on read register by logical address (la) */ 32 | uint16_t user_mbus_protocol_read(uint32_t la){ 33 | switch(la){ 34 | case 40001: 35 | return my_buffer_reg_4xxxx[0]; 36 | case 40002: 37 | return some_register_from_you_device; 38 | ... 39 | } 40 | } 41 | 42 | //Function for write to some register by logic address 43 | uint16_t user_mbus_protocol_write(uint32_t la, uint16_t value) 44 | { 45 | if ( la > 40000 && la <= 40013 ){ 46 | my_buffer_reg_4xxxx[la-40001] = value; 47 | } 48 | if (la == 40018 ){ 49 | output = (value >> 8) | (value << 8); 50 | } 51 | 52 | return value; 53 | } 54 | ``` 55 | 56 | 3. Add recv modbus function 57 | 58 | Place mbus_poll(modbus, modbus_byte); in the receiving loop of the incoming stream. 59 | 60 | mbus_poll processes incoming data byte-by-byte. In the examples, you can find batch processing using dma. 61 | 62 | ```c 63 | void HAL_UART_DMA_IdleLineDetect(UART_HandleTypeDef *huart){ 64 | ... 65 | if (huart == &huart1){ 66 | for (i=... { 67 | mbus_poll(modbus, data[i] ); 68 | } 69 | clear buffer.... 70 | } 71 | } 72 | ``` 73 | 74 | --- 75 | But it should be noted that the calls read and write functions from point 2 called in the context of this function. we plan to add the ability to use queues in future for different OS. 76 | 77 | --- 78 | 79 | 4. Add send modbus function 80 | 81 | Implement the function of sending a data stream: 82 | 83 | ```c 84 | int mbus_send(const mbus_t context,const uint8_t* data, const uint16_t size){ 85 | HAL_UART_Transmit( &huart2, (uint8_t*) data,size, 1000); 86 | ... 87 | } 88 | 89 | ``` 90 | 91 | 5. After all this just configure modbus library 92 | 93 | ```c 94 | // Modbus context (we can use many context for example 95 | // if we use 2 or more RS485 ports or ethernet and serial) 96 | mbus_t modbus; 97 | Modbus_Conf_t mb_config; 98 | 99 | /* Device slave address */ 100 | mb_config.devaddr = 0x01; 101 | 102 | /* Just ptr on any external object, you can get it by context */ 103 | mb_config.device = (void*) 0; 104 | 105 | /* This that function for sending some data (use sendbuf for buf) */ 106 | mb_config.send = &mbus_send; 107 | 108 | //User Read callback function ( read by logical address) 109 | pconf->read = user_mbus_protocol_read; 110 | 111 | //Write callback function 112 | pconf->write = user_mbus_protocol_write; 113 | 114 | //Open modbus contex 115 | modbus = mbus_open(pconf); 116 | ``` 117 | 118 | 119 | 6. Customize config file 120 | 121 | Customize the modbus_conf.h file to suit your requirements (internal buffer size, number of context). The keil configuration wizard can be used for configuration. 122 | 123 | | Full documentation is planned for the release of the first version of alpha 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /projects/msvs/msvs/sample.c: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 4 | * Copyright (c) 2021+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 5 | * All rights reserved. 6 | * 7 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | * 27 | * @copyright Copyright (C) 2021+ 28 | * @author Iurii Bell (ds@inbox.ru) 29 | * @license MIT 30 | * @package stModbus 31 | */ 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | #include 38 | 39 | /* This is user's file for working with the modbus interface 40 | Here functions that need to be modified to work with the 41 | library. 42 | 43 | Let's define the address space of the modbus interface: 44 | 45 | Protocol address split like that: 46 | - 1-9999 Discrete Output Coils (DO) r/w 47 | - 10001-19999 Discrete Input Contacts (DI) r 48 | - 30001-39999 Analog Input Registers (AI) r 49 | - 40001-49999 Analog Output Holding Registers(AO) r/w 50 | 51 | For our example device define next protocol address space: 52 | - 1-8 Discrete Output Coils (DO) 8 coils 53 | - 10001-10008 Discrete Input Contacts (DI) 8 inputs 54 | - 30001 Input Registers 1 analog input 55 | - 40001-40008 Holding Registers 8 analog input 56 | 57 | ALL DATA IN 16-BIT 58 | 59 | */ 60 | 61 | //Let's go. Describe our sample device. 62 | 63 | // Define discrete output coils (emulation) 64 | uint8_t dev_output_coils; 65 | 66 | // Discrete input contacts 67 | // let it be the same coils (dev_output_coils) 68 | 69 | // Define input registers 70 | // let it be a counter of the number of writing 71 | uint16_t dev_input_registers_30001; 72 | 73 | // Define holding registers 74 | uint16_t holding_registers_4000x[8]; 75 | 76 | /* 77 | let's define a user function that will handle 78 | reading from registers 79 | 80 | @param la - protocol address (logic address) 81 | @return - value by logic address 82 | */ 83 | uint16_t mbus_protocol_read(uint32_t la) { 84 | 85 | // 1-8 86 | if (la >= 1 && la <= 8) { 87 | // get bit from reg 88 | return dev_output_coils & ( 1<<(la-1) ); 89 | // 10001-10008 90 | }else if (la >= 10001 && la <= 10008) { 91 | //the same 92 | return dev_output_coils & (1 << (la - 10001)); 93 | // 30001 94 | }else if (la == 30001) { 95 | return dev_input_registers_30001; 96 | }else if (la >= 40001 && la <= 40008) { 97 | return holding_registers_4000x[la - 40001]; 98 | } 99 | // else error code 02 (the query have illegal address) 100 | return mbus_error(MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS); 101 | } 102 | 103 | 104 | /* 105 | let's define a user function that will handle 106 | writing to registers 107 | 108 | @param la - protocol address (logic address) 109 | @param value - value for writing 110 | @return - none 111 | */ 112 | void mbus_protocol_write(uint32_t la, uint16_t value) { 113 | 114 | //Counter of writings 115 | dev_input_registers_30001++; 116 | // 1-8 117 | if (la >= 1 && la <= 8) { 118 | // get bit from reg 119 | if (value) 120 | dev_output_coils|= (1 << (la - 1)); 121 | else 122 | dev_output_coils&= ~(1 << (la - 1)); 123 | return value; 124 | // 10001-10008 125 | }else if (la >= 10001 && la <= 10008) { 126 | // we can't write to here address 127 | return mbus_error(MBUS_RESPONSE_ILLEGAL_FUNCTION); 128 | } 129 | else if (la == 30001) { 130 | // we can't write to here address 131 | return mbus_error(MBUS_RESPONSE_ILLEGAL_FUNCTION); 132 | } 133 | else if (la >= 40001 && la <= 40008) { 134 | holding_registers_4000x[la - 40001] = value; 135 | return value; 136 | } 137 | // else error code 02 (the query have illegal address) 138 | return mbus_error(MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS); 139 | } 140 | 141 | 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif -------------------------------------------------------------------------------- /src/rtu/mbutils.c: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | #include 32 | 33 | static const uint8_t aucCRCHi[] = { 34 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 35 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 36 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 37 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 38 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 39 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 40 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 41 | 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 42 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 43 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 44 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 45 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 46 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 47 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 48 | 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 49 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 50 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 51 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 52 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 53 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 54 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 55 | 0x00, 0xC1, 0x81, 0x40}; 56 | 57 | static const uint8_t aucCRCLo[] = { 58 | 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 59 | 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 60 | 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 61 | 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 62 | 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 63 | 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 64 | 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 65 | 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 66 | 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 67 | 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 68 | 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 69 | 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 70 | 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 71 | 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 72 | 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 73 | 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 74 | 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 75 | 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 76 | 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 77 | 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 78 | 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 79 | 0x41, 0x81, 0x80, 0x40}; 80 | 81 | /* 82 | USHORT 83 | usMBCRC16( UCHAR * pucFrame, USHORT usLen ) 84 | { 85 | UCHAR ucCRCHi = 0xFF; 86 | UCHAR ucCRCLo = 0xFF; 87 | int iIndex; 88 | 89 | while( usLen-- ) 90 | { 91 | iIndex = ucCRCLo ^ *( pucFrame++ ); 92 | ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] ); 93 | ucCRCHi = aucCRCLo[iIndex]; 94 | } 95 | return ( USHORT )( ucCRCHi << 8 | ucCRCLo ); 96 | } 97 | 98 | */ 99 | 100 | uint16_t mbus_crc16(const uint16_t crc16, const uint8_t byte) { 101 | const int index = (crc16 & 0xFF) ^ byte; 102 | return (aucCRCLo[index] << 8) | ((crc16 >> 8) ^ aucCRCHi[index]); 103 | } 104 | 105 | __attribute__((weak)) uint32_t mbus_tickcount() { return 0; } 106 | -------------------------------------------------------------------------------- /src/dev/sample.c: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 4 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 5 | * All rights reserved. 6 | * 7 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | * 27 | * @copyright Copyright (C) 2017+ 28 | * @author Iurii Bell (ds@inbox.ru) 29 | * @license MIT 30 | * @package stModbus 31 | */ 32 | 33 | #include "dev/sample.h" 34 | 35 | #include "spi_ion_board.h" 36 | 37 | #include "gpio_ion_board.h" 38 | 39 | #include 40 | 41 | #include 42 | 43 | 44 | #ifdef __cplusplus 45 | extern "C" 46 | { 47 | #endif 48 | 49 | 50 | 51 | 52 | //Define device register 53 | uint16_t device_reg_4xxxx[13]; 54 | 55 | //Define some 16-bit output 56 | uint16_t output; 57 | 58 | //Define some 16-bit input 59 | uint16_t input; 60 | 61 | 62 | extern uint32_t ddd2; 63 | 64 | 65 | //Function for initialization modbus on you device 66 | mbus_t mbus_somedevice_open(Modbus_Conf_t *pconf) 67 | { 68 | mbus_t mb; 69 | 70 | //Define read callback function 71 | pconf->read = mbus_somedev_read; 72 | 73 | //Define write callback function 74 | pconf->write = mbus_somedev_write; 75 | 76 | //Open modbus context 77 | mb = mbus_open(pconf); 78 | 79 | if (mb < 0 ) return (mbus_t)MBUS_ERROR; 80 | 81 | //We can map some function on modbus commands 82 | //if ( mbus_connect(mb, mbus_somedevice_read_3xxxx, MBUS_FUNC_READ_INPUT_REGS ) ) return (mbus_t)MBUS_ERROR; 83 | 84 | //if ( mbus_connect(mb, mbus_somedevice_read_4xxxx, MBUS_FUNC_READ_REGS ) ) return (mbus_t)MBUS_ERROR; 85 | 86 | //Set default values for registers as you need 87 | 88 | device_reg_4xxxx[0] = 0x322A; //40001 89 | device_reg_4xxxx[1] = pconf->devaddr; //40002 Device addr 90 | device_reg_4xxxx[2] = 0x7; //40003 91 | 92 | device_reg_4xxxx[3] = 0x0; //40004 93 | device_reg_4xxxx[4] = 0x0; // 94 | 95 | device_reg_4xxxx[5] = 0x0; //40006 96 | device_reg_4xxxx[6] = 0x0; // 97 | 98 | device_reg_4xxxx[7] = 0x0; //40008 99 | device_reg_4xxxx[8] = 0x0; // 100 | 101 | device_reg_4xxxx[11] = 0x0; //Up time // 40012 102 | 103 | 104 | return mb; 105 | } 106 | 107 | 108 | mbus_status_t mbus_somedevice_read_3xxxx(mbus_t mb_context) 109 | { 110 | mbus_context_t ctx = mbus_context(mb_context); 111 | if (ctx == 0) return MBUS_ERROR; 112 | // printf("Isma read:%d\n", ctx->header.addr+30001); 113 | 114 | 115 | return MBUS_OK; 116 | 117 | } 118 | 119 | mbus_status_t mbus_somedevice_read_4xxxx(mbus_t mb_context) 120 | { 121 | mbus_context_t ctx = mbus_context(mb_context); 122 | if (ctx == 0) return MBUS_ERROR; 123 | //printf("Isma read:%d\n", ctx->header.addr+40001); 124 | 125 | uint16_t size = 0; 126 | uint16_t* buf = (uint16_t*)( ctx->conf.sendbuf + 3 ); 127 | 128 | /*Setting register 40001 according to the table below will enable 1 of 4 available 129 | * actions: module reset, reloading thesettings, settingto defaultand entering thebootloader. * 40001 130 | */ 131 | 132 | 133 | if (ctx->header.addr + ctx->header.num < 13 ){ 134 | //memcpy(buf, isma_reg_4xxxx + ctx->header.addr, ctx->header.num*2 ); 135 | size= ctx->header.num; 136 | }else{ 137 | //Hack 138 | //memset(buf,0,ctx->header.num*2); 139 | buf[0]++; 140 | size= ctx->header.num; 141 | } 142 | 143 | 144 | if ( size != 0 ){ 145 | ctx->conf.sendbuf[2] = size*2; 146 | return mbus_send_data(mb_context, size*2 + 3 ); 147 | } 148 | 149 | return mbus_response(mb_context, MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS); 150 | } 151 | 152 | uint16_t adc[3]; 153 | 154 | uint16_t sdadc1[2]; 155 | 156 | 157 | uint16_t dac[16]; 158 | 159 | uint16_t sdadc2[3]; 160 | 161 | uint16_t sdadc3[8]; 162 | 163 | extern float vout1; 164 | extern float v2; 165 | extern float r1; 166 | 167 | /* It's modbus request on read register by logical address (la) */ 168 | uint16_t mbus_somedev_read(uint32_t la) 169 | { 170 | short val; 171 | if ( la > 40000 && la <= 40016 ){ 172 | return dac[la-40001]; 173 | } 174 | 175 | //Digital outputs 176 | switch (la){ 177 | case 40017: //State 178 | return ddd2; 179 | case 40143: //Default state 180 | return 0; 181 | } 182 | 183 | uint32_t* ff = (uint32_t*) &vout1; 184 | 185 | if (la == 40018 ){ 186 | return (*ff)&0xFFFF; 187 | } 188 | if (la == 40019 ){ 189 | return ((*ff)>>16)&0xFFFF; 190 | } 191 | 192 | 193 | ff = (uint32_t*) &v2; 194 | 195 | if (la == 40020 ){ 196 | return (*ff)&0xFFFF; 197 | } 198 | if (la == 40021 ){ 199 | return ((*ff)>>16)&0xFFFF; 200 | } 201 | 202 | ff = (uint32_t*) &r1; 203 | 204 | if (la == 40022 ){ 205 | return (*ff)&0xFFFF; 206 | } 207 | if (la == 40023 ){ 208 | return ((*ff)>>16)&0xFFFF; 209 | } 210 | 211 | 212 | if (la > 40022 && la< 40047){ 213 | return 0; 214 | } 215 | 216 | if (la < 40000){ 217 | return 1; 218 | } 219 | 220 | //Analog outputs 221 | if (la == 40019){ 222 | return 0; 223 | } 224 | 225 | //Analog inputs 226 | if (la == 40087){ 227 | return 0; 228 | } 229 | if (la == 40088){ 230 | val = (short) sdadc1[1]; 231 | if (val < 0 ) val = 0; 232 | //return (uint16_t)((float)val*0.07*2); 233 | } 234 | if (la == 40089){ 235 | val = (short) sdadc1[0]; 236 | if (val < 0 ) val = 0; 237 | //return (uint16_t)((float)val*0.05); 238 | } 239 | if (la == 40090){ 240 | return 4; 241 | } 242 | if (la == 40091){ 243 | return 5; 244 | } 245 | if (la == 40092){ 246 | return 6; 247 | } 248 | if ( 249 | la > 40087){ 250 | //return la -40087; 251 | } 252 | 253 | if (la > 40100){ 254 | return 0; 255 | } 256 | 257 | 258 | 259 | 260 | 261 | return la; 262 | } 263 | 264 | 265 | //Function for write to some register by logic address 266 | uint16_t mbus_somedev_write(uint32_t la, uint16_t value) 267 | { 268 | //printf("We write: %d %d\n",la, value); 269 | if ( la > 40000 && la <= 40016 ){ 270 | uint8_t ch = la - 40001; 271 | dac[ch] = value; 272 | spi_dac_set(dac[ch]&0xFF,ch); 273 | } 274 | if (la == 40017 ){ 275 | ion_adc_writereg(0x1, 1, value&0xFF); 276 | } 277 | if (la == 40018 ){ 278 | ion_mux_select(value&0xF); 279 | ion_mux_output(value&0x10); 280 | } 281 | 282 | 283 | 284 | return value; 285 | } 286 | 287 | 288 | 289 | #ifdef __cplusplus 290 | } 291 | #endif 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /projects/msvs/msvs/msvs.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {6a2da4d7-5814-4262-a5f0-4ac3dd4f8413} 25 | msvs 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | ../../../include 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | true 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Level3 129 | true 130 | true 131 | true 132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | 135 | 136 | Console 137 | true 138 | true 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /include/modbus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #ifndef _STMODBUS_DEFINE_H_ 33 | #define _STMODBUS_DEFINE_H_ 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | #if (STMODBUS_USE_CRITICAL_SECTIONS == 0) 44 | #define stmbEnterCriticalSection 45 | #define stmbLeaveCriticalSection 46 | #else 47 | 48 | #ifndef stmbEnterCriticalSection 49 | #error \ 50 | "If you use RTOS/FreeRTOS plese define mutex '#define stmbEnterCriticalSection mutex.lock' or empty" 51 | #endif 52 | 53 | #ifndef stmbLeaveCriticalSection 54 | #error \ 55 | "If you use RTOS/FreeRTOS plese define mutex '#define stmbLeaveCriticalSection mutex.unlock' or empty" 56 | #endif 57 | 58 | #endif 59 | 60 | #if (STMODBUS_COUNT_CONTEXT < 1) 61 | #error "Count modbus context must be more then 0" 62 | #endif 63 | 64 | /* Typedef definition */ 65 | #include 66 | 67 | typedef enum { MBUS_OK = 0, MBUS_ERROR = -1 } mbus_status_t; 68 | 69 | typedef enum { 70 | MBUS_FUNC_READ_COILS = 1, 71 | MBUS_FUNC_READ_DISCRETE = 2, 72 | MBUS_FUNC_READ_REGS = 3, 73 | MBUS_FUNC_READ_INPUT_REGS = 4, 74 | MBUS_FUNC_WRITE_COIL = 5, 75 | MBUS_FUNC_WRITE_REG = 6, 76 | MBUS_FUNC_READ_EXCEPT_STATUS = 7, 77 | MBUS_FUNC_DIAGNOSTICS = 8, 78 | MBUS_FUNC_GET_COMM_EVENT_COUNTER = 11, 79 | MBUS_FUNC_GET_COMM_EVENT_LOG = 12, 80 | MBUS_FUNC_WRITE_COILS = 15, 81 | MBUS_FUNC_WRITE_REGS = 16, 82 | MBUS_FUNC_READ_SLAVE_ID = 17, 83 | MBUS_FUNC_READ_FILE_RECORD = 20, 84 | MBUS_FUNC_WRITE_FILE_RECORD = 21, 85 | MBUS_FUNC_READ_WRITE_MASK_REGS = 22, 86 | MBUS_FUNC_READ_WRITE_REGS = 23, 87 | MBUS_FUNC_READ_FIFO_QUEUE = 24, 88 | MBUS_FUNC_READ_DEVICE_ID = 43, 89 | MBUS_FUNC_EXCEPTION = 0x81, 90 | } Modbus_ConnectFuncType; 91 | 92 | typedef enum { 93 | MBUS_STATE_IDLE = 0, 94 | MBUS_STATE_DEVADD, 95 | MBUS_STATE_FUNCTION, 96 | MBUS_STATE_REGADDR_LO, 97 | MBUS_STATE_REGADDR_HI, 98 | MBUS_STATE_REGNUM_LO, 99 | MBUS_STATE_REGNUM_HI, 100 | MBUS_STATE_DATA_LO, 101 | MBUS_STATE_DATA_HI, 102 | MBUS_STATE_DATA_SIZE, 103 | MBUS_STATE_DATA, 104 | MBUS_STATE_CRC_LO, 105 | MBUS_STATE_CRC_HI, 106 | MBUS_STATE_FINISH, 107 | MBUS_STATE_RESPONSE 108 | 109 | } Modbus_StateType; 110 | 111 | typedef enum MBUS_RESPONSE { 112 | 113 | MBUS_RESPONSE_OK = 0x00, 114 | MBUS_RESPONSE_NONE = 0xFF, 115 | /* MBUS_RESPONSE_ILLEGAL_FUNCTION 116 | The function code received in the query is not an allowable action 117 | for the server. This may be because the function code is only 118 | applicable to newerdevices, and was not implemented in the unit 119 | selected. It could also indicate that the serveris in the wrong state to 120 | process a request of this type, for example because it is 121 | unconfigured and is being asked to return register values. 122 | */ 123 | MBUS_RESPONSE_ILLEGAL_FUNCTION = 0x01, 124 | 125 | /* MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS 126 | The data address received in the query is not an allowable address 127 | for the server. More specifically, the combination of reference number 128 | and transfer length is invalid. For a controller with 100 registers, 129 | the PDU addresses the first register as 0, and the last one as 99. If 130 | a request is submitted with a starting register address of 96 and a 131 | quantity of registers of 4, then this request will successfully 132 | operate (address-wise at least) on registers 96, 97, 98, 99. If 133 | a request is submitted with a starting register address of 96 and 134 | a quantity of registers of 5, then this request will fail with 135 | Exception Code 0x02 “Illegal Data Address” since it attempts to 136 | operate on registers 96, 97, 98, 99 and 100, and there is no 137 | register with address 100. 138 | */ 139 | MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS = 0x02, 140 | 141 | /* A value contained in the query data field is not an allowable value 142 | for server. This indicates a fault in the structure of the remainder of 143 | a complex request, such as that the implied length is 144 | incorrect. It specifically does NOT mean that a data item submitted for 145 | storage in a register has a value outside the expectation of the application 146 | program, since the MODBUS protocol is unaware of the significance of 147 | any particular val ue of any particular register. 148 | */ 149 | MBUS_RESPONSE_ILLEGAL_DATA_VALUE = 0x03, 150 | /* 151 | An unrecoverable error occurred while the server 152 | was attempting to perform the requested action. 153 | */ 154 | MBUS_RESPONSE_SERVICE_DEVICE_FAILURE = 0x04, 155 | } Modbus_ResponseType; 156 | 157 | /* Simple function for many usage 158 | * 159 | */ 160 | 161 | typedef int8_t mbus_t; 162 | 163 | typedef void (*stmbFunc)(void); 164 | 165 | typedef mbus_status_t (*stmbCallBackFunc)(const mbus_t mb_context); 166 | 167 | typedef uint16_t (*stmbReadFunc)(const uint32_t logicAddress); 168 | typedef uint16_t (*stmbWriteFunc)(const uint32_t logicAddress, uint16_t value); 169 | 170 | typedef int (*stmbSendFunc)(const mbus_t func, const uint8_t *data, 171 | const uint16_t size); 172 | 173 | typedef struct __stmodbus_request_header { 174 | uint8_t devaddr; 175 | uint8_t func; 176 | uint16_t addr; 177 | uint16_t num; 178 | uint16_t rnum; 179 | uint8_t size; 180 | uint8_t rsize; 181 | } _stmodbus_request_header; 182 | 183 | typedef struct __stmodbus_bind_func { 184 | uint8_t code; 185 | stmbCallBackFunc func; 186 | } _stmodbus_bind_func; 187 | 188 | typedef struct __stmodbus_area_t { 189 | uint32_t size; 190 | void *ptr; 191 | uint16_t num; 192 | } _stmodbus_area_t; 193 | 194 | typedef struct __stmodbus_conf_t { 195 | uint8_t devaddr; 196 | uint16_t coils; 197 | uint16_t discrete; 198 | void *device; 199 | stmbSendFunc send; 200 | stmbReadFunc read; 201 | stmbWriteFunc write; 202 | uint8_t *sendbuf; 203 | uint16_t sendbuf_sz; 204 | uint8_t *recvbuf; 205 | uint16_t recvbuf_sz; 206 | 207 | } Modbus_Conf_t; 208 | 209 | typedef struct __stmodbus_context_t { 210 | Modbus_Conf_t conf; 211 | uint8_t open; 212 | Modbus_StateType state; 213 | uint16_t crc16; 214 | uint32_t timer; 215 | #if STMODBUS_COUNT_FUNC > 0 216 | _stmodbus_bind_func func[STMODBUS_COUNT_FUNC]; 217 | #endif 218 | _stmodbus_request_header header; 219 | _stmodbus_request_header response; 220 | } _stmodbus_context_t; 221 | 222 | typedef _stmodbus_context_t *mbus_context_t; 223 | 224 | /* Function definition */ 225 | 226 | /* 227 | * function mbus_open() 228 | * open new modbus context for new port 229 | * return: MODBUS_ERROR - if can't open context 230 | */ 231 | mbus_t mbus_open(Modbus_Conf_t *pconf); 232 | 233 | /* 234 | * function mbus_close() 235 | * close modbus context 236 | * return: none 237 | */ 238 | void mbus_close(mbus_t mb_context); 239 | 240 | /* 241 | * 242 | * 243 | */ 244 | mbus_context_t mbus_device(mbus_t mb_context); 245 | 246 | mbus_context_t mbus_context(mbus_t mb_context); 247 | 248 | /* 249 | * function mbus_connect() 250 | * connect function to callback modbus context 251 | * return: none 252 | */ 253 | mbus_status_t mbus_connect(const mbus_t mb_context, stmbCallBackFunc func, 254 | Modbus_ConnectFuncType type); 255 | 256 | mbus_status_t mbus_response(mbus_t mb_context, Modbus_ResponseType response); 257 | 258 | mbus_status_t mbus_flush(const mbus_t context); 259 | 260 | uint16_t mbus_hal_crc16(mbus_t mb_context, uint8_t byte); 261 | 262 | uint16_t mbus_crc16(const uint16_t crc16, const uint8_t byte); 263 | 264 | uint16_t mbus_error(Modbus_ResponseType error); 265 | 266 | uint32_t mbus_tickcount(); 267 | 268 | int mbus_proto_address( Modbus_ConnectFuncType func, int *r); 269 | 270 | /* 271 | * function mbus_close() 272 | * close modbus context 273 | * return: none 274 | */ 275 | mbus_status_t mbus_poll(mbus_t mb_context, uint8_t byte); 276 | 277 | mbus_status_t mbus_send(_stmodbus_context_t *ctx); 278 | 279 | mbus_status_t mbus_send_error(mbus_t mb_context, Modbus_ResponseType response); 280 | 281 | mbus_status_t mbus_send_data(mbus_t mb_context, uint16_t size); 282 | 283 | mbus_status_t mbus_poll_response(mbus_t mb_context); 284 | 285 | extern _stmodbus_context_t g_mbusContext[STMODBUS_COUNT_CONTEXT]; 286 | 287 | #ifdef __cplusplus 288 | } 289 | #endif 290 | 291 | #endif // _STMODBUS_DEFINE_H_ 292 | -------------------------------------------------------------------------------- /src/modbus.c: -------------------------------------------------------------------------------- 1 | /** 2 | * stModbus Libary: A tiny Modbus implementation for Modbus ASCII/RTU 3 | * Copyright (c) 2017+ [Iurii Bell] ds@inbox.ru (http://www.bel-tech.ru/) 4 | * All rights reserved. 5 | * 6 | * [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @copyright Copyright (C) 2017+ 27 | * @author Iurii Bell (ds@inbox.ru) 28 | * @license MIT 29 | * @package stModbus 30 | */ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #include "modbus.h" 37 | 38 | #include 39 | #include 40 | 41 | // Global variable for modbus context 42 | _stmodbus_context_t g_mbusContext[STMODBUS_COUNT_CONTEXT]; 43 | Modbus_ResponseType g_userError = MBUS_RESPONSE_OK; 44 | 45 | void lock() {} 46 | 47 | void unlock() {} 48 | 49 | /* 50 | * function mbus_open() 51 | * open new modbus context for new port 52 | * return: MODBUS_ERROR - if can't open context 53 | */ 54 | mbus_t mbus_open(Modbus_Conf_t *pconf) { 55 | mbus_t context; 56 | for (context = 0; context < STMODBUS_COUNT_CONTEXT; context++) { 57 | if (g_mbusContext[context].open == 0) { 58 | break; 59 | } 60 | } 61 | if (context == STMODBUS_COUNT_CONTEXT) 62 | return (mbus_t)MBUS_ERROR; 63 | // Clear context 64 | memset(&g_mbusContext[context], 0, sizeof(_stmodbus_context_t)); 65 | // Copy config to context 66 | memcpy((void *)&g_mbusContext[context].conf, (void *)pconf, 67 | sizeof(Modbus_Conf_t)); 68 | 69 | g_mbusContext[context].open = 1; 70 | return context; 71 | } 72 | 73 | mbus_status_t mbus_flush(const mbus_t context) { 74 | g_mbusContext[context].crc16 = 0xFFFF; 75 | g_mbusContext[context].state = MBUS_STATE_IDLE; 76 | return MBUS_OK; 77 | } 78 | 79 | mbus_status_t mbus_response(mbus_t mb_context, Modbus_ResponseType response) { 80 | 81 | if (response != MBUS_RESPONSE_OK) { 82 | return mbus_send_error(mb_context, response); 83 | } else { 84 | } 85 | return MBUS_ERROR; 86 | } 87 | 88 | uint16_t mbus_error(Modbus_ResponseType error) { 89 | g_userError = error; 90 | return 0; 91 | } 92 | 93 | inline mbus_status_t mbus_poll_response(mbus_t mb_context) { 94 | stmbCallBackFunc func = 0; 95 | _stmodbus_context_t *ctx = &g_mbusContext[mb_context]; 96 | int read = 1, la; 97 | uint16_t d; 98 | 99 | if (ctx->header.func == 0x04) { 100 | la = 10; 101 | } 102 | 103 | #if STMODBUS_COUNT_FUNC > 0 104 | for (int i = 0; i < STMODBUS_COUNT_FUNC; i++) { 105 | if ((ctx->func[i].code == ctx->response.func)) { 106 | func = ctx->func[i].func; 107 | break; 108 | } 109 | } 110 | #endif 111 | switch (ctx->header.func) { 112 | case MBUS_FUNC_WRITE_COILS: 113 | case MBUS_FUNC_READ_COILS: 114 | if ((ctx->header.num == 0) || (ctx->header.num > 0x07D0)) { 115 | return mbus_response(mb_context, MBUS_RESPONSE_ILLEGAL_DATA_VALUE); 116 | } 117 | if ((ctx->header.addr + ctx->header.num) >= ctx->conf.coils) { 118 | return mbus_response(mb_context, MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS); 119 | } 120 | break; 121 | case MBUS_FUNC_READ_DISCRETE: 122 | if ((ctx->header.num == 0) || (ctx->header.num > 0x07D0)) { 123 | return mbus_response(mb_context, MBUS_RESPONSE_ILLEGAL_DATA_VALUE); 124 | } 125 | if ((ctx->header.addr + ctx->header.num) > ctx->conf.discrete) { 126 | return mbus_response(mb_context, MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS); 127 | } 128 | break; 129 | default: 130 | break; 131 | } 132 | 133 | if (func != 0) { 134 | return func(mb_context); 135 | } 136 | 137 | la = mbus_proto_address((Modbus_ConnectFuncType)ctx->header.func, (int*)&read); 138 | if (la > 0) { 139 | la += ctx->header.addr; 140 | } 141 | if (la < 50001) { 142 | ctx->conf.sendbuf[0] = ctx->header.devaddr; 143 | ctx->conf.sendbuf[1] = ctx->header.func; 144 | ctx->conf.sendbuf[2] = ctx->header.num * 2; 145 | if (read && ctx->conf.read) { 146 | g_userError = MBUS_RESPONSE_OK; 147 | for (int i = 0; i < ctx->header.num; i++) { 148 | 149 | d = ctx->conf.read(la + i); 150 | ctx->conf.sendbuf[3 + (i << 1)] = d >> 8; 151 | ctx->conf.sendbuf[3 + (i << 1) + 1] = d & 0xFF; 152 | } 153 | if (g_userError == MBUS_RESPONSE_OK) { 154 | return mbus_send_data(mb_context, 3 + ctx->conf.sendbuf[2]); 155 | }else { 156 | return mbus_response(mb_context, g_userError); 157 | } 158 | } else if (ctx->conf.write) { 159 | uint16_t *value; 160 | ctx->conf.sendbuf[2] = 0; 161 | switch (ctx->header.func) { 162 | case MBUS_FUNC_WRITE_REG: 163 | case MBUS_FUNC_WRITE_COIL: 164 | // in both these cases, we should return the same packet that we 165 | // received. in both cases, the packes have 6 bytes of data + 2 CRC 166 | // bytes = 8 bytes 167 | value = (uint16_t *)ctx->conf.recvbuf; 168 | ctx->conf.write(la, *value); 169 | ctx->conf.sendbuf[2] = ctx->header.addr >> 8; 170 | ctx->conf.sendbuf[3] = ctx->header.addr & 0xFF; 171 | ctx->conf.sendbuf[4] = ctx->conf.recvbuf[1]; 172 | ctx->conf.sendbuf[5] = ctx->conf.recvbuf[0]; 173 | return mbus_send_data(mb_context, 6); 174 | 175 | case MBUS_FUNC_WRITE_REGS: 176 | value = (uint16_t *)ctx->conf.recvbuf; 177 | for (int i = 0; i < ctx->header.num; i++) { 178 | ctx->conf.write(la + i, *value++); 179 | } 180 | ctx->conf.sendbuf[2] = ctx->header.addr >> 8; 181 | ctx->conf.sendbuf[3] = ctx->header.addr & 0xFF; 182 | ctx->conf.sendbuf[4] = ctx->header.num >> 8; 183 | ctx->conf.sendbuf[5] = ctx->header.num & 0xFF; 184 | return mbus_send_data(mb_context, 6); 185 | } // end of switch 186 | } 187 | } 188 | return mbus_response(mb_context, MBUS_RESPONSE_ILLEGAL_FUNCTION); 189 | } 190 | 191 | //#include 192 | /* 193 | * function mbus_close() 194 | * close modbus context 195 | * return: none 196 | */ 197 | mbus_status_t mbus_poll(mbus_t mb_context, uint8_t byte) { 198 | // State machine 199 | _stmodbus_context_t *ctx = &g_mbusContext[mb_context]; 200 | 201 | if (mbus_tickcount() - ctx->timer > 4) { 202 | mbus_flush(mb_context); 203 | } 204 | ctx->timer = mbus_tickcount(); 205 | 206 | switch (ctx->state) { 207 | case MBUS_STATE_IDLE: 208 | mbus_flush(mb_context); 209 | ctx->state = MBUS_STATE_FUNCTION; 210 | ctx->header.devaddr = byte; 211 | break; 212 | case MBUS_STATE_FUNCTION: 213 | ctx->header.func = byte; 214 | switch (byte) { 215 | case MBUS_FUNC_WRITE_REG: 216 | ctx->header.rnum = 1; 217 | ctx->header.num = 1; 218 | ctx->state = MBUS_STATE_REGADDR_HI; 219 | break; 220 | case MBUS_FUNC_WRITE_REGS: 221 | case MBUS_FUNC_WRITE_COILS: 222 | ctx->header.rnum = 1; 223 | ctx->header.num = 0; 224 | ctx->state = MBUS_STATE_REGADDR_HI; 225 | break; 226 | case MBUS_FUNC_READ_INPUT_REGS: 227 | case MBUS_FUNC_READ_COILS: 228 | case MBUS_FUNC_READ_REGS: 229 | ctx->state = MBUS_STATE_REGADDR_HI; 230 | ctx->header.rnum = 0; 231 | ctx->header.num = 0; 232 | break; 233 | case MBUS_FUNC_WRITE_COIL: 234 | ctx->header.rnum = 1; 235 | ctx->header.num = 1; 236 | ctx->state = MBUS_STATE_REGADDR_HI; 237 | break; 238 | default: 239 | // ctx->state = MBUS_STATE_IDLE; 240 | mbus_flush(mb_context); 241 | break; 242 | } 243 | break; 244 | case MBUS_STATE_REGADDR_HI: 245 | ctx->state = MBUS_STATE_REGADDR_LO; 246 | ctx->header.addr = byte << 8; 247 | break; 248 | case MBUS_STATE_REGADDR_LO: 249 | ctx->header.addr |= byte; 250 | if (ctx->header.num == 1 && ctx->header.rnum == 1) { 251 | ctx->state = MBUS_STATE_DATA_HI; 252 | } else { 253 | ctx->state = MBUS_STATE_REGNUM_HI; 254 | } 255 | break; 256 | case MBUS_STATE_DATA_HI: 257 | ctx->state = MBUS_STATE_DATA_LO; 258 | ctx->conf.recvbuf[2 * (ctx->header.num - ctx->header.rnum) + 1] = byte; 259 | break; 260 | case MBUS_STATE_DATA_LO: 261 | ctx->conf.recvbuf[2 * (ctx->header.num - ctx->header.rnum)] = byte; 262 | ctx->header.rnum--; 263 | if (ctx->header.rnum == 0) { 264 | ctx->state = MBUS_STATE_CRC_LO; 265 | } else { 266 | ctx->state = MBUS_STATE_DATA_HI; 267 | } 268 | break; 269 | case MBUS_STATE_DATA_SIZE: 270 | ctx->state = MBUS_STATE_DATA; 271 | ctx->header.size = byte; 272 | ctx->header.rsize = byte; 273 | break; 274 | case MBUS_STATE_DATA: 275 | ctx->conf.recvbuf[ctx->header.size - ctx->header.rsize] = byte; 276 | ctx->header.rsize--; 277 | if (ctx->header.rsize == 0) { 278 | ctx->state = MBUS_STATE_CRC_LO; 279 | } 280 | break; 281 | case MBUS_STATE_REGNUM_HI: 282 | ctx->state = MBUS_STATE_REGNUM_LO; 283 | ctx->header.num = byte << 8; 284 | break; 285 | case MBUS_STATE_REGNUM_LO: 286 | ctx->state = MBUS_STATE_CRC_LO; 287 | ctx->header.num |= byte; 288 | if (ctx->header.rnum == 0) { 289 | ctx->state = MBUS_STATE_CRC_LO; 290 | } else { 291 | ctx->header.rnum = ctx->header.num; 292 | ctx->state = MBUS_STATE_DATA_HI; 293 | if (ctx->header.func == MBUS_FUNC_WRITE_REGS) { 294 | ctx->state = MBUS_STATE_DATA_SIZE; 295 | } 296 | } 297 | 298 | break; 299 | case MBUS_STATE_CRC_LO: 300 | ctx->state = MBUS_STATE_CRC_HI; 301 | break; 302 | case MBUS_STATE_CRC_HI: 303 | ctx->state = MBUS_STATE_FINISH; 304 | break; 305 | // We can't processing any more before callback not returned 306 | case MBUS_STATE_RESPONSE: 307 | return MBUS_ERROR; 308 | default: 309 | mbus_flush(mb_context); 310 | break; 311 | } 312 | 313 | ctx->crc16 = mbus_crc16(ctx->crc16, byte); 314 | 315 | if (ctx->state == MBUS_STATE_FINISH) { 316 | // CRC error 317 | if (ctx->crc16 != 0) { 318 | mbus_flush(mb_context); 319 | return MBUS_ERROR; 320 | } 321 | 322 | // TODO: Add broadcast messages 323 | if (ctx->header.devaddr == ctx->conf.devaddr) { 324 | ctx->state = MBUS_STATE_RESPONSE; 325 | if (mbus_poll_response(mb_context) == MBUS_OK) { 326 | mbus_flush(mb_context); 327 | return MBUS_OK; 328 | } 329 | mbus_flush(mb_context); 330 | return MBUS_ERROR; 331 | } 332 | mbus_flush(mb_context); 333 | } 334 | return MBUS_OK; 335 | } 336 | 337 | mbus_context_t mbus_device(mbus_t mb_context) { 338 | return (mbus_context_t)&g_mbusContext[mb_context]; 339 | } 340 | 341 | mbus_context_t mbus_context(mbus_t mb_context) { 342 | if (g_mbusContext[mb_context].open) 343 | return (mbus_context_t)&g_mbusContext[mb_context]; 344 | return 0; 345 | } 346 | 347 | mbus_status_t mbus_send_error(mbus_t mb_context, Modbus_ResponseType response) { 348 | uint16_t *pbuf = (uint16_t *)(g_mbusContext[mb_context].conf.sendbuf + 2); 349 | *pbuf = 0x8300 | (uint8_t)response; 350 | return mbus_send_data(mb_context, 4); 351 | } 352 | 353 | mbus_status_t mbus_send_data(mbus_t mb_context, uint16_t size) { 354 | // if size > ( conf.send_sz-2) error 355 | uint16_t crc32 = 0xFFFF; 356 | const _stmodbus_context_t *ctx = &g_mbusContext[mb_context]; 357 | uint8_t *pbuf = ctx->conf.sendbuf; 358 | if (ctx->conf.send == 0 || pbuf == 0 || ctx->conf.sendbuf_sz < (size + 2)) 359 | return MBUS_ERROR; 360 | for (int i = 0; i < size; i++) { 361 | crc32 = mbus_crc16(crc32, pbuf[i]); 362 | } 363 | pbuf[size++] = crc32 & 0xFF; 364 | pbuf[size++] = (crc32 >> 8); 365 | 366 | if (ctx->conf.send(mb_context, pbuf, size) != size) 367 | return MBUS_ERROR; 368 | return MBUS_OK; 369 | } 370 | 371 | mbus_status_t mbus_connect(const mbus_t mb_context, stmbCallBackFunc func, 372 | Modbus_ConnectFuncType type) { 373 | #if STMODBUS_COUNT_FUNC > 0 374 | _stmodbus_context_t *ctx = &g_mbusContext[mb_context]; 375 | for (int i = 0; i < STMODBUS_COUNT_FUNC; i++) { 376 | if ((ctx->func[i].code == 0)) { 377 | ctx->func[i].func = func; 378 | ctx->func[i].code = (uint8_t)type; 379 | return MBUS_OK; 380 | } 381 | } 382 | #endif 383 | return MBUS_ERROR; 384 | } 385 | 386 | int mbus_proto_address( Modbus_ConnectFuncType func, int *r) { 387 | int adr = 0; 388 | *r = 1; 389 | switch (func) { 390 | case MBUS_FUNC_WRITE_REG: 391 | case MBUS_FUNC_WRITE_REGS: 392 | case MBUS_FUNC_READ_WRITE_MASK_REGS: 393 | case MBUS_FUNC_READ_WRITE_REGS: 394 | *r = 0; 395 | case MBUS_FUNC_READ_REGS: 396 | adr = 40001; 397 | break; 398 | case MBUS_FUNC_READ_INPUT_REGS: 399 | adr = 30001; 400 | break; 401 | case MBUS_FUNC_READ_DISCRETE: 402 | adr = 10001; 403 | break; 404 | case MBUS_FUNC_WRITE_COILS: 405 | case MBUS_FUNC_WRITE_COIL: 406 | *r = 0; 407 | case MBUS_FUNC_READ_COILS: 408 | adr = 0001; 409 | break; 410 | default: 411 | break; 412 | } 413 | return adr; 414 | } 415 | 416 | #ifdef __cplusplus 417 | } 418 | #endif 419 | -------------------------------------------------------------------------------- /projects/keil/stModbus.uvprojx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.1 5 | 6 |
### uVision Project, (C) Keil Software
7 | 8 | 9 | 10 | stModbus 11 | 0x4 12 | ARM-ADS 13 | 5060422::V5.06 update 4 (build 422)::ARMCC 14 | 15 | 16 | ARMCM3 17 | ARM 18 | ARM.CMSIS.5.0.1 19 | http://www.keil.com/pack/ 20 | IRAM(0x20000000,0x00020000) IROM(0x00000000,0x00040000) CPUTYPE("Cortex-M3") CLOCK(12000000) ESEL ELITTLE 21 | 22 | 23 | UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000) 24 | 0 25 | $$Device:ARMCM3$Device\ARM\ARMCM3\Include\ARMCM3.h 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | $$Device:ARMCM3$Device\ARM\SVD\ARMCM3.svd 36 | 0 37 | 0 38 | 39 | 40 | 41 | 42 | 43 | 44 | 0 45 | 0 46 | 0 47 | 0 48 | 1 49 | 50 | ..\..\build\stModbus_Objects\ 51 | stModbus 52 | 0 53 | 1 54 | 0 55 | 1 56 | 1 57 | ..\..\build\stModbus_Listing\ 58 | 1 59 | 0 60 | 0 61 | 62 | 0 63 | 0 64 | 65 | 66 | 0 67 | 0 68 | 0 69 | 0 70 | 71 | 72 | 0 73 | 0 74 | 75 | 76 | 0 77 | 0 78 | 0 79 | 0 80 | 81 | 82 | 0 83 | 0 84 | 85 | 86 | 0 87 | 0 88 | 0 89 | 0 90 | 91 | 0 92 | 93 | 94 | 95 | 0 96 | 0 97 | 0 98 | 0 99 | 0 100 | 1 101 | 0 102 | 0 103 | 0 104 | 0 105 | 3 106 | 107 | 108 | 1 109 | 110 | 111 | SARMCM3.DLL 112 | -MPU 113 | DCM.DLL 114 | -pCM3 115 | SARMCM3.DLL 116 | -MPU 117 | TCM.DLL 118 | -pCM3 119 | 120 | 121 | 122 | 1 123 | 0 124 | 0 125 | 0 126 | 16 127 | 128 | 129 | 130 | 131 | 1 132 | 0 133 | 0 134 | 1 135 | 0 136 | -1 137 | 138 | 1 139 | BIN\UL2CM3.DLL 140 | 141 | 142 | 143 | 144 | 145 | 0 146 | 147 | 148 | 149 | 0 150 | 1 151 | 1 152 | 1 153 | 1 154 | 1 155 | 1 156 | 1 157 | 0 158 | 1 159 | 1 160 | 0 161 | 1 162 | 1 163 | 0 164 | 0 165 | 1 166 | 1 167 | 1 168 | 1 169 | 1 170 | 1 171 | 1 172 | 1 173 | 1 174 | 0 175 | 0 176 | "Cortex-M3" 177 | 178 | 0 179 | 0 180 | 0 181 | 1 182 | 1 183 | 0 184 | 0 185 | 0 186 | 0 187 | 0 188 | 8 189 | 0 190 | 1 191 | 0 192 | 0 193 | 3 194 | 3 195 | 0 196 | 0 197 | 0 198 | 0 199 | 0 200 | 0 201 | 0 202 | 0 203 | 0 204 | 0 205 | 1 206 | 0 207 | 0 208 | 0 209 | 0 210 | 1 211 | 0 212 | 213 | 214 | 0 215 | 0x0 216 | 0x0 217 | 218 | 219 | 0 220 | 0x0 221 | 0x0 222 | 223 | 224 | 0 225 | 0x0 226 | 0x0 227 | 228 | 229 | 0 230 | 0x0 231 | 0x0 232 | 233 | 234 | 0 235 | 0x0 236 | 0x0 237 | 238 | 239 | 0 240 | 0x0 241 | 0x0 242 | 243 | 244 | 0 245 | 0x20000000 246 | 0x20000 247 | 248 | 249 | 1 250 | 0x0 251 | 0x40000 252 | 253 | 254 | 0 255 | 0x0 256 | 0x0 257 | 258 | 259 | 1 260 | 0x0 261 | 0x0 262 | 263 | 264 | 1 265 | 0x0 266 | 0x0 267 | 268 | 269 | 1 270 | 0x0 271 | 0x0 272 | 273 | 274 | 1 275 | 0x0 276 | 0x40000 277 | 278 | 279 | 1 280 | 0x0 281 | 0x0 282 | 283 | 284 | 0 285 | 0x0 286 | 0x0 287 | 288 | 289 | 0 290 | 0x0 291 | 0x0 292 | 293 | 294 | 0 295 | 0x0 296 | 0x0 297 | 298 | 299 | 0 300 | 0x20000000 301 | 0x20000 302 | 303 | 304 | 0 305 | 0x0 306 | 0x0 307 | 308 | 309 | 310 | 311 | 312 | 1 313 | 1 314 | 0 315 | 0 316 | 1 317 | 0 318 | 0 319 | 0 320 | 0 321 | 0 322 | 2 323 | 0 324 | 0 325 | 0 326 | 0 327 | 1 328 | 1 329 | 1 330 | 1 331 | 0 332 | 0 333 | 0 334 | 335 | 336 | 337 | 338 | ../../include 339 | 340 | 341 | 342 | 1 343 | 0 344 | 0 345 | 0 346 | 0 347 | 0 348 | 0 349 | 0 350 | 0 351 | 0 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 1 361 | 0 362 | 0 363 | 0 364 | 1 365 | 0 366 | 0x00000000 367 | 0x20000000 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | Source 381 | 382 | 383 | modbus.c 384 | 1 385 | ..\..\src\modbus.c 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 |
400 | --------------------------------------------------------------------------------