-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
6.2.1.16 20181015 * Add TasmotaModbus library for very basic modbus wrapper for TasmotaSerial * Change xsns_17_senseair.ino to use TasmotaModbus library * Fix xnrg_05_pzem2.ino for PZEM-014/016 support using TasmotaModbus library (#3694)
- Loading branch information
Showing
11 changed files
with
336 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# TasmotaSerial | ||
|
||
Implementation of software serial with hardware serial fallback library for the ESP8266 | ||
|
||
Allows for several instances to be active at the same time. | ||
|
||
Please note that due to the fact that the ESP always have other activities ongoing, there will be some inexactness in interrupt timings. This may lead to bit errors when having heavy data traffic. |
31 changes: 31 additions & 0 deletions
31
lib/TasmotaModbus-1.0.0/examples/modbustest/modbustest.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
#include <TasmotaModbus.h> | ||
|
||
TasmotaModbus Modbus(14, 12); | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
Modbus.Begin(9600); | ||
|
||
Serial.println("\nTasmotaModbus test started"); | ||
|
||
Modbus.Send(0x01, 0x04, 0, 8); | ||
} | ||
|
||
void loop() { | ||
if (Modbus.ReceiveReady()) { | ||
uint8_t buffer[26]; | ||
|
||
uint8_t error = Modbus.ReceiveBuffer(buffer, 8); | ||
if (error) { | ||
Serial.print("Modbus response error "); | ||
Serial.println(error); | ||
} else { | ||
Serial.print("Modbus received:"); | ||
for (int i = 0; i < (buffer[2]) ? buffer[2] +5 : sizeof(buffer); i++) { | ||
Serial.print(" "); | ||
Serial.print(buffer[i], HEX); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
####################################### | ||
# Syntax Coloring Map for TasmotaModbus | ||
# (esp8266) | ||
####################################### | ||
|
||
####################################### | ||
# Datatypes (KEYWORD1) | ||
####################################### | ||
|
||
TasmotaModbus KEYWORD1 | ||
|
||
####################################### | ||
# Methods and Functions (KEYWORD2) | ||
####################################### | ||
|
||
Begin KEYWORD2 | ||
Send KEYWORD2 | ||
ReceiveReady KEYWORD2 | ||
ReceiveBuffer KEYWORD2 | ||
Receive16BitRegister KEYWORD2 | ||
Receive32BitRegister KEYWORD2 | ||
|
||
####################################### | ||
# Constants (LITERAL1) | ||
####################################### | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "TasmotaModbus", | ||
"version": "1.0.0", | ||
"keywords": [ | ||
"serial", "io", "TasmotaModbus" | ||
], | ||
"description": "Basic modbus wrapper for TasmotaSerial for ESP8266.", | ||
"repository": | ||
{ | ||
"type": "git", | ||
"url": "https://github.com/arendst/Sonoff-Tasmota/lib/TasmotaModbus" | ||
}, | ||
"frameworks": "arduino", | ||
"platforms": "espressif8266" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name=TasmotaModbus | ||
version=1.0.0 | ||
author=Theo Arends | ||
maintainer=Theo Arends <[email protected]> | ||
sentence=Basic modbus wrapper for TasmotaSerial for ESP8266. | ||
paragraph= | ||
category=Signal Input/Output | ||
url= | ||
architectures=esp8266 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/* | ||
TasmotaModbus.cpp - Basic modbus wrapper for TasmotaSerial for Tasmota | ||
Copyright (C) 2018 Theo Arends | ||
This library is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include "TasmotaModbus.h" | ||
|
||
TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin) : TasmotaSerial(receive_pin, transmit_pin, 1) | ||
{ | ||
} | ||
|
||
TasmotaModbus::~TasmotaModbus() | ||
{ | ||
} | ||
|
||
uint16_t CalculateCRC(uint8_t *frame, uint8_t num) | ||
{ | ||
uint16_t crc = 0xFFFF; | ||
uint16_t flag; | ||
|
||
for (uint8_t i = 0; i < num; i++) { | ||
crc ^= frame[i]; | ||
for (uint8_t j = 8; j; j--) { | ||
if ((crc & 0x0001) != 0) { // If the LSB is set | ||
crc >>= 1; // Shift right and XOR 0xA001 | ||
crc ^= 0xA001; | ||
} else { // Else LSB is not set | ||
crc >>= 1; // Just shift right | ||
} | ||
} | ||
} | ||
return crc; | ||
} | ||
|
||
int TasmotaModbus::Begin(long speed) | ||
{ | ||
int result = 0; | ||
|
||
if (begin(speed)) { | ||
result = 1; | ||
if (hardwareSerial()) { result = 2; } | ||
} | ||
return result; | ||
} | ||
|
||
void TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint16_t start_address, uint16_t register_count) | ||
{ | ||
uint8_t frame[8]; | ||
|
||
frame[0] = device_address; // 0xFE default device address or dedicated like 0x01 | ||
frame[1] = function_code; | ||
frame[2] = (uint8_t)(start_address >> 8); | ||
frame[3] = (uint8_t)(start_address); | ||
frame[4] = (uint8_t)(register_count >> 8); | ||
frame[5] = (uint8_t)(register_count); | ||
uint16_t crc = CalculateCRC(frame, 6); | ||
frame[6] = (uint8_t)(crc); | ||
frame[7] = (uint8_t)(crc >> 8); | ||
|
||
flush(); | ||
write(frame, sizeof(frame)); | ||
} | ||
|
||
bool TasmotaModbus::ReceiveReady() | ||
{ | ||
return (available() > 4); | ||
} | ||
|
||
uint8_t TasmotaModbus::ReceiveBuffer(uint8_t *buffer, uint8_t register_count) | ||
{ | ||
uint8_t len = 0; | ||
uint32_t last = millis(); | ||
while ((available() > 0) && (len < (register_count *2) + 5) && (millis() - last < 10)) { | ||
buffer[len++] = (uint8_t)read(); | ||
if (3 == len) { | ||
if (buffer[1] & 0x80) { // fe 84 02 f2 f1 | ||
return buffer[2]; // 1 = Illegal Function, 2 = Illegal Address, 3 = Illegal Data, 4 = Slave Error | ||
} | ||
} | ||
last = millis(); | ||
} | ||
|
||
if (len < 7) { return 7; } // 7 = Not enough data | ||
if (len != buffer[2] + 5) { return 8; } // 8 = Unexpected result | ||
|
||
uint16_t crc = (buffer[len -1] << 8) | buffer[len -2]; | ||
if (CalculateCRC(buffer, len -2) != crc) { return 9; } // 9 = crc error | ||
|
||
return 0; // 0 = No error | ||
} | ||
|
||
uint8_t TasmotaModbus::Receive16BitRegister(uint16_t *value) | ||
{ | ||
// 0 1 2 3 4 5 6 | ||
// 01 04 02 43 21 HH LL | ||
// Id Cc Sz Regis Crc-- | ||
|
||
uint8_t buffer[7]; | ||
|
||
uint8_t error = ReceiveBuffer(buffer, 1); // 1 x 16bit register | ||
if (!error) { | ||
*value = (buffer[3] << 8) | buffer[4]; | ||
} | ||
|
||
return error; | ||
} | ||
|
||
uint8_t TasmotaModbus::Receive32BitRegister(float *value) | ||
{ | ||
// 0 1 2 3 4 5 6 7 8 | ||
// 01 04 04 87 65 43 21 HH LL | ||
// Id Cc Sz Register--- Crc-- | ||
|
||
uint8_t buffer[9]; | ||
|
||
*value = NAN; | ||
|
||
uint8_t error = ReceiveBuffer(buffer, 2); // 1 x 32bit register | ||
if (!error) { | ||
((uint8_t*)value)[3] = buffer[3]; | ||
((uint8_t*)value)[2] = buffer[4]; | ||
((uint8_t*)value)[1] = buffer[5]; | ||
((uint8_t*)value)[0] = buffer[6]; | ||
} | ||
|
||
return error; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
TasmotaModbus.h - Basic modbus wrapper for TasmotaSerial for Tasmota | ||
Copyright (C) 2018 Theo Arends | ||
This library is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#ifndef TasmotaModbus_h | ||
#define TasmotaModbus_h | ||
|
||
#include <Arduino.h> | ||
#include <TasmotaSerial.h> | ||
|
||
#define TM_MODBUS_BAUDRATE 9600 // Default baudrate | ||
|
||
class TasmotaModbus : public TasmotaSerial { | ||
public: | ||
TasmotaModbus(int receive_pin, int transmit_pin); | ||
~TasmotaModbus(); | ||
|
||
int Begin(long speed = TM_MODBUS_BAUDRATE); | ||
|
||
void Send(uint8_t device_address, uint8_t function_code, uint16_t start_address, uint16_t register_count); | ||
|
||
bool ReceiveReady(); | ||
|
||
/* Return codes: | ||
* 0 - No error | ||
* 1 - Illegal function | ||
* 2 - Illegal address | ||
* 3 - Illegal data | ||
* 4 - Slave error | ||
* 7 - Not enough minimal data received | ||
* 8 - Not enough data receieved | ||
* 9 - Crc error | ||
*/ | ||
uint8_t ReceiveBuffer(uint8_t *buffer, uint8_t register_count); | ||
uint8_t Receive16BitRegister(uint16_t *value); | ||
uint8_t Receive32BitRegister(float *value); | ||
}; | ||
|
||
#endif // TasmotaModbus_h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.