fuckit: clean slate
This commit is contained in:
@@ -71,16 +71,10 @@
|
||||
<option id="gnu.c.compiler.option.optimization.flags.13512348" name="Other optimization flags" superClass="gnu.c.compiler.option.optimization.flags" useByScannerDiscovery="false" value="-fno-common" valueType="string"/>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.c.compiler.option.include.paths.688644944" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/esp-vent-main}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/esp-vent-main/DigitalIoPin}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/lpc_board_nxp_lpcxpresso_1549/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/lpc_chip_15xx/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/DigitalIoPin/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/LiquidCrystal/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/I2C/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/StateHandler/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Timer/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/SwitchController/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/PressureWrapper/inc}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/SDP600Sensor/inc}""/>
|
||||
</option>
|
||||
<option id="com.crt.advproject.c.misc.dialect.1885316467" name="Language standard" superClass="com.crt.advproject.c.misc.dialect" useByScannerDiscovery="true" value="com.crt.advproject.misc.dialect.c11" valueType="enumerated"/>
|
||||
<inputType id="com.crt.advproject.compiler.input.1491212950" superClass="com.crt.advproject.compiler.input"/>
|
||||
@@ -130,13 +124,6 @@
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.cpp.link.option.libs.1364210590" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
|
||||
<listOptionValue builtIn="false" value="lpc_board_nxp_lpcxpresso_1549"/>
|
||||
<listOptionValue builtIn="false" value="lpc_chip_15xx"/>
|
||||
<listOptionValue builtIn="false" value="DigitalIoPin"/>
|
||||
<listOptionValue builtIn="false" value="LiquidCrystal"/>
|
||||
<listOptionValue builtIn="false" value="I2C"/>
|
||||
<listOptionValue builtIn="false" value="StateHandler"/>
|
||||
<listOptionValue builtIn="false" value="Timer"/>
|
||||
<listOptionValue builtIn="false" value="SwitchController"/>
|
||||
<listOptionValue builtIn="false" value="SDP600Sensor"/>
|
||||
</option>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.cpp.link.option.paths.804461696" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/lpc_board_nxp_lpcxpresso_1549/Debug}""/>
|
||||
@@ -163,7 +150,6 @@
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="inc"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
@@ -330,7 +316,6 @@
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="inc"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<configuration id="com.crt.advproject.config.exe.debug.1850577128" name="Debug">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider copy-of="extension" id="com.crt.advproject.GCCBuildCommandParser"/>
|
||||
<provider class="com.crt.advproject.specs.MCUGCCBuiltinSpecsDetector" console="false" env-hash="1334439975018836085" id="com.crt.advproject.GCCBuildSpecCompilerParser" keep-relative-paths="false" name="MCU GCC Built-in Compiler Parser" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="com.crt.advproject.GCCBuildCommandParser" keep-relative-paths="false" name="MCU GCC Build Output Parser" parameter="(arm-none-eabi-gcc)|(arm-none-eabi-[gc]\+\+)|(gcc)|([gc]\+\+)|(clang)" prefer-non-shared="true"/>
|
||||
<provider class="com.crt.advproject.specs.MCUGCCBuiltinSpecsDetector" console="false" env-hash="1877366442593287523" id="com.crt.advproject.GCCBuildSpecCompilerParser" keep-relative-paths="false" name="MCU GCC Built-in Compiler Parser" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
@@ -15,7 +15,7 @@
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider copy-of="extension" id="com.crt.advproject.GCCBuildCommandParser"/>
|
||||
<provider class="com.crt.advproject.specs.MCUGCCBuiltinSpecsDetector" console="false" env-hash="1351635246279194837" id="com.crt.advproject.GCCBuildSpecCompilerParser" keep-relative-paths="false" name="MCU GCC Built-in Compiler Parser" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<provider class="com.crt.advproject.specs.MCUGCCBuiltinSpecsDetector" console="false" env-hash="1932457957984350467" id="com.crt.advproject.GCCBuildSpecCompilerParser" keep-relative-paths="false" name="MCU GCC Built-in Compiler Parser" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
|
||||
43
esp-vent-main/inc/DigitalIoPin.h
Normal file
43
esp-vent-main/inc/DigitalIoPin.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* DigitalIoPin.h
|
||||
*
|
||||
* Created on: Aug 29, 2022
|
||||
* Author: Vasily Davydov
|
||||
*/
|
||||
|
||||
#ifndef DIGITALIOPIN_H_
|
||||
#define DIGITALIOPIN_H_
|
||||
|
||||
#define UINT8_MAX_VALUE 255
|
||||
|
||||
#include <assert.h>
|
||||
#include <chip.h>
|
||||
|
||||
typedef struct DigitalIOConfigStruct
|
||||
{
|
||||
uint8_t _port;
|
||||
uint8_t _pin;
|
||||
bool _input;
|
||||
bool _pullup;
|
||||
bool _invert;
|
||||
uint32_t IOCON_mode;
|
||||
uint32_t IOCON_inv;
|
||||
uint32_t DigitalEn;
|
||||
} DigitalIOConfigStruct;
|
||||
|
||||
class DigitalIoPin
|
||||
{
|
||||
public:
|
||||
DigitalIoPin (int port, int pin, bool input = true, bool pullup = true,
|
||||
bool invert = false);
|
||||
DigitalIoPin (const DigitalIoPin &) = delete;
|
||||
virtual ~DigitalIoPin ();
|
||||
bool read ();
|
||||
void write (bool value);
|
||||
|
||||
private:
|
||||
DigitalIOConfigStruct _io = { 0, 0, false, false, false, 0, 0, IOCON_DIGMODE_EN};
|
||||
void setIoPin ();
|
||||
};
|
||||
|
||||
#endif /* DIGITALIOPIN_H_ */
|
||||
27
esp-vent-main/inc/GMP252.h
Normal file
27
esp-vent-main/inc/GMP252.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* GMP252.h
|
||||
*
|
||||
* Created on: 20 Oct 2022
|
||||
* Author: evgenymeshcheryakov
|
||||
*/
|
||||
|
||||
#ifndef GMP252_H_
|
||||
#define GMP252_H_
|
||||
|
||||
#include "Modbus/ModbusMaster.h"
|
||||
#include "Modbus/ModbusRegister.h"
|
||||
|
||||
class GMP252
|
||||
{
|
||||
public:
|
||||
GMP252 ();
|
||||
int read ();
|
||||
virtual ~GMP252 ();
|
||||
|
||||
private:
|
||||
ModbusMaster sens;
|
||||
ModbusRegister regInt;
|
||||
ModbusRegister regFloat;
|
||||
};
|
||||
|
||||
#endif /* GMP252_H_ */
|
||||
29
esp-vent-main/inc/HMP60.h
Normal file
29
esp-vent-main/inc/HMP60.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* HMP60.h
|
||||
*
|
||||
* Created on: 20 Oct 2022
|
||||
* Author: evgenymeshcheryakov
|
||||
*/
|
||||
|
||||
#ifndef HMP60_H_
|
||||
#define HMP60_H_
|
||||
|
||||
#include "Modbus/ModbusMaster.h"
|
||||
#include "Modbus/ModbusRegister.h"
|
||||
|
||||
class HMP60
|
||||
{
|
||||
public:
|
||||
HMP60 ();
|
||||
int readRH ();
|
||||
int readT ();
|
||||
virtual ~HMP60 ();
|
||||
|
||||
private:
|
||||
ModbusMaster sens;
|
||||
ModbusRegister regRHint;
|
||||
ModbusRegister regRHfloat;
|
||||
ModbusRegister regTint;
|
||||
};
|
||||
|
||||
#endif /* HMP60_H_ */
|
||||
33
esp-vent-main/inc/I2C.h
Normal file
33
esp-vent-main/inc/I2C.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* I2C.h
|
||||
*
|
||||
* Created on: 21.2.2016
|
||||
* Author: krl
|
||||
*/
|
||||
|
||||
#ifndef I2C_H_
|
||||
#define I2C_H_
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
struct I2C_config {
|
||||
unsigned int device_number;
|
||||
unsigned int speed;
|
||||
unsigned int clock_divider;
|
||||
unsigned int i2c_mode;
|
||||
I2C_config(): device_number(0), speed(100000), clock_divider(40), i2c_mode(IOCON_SFI2C_EN) {};
|
||||
};
|
||||
|
||||
class I2C {
|
||||
public:
|
||||
I2C(const I2C_config &cfg);
|
||||
virtual ~I2C();
|
||||
bool transaction(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, uint8_t *rxBuffPtr, uint16_t rxSize);
|
||||
bool write(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize);
|
||||
bool read(uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize);
|
||||
private:
|
||||
LPC_I2C_T *device;
|
||||
static uint32_t I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer);
|
||||
};
|
||||
|
||||
#endif /* I2C_H_ */
|
||||
98
esp-vent-main/inc/LiquidCrystal.h
Normal file
98
esp-vent-main/inc/LiquidCrystal.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef LiquidCrystal_h
|
||||
#define LiquidCrystal_h
|
||||
|
||||
#include "DigitalIoPin.h"
|
||||
#include "chip.h"
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
class LiquidCrystal
|
||||
{
|
||||
public:
|
||||
LiquidCrystal (DigitalIoPin *rs, DigitalIoPin *enable, DigitalIoPin *d0,
|
||||
DigitalIoPin *d1, DigitalIoPin *d2, DigitalIoPin *d3);
|
||||
|
||||
void begin (uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||
|
||||
void clear ();
|
||||
void home ();
|
||||
|
||||
void noDisplay ();
|
||||
void display ();
|
||||
void noBlink ();
|
||||
void blink ();
|
||||
void noCursor ();
|
||||
void cursor ();
|
||||
void scrollDisplayLeft ();
|
||||
void scrollDisplayRight ();
|
||||
void leftToRight ();
|
||||
void rightToLeft ();
|
||||
void autoscroll ();
|
||||
void noAutoscroll ();
|
||||
|
||||
void createChar (uint8_t, uint8_t[]);
|
||||
void setCursor (uint8_t, uint8_t);
|
||||
virtual size_t write (uint8_t);
|
||||
void command (uint8_t);
|
||||
void print (std::string const &s);
|
||||
void print (const char *s);
|
||||
|
||||
private:
|
||||
void send (uint8_t, uint8_t);
|
||||
void write4bits (uint8_t);
|
||||
void pulseEnable ();
|
||||
|
||||
DigitalIoPin *rs_pin; // LOW(false): command. HIGH(true): character.
|
||||
DigitalIoPin *enable_pin; // activated by a HIGH pulse.
|
||||
DigitalIoPin *data_pins[4];
|
||||
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
|
||||
uint8_t _initialized;
|
||||
|
||||
uint8_t _numlines, _currline;
|
||||
uint8_t rows, col;
|
||||
};
|
||||
|
||||
#endif
|
||||
282
esp-vent-main/inc/Modbus/ModbusMaster.h
Normal file
282
esp-vent-main/inc/Modbus/ModbusMaster.h
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
@file
|
||||
Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
|
||||
|
||||
@defgroup setup ModbusMaster Object Instantiation/Initialization
|
||||
@defgroup buffer ModbusMaster Buffer Management
|
||||
@defgroup discrete Modbus Function Codes for Discrete Coils/Inputs
|
||||
@defgroup register Modbus Function Codes for Holding/Input Registers
|
||||
@defgroup constant Modbus Function Codes, Exception Codes
|
||||
*/
|
||||
/*
|
||||
|
||||
ModbusMaster.h - Arduino library for communicating with Modbus slaves
|
||||
over RS232/485 (via RTU protocol).
|
||||
|
||||
This file is part of ModbusMaster.
|
||||
|
||||
ModbusMaster 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.
|
||||
|
||||
ModbusMaster 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 ModbusMaster. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Doc Walker (Rx)
|
||||
Copyright © 2009-2013 Doc Walker <4-20ma at wvfans dot net>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ModbusMaster_h
|
||||
#define ModbusMaster_h
|
||||
|
||||
|
||||
/**
|
||||
@def __MODBUSMASTER_DEBUG__ (1).
|
||||
Set to 1 to enable debugging features within class:
|
||||
- pin 4 cycles for each byte read in the Modbus response
|
||||
- pin 5 cycles for each millisecond timeout during the Modbus response
|
||||
*/
|
||||
#define __MODBUSMASTER_DEBUG__ (0)
|
||||
|
||||
|
||||
/* _____STANDARD INCLUDES____________________________________________________ */
|
||||
// include types & constants of Wiring core API
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
//#include "WProgram.h"
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
uint32_t millis();
|
||||
#define BYTE 0xA5
|
||||
|
||||
/* _____UTILITY MACROS_______________________________________________________ */
|
||||
|
||||
|
||||
/* _____PROJECT INCLUDES_____________________________________________________ */
|
||||
// functions to calculate Modbus Application Data Unit CRC
|
||||
//#include "util/crc16.h"
|
||||
// moved inlcuding crc16.h to ModbusMaster.cpp
|
||||
|
||||
// functions to manipulate words
|
||||
///#include "util/word.h"
|
||||
#include "word.h"
|
||||
|
||||
|
||||
#include "SerialPort.h"
|
||||
|
||||
/* _____CLASS DEFINITIONS____________________________________________________ */
|
||||
/**
|
||||
Arduino class library for communicating with Modbus slaves over
|
||||
RS232/485 (via RTU protocol).
|
||||
*/
|
||||
class ModbusMaster
|
||||
{
|
||||
public:
|
||||
ModbusMaster();
|
||||
ModbusMaster(uint8_t);
|
||||
ModbusMaster(uint8_t, uint8_t);
|
||||
|
||||
void begin();
|
||||
void begin(uint16_t);
|
||||
void idle(void (*)());
|
||||
|
||||
// Modbus exception codes
|
||||
/**
|
||||
Modbus protocol illegal function exception.
|
||||
|
||||
The function code received in the query is not an allowable action for
|
||||
the server (or slave). This may be because the function code is only
|
||||
applicable to newer devices, and was not implemented in the unit
|
||||
selected. It could also indicate that the server (or slave) is in the
|
||||
wrong state to process a request of this type, for example because it is
|
||||
unconfigured and is being asked to return register values.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBIllegalFunction = 0x01;
|
||||
|
||||
/**
|
||||
Modbus protocol illegal data address exception.
|
||||
|
||||
The data address received in the query is not an allowable address for
|
||||
the server (or slave). More specifically, the combination of reference
|
||||
number and transfer length is invalid. For a controller with 100
|
||||
registers, the ADU addresses the first register as 0, and the last one
|
||||
as 99. If a request is submitted with a starting register address of 96
|
||||
and a quantity of registers of 4, then this request will successfully
|
||||
operate (address-wise at least) on registers 96, 97, 98, 99. If a
|
||||
request is submitted with a starting register address of 96 and a
|
||||
quantity of registers of 5, then this request will fail with Exception
|
||||
Code 0x02 "Illegal Data Address" since it attempts to operate on
|
||||
registers 96, 97, 98, 99 and 100, and there is no register with address
|
||||
100.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBIllegalDataAddress = 0x02;
|
||||
|
||||
/**
|
||||
Modbus protocol illegal data value exception.
|
||||
|
||||
A value contained in the query data field is not an allowable value for
|
||||
server (or slave). This indicates a fault in the structure of the
|
||||
remainder of a complex request, such as that the implied length is
|
||||
incorrect. It specifically does NOT mean that a data item submitted for
|
||||
storage in a register has a value outside the expectation of the
|
||||
application program, since the MODBUS protocol is unaware of the
|
||||
significance of any particular value of any particular register.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBIllegalDataValue = 0x03;
|
||||
|
||||
/**
|
||||
Modbus protocol slave device failure exception.
|
||||
|
||||
An unrecoverable error occurred while the server (or slave) was
|
||||
attempting to perform the requested action.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBSlaveDeviceFailure = 0x04;
|
||||
|
||||
// Class-defined success/exception codes
|
||||
/**
|
||||
ModbusMaster success.
|
||||
|
||||
Modbus transaction was successful; the following checks were valid:
|
||||
- slave ID
|
||||
- function code
|
||||
- response code
|
||||
- data
|
||||
- CRC
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBSuccess = 0x00;
|
||||
|
||||
/**
|
||||
ModbusMaster invalid response slave ID exception.
|
||||
|
||||
The slave ID in the response does not match that of the request.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBInvalidSlaveID = 0xE0;
|
||||
|
||||
/**
|
||||
ModbusMaster invalid response function exception.
|
||||
|
||||
The function code in the response does not match that of the request.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBInvalidFunction = 0xE1;
|
||||
|
||||
/**
|
||||
ModbusMaster response timed out exception.
|
||||
|
||||
The entire response was not received within the timeout period,
|
||||
ModbusMaster::ku8MBResponseTimeout.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBResponseTimedOut = 0xE2;
|
||||
|
||||
/**
|
||||
ModbusMaster invalid response CRC exception.
|
||||
|
||||
The CRC in the response does not match the one calculated.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBInvalidCRC = 0xE3;
|
||||
|
||||
uint16_t getResponseBuffer(uint8_t);
|
||||
void clearResponseBuffer();
|
||||
uint8_t setTransmitBuffer(uint8_t, uint16_t);
|
||||
void clearTransmitBuffer();
|
||||
|
||||
void beginTransmission(uint16_t);
|
||||
uint8_t requestFrom(uint16_t, uint16_t);
|
||||
void sendBit(bool);
|
||||
void send(uint8_t);
|
||||
void send(uint16_t);
|
||||
void send(uint32_t);
|
||||
uint8_t available(void);
|
||||
uint16_t receive(void);
|
||||
|
||||
|
||||
uint8_t readCoils(uint16_t, uint16_t);
|
||||
uint8_t readDiscreteInputs(uint16_t, uint16_t);
|
||||
uint8_t readHoldingRegisters(uint16_t, uint16_t);
|
||||
uint8_t readInputRegisters(uint16_t, uint8_t);
|
||||
uint8_t writeSingleCoil(uint16_t, uint8_t);
|
||||
uint8_t writeSingleRegister(uint16_t, uint16_t);
|
||||
uint8_t writeMultipleCoils(uint16_t, uint16_t);
|
||||
uint8_t writeMultipleCoils();
|
||||
uint8_t writeMultipleRegisters(uint16_t, uint16_t);
|
||||
uint8_t writeMultipleRegisters();
|
||||
uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t);
|
||||
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t);
|
||||
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t);
|
||||
|
||||
private:
|
||||
uint8_t _u8SerialPort; ///< serial port (0..3) initialized in constructor
|
||||
uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in constructor
|
||||
uint16_t _u16BaudRate; ///< baud rate (300..115200) initialized in begin()
|
||||
static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers
|
||||
uint16_t _u16ReadAddress; ///< slave register from which to read
|
||||
uint16_t _u16ReadQty; ///< quantity of words to read
|
||||
uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer()
|
||||
uint16_t _u16WriteAddress; ///< slave register to which to write
|
||||
uint16_t _u16WriteQty; ///< quantity of words to write
|
||||
uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
|
||||
uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx
|
||||
uint8_t _u8TransmitBufferIndex;
|
||||
uint16_t u16TransmitBufferLength;
|
||||
uint16_t* rxBuffer; // from Wire.h -- need to clean this up Rx
|
||||
uint8_t _u8ResponseBufferIndex;
|
||||
uint8_t _u8ResponseBufferLength;
|
||||
|
||||
// Modbus function codes for bit access
|
||||
static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils
|
||||
static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs
|
||||
static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil
|
||||
static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils
|
||||
|
||||
// Modbus function codes for 16 bit access
|
||||
static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers
|
||||
static const uint8_t ku8MBReadInputRegisters = 0x04; ///< Modbus function 0x04 Read Input Registers
|
||||
static const uint8_t ku8MBWriteSingleRegister = 0x06; ///< Modbus function 0x06 Write Single Register
|
||||
static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers
|
||||
static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register
|
||||
static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers
|
||||
|
||||
// Modbus timeout [milliseconds]
|
||||
static const uint16_t ku16MBResponseTimeout = 2000; ///< Modbus timeout [milliseconds]
|
||||
|
||||
// master function that conducts Modbus transactions
|
||||
uint8_t ModbusMasterTransaction(uint8_t u8MBFunction);
|
||||
|
||||
// idle callback function; gets called during idle time between TX and RX
|
||||
void (*_idle)();
|
||||
SerialPort *MBSerial = NULL; // added by KRL
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
@example examples/Basic/Basic.pde
|
||||
@example examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde
|
||||
*/
|
||||
19
esp-vent-main/inc/Modbus/ModbusRegister.h
Normal file
19
esp-vent-main/inc/Modbus/ModbusRegister.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef MODBUSREGISTER_H_
|
||||
#define MODBUSREGISTER_H_
|
||||
|
||||
#include "ModbusMaster.h"
|
||||
|
||||
class ModbusRegister {
|
||||
public:
|
||||
ModbusRegister(ModbusMaster *master, int address, bool holdingRegister = true);
|
||||
ModbusRegister(const ModbusRegister &) = delete;
|
||||
virtual ~ModbusRegister();
|
||||
int read();
|
||||
void write(int value);
|
||||
private:
|
||||
ModbusMaster *m;
|
||||
int addr;
|
||||
bool hr;
|
||||
};
|
||||
|
||||
#endif /* MODBUSREGISTER_H_ */
|
||||
20
esp-vent-main/inc/Modbus/SerialPort.h
Normal file
20
esp-vent-main/inc/Modbus/SerialPort.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef SERIALPORT_H_
|
||||
#define SERIALPORT_H_
|
||||
|
||||
#include "Uart.h"
|
||||
|
||||
class SerialPort {
|
||||
public:
|
||||
SerialPort();
|
||||
virtual ~SerialPort();
|
||||
int available();
|
||||
void begin(int speed = 9600);
|
||||
int read();
|
||||
int write(const char* buf, int len);
|
||||
int print(int val, int format);
|
||||
void flush();
|
||||
private:
|
||||
static LpcUart *u;
|
||||
};
|
||||
|
||||
#endif /* SERIALPORT_H_ */
|
||||
54
esp-vent-main/inc/Modbus/Uart.h
Normal file
54
esp-vent-main/inc/Modbus/Uart.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef LPCUART_H_
|
||||
#define LPCUART_H_
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
struct LpcPinMap {
|
||||
int port; /* set to -1 to indicate unused pin */
|
||||
int pin; /* set to -1 to indicate unused pin */
|
||||
};
|
||||
|
||||
struct LpcUartConfig {
|
||||
LPC_USART_T *pUART;
|
||||
uint32_t speed;
|
||||
uint32_t data;
|
||||
bool rs485;
|
||||
LpcPinMap tx;
|
||||
LpcPinMap rx;
|
||||
LpcPinMap rts; /* used as output enable if RS-485 mode is enabled */
|
||||
LpcPinMap cts;
|
||||
};
|
||||
|
||||
|
||||
class LpcUart {
|
||||
public:
|
||||
LpcUart(const LpcUartConfig &cfg);
|
||||
LpcUart(const LpcUart &) = delete;
|
||||
virtual ~LpcUart();
|
||||
int free(); /* get amount of free space in transmit buffer */
|
||||
int peek(); /* get number of received characters in receive buffer */
|
||||
int write(char c);
|
||||
int write(const char *s);
|
||||
int write(const char *buffer, int len);
|
||||
int read(char &c); /* get a single character. Returns number of characters read --> returns 0 if no character is available */
|
||||
int read(char *buffer, int len);
|
||||
void txbreak(bool brk); /* set break signal on */
|
||||
bool rxbreak(); /* check if break is received */
|
||||
void speed(int bps); /* change transmission speed */
|
||||
bool txempty();
|
||||
|
||||
void isr(); /* ISR handler. This will be called by the HW ISR handler. Do not call from application */
|
||||
private:
|
||||
LPC_USART_T *uart;
|
||||
IRQn_Type irqn;
|
||||
/* currently we support only fixed size ring buffers */
|
||||
static const int UART_RB_SIZE = 256;
|
||||
/* Transmit and receive ring buffers */
|
||||
RINGBUFF_T txring;
|
||||
RINGBUFF_T rxring;
|
||||
uint8_t rxbuff[UART_RB_SIZE];
|
||||
uint8_t txbuff[UART_RB_SIZE];
|
||||
static bool init; /* set when first UART is initialized. We have a global clock setting for all UARTSs */
|
||||
};
|
||||
|
||||
#endif /* LPCUART_H_ */
|
||||
86
esp-vent-main/inc/Modbus/crc16.h
Normal file
86
esp-vent-main/inc/Modbus/crc16.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
@file
|
||||
CRC Computations
|
||||
|
||||
@defgroup util_crc16 "util/crc16.h": CRC Computations
|
||||
@code#include "util/crc16.h"@endcode
|
||||
|
||||
This header file provides functions for calculating
|
||||
cyclic redundancy checks (CRC) using common polynomials.
|
||||
Modified by Doc Walker to be processor-independent (removed inline
|
||||
assembler to allow it to compile on SAM3X8E processors).
|
||||
|
||||
@par References:
|
||||
Jack Crenshaw's "Implementing CRCs" article in the January 1992 issue of @e
|
||||
Embedded @e Systems @e Programming. This may be difficult to find, but it
|
||||
explains CRC's in very clear and concise terms. Well worth the effort to
|
||||
obtain a copy.
|
||||
|
||||
*/
|
||||
/* Copyright (c) 2002, 2003, 2004 Marek Michalkiewicz
|
||||
Copyright (c) 2005, 2007 Joerg Wunsch
|
||||
Copyright (c) 2013 Dave Hylands
|
||||
Copyright (c) 2013 Frederic Nadeau
|
||||
Copyright (c) 2015 Doc Walker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#ifndef _UTIL_CRC16_H_
|
||||
#define _UTIL_CRC16_H_
|
||||
|
||||
/** @ingroup util_crc16
|
||||
Processor-independent CRC-16 calculation.
|
||||
|
||||
Polynomial: x^16 + x^15 + x^2 + 1 (0xA001)<br>
|
||||
Initial value: 0xFFFF
|
||||
|
||||
This CRC is normally used in disk-drive controllers.
|
||||
|
||||
@param uint16_t crc (0x0000..0xFFFF)
|
||||
@param uint8_t a (0x00..0xFF)
|
||||
@return calculated CRC (0x0000..0xFFFF)
|
||||
*/
|
||||
static uint16_t
|
||||
crc16_update (uint16_t crc, uint8_t a)
|
||||
{
|
||||
int i;
|
||||
|
||||
crc ^= a;
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ 0xA001;
|
||||
else
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#endif /* _UTIL_CRC16_H_ */
|
||||
98
esp-vent-main/inc/Modbus/word.h
Normal file
98
esp-vent-main/inc/Modbus/word.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
@file
|
||||
Utility Functions for Manipulating Words
|
||||
|
||||
@defgroup util_word "util/word.h": Utility Functions for Manipulating Words
|
||||
@code#include "util/word.h"@endcode
|
||||
|
||||
This header file provides utility functions for manipulating words.
|
||||
|
||||
*/
|
||||
/*
|
||||
|
||||
word.h - Utility Functions for Manipulating Words
|
||||
|
||||
This file is part of ModbusMaster.
|
||||
|
||||
ModbusMaster 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.
|
||||
|
||||
ModbusMaster 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 ModbusMaster. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Doc Walker (Rx)
|
||||
Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _UTIL_WORD_H_
|
||||
#define _UTIL_WORD_H_
|
||||
|
||||
|
||||
/** @ingroup util_word
|
||||
Return low word of a 32-bit integer.
|
||||
|
||||
@param uint32_t ww (0x00000000..0xFFFFFFFF)
|
||||
@return low word of input (0x0000..0xFFFF)
|
||||
*/
|
||||
static inline uint16_t lowWord(uint32_t ww)
|
||||
{
|
||||
return (uint16_t) ((ww) & 0xFFFF);
|
||||
}
|
||||
|
||||
|
||||
/** @ingroup util_word
|
||||
Return high word of a 32-bit integer.
|
||||
|
||||
@param uint32_t ww (0x00000000..0xFFFFFFFF)
|
||||
@return high word of input (0x0000..0xFFFF)
|
||||
*/
|
||||
static inline uint16_t highWord(uint32_t ww)
|
||||
{
|
||||
return (uint16_t) ((ww) >> 16);
|
||||
}
|
||||
|
||||
/* utility functions for porting ModbusMaster to LPCXpresso
|
||||
* added by krl
|
||||
*/
|
||||
static inline uint16_t word(uint8_t ww)
|
||||
{
|
||||
return (uint16_t) (ww);
|
||||
}
|
||||
|
||||
static inline uint16_t word(uint8_t h, uint8_t l)
|
||||
{
|
||||
return (uint16_t) ((h << 8) | l);
|
||||
}
|
||||
|
||||
static inline uint8_t highByte(uint16_t v)
|
||||
{
|
||||
return (uint8_t) ((v >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static inline uint16_t lowByte(uint16_t v)
|
||||
{
|
||||
return (uint8_t) (v & 0xFF);
|
||||
}
|
||||
|
||||
static inline uint8_t bitRead(uint8_t v, uint8_t n)
|
||||
{
|
||||
return (uint8_t) (v & (1 << n) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline void bitWrite(uint16_t& v, uint8_t n, uint8_t b)
|
||||
{
|
||||
if(b) v = v | (1 << n);
|
||||
else v = v & ~(1 << n);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _UTIL_WORD_H_ */
|
||||
48
esp-vent-main/inc/PressureWrapper.h
Normal file
48
esp-vent-main/inc/PressureWrapper.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* PressureWrapper.h
|
||||
*
|
||||
* Created on: 5 Oct 2022
|
||||
* Author: evgenymeshcheryakov
|
||||
*/
|
||||
|
||||
#ifndef PRESSUREWRAPPER_H_
|
||||
#define PRESSUREWRAPPER_H_
|
||||
|
||||
#include "I2C.h"
|
||||
#include <cstdio>
|
||||
|
||||
#define ADDRESS 0x40
|
||||
|
||||
|
||||
/**
|
||||
* @brief structure to hold a raw data from
|
||||
* the pressure sensor
|
||||
*/
|
||||
|
||||
typedef struct _PRESSURE{
|
||||
uint8_t rBuffer[2];
|
||||
uint8_t crc;
|
||||
}PRESSURE_DATA;
|
||||
|
||||
class PressureWrapper
|
||||
{
|
||||
public:
|
||||
PressureWrapper ();
|
||||
/*
|
||||
* @return pressure in Pascal
|
||||
*/
|
||||
int getPressure ();
|
||||
|
||||
virtual ~PressureWrapper ();
|
||||
|
||||
private:
|
||||
I2C *i2c;
|
||||
PRESSURE_DATA data = {{0, 0}, 0};
|
||||
/*
|
||||
* @return struct with pressure data in
|
||||
* rBuffer and CRC check in crc
|
||||
*/
|
||||
bool getRawPressure ();
|
||||
};
|
||||
|
||||
#endif /* PRESSUREWRAPPER_H_ */
|
||||
27
esp-vent-main/inc/StateHandler/Counter.h
Normal file
27
esp-vent-main/inc/StateHandler/Counter.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Counter.h
|
||||
*
|
||||
* Created on: Sep 1, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#ifndef COUNTER_H_
|
||||
#define COUNTER_H_
|
||||
|
||||
class Counter
|
||||
{
|
||||
|
||||
public:
|
||||
Counter (unsigned int i, unsigned int up);
|
||||
void inc ();
|
||||
void dec ();
|
||||
unsigned int getCurrent ();
|
||||
void setInit (unsigned int i);
|
||||
~Counter () = default;
|
||||
|
||||
private:
|
||||
unsigned int init;
|
||||
unsigned int up_lim;
|
||||
unsigned int down_lim;
|
||||
};
|
||||
#endif /* COUNTER_H_ */
|
||||
33
esp-vent-main/inc/StateHandler/Event.h
Normal file
33
esp-vent-main/inc/StateHandler/Event.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Event.h
|
||||
*
|
||||
* Created on: Oct 5, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#ifndef EVENT_H_
|
||||
#define EVENT_H_
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
virtual ~Event (){};
|
||||
|
||||
enum eventType
|
||||
{
|
||||
/** Start of the event */
|
||||
eEnter,
|
||||
/** End of the event*/
|
||||
eExit,
|
||||
/** Button toggle event type (has values:
|
||||
* temperature or button) */
|
||||
eKey,
|
||||
/** Time event */
|
||||
eTick
|
||||
};
|
||||
Event (eventType e = eTick, int val = 0) : type (e), value (val){};
|
||||
eventType type;
|
||||
int value;
|
||||
};
|
||||
|
||||
#endif /* EVENT_H_ */
|
||||
195
esp-vent-main/inc/StateHandler/StateHandler.h
Normal file
195
esp-vent-main/inc/StateHandler/StateHandler.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* StateHandler.h
|
||||
*
|
||||
* Created on: Sep 21, 2022
|
||||
* Author: tylen
|
||||
*
|
||||
* Purpose of this class is to store and pass
|
||||
* the events of the current mode to further process.
|
||||
*
|
||||
* Current goal is to make it to operate on interrupts
|
||||
* caused by button presses.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STATE_HANDLER_H_
|
||||
#define STATE_HANDLER_H_
|
||||
|
||||
#include "Counter.h"
|
||||
#include "DigitalIoPin.h"
|
||||
#include "Event.h"
|
||||
#include "GMP252.h"
|
||||
#include "HMP60.h"
|
||||
#include "LiquidCrystal.h"
|
||||
#include "Modbus/ModbusMaster.h"
|
||||
#include "Modbus/ModbusRegister.h"
|
||||
#include "PressureWrapper.h"
|
||||
#include "Timer.h"
|
||||
|
||||
/** Buttons enumeration
|
||||
*
|
||||
* Current switch state is being passed
|
||||
* from main to StateHandler through
|
||||
* a keyEvent. Enumeration determines the state
|
||||
* of the particular button.
|
||||
* */
|
||||
|
||||
enum _buttons
|
||||
{
|
||||
/** Raises the bar up */
|
||||
BUTTON_CONTROL_UP,
|
||||
/** Raises the bar down */
|
||||
BUTTON_CONTROL_DOWN,
|
||||
/** Toggles the mode between auto and
|
||||
* manual, which changes the state */
|
||||
BUTTON_CONTROL_TOG_MODE,
|
||||
/** Optional button to toggle the
|
||||
* activation of the current setting.
|
||||
* Not compulsory to be used. */
|
||||
BUTTON_CONTROL_TOG_ACTIVE
|
||||
};
|
||||
|
||||
enum _bars
|
||||
{
|
||||
/** 0-100 % */
|
||||
FAN_SPEED,
|
||||
/** 0-120 Pa */
|
||||
PRESSURE
|
||||
};
|
||||
|
||||
enum _mode
|
||||
{
|
||||
MANUAL,
|
||||
AUTO
|
||||
};
|
||||
|
||||
enum _sensors
|
||||
{
|
||||
PRESSUREDAT,
|
||||
TEMPERATURE,
|
||||
HUMIDITY,
|
||||
CO2
|
||||
};
|
||||
|
||||
class StateHandler;
|
||||
typedef void (StateHandler::*state_pointer) (const Event &);
|
||||
|
||||
class StateHandler
|
||||
{
|
||||
public:
|
||||
StateHandler (LiquidCrystal *lcd, ModbusRegister *A01,
|
||||
PressureWrapper *pressure, Timer *global);
|
||||
virtual ~StateHandler ();
|
||||
|
||||
/** Get currently set pressure
|
||||
*
|
||||
* @return pressure in range of 0-120
|
||||
*/
|
||||
unsigned int getSetPressure ();
|
||||
|
||||
/** Get currently set FanSpeed
|
||||
*
|
||||
* @return speed in range of 0-100
|
||||
*/
|
||||
unsigned int getSetSpeed ();
|
||||
|
||||
/** Display values on LCD depending on current mode
|
||||
*
|
||||
* MANUAL MODE: SPEED: XX% PRESSURE: XXPa
|
||||
*
|
||||
* AUTO MODE: P. SET: XXPa P. CURR: XXPa
|
||||
*
|
||||
* @param value1 value to be displayed on LCD line 0
|
||||
* @param value2 value to be displayed on LCD line 1
|
||||
*/
|
||||
void displaySet (unsigned int value1, unsigned int value2);
|
||||
|
||||
/** Handle the given event of the current state
|
||||
*
|
||||
* @param event event to be handled in the current state
|
||||
*/
|
||||
void HandleState (const Event &event);
|
||||
|
||||
private:
|
||||
state_pointer current;
|
||||
/** Set a new curremt state
|
||||
* @param newstate new state to be set to current
|
||||
*/
|
||||
void SetState (state_pointer newstate);
|
||||
bool current_mode;
|
||||
Counter value[2] = { { 0, 100 }, { 0, 120 } };
|
||||
/* motor of fan starts at value 90. probably because of some
|
||||
* weigh of fan, so voltage within range of 0-89 is not
|
||||
* sufficient to start motor.
|
||||
* TODO: Value 89 should be scaled to 0 at some point */
|
||||
Counter fan_speed = { 20, 1000 };
|
||||
/*integral controller for PID. should be global, since it
|
||||
* accumulates error signals encountered since startup*/
|
||||
int integral = 0;
|
||||
int saved_set_value[2] = { 0, 0 };
|
||||
int saved_curr_value[2] = { 0, 0 };
|
||||
int sensors_data[4] = { 0 };
|
||||
LiquidCrystal *_lcd;
|
||||
ModbusRegister *A01;
|
||||
PressureWrapper *pressure;
|
||||
Timer *state_timer;
|
||||
/* CO2 sensor object */
|
||||
GMP252 co2;
|
||||
|
||||
/* Humidity and temperature sensor object */
|
||||
HMP60 humidity;
|
||||
|
||||
/** Initialization state
|
||||
*
|
||||
* @param event event of the state
|
||||
*/
|
||||
void stateInit (const Event &event);
|
||||
|
||||
/** Manual state
|
||||
*
|
||||
* - set current speed
|
||||
* - print current pressure
|
||||
*
|
||||
* @param event event of the state
|
||||
*/
|
||||
void stateManual (const Event &event);
|
||||
|
||||
/** Automated state
|
||||
*
|
||||
* - print current pressure
|
||||
* - print set pressure
|
||||
* - inc/dec fan speed
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
void stateAuto (const Event &event);
|
||||
|
||||
/** Sensors state
|
||||
*
|
||||
* - print current sensrs readings
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
void stateSensors (const Event &event);
|
||||
|
||||
/** Handle button presses
|
||||
*
|
||||
* @param button current button
|
||||
*/
|
||||
void handleControlButtons (uint8_t button);
|
||||
|
||||
/** Save values to class' varibales
|
||||
*
|
||||
* @param eventValue value coming from an event
|
||||
* @param counterValue value of the inner Counter
|
||||
* @param mode current mode
|
||||
*/
|
||||
void save (int eventValue, size_t mode);
|
||||
|
||||
/** Calculates pid for fan control value
|
||||
*
|
||||
*/
|
||||
void pid ();
|
||||
};
|
||||
|
||||
#endif /* STATE_HANDLER_H_ */
|
||||
35
esp-vent-main/inc/SwitchController.h
Normal file
35
esp-vent-main/inc/SwitchController.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SwitchController.h
|
||||
*
|
||||
* Created on: Oct 17, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#ifndef SWITCHCONTROLLER_H_
|
||||
#define SWITCHCONTROLLER_H_
|
||||
|
||||
#include "DigitalIoPin.h"
|
||||
#include "StateHandler/StateHandler.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class SwitchController
|
||||
{
|
||||
public:
|
||||
SwitchController (DigitalIoPin *button, Timer *timer, StateHandler *handler,
|
||||
int button_mode);
|
||||
virtual ~SwitchController ();
|
||||
/** Listen to switch button
|
||||
*/
|
||||
void listen ();
|
||||
|
||||
private:
|
||||
DigitalIoPin *b;
|
||||
Timer *t;
|
||||
StateHandler *h;
|
||||
bool b_pressed;
|
||||
int b_mode;
|
||||
void buttonOnHold ();
|
||||
void buttonInLoop ();
|
||||
};
|
||||
|
||||
#endif /* SWITCHCONTROLLER_H_ */
|
||||
80
esp-vent-main/inc/Timer.h
Normal file
80
esp-vent-main/inc/Timer.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Timer.h
|
||||
*
|
||||
* Created on: Oct 14, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#ifndef TIMER_H_
|
||||
#define TIMER_H_
|
||||
|
||||
#include "board.h"
|
||||
#include <atomic>
|
||||
#include <climits>
|
||||
|
||||
static volatile std::atomic_int timer;
|
||||
static volatile std::atomic_int systicks;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
/**
|
||||
* @brief Handle interrupt from SysTick timer
|
||||
* @return Nothing
|
||||
*/
|
||||
void SysTick_Handler (void);
|
||||
}
|
||||
|
||||
uint32_t millis ();
|
||||
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Initalize the systick configuration with your frequency
|
||||
*
|
||||
*/
|
||||
Timer (uint32_t freq = 1000);
|
||||
virtual ~Timer ();
|
||||
|
||||
/**
|
||||
* @brief Tick the counter.
|
||||
*
|
||||
* Counter is incremented by one every tick,
|
||||
* if it gets over the INT_MAX (see limits.h),
|
||||
* the counter rolls up back to zero and starts
|
||||
* over.
|
||||
*
|
||||
*
|
||||
* @param ms Counter ticking frequency is provided in milliseconds
|
||||
*/
|
||||
void tickCounter (int ms);
|
||||
|
||||
/**
|
||||
* @brief Get the current counter value
|
||||
*
|
||||
* @return int counter value
|
||||
*/
|
||||
int getCounter ();
|
||||
|
||||
/**
|
||||
* @brief Set counter to 0.
|
||||
*
|
||||
*/
|
||||
void resetCounter ();
|
||||
|
||||
/**
|
||||
* @brief Sleep for amount of time
|
||||
*
|
||||
* Time is either in ms or in sec, defined
|
||||
* by systickInit_xx()
|
||||
*
|
||||
* @param ms milliseconds
|
||||
*/
|
||||
void Sleep (int ms);
|
||||
|
||||
private:
|
||||
volatile std::atomic_int counter;
|
||||
uint32_t freq;
|
||||
};
|
||||
|
||||
#endif /* TIMER_H_ */
|
||||
64
esp-vent-main/src/DigitalIoPin.cpp
Normal file
64
esp-vent-main/src/DigitalIoPin.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* DigitalIoPin.cpp
|
||||
*
|
||||
* Created on: Aug 29, 2022
|
||||
* Author: Vasily Davydov
|
||||
*/
|
||||
|
||||
#include "DigitalIoPin.h"
|
||||
|
||||
DigitalIoPin::DigitalIoPin (int port, int pin, bool input, bool pullup,
|
||||
bool invert)
|
||||
{
|
||||
assert ((port <= UINT8_MAX_VALUE) && (pin <= UINT8_MAX_VALUE));
|
||||
_io._port = (uint8_t)port;
|
||||
_io._pin = (uint8_t)pin;
|
||||
_io._input = input;
|
||||
_io._pullup = pullup;
|
||||
_io._invert = invert;
|
||||
_io.IOCON_mode = IOCON_MODE_INACT;
|
||||
_io.IOCON_inv = IOCON_FUNC0;
|
||||
setIoPin ();
|
||||
}
|
||||
|
||||
DigitalIoPin::~DigitalIoPin ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DigitalIoPin::setIoPin ()
|
||||
{
|
||||
bool direction = true;
|
||||
if (_io._input)
|
||||
{
|
||||
direction = false;
|
||||
_io.IOCON_mode = IOCON_MODE_PULLUP;
|
||||
if (!_io._pullup)
|
||||
{
|
||||
_io.IOCON_mode = IOCON_MODE_PULLDOWN;
|
||||
}
|
||||
if (_io._invert)
|
||||
{
|
||||
_io.IOCON_inv = IOCON_INV_EN;
|
||||
}
|
||||
}
|
||||
Chip_IOCON_PinMuxSet (LPC_IOCON, _io._port, _io._pin,
|
||||
(_io.IOCON_mode | _io.DigitalEn | _io.IOCON_inv));
|
||||
/** False direction equals input */
|
||||
Chip_GPIO_SetPinDIR (LPC_GPIO, _io._port, _io._pin, direction);
|
||||
}
|
||||
|
||||
bool
|
||||
DigitalIoPin::read ()
|
||||
{
|
||||
bool state = (Chip_GPIO_GetPinState (LPC_GPIO, _io._port, _io._pin));
|
||||
return (_io._invert && !_io._input) ? !state : state;
|
||||
}
|
||||
|
||||
void
|
||||
DigitalIoPin::write (bool value)
|
||||
{
|
||||
assert (!(_io._input));
|
||||
Chip_GPIO_SetPinState (LPC_GPIO, _io._port, _io._pin, ((_io._invert) ? !value : value));
|
||||
}
|
||||
|
||||
27
esp-vent-main/src/GMP252.cpp
Normal file
27
esp-vent-main/src/GMP252.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* GMP252.cpp
|
||||
*
|
||||
* Created on: 20 Oct 2022
|
||||
* Author: evgenymeshcheryakov
|
||||
*/
|
||||
|
||||
#include "GMP252.h"
|
||||
|
||||
GMP252::GMP252 ()
|
||||
: sens{ 240 }, regInt{ &sens, 0x0100 }, regFloat{ &sens, 0x0000 }
|
||||
{
|
||||
|
||||
sens.begin (9600);
|
||||
}
|
||||
|
||||
int
|
||||
GMP252::read ()
|
||||
{
|
||||
int result = regInt.read ();
|
||||
return result;
|
||||
}
|
||||
|
||||
GMP252::~GMP252 ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
32
esp-vent-main/src/HMP60.cpp
Normal file
32
esp-vent-main/src/HMP60.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* HMP60.cpp
|
||||
*
|
||||
* Created on: 20 Oct 2022
|
||||
* Author: evgenymeshcheryakov
|
||||
*/
|
||||
|
||||
#include <HMP60.h>
|
||||
|
||||
HMP60::HMP60 ()
|
||||
: sens{ 241 }, regRHint{ &sens, 0x0100 }, regTint{ &sens, 0x0101 },
|
||||
regRHfloat{ &sens, 0x0000 }
|
||||
{
|
||||
sens.begin (9600);
|
||||
}
|
||||
|
||||
int
|
||||
HMP60::readRH ()
|
||||
{
|
||||
return (regRHint.read ()) / 10;
|
||||
}
|
||||
|
||||
int
|
||||
HMP60::readT ()
|
||||
{
|
||||
return (regTint.read ()) / 10;
|
||||
}
|
||||
|
||||
HMP60::~HMP60 ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
@@ -1,162 +1,143 @@
|
||||
/*
|
||||
* I2C.cpp
|
||||
*
|
||||
* Created on: 21.2.2016
|
||||
* Author: krl
|
||||
* Based on example provided by NXP Semiconductors. See copyright notice
|
||||
* below.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @brief I2CM bus master example using polling mode
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2014
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under
|
||||
* any patent, copyright, mask work right, or any other intellectual property
|
||||
* rights in or to any products. NXP Semiconductors reserves the right to make
|
||||
* changes in the software without notification. NXP Semiconductors also makes
|
||||
* no representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that
|
||||
* it is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "I2C.h"
|
||||
|
||||
I2C::I2C (const I2C_config &cfg) : device (nullptr)
|
||||
{
|
||||
if (cfg.device_number == 0)
|
||||
{
|
||||
device = LPC_I2C0;
|
||||
// board init must have been called before the pins can be configured
|
||||
Chip_IOCON_PinMuxSet (LPC_IOCON, 0, 22, IOCON_DIGMODE_EN | cfg.i2c_mode);
|
||||
Chip_IOCON_PinMuxSet (LPC_IOCON, 0, 23, IOCON_DIGMODE_EN | cfg.i2c_mode);
|
||||
Chip_SWM_EnableFixedPin (SWM_FIXED_I2C0_SCL);
|
||||
Chip_SWM_EnableFixedPin (SWM_FIXED_I2C0_SDA);
|
||||
}
|
||||
else
|
||||
{
|
||||
// currently we support only I2C number 0
|
||||
}
|
||||
|
||||
if (device)
|
||||
{
|
||||
/* Enable I2C clock and reset I2C peripheral - the boot ROM does not
|
||||
do this */
|
||||
Chip_I2C_Init (device);
|
||||
|
||||
/* Setup clock rate for I2C */
|
||||
Chip_I2C_SetClockDiv (device, cfg.clock_divider);
|
||||
|
||||
/* Setup I2CM transfer rate */
|
||||
Chip_I2CM_SetBusSpeed (device, cfg.speed);
|
||||
|
||||
/* Enable Master Mode */
|
||||
Chip_I2CM_Enable (device);
|
||||
}
|
||||
}
|
||||
|
||||
I2C::~I2C ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
bool
|
||||
I2C::write (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize)
|
||||
{
|
||||
return transaction (devAddr, txBuffPtr, txSize, nullptr, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
I2C::read (uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize)
|
||||
{
|
||||
return transaction (devAddr, nullptr, 0, rxBuffPtr, rxSize);
|
||||
}
|
||||
|
||||
bool
|
||||
I2C::transaction (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize,
|
||||
uint8_t *rxBuffPtr, uint16_t rxSize)
|
||||
{
|
||||
I2CM_XFER_T i2cmXferRec;
|
||||
|
||||
// make sure that master is idle
|
||||
while (!Chip_I2CM_IsMasterPending (LPC_I2C0))
|
||||
;
|
||||
|
||||
/* Setup I2C transfer record */
|
||||
i2cmXferRec.slaveAddr = devAddr;
|
||||
i2cmXferRec.status = 0;
|
||||
i2cmXferRec.txSz = txSize;
|
||||
i2cmXferRec.rxSz = rxSize;
|
||||
i2cmXferRec.txBuff = txBuffPtr;
|
||||
i2cmXferRec.rxBuff = rxBuffPtr;
|
||||
|
||||
I2CM_XferBlocking (LPC_I2C0, &i2cmXferRec);
|
||||
// Chip_I2CM_XferBlocking returns before stop condition is fully completed
|
||||
// therefore we need to wait for master to be idle when doing back-to-back
|
||||
// transactions (see beginning of the function)
|
||||
|
||||
/* Test for valid operation */
|
||||
if (i2cmXferRec.status == I2CM_STATUS_OK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transmit and Receive data in master mode */
|
||||
/* This duplicates (and combines) the functionality of Chip_I2CM_Xfer and
|
||||
* Chip_I2CM_XferBlocking with a modification that allows us to do a zero
|
||||
* length write (needed to use honeywell humidity/temp sensor)
|
||||
*/
|
||||
uint32_t
|
||||
I2C::I2CM_XferBlocking (LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
/* start transfer */
|
||||
|
||||
/* set the transfer status as busy */
|
||||
xfer->status = I2CM_STATUS_BUSY;
|
||||
/* Clear controller state. */
|
||||
Chip_I2CM_ClearStatus (pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
|
||||
/* Write Address and RW bit to data register */
|
||||
// Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0)); //
|
||||
// original NXP version
|
||||
// krl : both read and write lenght is 0 --> write (for honeywell temp
|
||||
// sensor)
|
||||
Chip_I2CM_WriteByte (pI2C, (xfer->slaveAddr << 1)
|
||||
| (xfer->txSz == 0 && xfer->rxSz != 0));
|
||||
/* Enter to Master Transmitter mode */
|
||||
Chip_I2CM_SendStart (pI2C);
|
||||
|
||||
while (ret == 0)
|
||||
{
|
||||
/* wait for status change interrupt */
|
||||
while (!Chip_I2CM_IsMasterPending (pI2C))
|
||||
{
|
||||
}
|
||||
/* call state change handler */
|
||||
ret = Chip_I2CM_XferHandler (pI2C, xfer);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* I2C.cpp
|
||||
*
|
||||
* Created on: 21.2.2016
|
||||
* Author: krl
|
||||
* Based on example provided by NXP Semiconductors. See copyright notice below.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @brief I2CM bus master example using polling mode
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2014
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "I2C.h"
|
||||
|
||||
|
||||
I2C::I2C(const I2C_config &cfg): device(nullptr) {
|
||||
if(cfg.device_number == 0) {
|
||||
device = LPC_I2C0;
|
||||
// board init must have been called before the pins can be configured
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 22, IOCON_DIGMODE_EN | cfg.i2c_mode);
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 23, IOCON_DIGMODE_EN | cfg.i2c_mode);
|
||||
Chip_SWM_EnableFixedPin(SWM_FIXED_I2C0_SCL);
|
||||
Chip_SWM_EnableFixedPin(SWM_FIXED_I2C0_SDA);
|
||||
}
|
||||
else {
|
||||
// currently we support only I2C number 0
|
||||
}
|
||||
|
||||
if(device) {
|
||||
/* Enable I2C clock and reset I2C peripheral - the boot ROM does not
|
||||
do this */
|
||||
Chip_I2C_Init(device);
|
||||
|
||||
/* Setup clock rate for I2C */
|
||||
Chip_I2C_SetClockDiv(device, cfg.clock_divider);
|
||||
|
||||
/* Setup I2CM transfer rate */
|
||||
Chip_I2CM_SetBusSpeed(device, cfg.speed);
|
||||
|
||||
/* Enable Master Mode */
|
||||
Chip_I2CM_Enable(device);
|
||||
}
|
||||
}
|
||||
|
||||
I2C::~I2C() {
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
bool I2C::write(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize)
|
||||
{
|
||||
return transaction(devAddr, txBuffPtr, txSize, nullptr, 0);
|
||||
}
|
||||
|
||||
bool I2C::read(uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize)
|
||||
{
|
||||
return transaction(devAddr, nullptr, 0, rxBuffPtr, rxSize);
|
||||
}
|
||||
|
||||
|
||||
bool I2C::transaction(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, uint8_t *rxBuffPtr, uint16_t rxSize) {
|
||||
I2CM_XFER_T i2cmXferRec;
|
||||
|
||||
// make sure that master is idle
|
||||
while(!Chip_I2CM_IsMasterPending(device));
|
||||
|
||||
/* Setup I2C transfer record */
|
||||
i2cmXferRec.slaveAddr = devAddr;
|
||||
i2cmXferRec.status = 0;
|
||||
i2cmXferRec.txSz = txSize;
|
||||
i2cmXferRec.rxSz = rxSize;
|
||||
i2cmXferRec.txBuff = txBuffPtr;
|
||||
i2cmXferRec.rxBuff = rxBuffPtr;
|
||||
|
||||
I2CM_XferBlocking(device, &i2cmXferRec);
|
||||
// Chip_I2CM_XferBlocking returns before stop condition is fully completed
|
||||
// therefore we need to wait for master to be idle when doing back-to-back transactions (see beginning of the function)
|
||||
|
||||
/* Test for valid operation */
|
||||
if (i2cmXferRec.status == I2CM_STATUS_OK) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transmit and Receive data in master mode */
|
||||
/* This duplicates (and combines) the functionality of Chip_I2CM_Xfer and Chip_I2CM_XferBlocking with a modification
|
||||
* that allows us to do a zero length write (needed to use honeywell humidity/temp sensor)
|
||||
*/
|
||||
uint32_t I2C::I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
/* start transfer */
|
||||
|
||||
/* set the transfer status as busy */
|
||||
xfer->status = I2CM_STATUS_BUSY;
|
||||
/* Clear controller state. */
|
||||
Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
|
||||
/* Write Address and RW bit to data register */
|
||||
//Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0)); // original NXP version
|
||||
// krl : both read and write lenght is 0 --> write (for honeywell temp sensor)
|
||||
Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0 && xfer->rxSz != 0));
|
||||
/* Enter to Master Transmitter mode */
|
||||
Chip_I2CM_SendStart(pI2C);
|
||||
|
||||
while (ret == 0) {
|
||||
/* wait for status change interrupt */
|
||||
while (!Chip_I2CM_IsMasterPending(pI2C)) {}
|
||||
/* call state change handler */
|
||||
ret = Chip_I2CM_XferHandler(pI2C, xfer);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* I2C.h
|
||||
*
|
||||
* Created on: 21.2.2016
|
||||
* Author: krl
|
||||
*/
|
||||
|
||||
#ifndef I2C_H_
|
||||
#define I2C_H_
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
struct I2C_config
|
||||
{
|
||||
unsigned int device_number;
|
||||
unsigned int speed;
|
||||
unsigned int clock_divider;
|
||||
unsigned int i2c_mode;
|
||||
I2C_config ()
|
||||
: device_number (0), speed (100000), clock_divider (40),
|
||||
i2c_mode (IOCON_SFI2C_EN){};
|
||||
};
|
||||
|
||||
class I2C
|
||||
{
|
||||
public:
|
||||
I2C (const I2C_config &cfg);
|
||||
virtual ~I2C ();
|
||||
bool transaction (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize,
|
||||
uint8_t *rxBuffPtr, uint16_t rxSize);
|
||||
bool write (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize);
|
||||
bool read (uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize);
|
||||
|
||||
private:
|
||||
LPC_I2C_T *device;
|
||||
static uint32_t I2CM_XferBlocking (LPC_I2C_T *pI2C, I2CM_XFER_T *xfer);
|
||||
};
|
||||
|
||||
#endif /* I2C_H_ */
|
||||
350
esp-vent-main/src/LiquidCrystal.cpp
Normal file
350
esp-vent-main/src/LiquidCrystal.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
#include "LiquidCrystal.h"
|
||||
|
||||
#include "chip.h"
|
||||
#include <cstring>
|
||||
|
||||
#define LOW 0
|
||||
#define HIGH 1
|
||||
|
||||
void
|
||||
delayMicroseconds (unsigned int us)
|
||||
{
|
||||
uint32_t reg;
|
||||
// calculate compare value
|
||||
uint64_t cmp = (Chip_Clock_GetSystemClockRate () / 1000000)
|
||||
* us; // One cycle equals ~72 us, thus cycle * us
|
||||
// disable RIT – compare value may only be changed when RIT is disabled
|
||||
reg = LPC_RITIMER->CTRL & 0xF;
|
||||
LPC_RITIMER->CTRL = reg & ~RIT_CTRL_TEN;
|
||||
// set compare value to RIT
|
||||
LPC_RITIMER->COMPVAL = (uint32_t)cmp;
|
||||
LPC_RITIMER->COMPVAL_H = (uint32_t) (cmp >> 32);
|
||||
// clear RIT counter (so that counting starts from zero)
|
||||
LPC_RITIMER->COUNTER = (uint32_t)0;
|
||||
LPC_RITIMER->COUNTER_H = (uint32_t) (0 >> 32);
|
||||
// enable RIT
|
||||
reg = LPC_RITIMER->CTRL & 0xF;
|
||||
LPC_RITIMER->CTRL = reg | RIT_CTRL_TEN;
|
||||
// wait until RIT Int flag is set
|
||||
while (!(LPC_RITIMER->CTRL & RIT_CTRL_INT))
|
||||
;
|
||||
// disable RIT
|
||||
reg = LPC_RITIMER->CTRL & 0xF;
|
||||
LPC_RITIMER->CTRL = reg & ~RIT_CTRL_TEN;
|
||||
// clear RIT Int flag
|
||||
reg = LPC_RITIMER->CTRL & 0xF;
|
||||
LPC_RITIMER->CTRL = reg | RIT_CTRL_INT;
|
||||
}
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal::LiquidCrystal (DigitalIoPin *rs, DigitalIoPin *enable,
|
||||
DigitalIoPin *d0, DigitalIoPin *d1,
|
||||
DigitalIoPin *d2, DigitalIoPin *d3)
|
||||
{
|
||||
rs_pin = rs;
|
||||
enable_pin = enable;
|
||||
|
||||
data_pins[0] = d0;
|
||||
data_pins[1] = d1;
|
||||
data_pins[2] = d2;
|
||||
data_pins[3] = d3;
|
||||
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
|
||||
begin (16, 2); // default to 16x2 display
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::begin (uint8_t cols, uint8_t lines, uint8_t dotsize)
|
||||
{
|
||||
this->rows = lines;
|
||||
this->col = cols;
|
||||
if (lines > 1)
|
||||
{
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
_currline = 0;
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1))
|
||||
{
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait
|
||||
// 50
|
||||
delayMicroseconds (50000);
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
rs_pin->write (false); // digitalWrite(_rs_pin, LOW);
|
||||
enable_pin->write (false); // digitalWrite(_enable_pin, LOW);
|
||||
|
||||
// note: this port supports only 4 bit mode
|
||||
// put the LCD into 4 bit or 8 bit mode
|
||||
if (!(_displayfunction & LCD_8BITMODE))
|
||||
{
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits (0x03);
|
||||
delayMicroseconds (4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits (0x03);
|
||||
delayMicroseconds (4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits (0x03);
|
||||
delayMicroseconds (150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits (0x02);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// page 45 figure 23
|
||||
|
||||
// Send function set command sequence
|
||||
command (LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds (4500); // wait more than 4.1ms
|
||||
|
||||
// second try
|
||||
command (LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds (150);
|
||||
|
||||
// third go
|
||||
command (LCD_FUNCTIONSET | _displayfunction);
|
||||
}
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
command (LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display ();
|
||||
|
||||
// clear it off
|
||||
clear ();
|
||||
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command (LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void
|
||||
LiquidCrystal::clear ()
|
||||
{
|
||||
command (LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds (2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::home ()
|
||||
{
|
||||
command (LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds (2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::print (std::string const &s)
|
||||
{
|
||||
this->print (s.c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::print (const char *s)
|
||||
{
|
||||
int char_counter = 0;
|
||||
while (*s && char_counter < this->col)
|
||||
{
|
||||
send (*s, HIGH);
|
||||
char_counter++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::setCursor (uint8_t col, uint8_t row)
|
||||
{
|
||||
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
if (row >= _numlines)
|
||||
{
|
||||
row = _numlines - 1; // we count rows starting w/0
|
||||
}
|
||||
|
||||
command (LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void
|
||||
LiquidCrystal::noDisplay ()
|
||||
{
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command (LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void
|
||||
LiquidCrystal::display ()
|
||||
{
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command (LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void
|
||||
LiquidCrystal::noCursor ()
|
||||
{
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command (LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void
|
||||
LiquidCrystal::cursor ()
|
||||
{
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command (LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void
|
||||
LiquidCrystal::noBlink ()
|
||||
{
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command (LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void
|
||||
LiquidCrystal::blink ()
|
||||
{
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command (LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void
|
||||
LiquidCrystal::scrollDisplayLeft (void)
|
||||
{
|
||||
command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void
|
||||
LiquidCrystal::scrollDisplayRight (void)
|
||||
{
|
||||
command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void
|
||||
LiquidCrystal::leftToRight (void)
|
||||
{
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command (LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void
|
||||
LiquidCrystal::rightToLeft (void)
|
||||
{
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command (LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void
|
||||
LiquidCrystal::autoscroll (void)
|
||||
{
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command (LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void
|
||||
LiquidCrystal::noAutoscroll (void)
|
||||
{
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command (LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void
|
||||
LiquidCrystal::createChar (uint8_t location, uint8_t charmap[])
|
||||
{
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command (LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
write (charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void
|
||||
LiquidCrystal::command (uint8_t value)
|
||||
{
|
||||
send (value, LOW);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
LiquidCrystal::write (uint8_t value)
|
||||
{
|
||||
send (value, HIGH);
|
||||
return 1; // assume sucess
|
||||
}
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data
|
||||
void
|
||||
LiquidCrystal::send (uint8_t value, uint8_t mode)
|
||||
{
|
||||
rs_pin->write (mode); // digitalWrite(_rs_pin, mode);
|
||||
|
||||
write4bits (value >> 4);
|
||||
write4bits (value);
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::pulseEnable (void)
|
||||
{
|
||||
enable_pin->write (false); // digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds (1);
|
||||
enable_pin->write (true); // digitalWrite(_enable_pin, HIGH);
|
||||
delayMicroseconds (1); // enable pulse must be >450ns
|
||||
enable_pin->write (false); // digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds (100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void
|
||||
LiquidCrystal::write4bits (uint8_t value)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
data_pins[i]->write (
|
||||
(value >> i)
|
||||
& 0x01); // digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable ();
|
||||
}
|
||||
952
esp-vent-main/src/Modbus/ModbusMaster.cpp
Normal file
952
esp-vent-main/src/Modbus/ModbusMaster.cpp
Normal file
@@ -0,0 +1,952 @@
|
||||
/**
|
||||
@file
|
||||
Arduino library for communicating with Modbus slaves over RS232/485 (via RTU
|
||||
protocol).
|
||||
*/
|
||||
/*
|
||||
|
||||
ModbusMaster.cpp - Arduino library for communicating with Modbus slaves
|
||||
over RS232/485 (via RTU protocol).
|
||||
|
||||
This file is part of ModbusMaster.
|
||||
|
||||
ModbusMaster 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.
|
||||
|
||||
ModbusMaster 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 ModbusMaster. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Doc Walker (Rx)
|
||||
Copyright © 2009-2013 Doc Walker <4-20ma at wvfans dot net>
|
||||
|
||||
*/
|
||||
|
||||
/* _____PROJECT INCLUDES_____________________________________________________
|
||||
*/
|
||||
#include "Modbus/ModbusMaster.h"
|
||||
#include "Modbus/crc16.h"
|
||||
|
||||
/* _____GLOBAL VARIABLES_____________________________________________________
|
||||
*/
|
||||
#if defined(ARDUINO_ARCH_AVR)
|
||||
HardwareSerial *MBSerial = &Serial; ///< Pointer to Serial class object
|
||||
#elif defined(ARDUINO_ARCH_SAM)
|
||||
UARTClass *MBSerial = &Serial; ///< Pointer to Serial class object
|
||||
#else
|
||||
// In the case of undefined Serial the code should still function
|
||||
// #error "This library only supports boards with an AVR or SAM processor.
|
||||
// Please open an issue at https://github.com/4-20ma/ModbusMaster/issues and
|
||||
// indicate which processor/platform you're using."
|
||||
#endif
|
||||
|
||||
/* _____PUBLIC FUNCTIONS_____________________________________________________
|
||||
*/
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
Creates class object using default serial port 0, Modbus slave ID 1.
|
||||
|
||||
@ingroup setup
|
||||
*/
|
||||
ModbusMaster::ModbusMaster (void)
|
||||
{
|
||||
_u8SerialPort = 0;
|
||||
_u8MBSlave = 1;
|
||||
_u16BaudRate = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
Creates class object using default serial port 0, specified Modbus slave ID.
|
||||
|
||||
@overload void ModbusMaster::ModbusMaster(uint8_t u8MBSlave)
|
||||
@param u8MBSlave Modbus slave ID (1..255)
|
||||
@ingroup setup
|
||||
*/
|
||||
ModbusMaster::ModbusMaster (uint8_t u8MBSlave)
|
||||
{
|
||||
_u8SerialPort = 0;
|
||||
_u8MBSlave = u8MBSlave;
|
||||
_u16BaudRate = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
Creates class object using specified serial port, Modbus slave ID.
|
||||
|
||||
@overload void ModbusMaster::ModbusMaster(uint8_t u8SerialPort, uint8_t
|
||||
u8MBSlave)
|
||||
@param u8SerialPort serial port (Serial, Serial1..Serial3)
|
||||
@param u8MBSlave Modbus slave ID (1..255)
|
||||
@ingroup setup
|
||||
*/
|
||||
ModbusMaster::ModbusMaster (uint8_t u8SerialPort, uint8_t u8MBSlave)
|
||||
{
|
||||
_u8SerialPort = (u8SerialPort > 3) ? 0 : u8SerialPort;
|
||||
_u8MBSlave = u8MBSlave;
|
||||
_u16BaudRate = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize class object.
|
||||
|
||||
Sets up the serial port using default 19200 baud rate.
|
||||
Call once class has been instantiated, typically within setup().
|
||||
|
||||
@ingroup setup
|
||||
*/
|
||||
void
|
||||
ModbusMaster::begin (void)
|
||||
{
|
||||
begin (19200);
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize class object.
|
||||
|
||||
Sets up the serial port using specified baud rate.
|
||||
Call once class has been instantiated, typically within setup().
|
||||
|
||||
@overload ModbusMaster::begin(uint16_t u16BaudRate)
|
||||
@param u16BaudRate baud rate, in standard increments (300..115200)
|
||||
@ingroup setup
|
||||
*/
|
||||
void
|
||||
ModbusMaster::begin (uint16_t u16BaudRate)
|
||||
{
|
||||
// txBuffer = (uint16_t*) calloc(ku8MaxBufferSize, sizeof(uint16_t));
|
||||
_u8TransmitBufferIndex = 0;
|
||||
u16TransmitBufferLength = 0;
|
||||
|
||||
#if 0
|
||||
switch(_u8SerialPort)
|
||||
{
|
||||
#if defined(UBRR1H)
|
||||
case 1:
|
||||
MBSerial = &Serial1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(UBRR2H)
|
||||
case 2:
|
||||
MBSerial = &Serial2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(UBRR3H)
|
||||
case 3:
|
||||
MBSerial = &Serial3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 0:
|
||||
default:
|
||||
MBSerial = &Serial;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MBSerial == NULL)
|
||||
MBSerial = new SerialPort;
|
||||
if (u16BaudRate != _u16BaudRate)
|
||||
{
|
||||
_u16BaudRate = u16BaudRate;
|
||||
MBSerial->begin (u16BaudRate);
|
||||
}
|
||||
_idle = NULL;
|
||||
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
// pinMode(4, OUTPUT);
|
||||
// pinMode(5, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ModbusMaster::beginTransmission (uint16_t u16Address)
|
||||
{
|
||||
_u16WriteAddress = u16Address;
|
||||
_u8TransmitBufferIndex = 0;
|
||||
u16TransmitBufferLength = 0;
|
||||
}
|
||||
|
||||
// eliminate this function in favor of using existing MB request functions
|
||||
uint8_t
|
||||
ModbusMaster::requestFrom (uint16_t address, uint16_t quantity)
|
||||
{
|
||||
uint8_t read;
|
||||
read = 1; // krl: added this to prevent warning. This method is not called
|
||||
// anywhere...
|
||||
// clamp to buffer length
|
||||
if (quantity > ku8MaxBufferSize)
|
||||
{
|
||||
quantity = ku8MaxBufferSize;
|
||||
}
|
||||
// set rx buffer iterator vars
|
||||
_u8ResponseBufferIndex = 0;
|
||||
_u8ResponseBufferLength = read;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
void
|
||||
ModbusMaster::sendBit (bool data)
|
||||
{
|
||||
uint8_t txBitIndex = u16TransmitBufferLength % 16;
|
||||
if ((u16TransmitBufferLength >> 4) < ku8MaxBufferSize)
|
||||
{
|
||||
if (0 == txBitIndex)
|
||||
{
|
||||
_u16TransmitBuffer[_u8TransmitBufferIndex] = 0;
|
||||
}
|
||||
bitWrite (_u16TransmitBuffer[_u8TransmitBufferIndex], txBitIndex, data);
|
||||
u16TransmitBufferLength++;
|
||||
_u8TransmitBufferIndex = u16TransmitBufferLength >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ModbusMaster::send (uint16_t data)
|
||||
{
|
||||
if (_u8TransmitBufferIndex < ku8MaxBufferSize)
|
||||
{
|
||||
_u16TransmitBuffer[_u8TransmitBufferIndex++] = data;
|
||||
u16TransmitBufferLength = _u8TransmitBufferIndex << 4;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ModbusMaster::send (uint32_t data)
|
||||
{
|
||||
send (lowWord (data));
|
||||
send (highWord (data));
|
||||
}
|
||||
|
||||
void
|
||||
ModbusMaster::send (uint8_t data)
|
||||
{
|
||||
send (word (data));
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ModbusMaster::available (void)
|
||||
{
|
||||
return _u8ResponseBufferLength - _u8ResponseBufferIndex;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ModbusMaster::receive (void)
|
||||
{
|
||||
if (_u8ResponseBufferIndex < _u8ResponseBufferLength)
|
||||
{
|
||||
return _u16ResponseBuffer[_u8ResponseBufferIndex++];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set idle time callback function (cooperative multitasking).
|
||||
|
||||
This function gets called in the idle time between transmission of data
|
||||
and response from slave. Do not call functions that read from the serial
|
||||
buffer that is used by ModbusMaster. Use of i2c/TWI, 1-Wire, other
|
||||
serial ports, etc. is permitted within callback function.
|
||||
|
||||
@see ModbusMaster::ModbusMasterTransaction()
|
||||
*/
|
||||
void
|
||||
ModbusMaster::idle (void (*idle) ())
|
||||
{
|
||||
_idle = idle;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve data from response buffer.
|
||||
|
||||
@see ModbusMaster::clearResponseBuffer()
|
||||
@param u8Index index of response buffer array (0x00..0x3F)
|
||||
@return value in position u8Index of response buffer (0x0000..0xFFFF)
|
||||
@ingroup buffer
|
||||
*/
|
||||
uint16_t
|
||||
ModbusMaster::getResponseBuffer (uint8_t u8Index)
|
||||
{
|
||||
if (u8Index < ku8MaxBufferSize)
|
||||
{
|
||||
return _u16ResponseBuffer[u8Index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Clear Modbus response buffer.
|
||||
|
||||
@see ModbusMaster::getResponseBuffer(uint8_t u8Index)
|
||||
@ingroup buffer
|
||||
*/
|
||||
void
|
||||
ModbusMaster::clearResponseBuffer ()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ku8MaxBufferSize; i++)
|
||||
{
|
||||
_u16ResponseBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Place data in transmit buffer.
|
||||
|
||||
@see ModbusMaster::clearTransmitBuffer()
|
||||
@param u8Index index of transmit buffer array (0x00..0x3F)
|
||||
@param u16Value value to place in position u8Index of transmit buffer
|
||||
(0x0000..0xFFFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup buffer
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::setTransmitBuffer (uint8_t u8Index, uint16_t u16Value)
|
||||
{
|
||||
if (u8Index < ku8MaxBufferSize)
|
||||
{
|
||||
_u16TransmitBuffer[u8Index] = u16Value;
|
||||
return ku8MBSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ku8MBIllegalDataAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Clear Modbus transmit buffer.
|
||||
|
||||
@see ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value)
|
||||
@ingroup buffer
|
||||
*/
|
||||
void
|
||||
ModbusMaster::clearTransmitBuffer ()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ku8MaxBufferSize; i++)
|
||||
{
|
||||
_u16TransmitBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x01 Read Coils.
|
||||
|
||||
This function code is used to read from 1 to 2000 contiguous status of
|
||||
coils in a remote device. The request specifies the starting address,
|
||||
i.e. the address of the first coil specified, and the number of coils.
|
||||
Coils are addressed starting at zero.
|
||||
|
||||
The coils in the response buffer are packed as one coil per bit of the
|
||||
data field. Status is indicated as 1=ON and 0=OFF. The LSB of the first
|
||||
data word contains the output addressed in the query. The other coils
|
||||
follow toward the high order end of this word and from low order to high
|
||||
order in subsequent words.
|
||||
|
||||
If the returned quantity is not a multiple of sixteen, the remaining
|
||||
bits in the final data word will be padded with zeros (toward the high
|
||||
order end of the word).
|
||||
|
||||
@param u16ReadAddress address of first coil (0x0000..0xFFFF)
|
||||
@param u16BitQty quantity of coils to read (1..2000, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::readCoils (uint16_t u16ReadAddress, uint16_t u16BitQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16BitQty;
|
||||
return ModbusMasterTransaction (ku8MBReadCoils);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x02 Read Discrete Inputs.
|
||||
|
||||
This function code is used to read from 1 to 2000 contiguous status of
|
||||
discrete inputs in a remote device. The request specifies the starting
|
||||
address, i.e. the address of the first input specified, and the number
|
||||
of inputs. Discrete inputs are addressed starting at zero.
|
||||
|
||||
The discrete inputs in the response buffer are packed as one input per
|
||||
bit of the data field. Status is indicated as 1=ON; 0=OFF. The LSB of
|
||||
the first data word contains the input addressed in the query. The other
|
||||
inputs follow toward the high order end of this word, and from low order
|
||||
to high order in subsequent words.
|
||||
|
||||
If the returned quantity is not a multiple of sixteen, the remaining
|
||||
bits in the final data word will be padded with zeros (toward the high
|
||||
order end of the word).
|
||||
|
||||
@param u16ReadAddress address of first discrete input (0x0000..0xFFFF)
|
||||
@param u16BitQty quantity of discrete inputs to read (1..2000, enforced by
|
||||
remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::readDiscreteInputs (uint16_t u16ReadAddress, uint16_t u16BitQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16BitQty;
|
||||
return ModbusMasterTransaction (ku8MBReadDiscreteInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x03 Read Holding Registers.
|
||||
|
||||
This function code is used to read the contents of a contiguous block of
|
||||
holding registers in a remote device. The request specifies the starting
|
||||
register address and the number of registers. Registers are addressed
|
||||
starting at zero.
|
||||
|
||||
The register data in the response buffer is packed as one word per
|
||||
register.
|
||||
|
||||
@param u16ReadAddress address of the first holding register (0x0000..0xFFFF)
|
||||
@param u16ReadQty quantity of holding registers to read (1..125, enforced by
|
||||
remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::readHoldingRegisters (uint16_t u16ReadAddress,
|
||||
uint16_t u16ReadQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
return ModbusMasterTransaction (ku8MBReadHoldingRegisters);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x04 Read Input Registers.
|
||||
|
||||
This function code is used to read from 1 to 125 contiguous input
|
||||
registers in a remote device. The request specifies the starting
|
||||
register address and the number of registers. Registers are addressed
|
||||
starting at zero.
|
||||
|
||||
The register data in the response buffer is packed as one word per
|
||||
register.
|
||||
|
||||
@param u16ReadAddress address of the first input register (0x0000..0xFFFF)
|
||||
@param u16ReadQty quantity of input registers to read (1..125, enforced by
|
||||
remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::readInputRegisters (uint16_t u16ReadAddress, uint8_t u16ReadQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
return ModbusMasterTransaction (ku8MBReadInputRegisters);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x05 Write Single Coil.
|
||||
|
||||
This function code is used to write a single output to either ON or OFF
|
||||
in a remote device. The requested ON/OFF state is specified by a
|
||||
constant in the state field. A non-zero value requests the output to be
|
||||
ON and a value of 0 requests it to be OFF. The request specifies the
|
||||
address of the coil to be forced. Coils are addressed starting at zero.
|
||||
|
||||
@param u16WriteAddress address of the coil (0x0000..0xFFFF)
|
||||
@param u8State 0=OFF, non-zero=ON (0x00..0xFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::writeSingleCoil (uint16_t u16WriteAddress, uint8_t u8State)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = (u8State ? 0xFF00 : 0x0000);
|
||||
return ModbusMasterTransaction (ku8MBWriteSingleCoil);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x06 Write Single Register.
|
||||
|
||||
This function code is used to write a single holding register in a
|
||||
remote device. The request specifies the address of the register to be
|
||||
written. Registers are addressed starting at zero.
|
||||
|
||||
@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
|
||||
@param u16WriteValue value to be written to holding register (0x0000..0xFFFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::writeSingleRegister (uint16_t u16WriteAddress,
|
||||
uint16_t u16WriteValue)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = 0;
|
||||
_u16TransmitBuffer[0] = u16WriteValue;
|
||||
return ModbusMasterTransaction (ku8MBWriteSingleRegister);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x0F Write Multiple Coils.
|
||||
|
||||
This function code is used to force each coil in a sequence of coils to
|
||||
either ON or OFF in a remote device. The request specifies the coil
|
||||
references to be forced. Coils are addressed starting at zero.
|
||||
|
||||
The requested ON/OFF states are specified by contents of the transmit
|
||||
buffer. A logical '1' in a bit position of the buffer requests the
|
||||
corresponding output to be ON. A logical '0' requests it to be OFF.
|
||||
|
||||
@param u16WriteAddress address of the first coil (0x0000..0xFFFF)
|
||||
@param u16BitQty quantity of coils to write (1..2000, enforced by remote
|
||||
device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::writeMultipleCoils (uint16_t u16WriteAddress, uint16_t u16BitQty)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = u16BitQty;
|
||||
return ModbusMasterTransaction (ku8MBWriteMultipleCoils);
|
||||
}
|
||||
uint8_t
|
||||
ModbusMaster::writeMultipleCoils ()
|
||||
{
|
||||
_u16WriteQty = u16TransmitBufferLength;
|
||||
return ModbusMasterTransaction (ku8MBWriteMultipleCoils);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x10 Write Multiple Registers.
|
||||
|
||||
This function code is used to write a block of contiguous registers (1
|
||||
to 123 registers) in a remote device.
|
||||
|
||||
The requested written values are specified in the transmit buffer. Data
|
||||
is packed as one word per register.
|
||||
|
||||
@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
|
||||
@param u16WriteQty quantity of holding registers to write (1..123, enforced by
|
||||
remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::writeMultipleRegisters (uint16_t u16WriteAddress,
|
||||
uint16_t u16WriteQty)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = u16WriteQty;
|
||||
return ModbusMasterTransaction (ku8MBWriteMultipleRegisters);
|
||||
}
|
||||
|
||||
// new version based on Wire.h
|
||||
uint8_t
|
||||
ModbusMaster::writeMultipleRegisters ()
|
||||
{
|
||||
_u16WriteQty = _u8TransmitBufferIndex;
|
||||
return ModbusMasterTransaction (ku8MBWriteMultipleRegisters);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x16 Mask Write Register.
|
||||
|
||||
This function code is used to modify the contents of a specified holding
|
||||
register using a combination of an AND mask, an OR mask, and the
|
||||
register's current contents. The function can be used to set or clear
|
||||
individual bits in the register.
|
||||
|
||||
The request specifies the holding register to be written, the data to be
|
||||
used as the AND mask, and the data to be used as the OR mask. Registers
|
||||
are addressed starting at zero.
|
||||
|
||||
The function's algorithm is:
|
||||
|
||||
Result = (Current Contents && And_Mask) || (Or_Mask && (~And_Mask))
|
||||
|
||||
@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
|
||||
@param u16AndMask AND mask (0x0000..0xFFFF)
|
||||
@param u16OrMask OR mask (0x0000..0xFFFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::maskWriteRegister (uint16_t u16WriteAddress, uint16_t u16AndMask,
|
||||
uint16_t u16OrMask)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16TransmitBuffer[0] = u16AndMask;
|
||||
_u16TransmitBuffer[1] = u16OrMask;
|
||||
return ModbusMasterTransaction (ku8MBMaskWriteRegister);
|
||||
}
|
||||
|
||||
/**
|
||||
Modbus function 0x17 Read Write Multiple Registers.
|
||||
|
||||
This function code performs a combination of one read operation and one
|
||||
write operation in a single MODBUS transaction. The write operation is
|
||||
performed before the read. Holding registers are addressed starting at
|
||||
zero.
|
||||
|
||||
The request specifies the starting address and number of holding
|
||||
registers to be read as well as the starting address, and the number of
|
||||
holding registers. The data to be written is specified in the transmit
|
||||
buffer.
|
||||
|
||||
@param u16ReadAddress address of the first holding register (0x0000..0xFFFF)
|
||||
@param u16ReadQty quantity of holding registers to read (1..125, enforced by
|
||||
remote device)
|
||||
@param u16WriteAddress address of the first holding register (0x0000..0xFFFF)
|
||||
@param u16WriteQty quantity of holding registers to write (1..121, enforced by
|
||||
remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::readWriteMultipleRegisters (uint16_t u16ReadAddress,
|
||||
uint16_t u16ReadQty,
|
||||
uint16_t u16WriteAddress,
|
||||
uint16_t u16WriteQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = u16WriteQty;
|
||||
return ModbusMasterTransaction (ku8MBReadWriteMultipleRegisters);
|
||||
}
|
||||
uint8_t
|
||||
ModbusMaster::readWriteMultipleRegisters (uint16_t u16ReadAddress,
|
||||
uint16_t u16ReadQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
_u16WriteQty = _u8TransmitBufferIndex;
|
||||
return ModbusMasterTransaction (ku8MBReadWriteMultipleRegisters);
|
||||
}
|
||||
|
||||
/* _____PRIVATE FUNCTIONS____________________________________________________
|
||||
*/
|
||||
/**
|
||||
Modbus transaction engine.
|
||||
Sequence:
|
||||
- assemble Modbus Request Application Data Unit (ADU),
|
||||
based on particular function called
|
||||
- transmit request over selected serial port
|
||||
- wait for/retrieve response
|
||||
- evaluate/disassemble response
|
||||
- return status (success/exception)
|
||||
|
||||
@param u8MBFunction Modbus function (0x01..0xFF)
|
||||
@return 0 on success; exception number on failure
|
||||
*/
|
||||
uint8_t
|
||||
ModbusMaster::ModbusMasterTransaction (uint8_t u8MBFunction)
|
||||
{
|
||||
uint8_t u8ModbusADU[256];
|
||||
uint8_t u8ModbusADUSize = 0;
|
||||
uint8_t i, u8Qty;
|
||||
uint16_t u16CRC;
|
||||
uint32_t u32StartTime;
|
||||
uint8_t u8BytesLeft = 8;
|
||||
uint8_t u8MBStatus = ku8MBSuccess;
|
||||
|
||||
// assemble Modbus Request Application Data Unit
|
||||
u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave;
|
||||
u8ModbusADU[u8ModbusADUSize++] = u8MBFunction;
|
||||
|
||||
switch (u8MBFunction)
|
||||
{
|
||||
case ku8MBReadCoils:
|
||||
case ku8MBReadDiscreteInputs:
|
||||
case ku8MBReadInputRegisters:
|
||||
case ku8MBReadHoldingRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16ReadAddress);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16ReadAddress);
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16ReadQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16ReadQty);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (u8MBFunction)
|
||||
{
|
||||
case ku8MBWriteSingleCoil:
|
||||
case ku8MBMaskWriteRegister:
|
||||
case ku8MBWriteMultipleCoils:
|
||||
case ku8MBWriteSingleRegister:
|
||||
case ku8MBWriteMultipleRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16WriteAddress);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16WriteAddress);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (u8MBFunction)
|
||||
{
|
||||
case ku8MBWriteSingleCoil:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16WriteQty);
|
||||
break;
|
||||
|
||||
case ku8MBWriteSingleRegister:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16TransmitBuffer[0]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16TransmitBuffer[0]);
|
||||
break;
|
||||
|
||||
case ku8MBWriteMultipleCoils:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16WriteQty);
|
||||
u8Qty = (_u16WriteQty % 8) ? ((_u16WriteQty >> 3) + 1)
|
||||
: (_u16WriteQty >> 3);
|
||||
u8ModbusADU[u8ModbusADUSize++] = u8Qty;
|
||||
for (i = 0; i < u8Qty; i++)
|
||||
{
|
||||
switch (i % 2)
|
||||
{
|
||||
case 0: // i is even
|
||||
u8ModbusADU[u8ModbusADUSize++]
|
||||
= lowByte (_u16TransmitBuffer[i >> 1]);
|
||||
break;
|
||||
|
||||
case 1: // i is odd
|
||||
u8ModbusADU[u8ModbusADUSize++]
|
||||
= highByte (_u16TransmitBuffer[i >> 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ku8MBWriteMultipleRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16WriteQty << 1);
|
||||
|
||||
for (i = 0; i < lowByte (_u16WriteQty); i++)
|
||||
{
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16TransmitBuffer[i]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16TransmitBuffer[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ku8MBMaskWriteRegister:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16TransmitBuffer[0]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16TransmitBuffer[0]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (_u16TransmitBuffer[1]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (_u16TransmitBuffer[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
// append CRC
|
||||
u16CRC = 0xFFFF;
|
||||
for (i = 0; i < u8ModbusADUSize; i++)
|
||||
{
|
||||
u16CRC = crc16_update (u16CRC, u8ModbusADU[i]);
|
||||
}
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte (u16CRC);
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte (u16CRC);
|
||||
u8ModbusADU[u8ModbusADUSize] = 0;
|
||||
|
||||
// flush receive buffer before transmitting request
|
||||
while (MBSerial->read () != -1)
|
||||
;
|
||||
|
||||
#if 0
|
||||
// transmit request
|
||||
for (i = 0; i < u8ModbusADUSize; i++)
|
||||
{
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
MBSerial->write(u8ModbusADU[i]);
|
||||
#else
|
||||
MBSerial->print(u8ModbusADU[i], BYTE);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
MBSerial->write ((char *)u8ModbusADU, u8ModbusADUSize);
|
||||
#endif
|
||||
// printf("TX: %02X\n", u8ModbusADU[0]);
|
||||
u8ModbusADUSize = 0;
|
||||
MBSerial->flush (); // flush transmit buffer
|
||||
|
||||
// loop until we run out of time or bytes, or an error occurs
|
||||
u32StartTime = millis ();
|
||||
while (u8BytesLeft && !u8MBStatus)
|
||||
{
|
||||
if (MBSerial->available ())
|
||||
{
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite (4, true);
|
||||
#endif
|
||||
u8ModbusADU[u8ModbusADUSize++] = MBSerial->read ();
|
||||
u8BytesLeft--;
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite (4, false);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite (5, true);
|
||||
#endif
|
||||
if (_idle)
|
||||
{
|
||||
_idle ();
|
||||
}
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite (5, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
// evaluate slave ID, function code once enough bytes have been read
|
||||
if (u8ModbusADUSize == 5)
|
||||
{
|
||||
// verify response is for correct Modbus slave
|
||||
if (u8ModbusADU[0] != _u8MBSlave)
|
||||
{
|
||||
u8MBStatus = ku8MBInvalidSlaveID;
|
||||
break;
|
||||
}
|
||||
|
||||
// verify response is for correct Modbus function code (mask
|
||||
// exception bit 7)
|
||||
if ((u8ModbusADU[1] & 0x7F) != u8MBFunction)
|
||||
{
|
||||
u8MBStatus = ku8MBInvalidFunction;
|
||||
break;
|
||||
}
|
||||
|
||||
// check whether Modbus exception occurred; return Modbus Exception
|
||||
// Code
|
||||
if (bitRead (u8ModbusADU[1], 7))
|
||||
{
|
||||
u8MBStatus = u8ModbusADU[2];
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate returned Modbus function code
|
||||
switch (u8ModbusADU[1])
|
||||
{
|
||||
case ku8MBReadCoils:
|
||||
case ku8MBReadDiscreteInputs:
|
||||
case ku8MBReadInputRegisters:
|
||||
case ku8MBReadHoldingRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8BytesLeft = u8ModbusADU[2];
|
||||
break;
|
||||
|
||||
case ku8MBWriteSingleCoil:
|
||||
case ku8MBWriteMultipleCoils:
|
||||
case ku8MBWriteSingleRegister:
|
||||
case ku8MBWriteMultipleRegisters:
|
||||
u8BytesLeft = 3;
|
||||
break;
|
||||
|
||||
case ku8MBMaskWriteRegister:
|
||||
u8BytesLeft = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((millis () - u32StartTime) > ku16MBResponseTimeout)
|
||||
{
|
||||
u8MBStatus = ku8MBResponseTimedOut;
|
||||
}
|
||||
}
|
||||
|
||||
// verify response is large enough to inspect further
|
||||
if (!u8MBStatus && u8ModbusADUSize >= 5)
|
||||
{
|
||||
// calculate CRC
|
||||
u16CRC = 0xFFFF;
|
||||
for (i = 0; i < (u8ModbusADUSize - 2); i++)
|
||||
{
|
||||
u16CRC = crc16_update (u16CRC, u8ModbusADU[i]);
|
||||
}
|
||||
|
||||
// verify CRC
|
||||
if (!u8MBStatus
|
||||
&& (lowByte (u16CRC) != u8ModbusADU[u8ModbusADUSize - 2]
|
||||
|| highByte (u16CRC) != u8ModbusADU[u8ModbusADUSize - 1]))
|
||||
{
|
||||
u8MBStatus = ku8MBInvalidCRC;
|
||||
}
|
||||
}
|
||||
|
||||
// disassemble ADU into words
|
||||
if (!u8MBStatus)
|
||||
{
|
||||
// evaluate returned Modbus function code
|
||||
switch (u8ModbusADU[1])
|
||||
{
|
||||
case ku8MBReadCoils:
|
||||
case ku8MBReadDiscreteInputs:
|
||||
// load bytes into word; response bytes are ordered L, H, L, H, ...
|
||||
for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
|
||||
{
|
||||
if (i < ku8MaxBufferSize)
|
||||
{
|
||||
_u16ResponseBuffer[i]
|
||||
= word (u8ModbusADU[2 * i + 4], u8ModbusADU[2 * i + 3]);
|
||||
}
|
||||
|
||||
_u8ResponseBufferLength = i;
|
||||
}
|
||||
|
||||
// in the event of an odd number of bytes, load last byte into
|
||||
// zero-padded word
|
||||
if (u8ModbusADU[2] % 2)
|
||||
{
|
||||
if (i < ku8MaxBufferSize)
|
||||
{
|
||||
_u16ResponseBuffer[i] = word (0, u8ModbusADU[2 * i + 3]);
|
||||
}
|
||||
|
||||
_u8ResponseBufferLength = i + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ku8MBReadInputRegisters:
|
||||
case ku8MBReadHoldingRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
// load bytes into word; response bytes are ordered H, L, H, L, ...
|
||||
for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
|
||||
{
|
||||
if (i < ku8MaxBufferSize)
|
||||
{
|
||||
_u16ResponseBuffer[i]
|
||||
= word (u8ModbusADU[2 * i + 3], u8ModbusADU[2 * i + 4]);
|
||||
}
|
||||
|
||||
_u8ResponseBufferLength = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_u8TransmitBufferIndex = 0;
|
||||
u16TransmitBufferLength = 0;
|
||||
_u8ResponseBufferIndex = 0;
|
||||
return u8MBStatus;
|
||||
}
|
||||
29
esp-vent-main/src/Modbus/ModbusRegister.cpp
Normal file
29
esp-vent-main/src/Modbus/ModbusRegister.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "Modbus/ModbusRegister.h"
|
||||
|
||||
ModbusRegister::ModbusRegister(ModbusMaster *master, int address, bool holdingRegister)
|
||||
:m(master), addr(address), hr(holdingRegister) {
|
||||
// TODO Auto-generated constructor stub
|
||||
|
||||
}
|
||||
|
||||
ModbusRegister::~ModbusRegister() {
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
int ModbusRegister::read() {
|
||||
uint8_t result = hr ? m->readHoldingRegisters(addr, 1) : m->readInputRegisters(addr, 1) ;
|
||||
// check if we were able to read
|
||||
if (result == m->ku8MBSuccess) {
|
||||
return m->getResponseBuffer(0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ModbusRegister::write(int value)
|
||||
{
|
||||
// write only if not
|
||||
volatile uint8_t error = 15;
|
||||
if(hr)
|
||||
error = m->writeSingleRegister(addr, value);
|
||||
|
||||
}
|
||||
49
esp-vent-main/src/Modbus/SerialPort.cpp
Normal file
49
esp-vent-main/src/Modbus/SerialPort.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "Modbus/SerialPort.h"
|
||||
|
||||
|
||||
SerialPort::SerialPort() {
|
||||
if(!u) {
|
||||
LpcPinMap none = {-1, -1}; // unused pin has negative values in it
|
||||
LpcPinMap txpin = { 0, 28 }; // transmit pin that goes to rs485 driver chip
|
||||
LpcPinMap rxpin = { 0, 24 }; // receive pin that goes to rs485 driver chip
|
||||
LpcPinMap rtspin = { 1, 0 }; // handshake pin that is used to set tranmitter direction
|
||||
LpcUartConfig cfg = { LPC_USART1, 9600, UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_2, true, txpin, rxpin, rtspin, none };
|
||||
u = new LpcUart(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
LpcUart *SerialPort::u = nullptr;
|
||||
|
||||
SerialPort::~SerialPort() {
|
||||
/* DeInitialize UART peripheral */
|
||||
delete u;
|
||||
}
|
||||
|
||||
int SerialPort::available() {
|
||||
return u->peek();
|
||||
}
|
||||
|
||||
void SerialPort::begin(int speed) {
|
||||
u->speed(speed);
|
||||
|
||||
}
|
||||
|
||||
int SerialPort::read() {
|
||||
char byte;
|
||||
if(u->read(byte)> 0) return (byte);
|
||||
return -1;
|
||||
}
|
||||
int SerialPort::write(const char* buf, int len) {
|
||||
return u->write(buf, len);
|
||||
}
|
||||
|
||||
int SerialPort::print(int val, int format) {
|
||||
// here only to maintain compatibility with Arduino interface
|
||||
(void) val;
|
||||
(void) format;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void SerialPort::flush() {
|
||||
while(!u->txempty()) __WFI();
|
||||
}
|
||||
214
esp-vent-main/src/Modbus/Uart.cpp
Normal file
214
esp-vent-main/src/Modbus/Uart.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
#include <cstring>
|
||||
#include "Modbus/Uart.h"
|
||||
|
||||
static LpcUart *u0;
|
||||
static LpcUart *u1;
|
||||
static LpcUart *u2;
|
||||
|
||||
extern "C" {
|
||||
/**
|
||||
* @brief UART interrupt handler using ring buffers
|
||||
* @return Nothing
|
||||
*/
|
||||
void UART0_IRQHandler(void)
|
||||
{
|
||||
if(u0) u0->isr();
|
||||
}
|
||||
|
||||
void UART1_IRQHandler(void)
|
||||
{
|
||||
if(u1) u1->isr();
|
||||
}
|
||||
|
||||
void UART2_IRQHandler(void)
|
||||
{
|
||||
if(u2) u2->isr();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LpcUart::isr() {
|
||||
Chip_UART_IRQRBHandler(uart, &rxring, &txring);
|
||||
}
|
||||
|
||||
bool LpcUart::init = false;
|
||||
|
||||
LpcUart::LpcUart(const LpcUartConfig &cfg) {
|
||||
CHIP_SWM_PIN_MOVABLE_T tx;
|
||||
CHIP_SWM_PIN_MOVABLE_T rx;
|
||||
CHIP_SWM_PIN_MOVABLE_T cts;
|
||||
CHIP_SWM_PIN_MOVABLE_T rts;
|
||||
bool use_rts = (cfg.rts.port >= 0);
|
||||
bool use_cts = (cfg.cts.port >= 0);
|
||||
|
||||
if(!init) {
|
||||
init = true;
|
||||
/* Before setting up the UART, the global UART clock for USARTS 1-4
|
||||
* must first be setup. This requires setting the UART divider and
|
||||
* the UART base clock rate to 16x the maximum UART rate for all
|
||||
* UARTs.
|
||||
* */
|
||||
/* Use main clock rate as base for UART baud rate divider */
|
||||
Chip_Clock_SetUARTBaseClockRate(Chip_Clock_GetMainClockRate(), false);
|
||||
}
|
||||
|
||||
uart = nullptr; // set default value before checking which UART to configure
|
||||
|
||||
if(cfg.pUART == LPC_USART0) {
|
||||
if(u0) return; // already exists
|
||||
else u0 = this;
|
||||
tx = SWM_UART0_TXD_O;
|
||||
rx = SWM_UART0_RXD_I;
|
||||
rts = SWM_UART0_RTS_O;
|
||||
cts = SWM_UART0_CTS_I;
|
||||
irqn = UART0_IRQn;
|
||||
}
|
||||
else if(cfg.pUART == LPC_USART1) {
|
||||
if(u1) return; // already exists
|
||||
else u1 = this;
|
||||
tx = SWM_UART1_TXD_O;
|
||||
rx = SWM_UART1_RXD_I;
|
||||
rts = SWM_UART1_RTS_O;
|
||||
cts = SWM_UART1_CTS_I;
|
||||
irqn = UART1_IRQn;
|
||||
}
|
||||
else if(cfg.pUART == LPC_USART2) {
|
||||
if(u2) return; // already exists
|
||||
else u2 = this;
|
||||
tx = SWM_UART2_TXD_O;
|
||||
rx = SWM_UART2_RXD_I;
|
||||
use_rts = false; // UART2 does not support handshakes
|
||||
use_cts = false;
|
||||
irqn = UART2_IRQn;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
uart = cfg.pUART; // set the actual value after validity checking
|
||||
|
||||
|
||||
if(cfg.tx.port >= 0) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.tx.port, cfg.tx.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(tx, cfg.tx.port, cfg.tx.pin);
|
||||
}
|
||||
|
||||
if(cfg.rx.port >= 0) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.rx.port, cfg.rx.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(rx, cfg.rx.port, cfg.rx.pin);
|
||||
}
|
||||
|
||||
if(use_cts) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.cts.port, cfg.cts.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(cts, cfg.cts.port, cfg.cts.pin);
|
||||
}
|
||||
|
||||
if(use_rts) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.rts.port, cfg.rts.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(rts, cfg.rts.port, cfg.rts.pin);
|
||||
}
|
||||
|
||||
|
||||
/* Setup UART */
|
||||
Chip_UART_Init(uart);
|
||||
Chip_UART_ConfigData(uart, cfg.data);
|
||||
Chip_UART_SetBaud(uart, cfg.speed);
|
||||
|
||||
if(use_rts && cfg.rs485) {
|
||||
uart->CFG |= (1 << 20); // enable rs485 mode
|
||||
//uart->CFG |= (1 << 18); // OE turnaraound time
|
||||
uart->CFG |= (1 << 21);// driver enable polarity (active high)
|
||||
}
|
||||
|
||||
Chip_UART_Enable(uart);
|
||||
Chip_UART_TXEnable(uart);
|
||||
|
||||
/* Before using the ring buffers, initialize them using the ring
|
||||
buffer init function */
|
||||
RingBuffer_Init(&rxring, rxbuff, 1, UART_RB_SIZE);
|
||||
RingBuffer_Init(&txring, txbuff, 1, UART_RB_SIZE);
|
||||
|
||||
|
||||
/* Enable receive data and line status interrupt */
|
||||
Chip_UART_IntEnable(uart, UART_INTEN_RXRDY);
|
||||
Chip_UART_IntDisable(uart, UART_INTEN_TXRDY); /* May not be needed */
|
||||
|
||||
/* Enable UART interrupt */
|
||||
NVIC_EnableIRQ(irqn);
|
||||
}
|
||||
|
||||
LpcUart::~LpcUart() {
|
||||
if(uart != nullptr) {
|
||||
NVIC_DisableIRQ(irqn);
|
||||
Chip_UART_IntDisable(uart, UART_INTEN_RXRDY);
|
||||
Chip_UART_IntDisable(uart, UART_INTEN_TXRDY);
|
||||
|
||||
if(uart == LPC_USART0) {
|
||||
u0 = nullptr;
|
||||
}
|
||||
else if(uart == LPC_USART1) {
|
||||
u1 = nullptr;
|
||||
}
|
||||
else if(uart == LPC_USART2) {
|
||||
u2 = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LpcUart::free()
|
||||
{
|
||||
return RingBuffer_GetCount(&txring);;
|
||||
}
|
||||
|
||||
int LpcUart::peek()
|
||||
{
|
||||
return RingBuffer_GetCount(&rxring);
|
||||
}
|
||||
|
||||
int LpcUart::read(char &c)
|
||||
{
|
||||
return Chip_UART_ReadRB(uart, &rxring, &c, 1);
|
||||
}
|
||||
|
||||
int LpcUart::read(char *buffer, int len)
|
||||
{
|
||||
return Chip_UART_ReadRB(uart, &rxring, buffer, len);
|
||||
}
|
||||
|
||||
int LpcUart::write(char c)
|
||||
{
|
||||
return Chip_UART_SendRB(uart, &txring, &c, 1);
|
||||
}
|
||||
|
||||
int LpcUart::write(const char *s)
|
||||
{
|
||||
return Chip_UART_SendRB(uart, &txring, s, strlen(s));
|
||||
}
|
||||
|
||||
int LpcUart::write(const char *buffer, int len)
|
||||
{
|
||||
return Chip_UART_SendRB(uart, &txring, buffer, len);
|
||||
}
|
||||
|
||||
void LpcUart::txbreak(bool brk)
|
||||
{
|
||||
// break handling not implemented yeet
|
||||
}
|
||||
|
||||
bool LpcUart::rxbreak()
|
||||
{
|
||||
// break handling not implemented yeet
|
||||
return false;
|
||||
}
|
||||
|
||||
void LpcUart::speed(int bps)
|
||||
{
|
||||
Chip_UART_SetBaud(uart, bps);
|
||||
}
|
||||
|
||||
bool LpcUart::txempty()
|
||||
{
|
||||
return (RingBuffer_GetCount(&txring) == 0);
|
||||
}
|
||||
61
esp-vent-main/src/PressureWrapper.cpp
Normal file
61
esp-vent-main/src/PressureWrapper.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* PressureWrapper.cpp
|
||||
*
|
||||
* Created on: 5 Oct 2022
|
||||
* Author: evgenymeshcheryakov
|
||||
*/
|
||||
|
||||
#include "PressureWrapper.h"
|
||||
#include <cstdio>
|
||||
|
||||
static uint8_t crc8(uint8_t *data, size_t size) {
|
||||
uint8_t crc = 0x00;
|
||||
uint8_t byteCtr;
|
||||
//calculates 8-Bit checksum with given polynomial
|
||||
for (byteCtr = 0; byteCtr < size; ++byteCtr) {
|
||||
crc ^= (data[byteCtr]);
|
||||
for (uint8_t bit = 8; bit > 0; --bit) {
|
||||
if (crc & 0x80) crc = (crc << 1) ^ 0x131; //P(x)=x^8+x^5+x^4+1 = 0001 0011 0001
|
||||
else crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
PressureWrapper::PressureWrapper ()
|
||||
{
|
||||
NVIC_DisableIRQ(I2C0_IRQn);
|
||||
I2C_config config;
|
||||
I2C i2c_c(config);
|
||||
i2c = &i2c_c;
|
||||
}
|
||||
|
||||
PressureWrapper::~PressureWrapper ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
int PressureWrapper::getPressure() {
|
||||
int16_t pressure = 0;
|
||||
if(!getRawPressure ()) {
|
||||
unsigned int i = 0;
|
||||
while(i<7200) i++;
|
||||
getRawPressure ();
|
||||
i = 0;
|
||||
}
|
||||
if(crc8(data.rBuffer, 2) == data.crc){
|
||||
pressure = data.rBuffer[0];
|
||||
pressure = pressure << 8;
|
||||
pressure |= data.rBuffer[1];
|
||||
float result = (float) pressure * 0.95 / 240;
|
||||
return (int) result;
|
||||
}
|
||||
return -255;
|
||||
}
|
||||
|
||||
bool PressureWrapper::getRawPressure () {
|
||||
uint8_t getMeasurementComm = 0xF1;
|
||||
return (i2c->transaction(ADDRESS, &getMeasurementComm, 1, data.rBuffer, 3));
|
||||
}
|
||||
|
||||
|
||||
67
esp-vent-main/src/StateHandler/Counter.cpp
Normal file
67
esp-vent-main/src/StateHandler/Counter.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Counter.cpp
|
||||
*
|
||||
* Created on: Sep 1, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#include "StateHandler/Counter.h"
|
||||
|
||||
void
|
||||
Counter::inc ()
|
||||
{
|
||||
if (init < up_lim)
|
||||
{
|
||||
++init;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Counter::dec ()
|
||||
{
|
||||
if (init > down_lim)
|
||||
{
|
||||
--init;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
Counter::getCurrent ()
|
||||
{
|
||||
return this->init;
|
||||
}
|
||||
|
||||
Counter::Counter (unsigned int down, unsigned int up)
|
||||
{
|
||||
up_lim = up;
|
||||
down_lim = down;
|
||||
if (down > up)
|
||||
{
|
||||
init = up;
|
||||
}
|
||||
else if (down < 0)
|
||||
{
|
||||
init = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
init = down;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Counter::setInit (unsigned int newInit)
|
||||
{
|
||||
if (newInit > up_lim)
|
||||
{
|
||||
init = up_lim;
|
||||
}
|
||||
else if (newInit < down_lim)
|
||||
{
|
||||
init = down_lim;
|
||||
}
|
||||
else
|
||||
{
|
||||
init = newInit;
|
||||
}
|
||||
}
|
||||
249
esp-vent-main/src/StateHandler/StateHandler.cpp
Normal file
249
esp-vent-main/src/StateHandler/StateHandler.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* StateHandler.cpp
|
||||
*
|
||||
* Created on: Sep 21, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#include "StateHandler/StateHandler.h"
|
||||
#define PID 0
|
||||
|
||||
StateHandler::StateHandler (LiquidCrystal *lcd, ModbusRegister *A01,
|
||||
PressureWrapper *pressure, Timer *global)
|
||||
{
|
||||
this->_lcd = lcd;
|
||||
this->A01 = A01;
|
||||
this->pressure = pressure;
|
||||
this->state_timer = global;
|
||||
current = &StateHandler::stateInit;
|
||||
(this->*current) (Event (Event::eEnter));
|
||||
current_mode = MANUAL;
|
||||
}
|
||||
|
||||
StateHandler::~StateHandler ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::displaySet (unsigned int value1, unsigned int value2)
|
||||
{
|
||||
char line_up[16] = { 0 };
|
||||
char line_down[16] = { 0 };
|
||||
|
||||
if (current_mode == MANUAL)
|
||||
{
|
||||
snprintf (line_up, 16, "SPEED: %02d%", value1);
|
||||
snprintf (line_down, 16, "PRESSURE: %02dPa", value2);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf (line_up, 16, "P. SET: %02dPa", value1);
|
||||
snprintf (line_down, 16, "P. CURR: %02dPa", value2);
|
||||
}
|
||||
|
||||
_lcd->clear ();
|
||||
_lcd->setCursor (0, 0);
|
||||
_lcd->print (line_up);
|
||||
_lcd->setCursor (0, 1);
|
||||
_lcd->print (line_down);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
StateHandler::getSetPressure ()
|
||||
{
|
||||
return (unsigned int)this->value[PRESSURE].getCurrent ();
|
||||
}
|
||||
|
||||
unsigned int
|
||||
StateHandler::getSetSpeed ()
|
||||
{
|
||||
return (unsigned int)this->value[FAN_SPEED].getCurrent ();
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::HandleState (const Event &event)
|
||||
{
|
||||
(this->*current) (event);
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::SetState (state_pointer newstate)
|
||||
{
|
||||
(this->*current) (Event (Event::eExit));
|
||||
current = newstate;
|
||||
(this->*current) (Event (Event::eEnter));
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::stateInit (const Event &event)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case Event::eEnter:
|
||||
SetState (&StateHandler::stateSensors);
|
||||
break;
|
||||
case Event::eExit:
|
||||
_lcd->clear ();
|
||||
break;
|
||||
case Event::eKey:
|
||||
handleControlButtons (event.value);
|
||||
break;
|
||||
case Event::eTick:
|
||||
if (current_mode == MANUAL)
|
||||
{
|
||||
SetState (&StateHandler::stateManual);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetState (&StateHandler::stateAuto);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::stateManual (const Event &event)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case Event::eEnter:
|
||||
displaySet (saved_set_value[MANUAL], saved_curr_value[MANUAL]);
|
||||
this->A01->write (this->value[FAN_SPEED].getCurrent ());
|
||||
break;
|
||||
case Event::eExit:
|
||||
_lcd->clear ();
|
||||
break;
|
||||
case Event::eKey:
|
||||
handleControlButtons (event.value);
|
||||
this->A01->write (value[MANUAL].getCurrent () * 10);
|
||||
break;
|
||||
case Event::eTick:
|
||||
save (event.value, MANUAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::stateAuto (const Event &event)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case Event::eEnter:
|
||||
displaySet (saved_set_value[AUTO], saved_curr_value[AUTO]);
|
||||
break;
|
||||
case Event::eExit:
|
||||
_lcd->clear ();
|
||||
break;
|
||||
case Event::eKey:
|
||||
handleControlButtons (event.value);
|
||||
break;
|
||||
case Event::eTick:
|
||||
save (event.value, AUTO);
|
||||
#if PID
|
||||
pid ();
|
||||
this->A01->write (fan_speed.getCurrent ());
|
||||
#endif
|
||||
#if !PID
|
||||
if (saved_curr_value[AUTO] < saved_set_value[AUTO])
|
||||
{
|
||||
fan_speed.inc ();
|
||||
this->A01->write (fan_speed.getCurrent ());
|
||||
}
|
||||
else if (saved_curr_value[AUTO] > saved_set_value[AUTO])
|
||||
{
|
||||
fan_speed.dec ();
|
||||
this->A01->write (fan_speed.getCurrent ());
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::stateSensors (const Event &event)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case Event::eEnter:
|
||||
break;
|
||||
case Event::eExit:
|
||||
break;
|
||||
case Event::eKey:
|
||||
break;
|
||||
case Event::eTick:
|
||||
sensors_data[PRESSUREDAT] = pressure->getPressure ();
|
||||
sensors_data[TEMPERATURE] = humidity.readT ();
|
||||
sensors_data[HUMIDITY] = humidity.readRH ();
|
||||
sensors_data[CO2] = co2.read ();
|
||||
#if 1
|
||||
char line_up[16] = { 0 };
|
||||
char line_down[16] = { 0 };
|
||||
snprintf (line_up, 16, "PRE:%02d TEM:%02d", sensors_data[PRESSUREDAT],
|
||||
sensors_data[TEMPERATURE]);
|
||||
snprintf (line_down, 16, "HUM:%02d CO2:%02d", sensors_data[HUMIDITY],
|
||||
sensors_data[CO2]);
|
||||
|
||||
_lcd->clear ();
|
||||
_lcd->setCursor (0, 0);
|
||||
_lcd->print (line_up);
|
||||
_lcd->setCursor (0, 1);
|
||||
_lcd->print (line_down);
|
||||
#endif
|
||||
SetState (current_mode ? &StateHandler::stateAuto
|
||||
: &StateHandler::stateManual);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::handleControlButtons (uint8_t button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case BUTTON_CONTROL_DOWN:
|
||||
this->value[(current_mode) ? AUTO : MANUAL].dec ();
|
||||
break;
|
||||
case BUTTON_CONTROL_UP:
|
||||
this->value[(current_mode) ? AUTO : MANUAL].inc ();
|
||||
break;
|
||||
case BUTTON_CONTROL_TOG_MODE:
|
||||
current_mode = !current_mode;
|
||||
SetState (&StateHandler::stateInit);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::save (int eventValue, size_t mode)
|
||||
{
|
||||
/* if pressure is not provided from main it checks it in following if{}*/
|
||||
if (!eventValue)
|
||||
{
|
||||
/* Small delay for modbus communications with pressure sensor */
|
||||
state_timer->tickCounter (1);
|
||||
eventValue = pressure->getPressure ();
|
||||
}
|
||||
int counterValue = value[mode].getCurrent ();
|
||||
if (saved_curr_value[mode] != eventValue
|
||||
|| saved_set_value[mode] != counterValue)
|
||||
{
|
||||
saved_curr_value[mode] = eventValue;
|
||||
saved_set_value[mode] = counterValue;
|
||||
displaySet (saved_set_value[mode], saved_curr_value[mode]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StateHandler::pid ()
|
||||
{
|
||||
float kP = 0.1, kI = 0.01, kD = 0.01;
|
||||
int error = 0, last_error = 0, derivative = 0;
|
||||
error = saved_set_value[AUTO] - saved_curr_value[AUTO];
|
||||
last_error = error;
|
||||
integral += error;
|
||||
derivative = error - last_error;
|
||||
fan_speed.setInit ((kP * error) + (kI * integral) + (kD * derivative));
|
||||
}
|
||||
75
esp-vent-main/src/SwitchController.cpp
Normal file
75
esp-vent-main/src/SwitchController.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SwitchController.cpp
|
||||
*
|
||||
* Created on: Oct 17, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#include <SwitchController.h>
|
||||
|
||||
SwitchController::SwitchController (DigitalIoPin *button, Timer *timer,
|
||||
StateHandler *handler, int button_mode)
|
||||
{
|
||||
b = button;
|
||||
t = timer;
|
||||
h = handler;
|
||||
b_pressed = false;
|
||||
b_mode = button_mode;
|
||||
}
|
||||
|
||||
SwitchController::~SwitchController ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
void
|
||||
SwitchController::listen ()
|
||||
{
|
||||
int timer = t->getCounter ();
|
||||
/** Button is pressed for the first time*/
|
||||
if (b->read () && !b_pressed)
|
||||
{
|
||||
t->resetCounter ();
|
||||
b_pressed = true;
|
||||
}
|
||||
/** Button is released before 2 seconds*/
|
||||
if (!b->read () && b_pressed && timer < 2000)
|
||||
{
|
||||
h->HandleState (Event (Event::eKey, b_mode));
|
||||
b_pressed = false;
|
||||
t->resetCounter ();
|
||||
}
|
||||
/** Button is pressed after 2 seconds*/
|
||||
if (b->read () && b_pressed && timer >= 2000)
|
||||
{
|
||||
buttonOnHold ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwitchController::buttonOnHold ()
|
||||
{
|
||||
t->resetCounter ();
|
||||
while (b->read ())
|
||||
{
|
||||
buttonInLoop ();
|
||||
}
|
||||
if (b_mode == BUTTON_CONTROL_TOG_MODE)
|
||||
{
|
||||
h->HandleState (Event (Event::eKey, b_mode));
|
||||
}
|
||||
b_pressed = false;
|
||||
t->resetCounter ();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchController::buttonInLoop ()
|
||||
{
|
||||
if (t->getCounter () > 50 && b_mode != BUTTON_CONTROL_TOG_MODE)
|
||||
{
|
||||
h->HandleState (Event (Event::eKey, b_mode));
|
||||
h->HandleState (Event (Event::eTick));
|
||||
t->resetCounter ();
|
||||
}
|
||||
t->tickCounter (2);
|
||||
}
|
||||
73
esp-vent-main/src/Timer.cpp
Normal file
73
esp-vent-main/src/Timer.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Timer.cpp
|
||||
*
|
||||
* Created on: Oct 14, 2022
|
||||
* Author: tylen
|
||||
*/
|
||||
|
||||
#include <Timer.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void
|
||||
SysTick_Handler (void)
|
||||
{
|
||||
systicks++;
|
||||
if (timer > 0)
|
||||
timer--;
|
||||
}
|
||||
}
|
||||
|
||||
Timer::Timer (uint32_t freq) : freq (freq)
|
||||
{
|
||||
Chip_Clock_SetSysTickClockDiv (1);
|
||||
uint32_t sysTickRate = Chip_Clock_GetSysTickClockRate ();
|
||||
SysTick_Config (sysTickRate / freq);
|
||||
counter = 0;
|
||||
timer = 0;
|
||||
systicks = 0;
|
||||
}
|
||||
|
||||
Timer::~Timer ()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
void
|
||||
Timer::tickCounter (int ms)
|
||||
{
|
||||
if (counter >= INT_MAX)
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
counter++;
|
||||
Sleep (ms);
|
||||
}
|
||||
|
||||
void
|
||||
Timer::Sleep (int ms)
|
||||
{
|
||||
timer = ms;
|
||||
while (timer > 0)
|
||||
{
|
||||
__WFI ();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Timer::getCounter ()
|
||||
{
|
||||
return counter.load (std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void
|
||||
Timer::resetCounter ()
|
||||
{
|
||||
counter.store (0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
millis ()
|
||||
{
|
||||
return systicks;
|
||||
}
|
||||
@@ -17,10 +17,9 @@
|
||||
#endif
|
||||
|
||||
#include "DigitalIoPin.h"
|
||||
#include "I2C.h"
|
||||
#include "LiquidCrystal.h"
|
||||
#include "PressureWrapper.h"
|
||||
#include "StateHandler.h"
|
||||
#include "StateHandler/StateHandler.h"
|
||||
#include "SwitchController.h"
|
||||
#include "Timer.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user