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