Skip to content

Commit

Permalink
6.2.1.16 Add TasmotaModbus lib
Browse files Browse the repository at this point in the history
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
arendst committed Oct 15, 2018
1 parent 6b66002 commit fb6cc19
Show file tree
Hide file tree
Showing 11 changed files with 336 additions and 174 deletions.
7 changes: 7 additions & 0 deletions lib/TasmotaModbus-1.0.0/README.md
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 lib/TasmotaModbus-1.0.0/examples/modbustest/modbustest.ino
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);
}
}
}
}
26 changes: 26 additions & 0 deletions lib/TasmotaModbus-1.0.0/keywords.txt
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)
#######################################

15 changes: 15 additions & 0 deletions lib/TasmotaModbus-1.0.0/library.json
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"
}
9 changes: 9 additions & 0 deletions lib/TasmotaModbus-1.0.0/library.properties
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
141 changes: 141 additions & 0 deletions lib/TasmotaModbus-1.0.0/src/TasmotaModbus.cpp
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;
}
54 changes: 54 additions & 0 deletions lib/TasmotaModbus-1.0.0/src/TasmotaModbus.h
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
7 changes: 6 additions & 1 deletion sonoff/_changelog.ino
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/* 6.2.1.15 20181012
/* 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)
*
* 6.2.1.15 20181012
* Fix Color Temperature slider functionality regression from 6.2.1.5 (#4037)
* Add auto reload of main web page to some web restarts
* Add whitespace removal from RfRaw and SerialSend5 (#4020)
Expand Down
2 changes: 1 addition & 1 deletion sonoff/sonoff_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_

#define VERSION 0x0602010F
#define VERSION 0x06020110

#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"
Expand Down
Loading

0 comments on commit fb6cc19

Please sign in to comment.