This library meant to allow mbed boards (tested on F401RE) to act as modbus slave. I don't own this work, I just made some simple modifications so that it runs on mbed. My modification were labeled with "afdhal". Summary: Modified modbus Arduino library for mbed. See readme for more details. Feel free to use it as you want. Special thanks to the original authors.
Dependents: ModbusRTU-RS232 FoodComputerARM-alpha
ModbusSlave232.cpp@1:35fdc7056f66, 2016-07-22 (annotated)
- Committer:
- AfdhalAtiffTan
- Date:
- Fri Jul 22 09:44:55 2016 +0000
- Revision:
- 1:35fdc7056f66
- Parent:
- 0:6262fc7582a9
- Child:
- 2:5318159b5eab
Added small comments.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AfdhalAtiffTan | 0:6262fc7582a9 | 1 | /* |
AfdhalAtiffTan | 1:35fdc7056f66 | 2 | Modified by Afdhal: arduino library so that it can be used on mbed. |
AfdhalAtiffTan | 1:35fdc7056f66 | 3 | |
AfdhalAtiffTan | 1:35fdc7056f66 | 4 | Original message: |
AfdhalAtiffTan | 0:6262fc7582a9 | 5 | Modbus over serial line - RTU Slave Arduino Sketch |
AfdhalAtiffTan | 0:6262fc7582a9 | 6 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 7 | By Juan Pablo Zometa : jpmzometa@gmail.com |
AfdhalAtiffTan | 0:6262fc7582a9 | 8 | http://sites.google.com/site/jpmzometa/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 9 | Samuel Marco: sammarcoarmengol@gmail.com |
AfdhalAtiffTan | 0:6262fc7582a9 | 10 | and Andras Tucsni. |
AfdhalAtiffTan | 0:6262fc7582a9 | 11 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 12 | These functions implement functions 3, 6, and 16 (read holding registers, |
AfdhalAtiffTan | 0:6262fc7582a9 | 13 | preset single register and preset multiple registers) of the |
AfdhalAtiffTan | 0:6262fc7582a9 | 14 | Modbus RTU Protocol, to be used over the Arduino serial connection. |
AfdhalAtiffTan | 0:6262fc7582a9 | 15 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 16 | This implementation DOES NOT fully comply with the Modbus specifications. |
AfdhalAtiffTan | 0:6262fc7582a9 | 17 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 18 | This Arduino adaptation is derived from the work |
AfdhalAtiffTan | 0:6262fc7582a9 | 19 | By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au |
AfdhalAtiffTan | 0:6262fc7582a9 | 20 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 21 | These library of functions are designed to enable a program send and |
AfdhalAtiffTan | 0:6262fc7582a9 | 22 | receive data from a device that communicates using the Modbus protocol. |
AfdhalAtiffTan | 0:6262fc7582a9 | 23 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 24 | Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD. |
AfdhalAtiffTan | 0:6262fc7582a9 | 25 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 26 | This program is free software; you can redistribute it and/or modify |
AfdhalAtiffTan | 0:6262fc7582a9 | 27 | it under the terms of the GNU General Public License as published by |
AfdhalAtiffTan | 0:6262fc7582a9 | 28 | the Free Software Foundation; either version 2 of the License, or |
AfdhalAtiffTan | 0:6262fc7582a9 | 29 | (at your option) any later version. |
AfdhalAtiffTan | 0:6262fc7582a9 | 30 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 31 | This program is distributed in the hope that it will be useful, |
AfdhalAtiffTan | 0:6262fc7582a9 | 32 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
AfdhalAtiffTan | 0:6262fc7582a9 | 33 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
AfdhalAtiffTan | 0:6262fc7582a9 | 34 | GNU General Public License for more details. |
AfdhalAtiffTan | 0:6262fc7582a9 | 35 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 36 | You should have received a copy of the GNU General Public License |
AfdhalAtiffTan | 0:6262fc7582a9 | 37 | along with this program; if not, write to the Free Software |
AfdhalAtiffTan | 0:6262fc7582a9 | 38 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
AfdhalAtiffTan | 0:6262fc7582a9 | 39 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 40 | The functions included here have been derived from the |
AfdhalAtiffTan | 0:6262fc7582a9 | 41 | Modicon Modbus Protocol Reference Guide |
AfdhalAtiffTan | 0:6262fc7582a9 | 42 | which can be obtained from Schneider at www.schneiderautomation.com. |
AfdhalAtiffTan | 0:6262fc7582a9 | 43 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 44 | This code has its origins with |
AfdhalAtiffTan | 0:6262fc7582a9 | 45 | paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk) |
AfdhalAtiffTan | 0:6262fc7582a9 | 46 | who wrote a small program to read 100 registers from a modbus slave. |
AfdhalAtiffTan | 0:6262fc7582a9 | 47 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 48 | I have used his code as a catalist to produce this more functional set |
AfdhalAtiffTan | 0:6262fc7582a9 | 49 | of functions. Thanks paul. |
AfdhalAtiffTan | 0:6262fc7582a9 | 50 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 51 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 52 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 53 | //#include "Arduino.h" //afdhal |
AfdhalAtiffTan | 1:35fdc7056f66 | 54 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 55 | #include "millis.h" |
AfdhalAtiffTan | 0:6262fc7582a9 | 56 | #include "MODSERIAL.h" //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 57 | MODSERIAL pc(USBTX, USBRX); // tx, rx //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 58 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 59 | #ifndef ModbusSlave232_h |
AfdhalAtiffTan | 0:6262fc7582a9 | 60 | #include "ModbusSlave232.h" |
AfdhalAtiffTan | 0:6262fc7582a9 | 61 | #endif |
AfdhalAtiffTan | 0:6262fc7582a9 | 62 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 63 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 64 | /**************************************************************************** |
AfdhalAtiffTan | 0:6262fc7582a9 | 65 | * BEGIN MODBUS RTU SLAVE FUNCTIONS |
AfdhalAtiffTan | 0:6262fc7582a9 | 66 | ****************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 67 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 68 | /* constants */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 69 | enum { |
AfdhalAtiffTan | 0:6262fc7582a9 | 70 | MAX_READ_REGS = 0x7D, |
AfdhalAtiffTan | 0:6262fc7582a9 | 71 | MAX_WRITE_REGS = 0x7B, |
AfdhalAtiffTan | 0:6262fc7582a9 | 72 | MAX_MESSAGE_LENGTH = 256 |
AfdhalAtiffTan | 0:6262fc7582a9 | 73 | }; |
AfdhalAtiffTan | 0:6262fc7582a9 | 74 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 75 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 76 | enum { |
AfdhalAtiffTan | 0:6262fc7582a9 | 77 | RESPONSE_SIZE = 6, |
AfdhalAtiffTan | 0:6262fc7582a9 | 78 | EXCEPTION_SIZE = 3, |
AfdhalAtiffTan | 0:6262fc7582a9 | 79 | CHECKSUM_SIZE = 2 |
AfdhalAtiffTan | 0:6262fc7582a9 | 80 | }; |
AfdhalAtiffTan | 0:6262fc7582a9 | 81 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 82 | /* exceptions code */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 83 | enum { |
AfdhalAtiffTan | 0:6262fc7582a9 | 84 | NO_REPLY = -1, |
AfdhalAtiffTan | 0:6262fc7582a9 | 85 | EXC_FUNC_CODE = 1, |
AfdhalAtiffTan | 0:6262fc7582a9 | 86 | EXC_ADDR_RANGE = 2, |
AfdhalAtiffTan | 0:6262fc7582a9 | 87 | EXC_REGS_QUANT = 3, |
AfdhalAtiffTan | 0:6262fc7582a9 | 88 | EXC_EXECUTE = 4 |
AfdhalAtiffTan | 0:6262fc7582a9 | 89 | }; |
AfdhalAtiffTan | 0:6262fc7582a9 | 90 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 91 | /* positions inside the query/response array */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 92 | enum { |
AfdhalAtiffTan | 0:6262fc7582a9 | 93 | SLAVE = 0, |
AfdhalAtiffTan | 0:6262fc7582a9 | 94 | FUNC, |
AfdhalAtiffTan | 0:6262fc7582a9 | 95 | START_H, |
AfdhalAtiffTan | 0:6262fc7582a9 | 96 | START_L, |
AfdhalAtiffTan | 0:6262fc7582a9 | 97 | REGS_H, |
AfdhalAtiffTan | 0:6262fc7582a9 | 98 | REGS_L, |
AfdhalAtiffTan | 0:6262fc7582a9 | 99 | BYTE_CNT |
AfdhalAtiffTan | 0:6262fc7582a9 | 100 | }; |
AfdhalAtiffTan | 0:6262fc7582a9 | 101 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 102 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 103 | /* enum of supported modbus function codes. If you implement a new one, put its function code here ! */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 104 | enum { |
AfdhalAtiffTan | 0:6262fc7582a9 | 105 | FC_READ_REGS = 0x03, //Read contiguous block of holding register |
AfdhalAtiffTan | 0:6262fc7582a9 | 106 | FC_WRITE_REG = 0x06, //Write single holding register |
AfdhalAtiffTan | 0:6262fc7582a9 | 107 | FC_WRITE_REGS = 0x10 //Write block of contiguous registers |
AfdhalAtiffTan | 0:6262fc7582a9 | 108 | }; |
AfdhalAtiffTan | 0:6262fc7582a9 | 109 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 110 | /* supported functions. If you implement a new one, put its function code into this array! */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 111 | const unsigned char fsupported[] = { FC_READ_REGS, FC_WRITE_REG, FC_WRITE_REGS }; |
AfdhalAtiffTan | 0:6262fc7582a9 | 112 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 113 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 114 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 115 | CRC |
AfdhalAtiffTan | 0:6262fc7582a9 | 116 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 117 | INPUTS: |
AfdhalAtiffTan | 0:6262fc7582a9 | 118 | buf -> Array containing message to be sent to controller. |
AfdhalAtiffTan | 0:6262fc7582a9 | 119 | start -> Start of loop in crc counter, usually 0. |
AfdhalAtiffTan | 0:6262fc7582a9 | 120 | cnt -> Amount of bytes in message being sent to controller/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 121 | OUTPUTS: |
AfdhalAtiffTan | 0:6262fc7582a9 | 122 | temp -> Returns crc byte for message. |
AfdhalAtiffTan | 0:6262fc7582a9 | 123 | COMMENTS: |
AfdhalAtiffTan | 0:6262fc7582a9 | 124 | This routine calculates the crc high and low byte of a message. |
AfdhalAtiffTan | 0:6262fc7582a9 | 125 | Note that this crc is only used for Modbus, not Modbus+ etc. |
AfdhalAtiffTan | 0:6262fc7582a9 | 126 | ****************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 127 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 128 | unsigned int ModbusSlave232::crc(unsigned char *buf, unsigned char start, |
AfdhalAtiffTan | 0:6262fc7582a9 | 129 | unsigned char cnt) |
AfdhalAtiffTan | 0:6262fc7582a9 | 130 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 131 | unsigned char i, j; |
AfdhalAtiffTan | 0:6262fc7582a9 | 132 | unsigned temp, temp2, flag; |
AfdhalAtiffTan | 0:6262fc7582a9 | 133 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 134 | temp = 0xFFFF; |
AfdhalAtiffTan | 0:6262fc7582a9 | 135 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 136 | for (i = start; i < cnt; i++) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 137 | temp = temp ^ buf[i]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 138 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 139 | for (j = 1; j <= 8; j++) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 140 | flag = temp & 0x0001; |
AfdhalAtiffTan | 0:6262fc7582a9 | 141 | temp = temp >> 1; |
AfdhalAtiffTan | 0:6262fc7582a9 | 142 | if (flag) |
AfdhalAtiffTan | 0:6262fc7582a9 | 143 | temp = temp ^ 0xA001; |
AfdhalAtiffTan | 0:6262fc7582a9 | 144 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 145 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 146 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 147 | /* Reverse byte order. */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 148 | temp2 = temp >> 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 149 | temp = (temp << 8) | temp2; |
AfdhalAtiffTan | 0:6262fc7582a9 | 150 | temp &= 0xFFFF; |
AfdhalAtiffTan | 0:6262fc7582a9 | 151 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 152 | return (temp); |
AfdhalAtiffTan | 0:6262fc7582a9 | 153 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 154 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 155 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 156 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 157 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 158 | /*********************************************************************** |
AfdhalAtiffTan | 0:6262fc7582a9 | 159 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 160 | * The following functions construct the required query into |
AfdhalAtiffTan | 0:6262fc7582a9 | 161 | * a modbus query packet. |
AfdhalAtiffTan | 0:6262fc7582a9 | 162 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 163 | ***********************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 164 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 165 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 166 | * Start of the packet of a read_holding_register response |
AfdhalAtiffTan | 0:6262fc7582a9 | 167 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 168 | void ModbusSlave232::build_read_packet(unsigned char function, |
AfdhalAtiffTan | 0:6262fc7582a9 | 169 | unsigned char count, unsigned char *packet) |
AfdhalAtiffTan | 0:6262fc7582a9 | 170 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 171 | packet[SLAVE] = slave; |
AfdhalAtiffTan | 0:6262fc7582a9 | 172 | packet[FUNC] = function; |
AfdhalAtiffTan | 0:6262fc7582a9 | 173 | packet[2] = count * 2; |
AfdhalAtiffTan | 0:6262fc7582a9 | 174 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 175 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 176 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 177 | * Start of the packet of a preset_multiple_register response |
AfdhalAtiffTan | 0:6262fc7582a9 | 178 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 179 | void ModbusSlave232::build_write_packet(unsigned char function, |
AfdhalAtiffTan | 0:6262fc7582a9 | 180 | unsigned int start_addr, |
AfdhalAtiffTan | 0:6262fc7582a9 | 181 | unsigned char count, |
AfdhalAtiffTan | 0:6262fc7582a9 | 182 | unsigned char *packet) |
AfdhalAtiffTan | 0:6262fc7582a9 | 183 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 184 | packet[SLAVE] = slave; |
AfdhalAtiffTan | 0:6262fc7582a9 | 185 | packet[FUNC] = function; |
AfdhalAtiffTan | 0:6262fc7582a9 | 186 | packet[START_H] = start_addr >> 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 187 | packet[START_L] = start_addr & 0x00ff; |
AfdhalAtiffTan | 0:6262fc7582a9 | 188 | packet[REGS_H] = 0x00; |
AfdhalAtiffTan | 0:6262fc7582a9 | 189 | packet[REGS_L] = count; |
AfdhalAtiffTan | 0:6262fc7582a9 | 190 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 191 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 192 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 193 | * Start of the packet of a write_single_register response |
AfdhalAtiffTan | 0:6262fc7582a9 | 194 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 195 | void ModbusSlave232::build_write_single_packet(unsigned char function, |
AfdhalAtiffTan | 0:6262fc7582a9 | 196 | unsigned int write_addr, unsigned int reg_val, unsigned char* packet) |
AfdhalAtiffTan | 0:6262fc7582a9 | 197 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 198 | packet[SLAVE] = slave; |
AfdhalAtiffTan | 0:6262fc7582a9 | 199 | packet[FUNC] = function; |
AfdhalAtiffTan | 0:6262fc7582a9 | 200 | packet[START_H] = write_addr >> 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 201 | packet[START_L] = write_addr & 0x00ff; |
AfdhalAtiffTan | 0:6262fc7582a9 | 202 | packet[REGS_H] = reg_val >> 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 203 | packet[REGS_L] = reg_val & 0x00ff; |
AfdhalAtiffTan | 0:6262fc7582a9 | 204 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 205 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 206 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 207 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 208 | * Start of the packet of an exception response |
AfdhalAtiffTan | 0:6262fc7582a9 | 209 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 210 | void ModbusSlave232::build_error_packet( unsigned char function, |
AfdhalAtiffTan | 0:6262fc7582a9 | 211 | unsigned char exception, unsigned char *packet) |
AfdhalAtiffTan | 0:6262fc7582a9 | 212 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 213 | packet[SLAVE] = slave; |
AfdhalAtiffTan | 0:6262fc7582a9 | 214 | packet[FUNC] = function + 0x80; |
AfdhalAtiffTan | 0:6262fc7582a9 | 215 | packet[2] = exception; |
AfdhalAtiffTan | 0:6262fc7582a9 | 216 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 217 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 218 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 219 | /************************************************************************* |
AfdhalAtiffTan | 0:6262fc7582a9 | 220 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 221 | * modbus_query( packet, length) |
AfdhalAtiffTan | 0:6262fc7582a9 | 222 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 223 | * Function to add a checksum to the end of a packet. |
AfdhalAtiffTan | 0:6262fc7582a9 | 224 | * Please note that the packet array must be at least 2 fields longer than |
AfdhalAtiffTan | 0:6262fc7582a9 | 225 | * string_length. |
AfdhalAtiffTan | 0:6262fc7582a9 | 226 | **************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 227 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 228 | void ModbusSlave232::modbus_reply(unsigned char *packet, unsigned char string_length) |
AfdhalAtiffTan | 0:6262fc7582a9 | 229 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 230 | int temp_crc; |
AfdhalAtiffTan | 0:6262fc7582a9 | 231 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 232 | temp_crc = crc(packet, 0, string_length); |
AfdhalAtiffTan | 0:6262fc7582a9 | 233 | packet[string_length] = temp_crc >> 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 234 | string_length++; |
AfdhalAtiffTan | 0:6262fc7582a9 | 235 | packet[string_length] = temp_crc & 0x00FF; |
AfdhalAtiffTan | 0:6262fc7582a9 | 236 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 237 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 238 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 239 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 240 | /*********************************************************************** |
AfdhalAtiffTan | 0:6262fc7582a9 | 241 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 242 | * send_reply( query_string, query_length ) |
AfdhalAtiffTan | 0:6262fc7582a9 | 243 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 244 | * Function to send a reply to a modbus master. |
AfdhalAtiffTan | 0:6262fc7582a9 | 245 | * Returns: total number of characters sent |
AfdhalAtiffTan | 0:6262fc7582a9 | 246 | ************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 247 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 248 | int ModbusSlave232::send_reply(unsigned char *query, unsigned char string_length) |
AfdhalAtiffTan | 0:6262fc7582a9 | 249 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 250 | unsigned char i; |
AfdhalAtiffTan | 0:6262fc7582a9 | 251 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 252 | /*if (txenpin > 1) { // set MAX485 to speak mode //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 253 | UCSR0A=UCSR0A |(1 << TXC0); |
AfdhalAtiffTan | 0:6262fc7582a9 | 254 | digitalWrite( txenpin, HIGH); |
AfdhalAtiffTan | 0:6262fc7582a9 | 255 | delay(1); |
AfdhalAtiffTan | 0:6262fc7582a9 | 256 | }*/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 257 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 258 | modbus_reply(query, string_length); |
AfdhalAtiffTan | 0:6262fc7582a9 | 259 | string_length += 2; |
AfdhalAtiffTan | 0:6262fc7582a9 | 260 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 261 | for (i = 0; i < string_length; i++) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 262 | //Serial.print(char(query[i])); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 263 | pc.putc(char(query[i])); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 264 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 265 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 266 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 267 | return i; /* it does not mean that the write was succesful, though */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 268 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 269 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 270 | /*********************************************************************** |
AfdhalAtiffTan | 0:6262fc7582a9 | 271 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 272 | * receive_request( array_for_data ) |
AfdhalAtiffTan | 0:6262fc7582a9 | 273 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 274 | * Function to monitor for a request from the modbus master. |
AfdhalAtiffTan | 0:6262fc7582a9 | 275 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 276 | * Returns: Total number of characters received if OK |
AfdhalAtiffTan | 0:6262fc7582a9 | 277 | * 0 if there is no request |
AfdhalAtiffTan | 0:6262fc7582a9 | 278 | * A negative error code on failure |
AfdhalAtiffTan | 0:6262fc7582a9 | 279 | ***********************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 280 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 281 | int ModbusSlave232::receive_request(unsigned char *received_string) |
AfdhalAtiffTan | 0:6262fc7582a9 | 282 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 283 | int bytes_received = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 284 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 285 | /* FIXME: does Serial.available wait 1.5T or 3.5T before exiting the loop? */ |
AfdhalAtiffTan | 1:35fdc7056f66 | 286 | //while (Serial.available()) { //afdhal |
AfdhalAtiffTan | 1:35fdc7056f66 | 287 | while (pc.readable()) { //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 288 | received_string[bytes_received] = pc.getc(); //Serial.read(); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 289 | //Serial.print(received_string[bytes_received], DEC); |
AfdhalAtiffTan | 0:6262fc7582a9 | 290 | bytes_received++; |
AfdhalAtiffTan | 0:6262fc7582a9 | 291 | if (bytes_received >= MAX_MESSAGE_LENGTH) |
AfdhalAtiffTan | 0:6262fc7582a9 | 292 | return NO_REPLY; /* port error */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 293 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 294 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 295 | return (bytes_received); |
AfdhalAtiffTan | 0:6262fc7582a9 | 296 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 297 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 298 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 299 | /********************************************************************* |
AfdhalAtiffTan | 0:6262fc7582a9 | 300 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 301 | * modbus_request(request_data_array) |
AfdhalAtiffTan | 0:6262fc7582a9 | 302 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 303 | * Function to the correct request is returned and that the checksum |
AfdhalAtiffTan | 0:6262fc7582a9 | 304 | * is correct. |
AfdhalAtiffTan | 0:6262fc7582a9 | 305 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 306 | * Returns: string_length if OK |
AfdhalAtiffTan | 0:6262fc7582a9 | 307 | * 0 if failed |
AfdhalAtiffTan | 0:6262fc7582a9 | 308 | * Less than 0 for exception errors |
AfdhalAtiffTan | 0:6262fc7582a9 | 309 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 310 | * Note: All functions used for sending or receiving data via |
AfdhalAtiffTan | 0:6262fc7582a9 | 311 | * modbus return these return values. |
AfdhalAtiffTan | 0:6262fc7582a9 | 312 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 313 | **********************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 314 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 315 | int ModbusSlave232::modbus_request(unsigned char *data) |
AfdhalAtiffTan | 0:6262fc7582a9 | 316 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 317 | int response_length; |
AfdhalAtiffTan | 0:6262fc7582a9 | 318 | unsigned int crc_calc = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 319 | unsigned int crc_received = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 320 | unsigned char recv_crc_hi; |
AfdhalAtiffTan | 0:6262fc7582a9 | 321 | unsigned char recv_crc_lo; |
AfdhalAtiffTan | 0:6262fc7582a9 | 322 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 323 | response_length = receive_request(data); |
AfdhalAtiffTan | 0:6262fc7582a9 | 324 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 325 | if (response_length > 0) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 326 | crc_calc = crc(data, 0, response_length - 2); |
AfdhalAtiffTan | 0:6262fc7582a9 | 327 | recv_crc_hi = (unsigned) data[response_length - 2]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 328 | recv_crc_lo = (unsigned) data[response_length - 1]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 329 | crc_received = data[response_length - 2]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 330 | crc_received = (unsigned) crc_received << 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 331 | crc_received = |
AfdhalAtiffTan | 0:6262fc7582a9 | 332 | crc_received | (unsigned) data[response_length - 1]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 333 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 334 | /*********** check CRC of response ************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 335 | if (crc_calc != crc_received) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 336 | return NO_REPLY; |
AfdhalAtiffTan | 0:6262fc7582a9 | 337 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 338 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 339 | /* check for slave id */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 340 | if (slave != data[SLAVE]) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 341 | return NO_REPLY; |
AfdhalAtiffTan | 0:6262fc7582a9 | 342 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 343 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 344 | return (response_length); |
AfdhalAtiffTan | 0:6262fc7582a9 | 345 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 346 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 347 | /********************************************************************* |
AfdhalAtiffTan | 0:6262fc7582a9 | 348 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 349 | * validate_request(request_data_array, request_length, available_regs) |
AfdhalAtiffTan | 0:6262fc7582a9 | 350 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 351 | * Function to check that the request can be processed by the slave. |
AfdhalAtiffTan | 0:6262fc7582a9 | 352 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 353 | * Returns: 0 if OK |
AfdhalAtiffTan | 0:6262fc7582a9 | 354 | * A negative exception code on error |
AfdhalAtiffTan | 0:6262fc7582a9 | 355 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 356 | **********************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 357 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 358 | int ModbusSlave232::validate_request(unsigned char *data, unsigned char length, |
AfdhalAtiffTan | 0:6262fc7582a9 | 359 | unsigned int regs_size) |
AfdhalAtiffTan | 0:6262fc7582a9 | 360 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 361 | int i, fcnt = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 362 | unsigned int regs_num = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 363 | unsigned int start_addr = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 364 | unsigned char max_regs_num; |
AfdhalAtiffTan | 0:6262fc7582a9 | 365 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 366 | /* check function code */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 367 | for (i = 0; i < sizeof(fsupported); i++) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 368 | if (fsupported[i] == data[FUNC]) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 369 | fcnt = 1; |
AfdhalAtiffTan | 0:6262fc7582a9 | 370 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 371 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 372 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 373 | if (0 == fcnt) |
AfdhalAtiffTan | 0:6262fc7582a9 | 374 | return EXC_FUNC_CODE; |
AfdhalAtiffTan | 0:6262fc7582a9 | 375 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 376 | if (FC_WRITE_REG == data[FUNC]) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 377 | /* For function write single reg, this is the target reg.*/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 378 | regs_num = ((int) data[START_H] << 8) + (int) data[START_L]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 379 | if (regs_num >= regs_size) |
AfdhalAtiffTan | 0:6262fc7582a9 | 380 | return EXC_ADDR_RANGE; |
AfdhalAtiffTan | 0:6262fc7582a9 | 381 | return 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 382 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 383 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 384 | /* For functions read/write regs, this is the range. */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 385 | regs_num = ((int) data[REGS_H] << 8) + (int) data[REGS_L]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 386 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 387 | /* check quantity of registers */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 388 | if (FC_READ_REGS == data[FUNC]) |
AfdhalAtiffTan | 0:6262fc7582a9 | 389 | max_regs_num = MAX_READ_REGS; |
AfdhalAtiffTan | 0:6262fc7582a9 | 390 | else if (FC_WRITE_REGS == data[FUNC]) |
AfdhalAtiffTan | 0:6262fc7582a9 | 391 | max_regs_num = MAX_WRITE_REGS; |
AfdhalAtiffTan | 0:6262fc7582a9 | 392 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 393 | if ((regs_num < 1) || (regs_num > max_regs_num)) |
AfdhalAtiffTan | 0:6262fc7582a9 | 394 | return EXC_REGS_QUANT; |
AfdhalAtiffTan | 0:6262fc7582a9 | 395 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 396 | /* check registers range, start address is 0 */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 397 | start_addr = ((int) data[START_H] << 8) + (int) data[START_L]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 398 | if ((start_addr + regs_num) > regs_size) |
AfdhalAtiffTan | 0:6262fc7582a9 | 399 | return EXC_ADDR_RANGE; |
AfdhalAtiffTan | 0:6262fc7582a9 | 400 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 401 | return 0; /* OK, no exception */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 402 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 403 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 404 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 405 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 406 | /************************************************************************ |
AfdhalAtiffTan | 0:6262fc7582a9 | 407 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 408 | * write_regs(first_register, data_array, registers_array) |
AfdhalAtiffTan | 0:6262fc7582a9 | 409 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 410 | * writes into the slave's holding registers the data in query, |
AfdhalAtiffTan | 0:6262fc7582a9 | 411 | * starting at start_addr. |
AfdhalAtiffTan | 0:6262fc7582a9 | 412 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 413 | * Returns: the number of registers written |
AfdhalAtiffTan | 0:6262fc7582a9 | 414 | ************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 415 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 416 | int ModbusSlave232::write_regs(unsigned int start_addr, unsigned char *query, int *regs) |
AfdhalAtiffTan | 0:6262fc7582a9 | 417 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 418 | int temp; |
AfdhalAtiffTan | 0:6262fc7582a9 | 419 | unsigned int i; |
AfdhalAtiffTan | 0:6262fc7582a9 | 420 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 421 | for (i = 0; i < query[REGS_L]; i++) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 422 | /* shift reg hi_byte to temp */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 423 | temp = (int) query[(BYTE_CNT + 1) + i * 2] << 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 424 | /* OR with lo_byte */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 425 | temp = temp | (int) query[(BYTE_CNT + 2) + i * 2]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 426 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 427 | regs[start_addr + i] = temp; |
AfdhalAtiffTan | 0:6262fc7582a9 | 428 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 429 | return i; |
AfdhalAtiffTan | 0:6262fc7582a9 | 430 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 431 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 432 | /************************************************************************ |
AfdhalAtiffTan | 0:6262fc7582a9 | 433 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 434 | * preset_multiple_registers(first_register, number_of_registers, |
AfdhalAtiffTan | 0:6262fc7582a9 | 435 | * data_array, registers_array) |
AfdhalAtiffTan | 0:6262fc7582a9 | 436 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 437 | * Write the data from an array into the holding registers of the slave. |
AfdhalAtiffTan | 0:6262fc7582a9 | 438 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 439 | *************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 440 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 441 | int ModbusSlave232::preset_multiple_registers(unsigned int start_addr, |
AfdhalAtiffTan | 0:6262fc7582a9 | 442 | unsigned char count, |
AfdhalAtiffTan | 0:6262fc7582a9 | 443 | unsigned char *query, |
AfdhalAtiffTan | 0:6262fc7582a9 | 444 | int *regs) |
AfdhalAtiffTan | 0:6262fc7582a9 | 445 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 446 | unsigned char function = FC_WRITE_REGS; /* Preset Multiple Registers */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 447 | int status = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 448 | unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 449 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 450 | build_write_packet(function, start_addr, count, packet); |
AfdhalAtiffTan | 0:6262fc7582a9 | 451 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 452 | if (write_regs(start_addr, query, regs)) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 453 | status = send_reply(packet, RESPONSE_SIZE); |
AfdhalAtiffTan | 0:6262fc7582a9 | 454 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 455 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 456 | return (status); |
AfdhalAtiffTan | 0:6262fc7582a9 | 457 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 458 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 459 | /************************************************************************ |
AfdhalAtiffTan | 0:6262fc7582a9 | 460 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 461 | * write_single_register(slave_id, write_addr, data_array, registers_array) |
AfdhalAtiffTan | 0:6262fc7582a9 | 462 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 463 | * Write a single int val into a single holding register of the slave. |
AfdhalAtiffTan | 0:6262fc7582a9 | 464 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 465 | *************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 466 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 467 | int ModbusSlave232::write_single_register(unsigned int write_addr, unsigned char *query, int *regs) |
AfdhalAtiffTan | 0:6262fc7582a9 | 468 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 469 | unsigned char function = FC_WRITE_REG; /* Function: Write Single Register */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 470 | int status = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 471 | unsigned int reg_val; |
AfdhalAtiffTan | 0:6262fc7582a9 | 472 | unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 473 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 474 | reg_val = query[REGS_H] << 8 | query[REGS_L]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 475 | build_write_single_packet(function, write_addr, reg_val, packet); |
AfdhalAtiffTan | 0:6262fc7582a9 | 476 | regs[write_addr] = (int) reg_val; |
AfdhalAtiffTan | 0:6262fc7582a9 | 477 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 478 | written.start_addr=write_addr; |
AfdhalAtiffTan | 0:6262fc7582a9 | 479 | written.num_regs=1; |
AfdhalAtiffTan | 0:6262fc7582a9 | 480 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 481 | status = send_reply(packet, RESPONSE_SIZE); |
AfdhalAtiffTan | 0:6262fc7582a9 | 482 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 483 | return (status); |
AfdhalAtiffTan | 0:6262fc7582a9 | 484 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 485 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 486 | /************************************************************************ |
AfdhalAtiffTan | 0:6262fc7582a9 | 487 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 488 | * read_holding_registers(first_register, number_of_registers, |
AfdhalAtiffTan | 0:6262fc7582a9 | 489 | * registers_array) |
AfdhalAtiffTan | 0:6262fc7582a9 | 490 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 491 | * reads the slave's holdings registers and sends them to the Modbus master |
AfdhalAtiffTan | 0:6262fc7582a9 | 492 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 493 | *************************************************************************/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 494 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 495 | int ModbusSlave232::read_holding_registers( unsigned int start_addr, |
AfdhalAtiffTan | 0:6262fc7582a9 | 496 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 497 | unsigned char reg_count, int *regs) |
AfdhalAtiffTan | 0:6262fc7582a9 | 498 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 499 | unsigned char function = FC_READ_REGS; /* Read Holding Registers */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 500 | int packet_size = 3; |
AfdhalAtiffTan | 0:6262fc7582a9 | 501 | int status; |
AfdhalAtiffTan | 0:6262fc7582a9 | 502 | unsigned int i; |
AfdhalAtiffTan | 0:6262fc7582a9 | 503 | unsigned char packet[MAX_MESSAGE_LENGTH]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 504 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 505 | build_read_packet(function, reg_count, packet); |
AfdhalAtiffTan | 0:6262fc7582a9 | 506 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 507 | for (i = start_addr; i < (start_addr + (unsigned int) reg_count); |
AfdhalAtiffTan | 0:6262fc7582a9 | 508 | i++) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 509 | packet[packet_size] = regs[i] >> 8; |
AfdhalAtiffTan | 0:6262fc7582a9 | 510 | packet_size++; |
AfdhalAtiffTan | 0:6262fc7582a9 | 511 | packet[packet_size] = regs[i] & 0x00FF; |
AfdhalAtiffTan | 0:6262fc7582a9 | 512 | packet_size++; |
AfdhalAtiffTan | 0:6262fc7582a9 | 513 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 514 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 515 | status = send_reply(packet, packet_size); |
AfdhalAtiffTan | 0:6262fc7582a9 | 516 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 517 | return (status); |
AfdhalAtiffTan | 0:6262fc7582a9 | 518 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 519 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 520 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 521 | * configure(slave, baud, parity, txenpin) |
AfdhalAtiffTan | 0:6262fc7582a9 | 522 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 523 | * sets the communication parameters for of the serial line. |
AfdhalAtiffTan | 0:6262fc7582a9 | 524 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 525 | * slave: identification number of the slave in the Modbus network (1 to 127) |
AfdhalAtiffTan | 0:6262fc7582a9 | 526 | * baud: baudrate in bps (typical values 9600, 19200... 115200) |
AfdhalAtiffTan | 0:6262fc7582a9 | 527 | * parity: a single character sets the parity mode (character frame format): |
AfdhalAtiffTan | 0:6262fc7582a9 | 528 | * 'n' no parity (8N1); 'e' even parity (8E1), 'o' for odd parity (8O1). |
AfdhalAtiffTan | 0:6262fc7582a9 | 529 | * txenpin: arduino pin number that controls transmision/reception |
AfdhalAtiffTan | 0:6262fc7582a9 | 530 | * of an external half-duplex device (e.g. a RS485 interface chip). |
AfdhalAtiffTan | 0:6262fc7582a9 | 531 | * 0 or 1 disables this function (for a two-device network) |
AfdhalAtiffTan | 0:6262fc7582a9 | 532 | * >2 for point-to-multipoint topology (e.g. several arduinos) |
AfdhalAtiffTan | 0:6262fc7582a9 | 533 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 534 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 535 | void ModbusSlave232::configure(unsigned char slave, long baud, char parity) |
AfdhalAtiffTan | 0:6262fc7582a9 | 536 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 537 | this->slave = slave; |
AfdhalAtiffTan | 0:6262fc7582a9 | 538 | //this->txenpin = 2; //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 539 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 540 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 541 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 542 | //Serial.begin(baud); //afdhal |
AfdhalAtiffTan | 1:35fdc7056f66 | 543 | pc.baud(baud); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 544 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 545 | switch (parity) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 546 | case 'e': // 8E1 |
AfdhalAtiffTan | 0:6262fc7582a9 | 547 | //UCSR0C |= ((1<<UPM01) | (1<<UCSZ01) | (1<<UCSZ00)); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 548 | pc.format(8, SerialBase::Even, 1); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 549 | // UCSR0C &= ~((1<<UPM00) | (1<<UCSZ02) | (1<<USBS0)); |
AfdhalAtiffTan | 0:6262fc7582a9 | 550 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 551 | case 'o': // 8O1 |
AfdhalAtiffTan | 0:6262fc7582a9 | 552 | //UCSR0C |= ((1<<UPM01) | (1<<UPM00) | (1<<UCSZ01) | (1<<UCSZ00)); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 553 | pc.format(8, SerialBase::Odd, 1); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 554 | // UCSR0C &= ~((1<<UCSZ02) | (1<<USBS0)); |
AfdhalAtiffTan | 0:6262fc7582a9 | 555 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 556 | case 'n': // 8N1 |
AfdhalAtiffTan | 0:6262fc7582a9 | 557 | //UCSR0C |= ((1<<UCSZ01) | (1<<UCSZ00)); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 558 | pc.format(8, SerialBase::None, 1); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 559 | // UCSR0C &= ~((1<<UPM01) | (1<<UPM00) | (1<<UCSZ02) | (1<<USBS0)); |
AfdhalAtiffTan | 0:6262fc7582a9 | 560 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 561 | default: |
AfdhalAtiffTan | 0:6262fc7582a9 | 562 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 563 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 564 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 565 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 566 | if (txenpin > 1) { // pin 0 & pin 1 are reserved for RX/TX |
AfdhalAtiffTan | 0:6262fc7582a9 | 567 | pinMode(txenpin, OUTPUT); |
AfdhalAtiffTan | 0:6262fc7582a9 | 568 | digitalWrite(txenpin, LOW); |
AfdhalAtiffTan | 0:6262fc7582a9 | 569 | }*/ |
AfdhalAtiffTan | 0:6262fc7582a9 | 570 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 571 | return; |
AfdhalAtiffTan | 0:6262fc7582a9 | 572 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 573 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 574 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 575 | /* |
AfdhalAtiffTan | 0:6262fc7582a9 | 576 | * update(regs, regs_size) |
AfdhalAtiffTan | 0:6262fc7582a9 | 577 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 578 | * checks if there is any valid request from the modbus master. If there is, |
AfdhalAtiffTan | 0:6262fc7582a9 | 579 | * performs the requested action |
AfdhalAtiffTan | 0:6262fc7582a9 | 580 | * |
AfdhalAtiffTan | 0:6262fc7582a9 | 581 | * regs: an array with the holding registers. They start at address 1 (master point of view) |
AfdhalAtiffTan | 0:6262fc7582a9 | 582 | * regs_size: total number of holding registers. |
AfdhalAtiffTan | 0:6262fc7582a9 | 583 | * returns: 0 if no request from master, |
AfdhalAtiffTan | 0:6262fc7582a9 | 584 | * NO_REPLY (-1) if no reply is sent to the master |
AfdhalAtiffTan | 0:6262fc7582a9 | 585 | * an exception code (1 to 4) in case of a modbus exceptions |
AfdhalAtiffTan | 0:6262fc7582a9 | 586 | * the number of bytes sent as reply ( > 4) if OK. |
AfdhalAtiffTan | 0:6262fc7582a9 | 587 | */ |
AfdhalAtiffTan | 0:6262fc7582a9 | 588 | unsigned long Nowdt = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 589 | unsigned int lastBytesReceived; |
AfdhalAtiffTan | 0:6262fc7582a9 | 590 | const unsigned long T35 = 5; |
AfdhalAtiffTan | 0:6262fc7582a9 | 591 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 592 | int ModbusSlave232::update(int *regs, |
AfdhalAtiffTan | 0:6262fc7582a9 | 593 | unsigned int regs_size) |
AfdhalAtiffTan | 0:6262fc7582a9 | 594 | { |
AfdhalAtiffTan | 0:6262fc7582a9 | 595 | unsigned char query[MAX_MESSAGE_LENGTH]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 596 | unsigned char errpacket[EXCEPTION_SIZE + CHECKSUM_SIZE]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 597 | unsigned int start_addr; |
AfdhalAtiffTan | 0:6262fc7582a9 | 598 | int exception; |
AfdhalAtiffTan | 0:6262fc7582a9 | 599 | int length = pc.rxBufferGetCount(); //Serial.available(); //afdhal |
AfdhalAtiffTan | 0:6262fc7582a9 | 600 | unsigned long now = millis(); |
AfdhalAtiffTan | 0:6262fc7582a9 | 601 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 602 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 603 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 604 | if (length == 0) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 605 | lastBytesReceived = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 606 | return 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 607 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 608 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 609 | if (lastBytesReceived != length) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 610 | lastBytesReceived = length; |
AfdhalAtiffTan | 0:6262fc7582a9 | 611 | Nowdt = now + T35; |
AfdhalAtiffTan | 0:6262fc7582a9 | 612 | return 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 613 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 614 | if (now < Nowdt) |
AfdhalAtiffTan | 0:6262fc7582a9 | 615 | return 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 616 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 617 | lastBytesReceived = 0; |
AfdhalAtiffTan | 0:6262fc7582a9 | 618 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 619 | length = modbus_request(query); |
AfdhalAtiffTan | 0:6262fc7582a9 | 620 | if (length < 1) |
AfdhalAtiffTan | 0:6262fc7582a9 | 621 | return length; |
AfdhalAtiffTan | 0:6262fc7582a9 | 622 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 623 | exception = validate_request(query, length, regs_size); |
AfdhalAtiffTan | 0:6262fc7582a9 | 624 | if (exception) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 625 | build_error_packet( query[FUNC], exception, |
AfdhalAtiffTan | 0:6262fc7582a9 | 626 | errpacket); |
AfdhalAtiffTan | 0:6262fc7582a9 | 627 | send_reply(errpacket, EXCEPTION_SIZE); |
AfdhalAtiffTan | 0:6262fc7582a9 | 628 | return (exception); |
AfdhalAtiffTan | 0:6262fc7582a9 | 629 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 630 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 631 | start_addr = |
AfdhalAtiffTan | 0:6262fc7582a9 | 632 | ((int) query[START_H] << 8) + |
AfdhalAtiffTan | 0:6262fc7582a9 | 633 | (int) query[START_L]; |
AfdhalAtiffTan | 0:6262fc7582a9 | 634 | |
AfdhalAtiffTan | 0:6262fc7582a9 | 635 | switch (query[FUNC]) { |
AfdhalAtiffTan | 0:6262fc7582a9 | 636 | case FC_READ_REGS: |
AfdhalAtiffTan | 0:6262fc7582a9 | 637 | return read_holding_registers( |
AfdhalAtiffTan | 0:6262fc7582a9 | 638 | start_addr, |
AfdhalAtiffTan | 0:6262fc7582a9 | 639 | query[REGS_L], |
AfdhalAtiffTan | 0:6262fc7582a9 | 640 | regs); |
AfdhalAtiffTan | 0:6262fc7582a9 | 641 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 642 | case FC_WRITE_REGS: |
AfdhalAtiffTan | 0:6262fc7582a9 | 643 | return preset_multiple_registers( |
AfdhalAtiffTan | 0:6262fc7582a9 | 644 | start_addr, |
AfdhalAtiffTan | 0:6262fc7582a9 | 645 | query[REGS_L], |
AfdhalAtiffTan | 0:6262fc7582a9 | 646 | query, |
AfdhalAtiffTan | 0:6262fc7582a9 | 647 | regs); |
AfdhalAtiffTan | 0:6262fc7582a9 | 648 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 649 | case FC_WRITE_REG: |
AfdhalAtiffTan | 0:6262fc7582a9 | 650 | write_single_register( |
AfdhalAtiffTan | 0:6262fc7582a9 | 651 | start_addr, |
AfdhalAtiffTan | 0:6262fc7582a9 | 652 | query, |
AfdhalAtiffTan | 0:6262fc7582a9 | 653 | regs); |
AfdhalAtiffTan | 0:6262fc7582a9 | 654 | break; |
AfdhalAtiffTan | 0:6262fc7582a9 | 655 | } |
AfdhalAtiffTan | 0:6262fc7582a9 | 656 | |
AfdhalAtiffTan | 1:35fdc7056f66 | 657 | } |