add net manager
This commit is contained in:
22
components/meter_manager/CMakeLists.txt
Executable file
22
components/meter_manager/CMakeLists.txt
Executable file
@@ -0,0 +1,22 @@
|
||||
# List the source files to be compiled
|
||||
set(srcs
|
||||
"driver/meter_ade7758/meter_ade7758.c"
|
||||
"driver/meter_orno/meter_orno513.c"
|
||||
"driver/meter_orno/meter_orno516.c"
|
||||
"driver/meter_orno/modbus_params.c"
|
||||
"driver/meter_zigbee/meter_zigbee.c"
|
||||
"src/meter_manager.c"
|
||||
)
|
||||
|
||||
# List the include directories
|
||||
set(includes
|
||||
"include"
|
||||
"driver/meter_ade7758"
|
||||
"driver/meter_orno"
|
||||
"driver/meter_zigbee"
|
||||
)
|
||||
|
||||
# Register the component with the ESP-IDF build system
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${includes}"
|
||||
REQUIRES esp_event esp-modbus)
|
||||
1127
components/meter_manager/driver/meter_ade7758/ade7758.c
Executable file
1127
components/meter_manager/driver/meter_ade7758/ade7758.c
Executable file
File diff suppressed because it is too large
Load Diff
455
components/meter_manager/driver/meter_ade7758/ade7758.h
Executable file
455
components/meter_manager/driver/meter_ade7758/ade7758.h
Executable file
@@ -0,0 +1,455 @@
|
||||
#include "driver/spi_common.h"
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
|
||||
|
||||
#define WRITE 0x80 // WRITE bit BT7 to write to registers
|
||||
#define CLKIN 10000000 // ADE7758 frec, 10.000000MHz
|
||||
#define PERIODO 50 // Actually it is frequency, it is used to calculate the amount of Cycles that it accumulates for energy.
|
||||
#define PHASE_A 1
|
||||
#define PHASE_B 2
|
||||
#define PHASE_C 3
|
||||
|
||||
|
||||
//Register address
|
||||
|
||||
//------Name--------Address---------Lenght
|
||||
#define AWATTHR 0x01 //---------16
|
||||
#define BWATTHR 0x02 //---------16
|
||||
#define CWATTHR 0x03 //---------16
|
||||
|
||||
#define AVARHR 0x04 //---------16
|
||||
#define BVARHR 0x05 //---------16
|
||||
#define CVARHR 0x06 //---------16
|
||||
|
||||
#define AVAHR 0x07 //---------16
|
||||
#define BVAHR 0x08 //---------16
|
||||
#define CVAHR 0x09 //---------16
|
||||
|
||||
#define AIRMS 0x0A //---------24
|
||||
#define BIRMS 0x0B //---------24
|
||||
#define CIRMS 0x0C //---------24
|
||||
|
||||
#define AVRMS 0x0D //---------24
|
||||
#define BVRMS 0x0E //---------24
|
||||
#define CVRMS 0x0F //---------24
|
||||
|
||||
#define FREQ 0x10 //---------12
|
||||
#define TEMP 0x11 //---------8
|
||||
#define WFORM 0x12 //---------24
|
||||
#define OPMODE 0x13 //---------8
|
||||
#define MMODE 0x14 //---------8
|
||||
#define WAVMODE 0x15 //---------8
|
||||
#define COMPMODE 0x16 //---------8
|
||||
#define LCYCMODE 0x17 //---------8
|
||||
#define MASK 0x18 //---------24
|
||||
#define STATUS 0x19 //---------24
|
||||
#define RSTATUS 0x1A //---------24
|
||||
#define ZXTOUT 0x1B //---------16
|
||||
#define LINECYC 0x1C //---------16
|
||||
#define SAGCYC 0x1D //---------8
|
||||
#define SAGLVL 0x1E //---------8
|
||||
#define VPINTLVL 0x1F //---------8
|
||||
#define IPINTLVL 0x20 //---------8
|
||||
#define VPEAK 0x21 //---------8
|
||||
#define IPEAK 0x22 //---------8
|
||||
#define GAIN 0x23 //---------8
|
||||
#define AVRMSGAIN 0x24 //---------12
|
||||
#define BVRMSGAIN 0x25 //---------12
|
||||
#define CVRMSGAIN 0x26 //---------12
|
||||
#define AIGAIN 0x27 //---------12
|
||||
#define BIGAIN 0x28 //---------12
|
||||
#define CIGAIN 0x29 //---------12
|
||||
#define AWG 0x2A //---------12
|
||||
#define BWG 0x2B //---------12
|
||||
#define CWG 0x2C //---------12
|
||||
#define AVARG 0x2D //---------12
|
||||
#define BVARG 0x2E //---------12
|
||||
#define CVARG 0x2F //---------12
|
||||
#define AVAG 0x30 //---------12
|
||||
#define BVAG 0X31 //---------12
|
||||
#define CVAG 0x32 //---------12
|
||||
#define AVRMSOS 0x33 //---------12
|
||||
#define BVRMSOS 0X34 //---------12
|
||||
#define CVRMSOS 0X35 //---------12
|
||||
#define AIRMSOS 0X36 //---------12
|
||||
#define BIRMSOS 0X37 //---------12
|
||||
#define CIRMSOS 0X38 //---------12
|
||||
#define AWATTOS 0X39 //---------12
|
||||
#define BWATTOS 0X3A //---------12
|
||||
#define CWATTOS 0X3B //---------12
|
||||
#define AVAROS 0X3C //---------12
|
||||
#define BVAROS 0X3D //---------12
|
||||
#define CVAROS 0X3E //---------12
|
||||
#define APHCAL 0X3F //---------7
|
||||
#define BPHCAL 0X40 //---------7
|
||||
#define CPHCAL 0X41 //---------7
|
||||
#define WDIV 0X42 //---------8
|
||||
#define VARDIV 0X43 //---------8
|
||||
#define VADIV 0X44 //---------8
|
||||
#define APCFNUM 0X45 //---------16
|
||||
#define APCFDEN 0X46 //---------12
|
||||
#define VARCFNUM 0X47 //---------16
|
||||
#define VARCFDEN 0X48 //---------12
|
||||
|
||||
#define CHKSUM 0X7E //---------8
|
||||
#define VERSION 0x7f //---------8
|
||||
#define DUMMY_BYTE 0xFF
|
||||
|
||||
|
||||
//bits
|
||||
|
||||
/**
|
||||
OPERATIONAL MODE REGISTER (0x13)
|
||||
The general configuration of the ADE7758 is defined by writing to the OPMODE register.
|
||||
Table 18 summarizes the functionality of each bit in the OPMODE register.
|
||||
|
||||
Bit Location Bit Mnemonic Default Value Description
|
||||
0 DISHPF 0 The HPFs in all current channel inputs are disabled when this bit is set.
|
||||
1 DISLPF 0 The LPFs after the watt and VAR multipliers are disabled when this bit is set.
|
||||
2 DISCF 1 The frequency outputs APCF and VARCF are disabled when this bit is set.
|
||||
3 to 5 DISMOD 0 By setting these bits, ADE7758<35>s ADCs can be turned off. In normal operation, these bits should be left at Logic 0.
|
||||
DISMOD[2:0] Description
|
||||
0 0 0 Normal operation.
|
||||
1 0 0 Redirect the voltage inputs to the signal paths for the current channels and the current inputs to the signal paths for the voltage channels.
|
||||
0 0 1 Switch off only the current channel ADCs.
|
||||
1 0 1 Switch off current channel ADCs and redirect the current input signals to the voltage channel signal paths.
|
||||
0 1 0 Switch off only the voltage channel ADCs.
|
||||
1 1 0 Switch off voltage channel ADCs and redirect the voltage input signals to the current channel signal paths.
|
||||
0 1 1 Put the ADE7758 in sleep mode.
|
||||
1 1 1 Put the ADE7758 in power-down mode (reduces AIDD to 1 mA typ).
|
||||
6 SWRST 0 Software Chip Reset. A data transfer to the ADE7758 should not take place for at least 18 <20>s after a software reset.
|
||||
7 RESERVED 0 This should be left at 0.
|
||||
|
||||
*/
|
||||
|
||||
#define DISHPF 0x01
|
||||
#define DISLPF 0x02
|
||||
#define DISCF 0x04
|
||||
#define SWRST 0x40
|
||||
|
||||
/**
|
||||
MEASUREMENT MODE REGISTER (0x14)
|
||||
The configuration of the PERIOD and peak measurements made by the ADE7758 is defined by writing to the MMODE register.
|
||||
Table 19 summarizes the functionality of each bit in the MMODE register.
|
||||
|
||||
Bit Location Bit Mnemonic Default Value Description
|
||||
0 to 1 FREQSEL 0 These bits are used to select the source of the measurement of the voltage line frequency.
|
||||
FREQSEL1 FREQSEL0 Source
|
||||
0 0 Phase A
|
||||
0 1 Phase B
|
||||
1 0 Phase C
|
||||
1 1 Reserved
|
||||
2 to 4 PEAKSEL 7 These bits select the phases used for the voltage and current peak registers.
|
||||
Setting Bit 2 switches the IPEAK and VPEAK registers to hold the absolute values
|
||||
of the largest current and voltage waveform (over a fixed number of half-line cycles)
|
||||
from Phase A. The number of half-line cycles is determined by the content of the
|
||||
LINECYC register. At the end of the LINECYC number of half-line cycles, the content
|
||||
of the registers is replaced with the new peak values. Similarly, setting Bit 3 turns
|
||||
on the peak detection for Phase B, and Bit 4 for Phase C. Note that if more than one
|
||||
bit is set, the VPEAK and IPEAK registers can hold values from two different phases, that is,
|
||||
the voltage and current peak are independently processed (see the Peak Current Detection section).
|
||||
5 to 7 PKIRQSEL 7 These bits select the phases used for the peak interrupt detection.
|
||||
Setting Bit 5 switches on the monitoring of the absolute current and voltage waveform to Phase A.
|
||||
Similarly, setting Bit 6 turns on the waveform detection for Phase B, and Bit 7 for Phase C.
|
||||
Note that more than one bit can be set for detection on multiple phases.
|
||||
If the absolute values of the voltage or current waveform samples in the selected phases exceeds
|
||||
the preset level specified in the VPINTLVL or IPINTLVL registers the corresponding bit(s) in the
|
||||
STATUS registers are set (see the Peak Current Detection section).
|
||||
|
||||
*/
|
||||
|
||||
#define FREQSEL0 0x01
|
||||
#define FREQSEL1 0x02
|
||||
|
||||
|
||||
/**
|
||||
WAVEFORM MODE REGISTER (0x15)
|
||||
The waveform sampling mode of the ADE7758 is defined by writing to the WAVMODE register.
|
||||
Table 20 summarizes the functionality of each bit in the WAVMODE register.
|
||||
|
||||
Bit Location Bit Mnemonic Default Value Description
|
||||
0 to 1 PHSEL 0 These bits are used to select the phase of the waveform sample.
|
||||
PHSEL[1:0] Source
|
||||
0 0 Phase A
|
||||
0 1 Phase B
|
||||
1 0 Phase C
|
||||
1 1 Reserved
|
||||
2 to 4 WAVSEL 0 These bits are used to select the type of waveform.
|
||||
WAVSEL[2:0] Source
|
||||
0 0 0 Current
|
||||
0 0 1 Voltage
|
||||
0 1 0 Active Power Multiplier Output
|
||||
0 1 1 Reactive Power Multiplier Output
|
||||
1 0 0 VA Multiplier Output
|
||||
-Others- Reserved
|
||||
5 to 6 DTRT 0 These bits are used to select the data rate.
|
||||
DTRT[1:0] Update Rate
|
||||
0 0 26.04 kSPS (CLKIN/3/128)
|
||||
0 1 13.02 kSPS (CLKIN/3/256)
|
||||
1 0 6.51 kSPS (CLKIN/3/512)
|
||||
1 1 3.25 kSPS (CLKIN/3/1024)
|
||||
7 VACF 0 Setting this bit to Logic 1 switches the VARCF output pin to an output
|
||||
frequency that is proportional to the total apparent power (VA).
|
||||
In the default state, Logic 0, the VARCF pin outputs a frequency proportional
|
||||
to the total reactive power (VAR).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
COMPUTATIONAL MODE REGISTER (0x16)
|
||||
The computational method of the ADE7758 is defined by writing to the COMPMODE register.
|
||||
|
||||
Bit Location Bit Mnemonic Default Value Description
|
||||
0 to 1 CONSEL 0 These bits are used to select the input to the energy accumulation registers.
|
||||
CONSEL[1:0] = 11 is reserved. IA, IB, and IC are IA, IB, and IC phase shifted by <20>90<39>, respectively.
|
||||
Registers CONSEL[1, 0] = 00 CONSEL[1, 0] = 01 CONSEL[1, 0] = 10
|
||||
AWATTHR VA <20> IA VA <20> (IA <20> IB) VA <20> (IA<49>IB)
|
||||
BWATTHR VB <20> IB 0 0
|
||||
CWATTHR VC <20> IC VC <20> (IC <20> IB) VC <20> IC
|
||||
|
||||
AVARHR VA <20> IA VA <20> (IA <20> IB) VA <20> (IA<49>IB)
|
||||
BVARHR VB <20> IB 0 0
|
||||
CVARHR VC <20> IC VC <20> (IC <20> IB) VC <20> IC
|
||||
|
||||
AVAHR VARMS <20> IARMS VARMS <20> IARMS VARMS <20> ARMS
|
||||
BVAHR VBRMS <20> IBRMS (VARMS + VCRMS)/2 <20> IBRMS VARMS <20> IBRMS
|
||||
CVAHR VCRMS <20> ICRMS VCRMS <20> ICRMS VCRMS <20> ICRMS
|
||||
|
||||
2 to 4 TERMSEL 7 These bits are used to select the phases to be included in the APCF and VARCF pulse outputs.
|
||||
Setting Bit 2 selects Phase A (the inputs to AWATTHR and AVARHR registers) to be included.
|
||||
Bit 3 and Bit 4 are for Phase B and Phase C, respectively.
|
||||
Setting all three bits enables the sum of all three phases to be included in the frequency outputs
|
||||
(see the Active Power Frequency Output and the Reactive Power Frequency Output sections).
|
||||
|
||||
5 ABS 0 Setting this bit places the APCF output pin in absolute only mode.
|
||||
Namely, the APCF output frequency is proportional to the sum of the absolute values of the watt-hour
|
||||
accumulation registers (AWATTHR, BWATTHR, and CWATTHR).
|
||||
Note that this bit only affects the APCF pin and has no effect on the content of the corresponding
|
||||
registers.
|
||||
|
||||
6 SAVAR 0 Setting this bit places the VARCF output pin in the signed adjusted mode.
|
||||
Namely, the VARCF output frequency is proportional to the sign-adjusted sum of the VAR-hour accumulation
|
||||
registers (AVARHR, BVARHR, and CVARHR).
|
||||
The sign of the VAR is determined from the sign of the watt calculation from the corresponding phase,
|
||||
that is, the sign of the VAR is flipped if the sign of the watt is negative, and if the watt is positive,
|
||||
there is no change to the sign of the VAR.
|
||||
Note that this bit only affects the VARCF pin and has no effect on the content of the corresponding
|
||||
registers.
|
||||
|
||||
7 NOLOAD 0 Setting this bit activates the no-load threshold in the ADE7758.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
LINE CYCLE ACCUMULATION MODE REGISTER (0x17)
|
||||
The functionalities involved the line-cycle accumulation mode in the ADE7758 are defined by writing to the LCYCMODE register.
|
||||
|
||||
Bit Location Bit Mnemonic Default Value Description
|
||||
|
||||
0 LWATT 0 Setting this bit places the watt-hour accumulation registers
|
||||
(AWATTHR, BWATTHR, and CWATTHR registers) into line-cycle accumulation mode.
|
||||
1 LVAR 0 Setting this bit places the VAR-hour accumulation registers (AVARHR, BVARHR, and CVARHR registers)
|
||||
into line-cycle accumulation mode.
|
||||
2 LVA 0 Setting this bit places the VA-hour accumulation registers (AVAHR, BVAHR, and CVAHR registers)
|
||||
into line-cycle accumulation mode.
|
||||
3 to 5 ZXSEL 7 These bits select the phases used for counting the number of zero crossings in the line-cycle
|
||||
accumulation mode. Bit 3, Bit 4, and Bit 5 select Phase A, Phase B, and Phase C, respectively.
|
||||
More than one phase can be selected for the zero-crossing detection,
|
||||
and the accumulation time is shortened accordingly.
|
||||
6 RSTREAD 1 Setting this bit enables the read-with-reset for all the WATTHR, VARHR, and VAHR registers for all three
|
||||
phases, that is, a read to those registers resets the registers to 0 after the content of the registers
|
||||
have been read. This bit should be set to Logic 0 when the LWATT, LVAR, or LVA bits are set to Logic 1.
|
||||
7 FREQSEL 0 Setting this bit causes the FREQ (0x10) register to display the period, instead of the frequency of the
|
||||
line input.
|
||||
*/
|
||||
|
||||
|
||||
#define LWATT 0x01
|
||||
#define LVAR 0x02
|
||||
#define LVA 0x04
|
||||
#define ZXSEL_A 0x08
|
||||
#define ZXSEL_B 0x10
|
||||
#define ZXSEL_C 0x20
|
||||
#define RSTREAD 0x40
|
||||
#define FREQSEL 0x80
|
||||
|
||||
|
||||
|
||||
/** INTERRUPT MASK REGISTER (0x18)
|
||||
When an interrupt event occurs in the ADE7758, the IRQ logic output goes active low if the mask bit for this event is Logic 1 in the MASK register.
|
||||
The IRQ logic output is reset to its default collector open state when the RSTATUS register is read.
|
||||
describes the function of each bit in the interrupt mask register.
|
||||
**/
|
||||
|
||||
// The next table summarizes the function of each bit for
|
||||
// the Interrupt Enable Register
|
||||
|
||||
/* Bit Mask // Bit Location / Description
|
||||
#define AEHF 0x0001 // bit 0 - Enables an interrupt when there is a change in Bit 14 of any one of the three WATTHR registers, that is, the WATTHR register is half full.
|
||||
#define REHF 0x0002 // bit 1 - Enables an interrupt when there is a change in Bit 14 of any one of the three VARHR registers, that is, the VARHR register is half full.
|
||||
#define VAEHF 0x0004 // bit 2 - Enables an interrupt when there is a 0 to 1 transition in the MSB of any one of the three VAHR registers, that is, the VAHR register is half full.
|
||||
#define SAGA 0x0008 // bit 3 - Enables an interrupt when there is a SAG on the line voltage of the Phase A.
|
||||
#define SAGB 0x0010 // bit 4 - Enables an interrupt when there is a SAG on the line voltage of the Phase B.
|
||||
#define SAGC 0x0020 // bit 5 - Enables an interrupt when there is a SAG on the line voltage of the Phase C.
|
||||
#define ZXTOA 0x0040 // bit 6 - Enables an interrupt when there is a zero-crossing timeout detection on Phase A.
|
||||
#define ZXTOB 0x0080 // bit 7 - Enables an interrupt when there is a zero-crossing timeout detection on Phase B.
|
||||
#define ZXTOC 0x0100 // bit 8 - Enables an interrupt when there is a zero-crossing timeout detection on Phase C.
|
||||
#define ZXA 0x0200 // bit 9 - Enables an interrupt when there is a zero crossing in the voltage channel of Phase A
|
||||
#define ZXB 0x0400 // bit 10 - Enables an interrupt when there is a zero crossing in the voltage channel of Phase B
|
||||
#define ZXC 0x0800 // bit 11 - Enables an interrupt when there is a zero crossing in the voltage channel of Phase C
|
||||
#define LENERGY 0x1000 // bit 12 - Enables an interrupt when the energy accumulations over LINECYC are finished.
|
||||
//RESERVED 0x2000 // bit 13 - RESERVED
|
||||
#define PKV 0x4000 // bit 14 - Enables an interrupt when the voltage input selected in the MMODE register is above the value in the VPINTLVL register.
|
||||
#define PKI 0x8000 // bit 15 - Enables an interrupt when the current input selected in the MMODE register is above the value in the IPINTLVL register.
|
||||
#define WFSM 0x010000 // bit 16 - Enables an interrupt when data is present in the WAVEMODE register.
|
||||
#define REVPAP 0x020000 // bit 17 - Enables an interrupt when there is a sign change in the watt calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register.
|
||||
#define REVPRP 0x040000 // bit 18 - Enables an interrupt when there is a sign change in the VAR calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register.
|
||||
#define SEQERR 0x080000 // bit 19 - Enables an interrupt when the zero crossing from Phase A is followed not by the zero crossing of Phase C but with that of Phase B.
|
||||
*/
|
||||
/** INTERRUPT STATUS REGISTER (0x19)/RESET INTERRUPT STATUS REGISTER (0x1A)
|
||||
The interrupt status register is used to determine the source of an interrupt event.
|
||||
When an interrupt event occurs in the ADE7758, the corresponding flag in the interrupt status register is set.
|
||||
The IRQ pin goes active low if the corresponding bit in the interrupt mask register is set.
|
||||
When the MCU services the interrupt, it must first carry out a read from the interrupt status register to determine the source of the interrupt.
|
||||
All the interrupts in the interrupt status register stay at their logic high state after an event occurs.
|
||||
The state of the interrupt bit in the interrupt status register is reset to its default value once the reset interrupt status register is read.
|
||||
**/
|
||||
|
||||
// The next table summarizes the function of each bit for
|
||||
// the Interrupt Status Register, the Reset Interrupt Status Register.
|
||||
|
||||
// Bit Mask // Bit Location / Description
|
||||
#define AEHF 0x0001 // bit 0 - Indicates that an interrupt was caused by a change in Bit 14 among any one of the three WATTHR registers, that is, the WATTHR register is half full.
|
||||
#define REHF 0x0002 // bit 1 - Indicates that an interrupt was caused by a change in Bit 14 among any one of the three VARHR registers, that is, the VARHR register is half full.
|
||||
#define VAEHF 0x0004 // bit 2 - Indicates that an interrupt was caused by a 0 to 1 transition in Bit 15 among any one of the three VAHR registers, that is, the VAHR register is half full.
|
||||
#define SAGA 0x0008 // bit 3 - Indicates that an interrupt was caused by a SAG on the line voltage of the Phase A.
|
||||
#define SAGB 0x0010 // bit 4 - Indicates that an interrupt was caused by a SAG on the line voltage of the Phase B.
|
||||
#define SAGC 0x0020 // bit 5 - Indicates that an interrupt was caused by a SAG on the line voltage of the Phase C.
|
||||
#define ZXTOA 0x0040 // bit 6 - Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase A.
|
||||
#define ZXTOB 0x0080 // bit 7 - Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase B.
|
||||
#define ZXTOC 0x0100 // bit 8 - Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase C
|
||||
#define ZXA 0x0200 // bit 9 - Indicates a detection of a rising edge zero crossing in the voltage channel of Phase A.
|
||||
#define ZXB 0x0400 // bit 10 - Indicates a detection of a rising edge zero crossing in the voltage channel of Phase B
|
||||
#define ZXC 0x0800 // bit 11 - Indicates a detection of a rising edge zero crossing in the voltage channel of Phase C
|
||||
#define LENERGY 0x1000 // bit 12 - In line energy accumulation, indicates the end of an integration over an integer number of half- line cycles (LINECYC). See the Calibration section.
|
||||
#define RESET 0x2000 // bit 13 - Indicates that the 5 V power supply is below 4 V. Enables a software reset of the ADE7758 and sets the registers back to their default values. This bit in the STATUS or RSTATUS register is logic high for only one clock cycle after a reset event.
|
||||
#define PKV 0x4000 // bit 14 - Indicates that an interrupt was caused when the selected voltage input is above the value in the VPINTLVL register.
|
||||
#define PKI 0x8000 // bit 15 - Indicates that an interrupt was caused when the selected current input is above the value in the IPINTLVL register.
|
||||
#define WFSM 0x010000 // bit 16 - Indicates that new data is present in the waveform register.
|
||||
#define REVPAP 0x020000 // bit 17 - Indicates that an interrupt was caused by a sign change in the watt calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register.
|
||||
#define REVPRP 0x040000 // bit 18 - Indicates that an interrupt was caused by a sign change in the VAR calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register.
|
||||
#define SEQERR 0x080000 // bit 19 - Indicates that an interrupt was caused by a zero crossing from Phase A followed not by the zero crossing of Phase C but by that of Phase B.
|
||||
|
||||
|
||||
//constants
|
||||
#define GAIN_1 0x00
|
||||
#define GAIN_2 0x01
|
||||
#define GAIN_4 0x02
|
||||
#define INTEGRATOR_ON 1
|
||||
#define INTEGRATOR_OFF 0
|
||||
#define FULLSCALESELECT_0_5V 0x00
|
||||
#define FULLSCALESELECT_0_25V 0x01
|
||||
#define FULLSCALESELECT_0_125V 0x02
|
||||
|
||||
esp_err_t transferByte(const uint8_t reg_addr, const uint8_t data, const uint8_t command);
|
||||
esp_err_t transferMultiplesBytes(const uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t data_length, const uint8_t command);
|
||||
|
||||
esp_err_t Init(const spi_host_device_t spi_peripheral, const int pin_miso, const int pin_mosi, const int pin_sclk);
|
||||
esp_err_t InitSpi(const int ss);
|
||||
|
||||
esp_err_t RegisterDevice(const uint8_t mode, const int ss, const int addr_length, const int command_length, const int bus_speed);
|
||||
uint8_t ReadRegister(const uint8_t reg_addr, const uint8_t command);
|
||||
esp_err_t WriteRegister(const uint8_t reg_addr, const uint8_t reg_data, const uint8_t command);
|
||||
esp_err_t WriteRegisterMultipleBytes(const uint8_t reg_addr, uint8_t *reg_data_buffer, const uint8_t byte_count, const uint8_t command);
|
||||
esp_err_t ReadRegisterMultipleBytes(const uint8_t reg_addr, uint8_t *reg_data_buffer, const uint8_t byte_count, const uint8_t command);
|
||||
spi_device_handle_t GetHandle();
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Modes and configurations
|
||||
//----------------------------------------------------------------------------
|
||||
void setOpMode(uint8_t m);
|
||||
uint8_t getOpMode();
|
||||
void setMMode(uint8_t m);
|
||||
uint8_t getMMode();
|
||||
void setWavMode(uint8_t m);
|
||||
uint8_t getWavMode();
|
||||
void setCompMode(uint8_t m);
|
||||
uint8_t getCompMode();
|
||||
void setLcycMode(uint8_t m);
|
||||
uint8_t getLcycMode();
|
||||
void gainSetup(uint8_t integrator, uint8_t scale, uint8_t PGA2, uint8_t PGA1);
|
||||
void setupDivs(uint8_t Watt_div,uint8_t VAR_div,uint8_t VA_div);
|
||||
uint32_t getMaskInterrupts();
|
||||
void setMaskInterrupts(uint32_t m);
|
||||
uint32_t getStatus();
|
||||
uint32_t resetStatus();
|
||||
int32_t getAIRMS();
|
||||
int32_t getBIRMS();
|
||||
int32_t getCIRMS();
|
||||
int32_t getAVRMS();
|
||||
int32_t getBVRMS();
|
||||
int32_t getCVRMS();
|
||||
uint32_t avrms();
|
||||
uint32_t bvrms();
|
||||
uint32_t cvrms();
|
||||
uint32_t airms();
|
||||
uint32_t birms();
|
||||
int32_t cirms();
|
||||
int32_t getFreq();
|
||||
void setLineCyc(uint32_t d);
|
||||
int32_t getACurrentOffset();
|
||||
int32_t getBCurrentOffset();
|
||||
int32_t getCCurrentOffset();
|
||||
void setACurrentOffset(int32_t o);
|
||||
void setBCurrentOffset(int32_t o);
|
||||
void setCCurrentOffset(int32_t o);
|
||||
int32_t getAVoltageOffset();
|
||||
int32_t getBVoltageOffset();
|
||||
int32_t getCVoltageOffset();
|
||||
void setAVoltageOffset(int32_t o);
|
||||
void setBVoltageOffset(int32_t o);
|
||||
void setCVoltageOffset(int32_t o);
|
||||
void setAWattOffset(int32_t o);
|
||||
void setBWattOffset(int32_t o);
|
||||
void setCWattOffset(int32_t o);
|
||||
void setZeroCrossingTimeout(int32_t d);
|
||||
int32_t getZeroCrossingTimeout();
|
||||
uint8_t setPotLine(uint8_t Phase, uint32_t Ciclos);
|
||||
int32_t getWatt(uint8_t Phase);
|
||||
int32_t getVar(uint8_t Phase);
|
||||
int32_t getVa(uint8_t Phase);
|
||||
uint8_t getVersion();
|
||||
uint8_t read8(uint8_t reg);
|
||||
uint32_t read16(uint8_t reg);
|
||||
uint32_t read24(uint8_t reg);
|
||||
|
||||
esp_err_t write24(uint8_t reg, uint32_t data);
|
||||
esp_err_t write16(uint8_t reg, uint32_t data);
|
||||
esp_err_t write8(uint8_t reg, uint8_t data);
|
||||
|
||||
void enableADE7758Chip();
|
||||
void disableADE7758Chip();
|
||||
void setAPCFDEN(int32_t d);
|
||||
int32_t getAPCFDEN();
|
||||
void setAPCFNUM(int32_t d);
|
||||
int32_t getAPCFNUM();
|
||||
void setVARCFNUM(int32_t d);
|
||||
int32_t getVARCFNUM();
|
||||
void setVARCFDEN(int32_t d);
|
||||
int32_t getVARCFDEN();
|
||||
void setAWG(int32_t d);
|
||||
int32_t getAWG();
|
||||
void setBWG(int32_t d);
|
||||
void setCWG(int32_t d);
|
||||
void setAVARG(int32_t d);
|
||||
int32_t getAVARG();
|
||||
void setBVARG(int32_t d);
|
||||
int32_t getBVARG();
|
||||
void setCVARG(int32_t d);
|
||||
int32_t getCVARG();
|
||||
void setAVAG(int32_t d);
|
||||
void setBVAG(int32_t d);
|
||||
void setCVAG(int32_t d);
|
||||
176
components/meter_manager/driver/meter_ade7758/meter_ade7758.c
Executable file
176
components/meter_manager/driver/meter_ade7758/meter_ade7758.c
Executable file
@@ -0,0 +1,176 @@
|
||||
#include "meter_ade7758.h"
|
||||
#include "ade7758.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
#define TAG "meter_ade7758"
|
||||
|
||||
// === Configurações de hardware ===
|
||||
#define PIN_NUM_CLK 15
|
||||
#define PIN_NUM_MOSI 2
|
||||
#define PIN_NUM_MISO 4
|
||||
#define PIN_NUM_CS 23
|
||||
#define EEPROM_HOST HSPI_HOST
|
||||
|
||||
// === Constantes de calibração ===
|
||||
#define VRMS_CAL 4732.78f
|
||||
#define IRMS_CAL 53416.0f
|
||||
|
||||
#define METER_READ_INTERVAL_MS 5000
|
||||
|
||||
// === Dados internos ===
|
||||
typedef struct {
|
||||
float vrms[3];
|
||||
float irms[3];
|
||||
int watt[3];
|
||||
int var[3]; // reservados
|
||||
int va[3]; // reservados
|
||||
} meter_ade7758_internal_data_t;
|
||||
|
||||
static meter_ade7758_internal_data_t meter_data;
|
||||
static TaskHandle_t meter_task = NULL;
|
||||
static SemaphoreHandle_t meter_mutex = NULL;
|
||||
static uint32_t meter_watchdog_counter = 0;
|
||||
|
||||
// === Utilitários internos ===
|
||||
|
||||
static void meter_ade7758_clear_internal_data(void) {
|
||||
if (meter_mutex && xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
memset(&meter_data, 0, sizeof(meter_data));
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static bool meter_ade7758_read_internal(meter_ade7758_internal_data_t *out) {
|
||||
if (!out) return false;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
*out = meter_data;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void meter_ade7758_task_func(void *param) {
|
||||
ESP_LOGI(TAG, "Meter task started");
|
||||
|
||||
meter_ade7758_internal_data_t previous = {0};
|
||||
|
||||
while (true) {
|
||||
meter_ade7758_internal_data_t current = {0};
|
||||
|
||||
current.vrms[0] = avrms() / VRMS_CAL;
|
||||
current.vrms[1] = bvrms() / VRMS_CAL;
|
||||
current.vrms[2] = cvrms() / VRMS_CAL;
|
||||
|
||||
current.irms[0] = airms() / IRMS_CAL;
|
||||
current.irms[1] = birms() / IRMS_CAL;
|
||||
current.irms[2] = cirms() / IRMS_CAL;
|
||||
|
||||
if (setPotLine(PHASE_A, 20)) current.watt[0] = getWatt(PHASE_A);
|
||||
if (setPotLine(PHASE_B, 20)) current.watt[1] = getWatt(PHASE_B);
|
||||
if (setPotLine(PHASE_C, 20)) current.watt[2] = getWatt(PHASE_C);
|
||||
|
||||
if (memcmp(&previous, ¤t, sizeof(current)) != 0) {
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
meter_data = current;
|
||||
meter_watchdog_counter++;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(METER_READ_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
|
||||
// === Interface pública: controle ===
|
||||
|
||||
esp_err_t meter_ade7758_init(void) {
|
||||
ESP_LOGI(TAG, "Inicializando medidor ADE7758...");
|
||||
|
||||
if (!meter_mutex) {
|
||||
meter_mutex = xSemaphoreCreateMutex();
|
||||
if (!meter_mutex) {
|
||||
ESP_LOGE(TAG, "Falha ao criar mutex");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
meter_ade7758_clear_internal_data();
|
||||
|
||||
esp_err_t err = Init(EEPROM_HOST, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Erro ao inicializar SPI (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
InitSpi(PIN_NUM_CS);
|
||||
gainSetup(INTEGRATOR_OFF, FULLSCALESELECT_0_5V, GAIN_1, GAIN_1);
|
||||
setupDivs(1, 1, 1);
|
||||
setLcycMode(0x00);
|
||||
resetStatus();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t meter_ade7758_start(void) {
|
||||
if (meter_task) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
meter_ade7758_clear_internal_data();
|
||||
BaseType_t result = xTaskCreate(meter_ade7758_task_func, "meter_ade7758_task", 4096, NULL, 5, &meter_task);
|
||||
return result == pdPASS ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
void meter_ade7758_stop(void) {
|
||||
if (meter_task) {
|
||||
vTaskDelete(meter_task);
|
||||
meter_task = NULL;
|
||||
}
|
||||
meter_ade7758_clear_internal_data();
|
||||
}
|
||||
|
||||
bool meter_ade7758_is_running(void) {
|
||||
return meter_task != NULL;
|
||||
}
|
||||
|
||||
void meter_ade7758_clear_data(void) {
|
||||
meter_ade7758_clear_internal_data();
|
||||
}
|
||||
|
||||
// === Interface pública: acesso aos dados ===
|
||||
|
||||
float meter_ade7758_get_vrms_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[0] : 0; }
|
||||
float meter_ade7758_get_vrms_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[1] : 0; }
|
||||
float meter_ade7758_get_vrms_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[2] : 0; }
|
||||
|
||||
float meter_ade7758_get_irms_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[0] : 0; }
|
||||
float meter_ade7758_get_irms_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[1] : 0; }
|
||||
float meter_ade7758_get_irms_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[2] : 0; }
|
||||
|
||||
int meter_ade7758_get_watt_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[0] : 0; }
|
||||
int meter_ade7758_get_watt_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[1] : 0; }
|
||||
int meter_ade7758_get_watt_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[2] : 0; }
|
||||
|
||||
int meter_ade7758_get_var_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[0] : 0; }
|
||||
int meter_ade7758_get_var_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[1] : 0; }
|
||||
int meter_ade7758_get_var_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[2] : 0; }
|
||||
|
||||
int meter_ade7758_get_va_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[0] : 0; }
|
||||
int meter_ade7758_get_va_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[1] : 0; }
|
||||
int meter_ade7758_get_va_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[2] : 0; }
|
||||
|
||||
// === Diagnóstico ===
|
||||
|
||||
uint32_t meter_ade7758_get_watchdog_counter(void) {
|
||||
return meter_watchdog_counter;
|
||||
}
|
||||
70
components/meter_manager/driver/meter_ade7758/meter_ade7758.h
Executable file
70
components/meter_manager/driver/meter_ade7758/meter_ade7758.h
Executable file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do medidor ADE7758 (SPI, mutex, registradores).
|
||||
*/
|
||||
esp_err_t meter_ade7758_init(void);
|
||||
|
||||
/**
|
||||
* @brief Inicia a tarefa de leitura de dados do medidor ADE7758.
|
||||
*/
|
||||
esp_err_t meter_ade7758_start(void);
|
||||
|
||||
/**
|
||||
* @brief Para a tarefa de leitura e limpa os dados internos do medidor ADE7758.
|
||||
*/
|
||||
void meter_ade7758_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Verifica se o medidor ADE7758 está em execução.
|
||||
*
|
||||
* @return true se a tarefa estiver ativa, false caso contrário.
|
||||
*/
|
||||
bool meter_ade7758_is_running(void);
|
||||
|
||||
/**
|
||||
* @brief Limpa os dados armazenados no medidor ADE7758 (zera todos os valores).
|
||||
*/
|
||||
void meter_ade7758_clear_data(void);
|
||||
|
||||
// ----- Leituras por fase (L1, L2, L3) -----
|
||||
|
||||
// Tensão RMS (em volts)
|
||||
float meter_ade7758_get_vrms_l1(void);
|
||||
float meter_ade7758_get_vrms_l2(void);
|
||||
float meter_ade7758_get_vrms_l3(void);
|
||||
|
||||
// Corrente RMS (em amperes)
|
||||
float meter_ade7758_get_irms_l1(void);
|
||||
float meter_ade7758_get_irms_l2(void);
|
||||
float meter_ade7758_get_irms_l3(void);
|
||||
|
||||
// Potência ativa (W)
|
||||
int meter_ade7758_get_watt_l1(void);
|
||||
int meter_ade7758_get_watt_l2(void);
|
||||
int meter_ade7758_get_watt_l3(void);
|
||||
|
||||
// Potência reativa (VAR)
|
||||
int meter_ade7758_get_var_l1(void);
|
||||
int meter_ade7758_get_var_l2(void);
|
||||
int meter_ade7758_get_var_l3(void);
|
||||
|
||||
// Potência aparente (VA)
|
||||
int meter_ade7758_get_va_l1(void);
|
||||
int meter_ade7758_get_va_l2(void);
|
||||
int meter_ade7758_get_va_l3(void);
|
||||
|
||||
// (Opcional) contador de watchdog para diagnóstico
|
||||
uint32_t meter_ade7758_get_watchdog_counter(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
73
components/meter_manager/driver/meter_orno/meter_orno.h
Executable file
73
components/meter_manager/driver/meter_orno/meter_orno.h
Executable file
@@ -0,0 +1,73 @@
|
||||
#ifndef ORNO_MODBUS_H_
|
||||
#define ORNO_MODBUS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do medidor (SPI, mutex, registradores ADE7758).
|
||||
*/
|
||||
esp_err_t meter_init(void);
|
||||
|
||||
/**
|
||||
* @brief Inicia a tarefa de leitura de dados do medidor.
|
||||
*/
|
||||
esp_err_t meter_start(void);
|
||||
|
||||
/**
|
||||
* @brief Para a tarefa de leitura e limpa os dados internos.
|
||||
*/
|
||||
void meter_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Verifica se o medidor está em execução.
|
||||
*
|
||||
* @return true se a tarefa estiver ativa, false caso contrário.
|
||||
*/
|
||||
bool meter_is_running(void);
|
||||
|
||||
/**
|
||||
* @brief Limpa os dados armazenados no medidor (zera todos os valores).
|
||||
*/
|
||||
void meter_clear_data(void);
|
||||
|
||||
// ----- Leituras por fase (L1, L2, L3) -----
|
||||
|
||||
// Tensão RMS (em volts)
|
||||
float meter_get_vrms_l1(void);
|
||||
float meter_get_vrms_l2(void);
|
||||
float meter_get_vrms_l3(void);
|
||||
|
||||
// Corrente RMS (em amperes)
|
||||
float meter_get_irms_l1(void);
|
||||
float meter_get_irms_l2(void);
|
||||
float meter_get_irms_l3(void);
|
||||
|
||||
// Potência ativa (W)
|
||||
int meter_get_watt_l1(void);
|
||||
int meter_get_watt_l2(void);
|
||||
int meter_get_watt_l3(void);
|
||||
|
||||
// Potência reativa (VAR)
|
||||
int meter_get_var_l1(void);
|
||||
int meter_get_var_l2(void);
|
||||
int meter_get_var_l3(void);
|
||||
|
||||
// Potência aparente (VA)
|
||||
int meter_get_va_l1(void);
|
||||
int meter_get_va_l2(void);
|
||||
int meter_get_va_l3(void);
|
||||
|
||||
// (Opcional) contador de watchdog para diagnóstico
|
||||
uint32_t meter_get_watchdog_counter(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ORNO_MODBUS_H_ */
|
||||
325
components/meter_manager/driver/meter_orno/meter_orno513.c
Executable file
325
components/meter_manager/driver/meter_orno/meter_orno513.c
Executable file
@@ -0,0 +1,325 @@
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "meter_orno513.h"
|
||||
#include "modbus_params.h" // for modbus parameters structures
|
||||
#include "mbcontroller.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define TXD_PIN (GPIO_NUM_17)
|
||||
#define RXD_PIN (GPIO_NUM_16)
|
||||
|
||||
static const char *TAG = "serial_mdb";
|
||||
|
||||
static bool enabled = false;
|
||||
static bool meterState = false;
|
||||
static bool meterTest = false;
|
||||
|
||||
static TaskHandle_t serial_mdb_task = NULL;
|
||||
|
||||
#define MB_PORT_NUM 2 //(CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
|
||||
#define MB_DEV_SPEED 9600 //(CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
|
||||
|
||||
#define MB_UART_TXD 17
|
||||
#define MB_UART_RXD 16
|
||||
#define MB_UART_RTS 5
|
||||
|
||||
// The number of parameters that intended to be used in the particular control process
|
||||
#define MASTER_MAX_CIDS num_device_parameters
|
||||
|
||||
// Number of reading of parameters from slave
|
||||
#define MASTER_MAX_RETRY 30
|
||||
|
||||
// Timeout to update cid over Modbus
|
||||
#define UPDATE_CIDS_TIMEOUT_MS (3000)
|
||||
#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS)
|
||||
|
||||
// Timeout between polls
|
||||
#define POLL_TIMEOUT_MS (500)
|
||||
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_PERIOD_MS)
|
||||
|
||||
// Timeout between errors
|
||||
#define ERROR_TIMEOUT_MS (1000)
|
||||
#define ERROR_TIMEOUT_TICS (ERROR_TIMEOUT_MS / portTICK_PERIOD_MS)
|
||||
|
||||
// The macro to get offset for parameter in the appropriate structure
|
||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
|
||||
// Discrete offset macro
|
||||
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
|
||||
|
||||
#define STR(fieldname) ((const char *)(fieldname))
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) \
|
||||
{ \
|
||||
.opt1 = min_val, .opt2 = max_val, .opt3 = step_val}
|
||||
|
||||
// Enumeration of modbus device addresses accessed by master device
|
||||
enum
|
||||
{
|
||||
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
|
||||
};
|
||||
|
||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
||||
enum
|
||||
{
|
||||
CID_HOLD_DATA_0 = 0,
|
||||
CID_HOLD_DATA_1 = 1,
|
||||
CID_HOLD_DATA_2 = 2,
|
||||
CID_HOLD_DATA_3 = 3,
|
||||
CID_HOLD_DATA_4 = 4,
|
||||
CID_HOLD_DATA_5 = 5,
|
||||
CID_HOLD_DATA_6 = 6
|
||||
};
|
||||
|
||||
#define SN 0x1000
|
||||
#define METERID 0x1003
|
||||
#define FW 0x1004
|
||||
|
||||
#define L1VOLTAGE 0x0100
|
||||
#define L1CURRENT 0x0102
|
||||
#define ACTIVEPOWER 0x0104
|
||||
#define APPARENTPOWER 0x0106
|
||||
#define REACTIVEPOWER 0x0108
|
||||
|
||||
#define TOTALFACTIVE 0x010E
|
||||
#define TOTALRACTIVE 0x0118
|
||||
|
||||
// Example Data (Object) Dictionary for Modbus parameters:
|
||||
const mb_parameter_descriptor_t device_parameters[] = {
|
||||
{CID_HOLD_DATA_0, STR("TOTALFACTIVE"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALFACTIVE, 2,
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_1, STR("TOTALRACTIVE"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALRACTIVE, 2,
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_2, STR("ACTIVEPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, ACTIVEPOWER, 2,
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_3, STR("APPARENTPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, APPARENTPOWER, 2,
|
||||
HOLD_OFFSET(holding_data3), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_4, STR("REACTIVEPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, REACTIVEPOWER, 2,
|
||||
HOLD_OFFSET(holding_data4), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_5, STR("L1CURRENT"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2,
|
||||
HOLD_OFFSET(holding_data5), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_6, STR("L1VOLTAGE"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1VOLTAGE, 2,
|
||||
HOLD_OFFSET(holding_data6), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}
|
||||
};
|
||||
|
||||
// Calculate number of parameters in the table
|
||||
const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
|
||||
|
||||
// Function to get pointer to parameter storage (instance) according to parameter description table
|
||||
static void *master_get_param_data(const mb_parameter_descriptor_t *param_descriptor)
|
||||
{
|
||||
assert(param_descriptor != NULL);
|
||||
void *instance_ptr = NULL;
|
||||
if (param_descriptor->param_offset != 0)
|
||||
{
|
||||
switch (param_descriptor->mb_param_type)
|
||||
{
|
||||
case MB_PARAM_HOLDING:
|
||||
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_INPUT:
|
||||
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_COIL:
|
||||
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_DISCRETE:
|
||||
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
default:
|
||||
instance_ptr = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid);
|
||||
assert(instance_ptr != NULL);
|
||||
}
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
// Float - Mid-Little Endian (CDAB)
|
||||
float ReverseFloat(const float inFloat)
|
||||
{
|
||||
float retVal;
|
||||
char *floatToConvert = (char *)&inFloat;
|
||||
char *returnFloat = (char *)&retVal;
|
||||
|
||||
// swap the bytes into a temporary buffer
|
||||
returnFloat[0] = floatToConvert[2];
|
||||
returnFloat[1] = floatToConvert[3];
|
||||
returnFloat[2] = floatToConvert[0];
|
||||
returnFloat[3] = floatToConvert[1];
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void serial_mdb_task_func(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "serial_mdb_task_func");
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
float l1current = 0;
|
||||
int error_count = 0;
|
||||
|
||||
bool alarm_state = false;
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
|
||||
ESP_LOGI(TAG, "Start modbus...");
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Read all found characteristics from slave(s)
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
|
||||
{
|
||||
// Get data from parameters description table
|
||||
err = mbc_master_get_cid_info(cid, ¶m_descriptor);
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
|
||||
{
|
||||
void *temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
uint8_t type = 0;
|
||||
|
||||
err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key,
|
||||
(uint8_t *)temp_data_ptr, &type);
|
||||
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
error_count = 0;
|
||||
meterState = true;
|
||||
|
||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT))
|
||||
{
|
||||
int value = *(int *)temp_data_ptr;
|
||||
|
||||
ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = %d (0x%" PRIx32 ") read successful.",
|
||||
param_descriptor->cid,
|
||||
param_descriptor->param_key,
|
||||
param_descriptor->param_units,
|
||||
value,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min)))
|
||||
{
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_count > 3 && !meterTest)
|
||||
{
|
||||
meterState = false;
|
||||
vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls
|
||||
}
|
||||
else
|
||||
{
|
||||
error_count++;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char *)esp_err_to_name(err));
|
||||
}
|
||||
|
||||
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
|
||||
}
|
||||
|
||||
if (alarm_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY);
|
||||
}
|
||||
ESP_LOGI(TAG, "Destroy master...");
|
||||
ESP_ERROR_CHECK(mbc_master_destroy());
|
||||
}
|
||||
|
||||
// Modbus master initialization
|
||||
static esp_err_t master_init(void)
|
||||
{
|
||||
mb_communication_info_t comm = {
|
||||
.port = MB_PORT_NUM,
|
||||
.mode = MB_MODE_RTU,
|
||||
.baudrate = MB_DEV_SPEED,
|
||||
.parity = UART_PARITY_DISABLE};
|
||||
void *master_handler = NULL;
|
||||
|
||||
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
|
||||
ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail.");
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail, returns(0x%x).", (int)err);
|
||||
err = mbc_master_setup((void *)&comm);
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller setup fail, returns(0x%x).", (int)err);
|
||||
|
||||
err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD,
|
||||
MB_UART_RTS, UART_PIN_NO_CHANGE);
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
|
||||
|
||||
err = mbc_master_start();
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller start fail, returned (0x%x).", (int)err);
|
||||
|
||||
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);
|
||||
|
||||
vTaskDelay(5);
|
||||
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller set descriptor fail, returns(0x%x).", (int)err);
|
||||
ESP_LOGI(TAG, "Modbus master stack initialized...");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
// Function to start the meter
|
||||
esp_err_t meter_orno513_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Starting MDB Serial");
|
||||
|
||||
// Call the initialization function directly
|
||||
esp_err_t err = master_init(); // Don't wrap this in ESP_ERROR_CHECK
|
||||
ESP_ERROR_CHECK(err); // Check if there was an error during initialization
|
||||
|
||||
// Create the task for reading Modbus data
|
||||
xTaskCreate(serial_mdb_task_func, "serial_mdb_task", 4 * 1024, NULL, 5, &serial_mdb_task);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// Function to stop the meter
|
||||
void meter_orno513_stop(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Stopping");
|
||||
|
||||
if (serial_mdb_task)
|
||||
{
|
||||
vTaskDelete(serial_mdb_task);
|
||||
serial_mdb_task = NULL;
|
||||
}
|
||||
|
||||
uart_driver_delete(MB_PORT_NUM);
|
||||
}
|
||||
60
components/meter_manager/driver/meter_orno/meter_orno513.h
Executable file
60
components/meter_manager/driver/meter_orno/meter_orno513.h
Executable file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do medidor ORNO 513 (SPI, mutex, registradores).
|
||||
*/
|
||||
esp_err_t meter_orno513_init(void);
|
||||
|
||||
/**
|
||||
* @brief Inicia a tarefa de leitura de dados do medidor ORNO 513.
|
||||
*/
|
||||
esp_err_t meter_orno513_start(void);
|
||||
|
||||
/**
|
||||
* @brief Para a tarefa de leitura e limpa os dados internos do medidor ORNO 513.
|
||||
*/
|
||||
void meter_orno513_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Verifica se o medidor ORNO 513 está em execução.
|
||||
*
|
||||
* @return true se a tarefa estiver ativa, false caso contrário.
|
||||
*/
|
||||
bool meter_orno513_is_running(void);
|
||||
|
||||
/**
|
||||
* @brief Limpa os dados armazenados no medidor ORNO 513 (zera todos os valores).
|
||||
*/
|
||||
void meter_orno513_clear_data(void);
|
||||
|
||||
// ----- Leituras por fase (L1) -----
|
||||
|
||||
// Tensão RMS (em volts)
|
||||
float meter_orno513_get_vrms_l1(void);
|
||||
|
||||
// Corrente RMS (em amperes)
|
||||
float meter_orno513_get_irms_l1(void);
|
||||
|
||||
// Potência ativa (W)
|
||||
int meter_orno513_get_watt_l1(void);
|
||||
|
||||
// Potência reativa (VAR)
|
||||
int meter_orno513_get_var_l1(void);
|
||||
|
||||
// Potência aparente (VA)
|
||||
int meter_orno513_get_va_l1(void);
|
||||
|
||||
// (Opcional) contador de watchdog para diagnóstico
|
||||
uint32_t meter_orno513_get_watchdog_counter(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
383
components/meter_manager/driver/meter_orno/meter_orno516.c
Executable file
383
components/meter_manager/driver/meter_orno/meter_orno516.c
Executable file
@@ -0,0 +1,383 @@
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "meter_orno516.h"
|
||||
#include "modbus_params.h" // for modbus parameters structures
|
||||
#include "mbcontroller.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define TXD_PIN (GPIO_NUM_17)
|
||||
#define RXD_PIN (GPIO_NUM_16)
|
||||
|
||||
static const char *TAG = "serial_mdb_orno516";
|
||||
|
||||
static bool enabled = false;
|
||||
static bool meterState = false;
|
||||
static bool meterTest = false;
|
||||
|
||||
static TaskHandle_t serial_mdb_task = NULL;
|
||||
|
||||
#define MB_PORT_NUM 2 //(CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
|
||||
#define MB_DEV_SPEED 9600 //(CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
|
||||
// #define MB_PARITY_EVEN
|
||||
|
||||
#define MB_UART_TXD 17
|
||||
#define MB_UART_RXD 16
|
||||
#define MB_UART_RTS 5
|
||||
|
||||
// Note: Some pins on target chip cannot be assigned for UART communication.
|
||||
// See UART documentation for selected board and target to configure pins using Kconfig.
|
||||
|
||||
// The number of parameters that intended to be used in the particular control process
|
||||
#define MASTER_MAX_CIDS num_device_parameters_orno516
|
||||
|
||||
// Number of reading of parameters from slave
|
||||
#define MASTER_MAX_RETRY 30
|
||||
|
||||
// Timeout to update cid over Modbus
|
||||
#define UPDATE_CIDS_TIMEOUT_MS (5000)
|
||||
#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS)
|
||||
|
||||
// Timeout between polls
|
||||
#define POLL_TIMEOUT_MS (1)
|
||||
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_PERIOD_MS)
|
||||
|
||||
// Timeout between erros
|
||||
#define ERROR_TIMEOUT_MS (30000)
|
||||
#define ERROR_TIMEOUT_TICS (ERROR_TIMEOUT_MS / portTICK_PERIOD_MS)
|
||||
|
||||
// The macro to get offset for parameter in the appropriate structure
|
||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
|
||||
// Discrete offset macro
|
||||
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
|
||||
|
||||
#define STR(fieldname) ((const char *)(fieldname))
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) \
|
||||
{ \
|
||||
.opt1 = min_val, .opt2 = max_val, .opt3 = step_val}
|
||||
|
||||
// Enumeration of modbus device addresses accessed by master device
|
||||
enum
|
||||
{
|
||||
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
|
||||
};
|
||||
|
||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
||||
enum
|
||||
{
|
||||
CID_HOLD_DATA_0 = 0,
|
||||
CID_HOLD_DATA_1 = 1,
|
||||
CID_HOLD_DATA_2 = 2,
|
||||
CID_HOLD_DATA_3 = 3,
|
||||
CID_HOLD_DATA_4 = 4,
|
||||
CID_HOLD_DATA_5 = 5,
|
||||
CID_HOLD_DATA_6 = 6
|
||||
};
|
||||
|
||||
#define SN 0x01
|
||||
#define METERID 0x02
|
||||
|
||||
#define L1VOLTAGE 0x000E
|
||||
#define L2VOLTAGE 0x0010
|
||||
#define L3VOLTAGE 0x0012
|
||||
|
||||
#define L1CURRENT 0x0016
|
||||
#define L2CURRENT 0x0018
|
||||
#define L3CURRENT 0x001A
|
||||
|
||||
#define TOTALACTIVEPOWER 0x001C
|
||||
|
||||
// Example Data (Object) Dictionary for Modbus parameters:
|
||||
// The CID field in the table must be unique.
|
||||
// Modbus Slave Addr field defines slave address of the device with correspond parameter.
|
||||
// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such).
|
||||
// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the characteristic accordingly.
|
||||
// The Instance Offset defines offset in the appropriate parameter structure that will be used as instance to save parameter value.
|
||||
// Data Type, Data Size specify type of the characteristic and its data size.
|
||||
// Parameter Options field specifies the options that can be used to process parameter value (limits or masks).
|
||||
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
|
||||
const mb_parameter_descriptor_t device_parameters_orno516[] = {
|
||||
// { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
|
||||
|
||||
{CID_HOLD_DATA_0, STR("L1"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2,
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_1, STR("L2"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L2CURRENT, 2,
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
|
||||
|
||||
{CID_HOLD_DATA_2, STR("L3"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L3CURRENT, 2,
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}
|
||||
};
|
||||
|
||||
// Calculate number of parameters in the table
|
||||
const uint16_t num_device_parameters_orno516 = (sizeof(device_parameters_orno516) / sizeof(device_parameters_orno516[0]));
|
||||
|
||||
// The function to get pointer to parameter storage (instance) according to parameter description table
|
||||
static void *master_get_param_data_orno516(const mb_parameter_descriptor_t *param_descriptor)
|
||||
{
|
||||
assert(param_descriptor != NULL);
|
||||
void *instance_ptr = NULL;
|
||||
if (param_descriptor->param_offset != 0)
|
||||
{
|
||||
switch (param_descriptor->mb_param_type)
|
||||
{
|
||||
case MB_PARAM_HOLDING:
|
||||
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_INPUT:
|
||||
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_COIL:
|
||||
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_DISCRETE:
|
||||
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
default:
|
||||
instance_ptr = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid);
|
||||
assert(instance_ptr != NULL);
|
||||
}
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
// Float - Mid-Little Endian (CDAB)
|
||||
float ReverseFloat_orno516(const float inFloat)
|
||||
{
|
||||
float retVal;
|
||||
char *floatToConvert = (char *)&inFloat;
|
||||
char *returnFloat = (char *)&retVal;
|
||||
|
||||
// swap the bytes into a temporary buffer
|
||||
returnFloat[0] = floatToConvert[2];
|
||||
returnFloat[1] = floatToConvert[3];
|
||||
returnFloat[2] = floatToConvert[0];
|
||||
returnFloat[3] = floatToConvert[1];
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void serial_mdb_task_func_orno516(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "serial_mdb_task_func_orno516");
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
float maxcurrent = 0;
|
||||
float l1current = 0;
|
||||
float l2current = 0;
|
||||
float l3current = 0;
|
||||
int error_count = 0;
|
||||
|
||||
bool alarm_state = false;
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
|
||||
ESP_LOGI(TAG, "Start modbus...");
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Read all found characteristics from slave(s)
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
|
||||
{
|
||||
// Get data from parameters description table
|
||||
// and use this information to fill the characteristics description table
|
||||
// and having all required fields in just one table
|
||||
err = mbc_master_get_cid_info(cid, ¶m_descriptor);
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
|
||||
{
|
||||
void *temp_data_ptr = master_get_param_data_orno516(param_descriptor);
|
||||
uint8_t type = 0;
|
||||
|
||||
err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key,
|
||||
(uint8_t *)temp_data_ptr, &type);
|
||||
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
error_count = 0;
|
||||
meterState = true;
|
||||
|
||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT))
|
||||
{
|
||||
float value = *(float *)temp_data_ptr;
|
||||
value = ReverseFloat_orno516(value);
|
||||
|
||||
switch (cid)
|
||||
{
|
||||
case 0:
|
||||
maxcurrent = 0;
|
||||
l1current = 0;
|
||||
l2current = 0;
|
||||
l3current = 0;
|
||||
|
||||
l1current = value;
|
||||
break;
|
||||
case 1:
|
||||
l2current = value;
|
||||
break;
|
||||
case 2:
|
||||
l3current = value;
|
||||
break;
|
||||
default:
|
||||
// code block
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Characteristic #%u %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
param_descriptor->cid,
|
||||
param_descriptor->param_key,
|
||||
param_descriptor->param_units,
|
||||
value,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min)))
|
||||
{
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_count > 3 && !meterTest)
|
||||
{
|
||||
meterState = false;
|
||||
vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls
|
||||
}
|
||||
else
|
||||
{
|
||||
error_count++;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char *)esp_err_to_name(err));
|
||||
}
|
||||
|
||||
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
|
||||
}
|
||||
|
||||
if (alarm_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY);
|
||||
}
|
||||
ESP_LOGI(TAG, "Destroy master...");
|
||||
ESP_ERROR_CHECK(mbc_master_destroy());
|
||||
}
|
||||
|
||||
// Modbus master initialization
|
||||
static esp_err_t master_init_orno516(void)
|
||||
{
|
||||
// Initialize and start Modbus controller
|
||||
mb_communication_info_t comm = {
|
||||
//.slave_addr = 1,
|
||||
.port = MB_PORT_NUM,
|
||||
.mode = MB_MODE_RTU,
|
||||
.baudrate = MB_DEV_SPEED,
|
||||
.parity = UART_PARITY_EVEN};
|
||||
void *master_handler = NULL;
|
||||
|
||||
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
|
||||
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail.");
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail, returns(0x%x).", (int)err);
|
||||
err = mbc_master_setup((void *)&comm);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller setup fail, returns(0x%x).", (int)err);
|
||||
|
||||
// Set UART pin numbers
|
||||
err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD,
|
||||
MB_UART_RTS, UART_PIN_NO_CHANGE);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
|
||||
|
||||
err = mbc_master_start();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller start fail, returned (0x%x).", (int)err);
|
||||
|
||||
// Set driver mode to Half Duplex
|
||||
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);
|
||||
|
||||
vTaskDelay(5);
|
||||
err = mbc_master_set_descriptor(&device_parameters_orno516[0], num_device_parameters_orno516);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller set descriptor fail, returns(0x%x).", (int)err);
|
||||
ESP_LOGI(TAG, "Modbus master stack initialized...");
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set meter model
|
||||
*
|
||||
*/
|
||||
void serial_mdb_set_model_orno516(bool _enabled)
|
||||
{
|
||||
enabled = _enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set meter state
|
||||
*
|
||||
*/
|
||||
bool serial_mdb_get_meter_state_orno516()
|
||||
{
|
||||
return meterState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set meter test state
|
||||
*
|
||||
*/
|
||||
void serial_mdb_set_meter_test_orno516(bool _meterTest)
|
||||
{
|
||||
meterTest = _meterTest;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t serial_mdb_start_orno516()
|
||||
{
|
||||
ESP_LOGI(TAG, "Starting MDB Serial");
|
||||
|
||||
// Call the initialization function and check for errors
|
||||
esp_err_t err = master_init_orno516();
|
||||
ESP_ERROR_CHECK(err); // Check if there was an error during initialization
|
||||
|
||||
// Create the task to handle the MDB serial communication
|
||||
xTaskCreate(serial_mdb_task_func_orno516, "serial_mdb_task_orno516", 4 * 1024, NULL, 5, &serial_mdb_task);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void serial_mdb_stop_orno516(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Stopping");
|
||||
|
||||
if (serial_mdb_task)
|
||||
{
|
||||
vTaskDelete(serial_mdb_task);
|
||||
serial_mdb_task = NULL;
|
||||
}
|
||||
|
||||
uart_driver_delete(MB_PORT_NUM);
|
||||
}
|
||||
73
components/meter_manager/driver/meter_orno/meter_orno516.h
Executable file
73
components/meter_manager/driver/meter_orno/meter_orno516.h
Executable file
@@ -0,0 +1,73 @@
|
||||
#ifndef METER_ORNO516_H_
|
||||
#define METER_ORNO516_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do medidor ORNO 516 (SPI, mutex, registradores).
|
||||
*
|
||||
* @return esp_err_t Retorna ESP_OK se a inicialização for bem-sucedida, caso contrário retorna um erro.
|
||||
*/
|
||||
esp_err_t meter_init_orno516(void);
|
||||
|
||||
/**
|
||||
* @brief Inicia a tarefa de leitura de dados do medidor ORNO 516.
|
||||
*
|
||||
* @return esp_err_t Retorna ESP_OK se a tarefa for iniciada com sucesso, caso contrário retorna um erro.
|
||||
*/
|
||||
esp_err_t meter_start_orno516(void);
|
||||
|
||||
/**
|
||||
* @brief Para a tarefa de leitura e limpa os dados internos do medidor ORNO 516.
|
||||
*/
|
||||
void meter_stop_orno516(void);
|
||||
|
||||
/**
|
||||
* @brief Verifica se o medidor ORNO 516 está em execução.
|
||||
*
|
||||
* @return true Se a tarefa estiver ativa, false caso contrário.
|
||||
*/
|
||||
bool meter_is_running_orno516(void);
|
||||
|
||||
/**
|
||||
* @brief Limpa os dados armazenados no medidor ORNO 516 (zera todos os valores).
|
||||
*/
|
||||
void meter_clear_data_orno516(void);
|
||||
|
||||
// ----- Leituras por fase (L1, L2, L3) -----
|
||||
|
||||
// Tensão RMS (em volts)
|
||||
float meter_get_vrms_l1_orno516(void);
|
||||
float meter_get_vrms_l2_orno516(void);
|
||||
float meter_get_vrms_l3_orno516(void);
|
||||
|
||||
// Corrente RMS (em amperes)
|
||||
float meter_get_irms_l1_orno516(void);
|
||||
float meter_get_irms_l2_orno516(void);
|
||||
float meter_get_irms_l3_orno516(void);
|
||||
|
||||
// Potência ativa (W)
|
||||
int meter_get_watt_l1_orno516(void);
|
||||
int meter_get_watt_l2_orno516(void);
|
||||
int meter_get_watt_l3_orno516(void);
|
||||
|
||||
// Potência reativa (VAR)
|
||||
int meter_get_var_l1_orno516(void);
|
||||
int meter_get_var_l2_orno516(void);
|
||||
int meter_get_var_l3_orno516(void);
|
||||
|
||||
// Potência aparente (VA)
|
||||
int meter_get_va_l1_orno516(void);
|
||||
int meter_get_va_l2_orno516(void);
|
||||
int meter_get_va_l3_orno516(void);
|
||||
|
||||
// (Opcional) contador de watchdog para diagnóstico
|
||||
uint32_t meter_get_watchdog_counter_orno516(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* METER_ORNO516_H_ */
|
||||
20
components/meter_manager/driver/meter_orno/modbus_params.c
Executable file
20
components/meter_manager/driver/meter_orno/modbus_params.c
Executable file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/*=====================================================================================
|
||||
* Description:
|
||||
* C file to define parameter storage instances
|
||||
*====================================================================================*/
|
||||
#include "modbus_params.h"
|
||||
|
||||
// Here are the user defined instances for device parameters packed by 1 byte
|
||||
// These are keep the values that can be accessed from Modbus master
|
||||
holding_reg_params_t holding_reg_params = { 0 };
|
||||
|
||||
input_reg_params_t input_reg_params = { 0 };
|
||||
|
||||
coil_reg_params_t coil_reg_params = { 0 };
|
||||
|
||||
discrete_reg_params_t discrete_reg_params = { 0 };
|
||||
86
components/meter_manager/driver/meter_orno/modbus_params.h
Executable file
86
components/meter_manager/driver/meter_orno/modbus_params.h
Executable file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*=====================================================================================
|
||||
* Description:
|
||||
* The Modbus parameter structures used to define Modbus instances that
|
||||
* can be addressed by Modbus protocol. Define these structures per your needs in
|
||||
* your application. Below is just an example of possible parameters.
|
||||
*====================================================================================*/
|
||||
#ifndef _DEVICE_PARAMS
|
||||
#define _DEVICE_PARAMS
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// This file defines structure of modbus parameters which reflect correspond modbus address space
|
||||
// for each modbus register type (coils, discreet inputs, holding registers, input registers)
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t discrete_input0:1;
|
||||
uint8_t discrete_input1:1;
|
||||
uint8_t discrete_input2:1;
|
||||
uint8_t discrete_input3:1;
|
||||
uint8_t discrete_input4:1;
|
||||
uint8_t discrete_input5:1;
|
||||
uint8_t discrete_input6:1;
|
||||
uint8_t discrete_input7:1;
|
||||
uint8_t discrete_input_port1;
|
||||
uint8_t discrete_input_port2;
|
||||
} discrete_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t coils_port0;
|
||||
uint8_t coils_port1;
|
||||
uint8_t coils_port2;
|
||||
} coil_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
float input_data0; // 0
|
||||
float input_data1; // 2
|
||||
float input_data2; // 4
|
||||
float input_data3; // 6
|
||||
uint16_t data[150]; // 8 + 150 = 158
|
||||
float input_data4; // 158
|
||||
float input_data5;
|
||||
float input_data6;
|
||||
float input_data7;
|
||||
uint16_t data_block1[150];
|
||||
} input_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t holding_data0;
|
||||
uint32_t holding_data1;
|
||||
uint32_t holding_data2;
|
||||
uint32_t holding_data3;
|
||||
uint32_t holding_data4;
|
||||
uint32_t holding_data5;
|
||||
uint32_t holding_data6;
|
||||
uint32_t holding_data7;
|
||||
uint32_t holding_data8;
|
||||
uint32_t holding_data9;
|
||||
uint32_t holding_data10;
|
||||
uint32_t holding_data11;
|
||||
uint32_t holding_data12;
|
||||
uint32_t holding_data13;
|
||||
} holding_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
extern holding_reg_params_t holding_reg_params;
|
||||
extern input_reg_params_t input_reg_params;
|
||||
extern coil_reg_params_t coil_reg_params;
|
||||
extern discrete_reg_params_t discrete_reg_params;
|
||||
|
||||
#endif // !defined(_DEVICE_PARAMS)
|
||||
277
components/meter_manager/driver/meter_zigbee/meter_zigbee.c
Executable file
277
components/meter_manager/driver/meter_zigbee/meter_zigbee.c
Executable file
@@ -0,0 +1,277 @@
|
||||
#include "meter_zigbee.h"
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#define TAG "meter_zigbee"
|
||||
|
||||
// UART config
|
||||
#define UART_PORT UART_NUM_1
|
||||
#define TXD_PIN GPIO_NUM_17
|
||||
#define RXD_PIN GPIO_NUM_16
|
||||
#define UART_BUF_SIZE 128
|
||||
#define RX_FRAME_SIZE 14
|
||||
|
||||
// Zigbee Attribute IDs
|
||||
#define ATTR_CURRENT_L1 0x0006
|
||||
#define ATTR_CURRENT_L2 0x0007
|
||||
#define ATTR_CURRENT_L3 0x0008
|
||||
|
||||
#define ATTR_VOLTAGE_L1 0x0266
|
||||
#define ATTR_CURRENT_L1_ALT 0x0267
|
||||
#define ATTR_POWER_L1 0x0268
|
||||
|
||||
#define ATTR_VOLTAGE_L2 0x0269
|
||||
#define ATTR_CURRENT_L2_ALT 0x026A
|
||||
#define ATTR_POWER_L2 0x026B
|
||||
|
||||
#define ATTR_VOLTAGE_L3 0x026C
|
||||
#define ATTR_CURRENT_L3_ALT 0x026D
|
||||
#define ATTR_POWER_L3 0x026E
|
||||
|
||||
#define ATTR_FREQUENCY 0x0265
|
||||
#define ATTR_POWER_FACTOR 0x020F
|
||||
#define ATTR_TOTAL_ENERGY 0x0201
|
||||
|
||||
#define PHASE_COUNT 3
|
||||
#define PHASE_L1 0
|
||||
#define PHASE_L2 1
|
||||
#define PHASE_L3 2
|
||||
|
||||
// Internal meter state
|
||||
typedef struct {
|
||||
float vrms[PHASE_COUNT];
|
||||
float irms[PHASE_COUNT];
|
||||
int watt[PHASE_COUNT];
|
||||
int var[PHASE_COUNT];
|
||||
int va[PHASE_COUNT];
|
||||
float frequency;
|
||||
float power_factor;
|
||||
float total_energy;
|
||||
} meter_zigbee_data_t;
|
||||
|
||||
static meter_zigbee_data_t meter_data = {0};
|
||||
static SemaphoreHandle_t meter_mutex = NULL;
|
||||
static TaskHandle_t meter_task = NULL;
|
||||
|
||||
// ---------- Utils ----------
|
||||
|
||||
static inline float decode_float(const uint8_t *buf) {
|
||||
return (buf[9] + (buf[8] << 8) + (buf[7] << 16)) / 100.0f;
|
||||
}
|
||||
|
||||
static float meter_data_get_float(const float *arr, uint8_t phase) {
|
||||
float val = 0.0f;
|
||||
if (phase >= PHASE_COUNT) return 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
val = arr[phase];
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static int meter_data_get_int(const int *arr, uint8_t phase) {
|
||||
int val = 0;
|
||||
if (phase >= PHASE_COUNT) return 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
val = arr[phase];
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void meter_data_clear(void) {
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
memset(&meter_data, 0, sizeof(meter_data));
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Frame Handler ----------
|
||||
|
||||
static void handle_zigbee_frame(const uint8_t *buf) {
|
||||
uint16_t attr = buf[1] | (buf[2] << 8);
|
||||
uint8_t size = buf[4];
|
||||
|
||||
if (size != 8) {
|
||||
ESP_LOGW(TAG, "Unexpected data size: %d", size);
|
||||
return;
|
||||
}
|
||||
|
||||
float value = decode_float(buf);
|
||||
ESP_LOGI(TAG, "Attr 0x%04X = %.2f", attr, value);
|
||||
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
switch (attr) {
|
||||
case ATTR_CURRENT_L1:
|
||||
case ATTR_CURRENT_L1_ALT:
|
||||
meter_data.irms[0] = value;
|
||||
break;
|
||||
|
||||
case ATTR_CURRENT_L2:
|
||||
case ATTR_CURRENT_L2_ALT:
|
||||
meter_data.irms[1] = value;
|
||||
break;
|
||||
|
||||
case ATTR_CURRENT_L3:
|
||||
case ATTR_CURRENT_L3_ALT:
|
||||
meter_data.irms[2] = value;
|
||||
break;
|
||||
|
||||
case ATTR_VOLTAGE_L1: meter_data.vrms[0] = value; break;
|
||||
case ATTR_VOLTAGE_L2: meter_data.vrms[1] = value; break;
|
||||
case ATTR_VOLTAGE_L3: meter_data.vrms[2] = value; break;
|
||||
|
||||
case ATTR_POWER_L1: meter_data.watt[0] = (int)value; break;
|
||||
case ATTR_POWER_L2: meter_data.watt[1] = (int)value; break;
|
||||
case ATTR_POWER_L3: meter_data.watt[2] = (int)value; break;
|
||||
|
||||
case ATTR_POWER_FACTOR: meter_data.power_factor = value; break;
|
||||
case ATTR_FREQUENCY: meter_data.frequency = value; break;
|
||||
case ATTR_TOTAL_ENERGY: meter_data.total_energy = value; break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unknown attr: 0x%04X", attr);
|
||||
break;
|
||||
}
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Task ----------
|
||||
|
||||
static void meter_task_func(void *param) {
|
||||
uint8_t *buf = malloc(RX_FRAME_SIZE);
|
||||
if (!buf) {
|
||||
ESP_LOGE(TAG, "Memory allocation failed");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Zigbee meter task started");
|
||||
|
||||
while (1) {
|
||||
int len = uart_read_bytes(UART_PORT, buf, RX_FRAME_SIZE, pdMS_TO_TICKS(1000));
|
||||
if (len >= 10) {
|
||||
handle_zigbee_frame(buf);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// ---------- Public API (meter.h) ----------
|
||||
|
||||
esp_err_t meter_init(void) {
|
||||
ESP_LOGI(TAG, "Initializing Zigbee meter");
|
||||
|
||||
if (!meter_mutex) {
|
||||
meter_mutex = xSemaphoreCreateMutex();
|
||||
if (!meter_mutex) return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
meter_data_clear();
|
||||
|
||||
uart_config_t config = {
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(uart_param_config(UART_PORT, &config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
ESP_ERROR_CHECK(uart_driver_install(UART_PORT, UART_BUF_SIZE * 2, 0, 0, NULL, 0));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t meter_start(void) {
|
||||
if (meter_task) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
xTaskCreate(meter_task_func, "meter_zigbee_task", 4096, NULL, 5, &meter_task);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void meter_stop(void) {
|
||||
if (meter_task) {
|
||||
vTaskDelete(meter_task);
|
||||
meter_task = NULL;
|
||||
}
|
||||
|
||||
uart_driver_delete(UART_PORT);
|
||||
|
||||
if (meter_mutex) {
|
||||
vSemaphoreDelete(meter_mutex);
|
||||
meter_mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool meter_is_running(void) {
|
||||
return meter_task != NULL;
|
||||
}
|
||||
|
||||
void meter_clear_data(void) {
|
||||
meter_data_clear();
|
||||
}
|
||||
|
||||
// ---------- RMS Current ----------
|
||||
float meter_get_irms_l1(void) { return meter_data_get_float(meter_data.irms, PHASE_L1); }
|
||||
float meter_get_irms_l2(void) { return meter_data_get_float(meter_data.irms, PHASE_L2); }
|
||||
float meter_get_irms_l3(void) { return meter_data_get_float(meter_data.irms, PHASE_L3); }
|
||||
|
||||
// ---------- RMS Voltage ----------
|
||||
float meter_get_vrms_l1(void) { return meter_data_get_float(meter_data.vrms, PHASE_L1); }
|
||||
float meter_get_vrms_l2(void) { return meter_data_get_float(meter_data.vrms, PHASE_L2); }
|
||||
float meter_get_vrms_l3(void) { return meter_data_get_float(meter_data.vrms, PHASE_L3); }
|
||||
|
||||
// ---------- Active Power ----------
|
||||
int meter_get_watt_l1(void) { return meter_data_get_int(meter_data.watt, PHASE_L1); }
|
||||
int meter_get_watt_l2(void) { return meter_data_get_int(meter_data.watt, PHASE_L2); }
|
||||
int meter_get_watt_l3(void) { return meter_data_get_int(meter_data.watt, PHASE_L3); }
|
||||
|
||||
// ---------- Reactive Power ----------
|
||||
int meter_get_var_l1(void) { return meter_data_get_int(meter_data.var, PHASE_L1); }
|
||||
int meter_get_var_l2(void) { return meter_data_get_int(meter_data.var, PHASE_L2); }
|
||||
int meter_get_var_l3(void) { return meter_data_get_int(meter_data.var, PHASE_L3); }
|
||||
|
||||
// ---------- Apparent Power ----------
|
||||
int meter_get_va_l1(void) { return meter_data_get_int(meter_data.va, PHASE_L1); }
|
||||
int meter_get_va_l2(void) { return meter_data_get_int(meter_data.va, PHASE_L2); }
|
||||
int meter_get_va_l3(void) { return meter_data_get_int(meter_data.va, PHASE_L3); }
|
||||
|
||||
// ---------- Extra Data ----------
|
||||
float meter_get_frequency(void) {
|
||||
float v = 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
v = meter_data.frequency;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
float meter_get_power_factor(void) {
|
||||
float v = 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
v = meter_data.power_factor;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
float meter_get_total_energy(void) {
|
||||
float v = 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
v = meter_data.total_energy;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
98
components/meter_manager/driver/meter_zigbee/meter_zigbee.h
Executable file
98
components/meter_manager/driver/meter_zigbee/meter_zigbee.h
Executable file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do medidor Zigbee (UART, mutex, etc.).
|
||||
*
|
||||
* @return ESP_OK se a inicialização for bem-sucedida, erro caso contrário.
|
||||
*/
|
||||
esp_err_t meter_init_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Inicia a tarefa de leitura dos dados do medidor Zigbee.
|
||||
*
|
||||
* @return ESP_OK se a tarefa for iniciada com sucesso, erro caso contrário.
|
||||
*/
|
||||
esp_err_t meter_start_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Interrompe a tarefa e limpa recursos (UART, mutex, etc.).
|
||||
*/
|
||||
void meter_stop_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Verifica se o medidor Zigbee está em execução.
|
||||
*
|
||||
* @return true se a tarefa está ativa, false se não.
|
||||
*/
|
||||
bool meter_is_running_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Limpa todos os dados armazenados em memória.
|
||||
*/
|
||||
void meter_clear_data_zigbee(void);
|
||||
|
||||
// ----------------------
|
||||
// Leituras por fase (L1, L2, L3)
|
||||
// ----------------------
|
||||
|
||||
// Corrente RMS (em amperes)
|
||||
float meter_get_irms_l1_zigbee(void);
|
||||
float meter_get_irms_l2_zigbee(void);
|
||||
float meter_get_irms_l3_zigbee(void);
|
||||
|
||||
// Tensão RMS (em volts)
|
||||
float meter_get_vrms_l1_zigbee(void);
|
||||
float meter_get_vrms_l2_zigbee(void);
|
||||
float meter_get_vrms_l3_zigbee(void);
|
||||
|
||||
// Potência ativa (W)
|
||||
int meter_get_watt_l1_zigbee(void);
|
||||
int meter_get_watt_l2_zigbee(void);
|
||||
int meter_get_watt_l3_zigbee(void);
|
||||
|
||||
// Potência reativa (VAR)
|
||||
int meter_get_var_l1_zigbee(void);
|
||||
int meter_get_var_l2_zigbee(void);
|
||||
int meter_get_var_l3_zigbee(void);
|
||||
|
||||
// Potência aparente (VA)
|
||||
int meter_get_va_l1_zigbee(void);
|
||||
int meter_get_va_l2_zigbee(void);
|
||||
int meter_get_va_l3_zigbee(void);
|
||||
|
||||
// ----------------------
|
||||
// Dados adicionais
|
||||
// ----------------------
|
||||
|
||||
/**
|
||||
* @brief Retorna a frequência da rede em Hz.
|
||||
*
|
||||
* @return Valor da frequência da rede em Hz.
|
||||
*/
|
||||
float meter_get_frequency_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Retorna o fator de potência médio.
|
||||
*
|
||||
* @return Valor do fator de potência médio.
|
||||
*/
|
||||
float meter_get_power_factor_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Retorna a energia total acumulada (kWh ou Wh, dependendo do dispositivo).
|
||||
*
|
||||
* @return Valor da energia total acumulada.
|
||||
*/
|
||||
float meter_get_total_energy_zigbee(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
29
components/meter_manager/include/meter_manager.h
Executable file
29
components/meter_manager/include/meter_manager.h
Executable file
@@ -0,0 +1,29 @@
|
||||
#ifndef METER_MANAGER_H
|
||||
#define METER_MANAGER_H
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
// Definindo tipos de medidores possíveis para EVSE e Grid
|
||||
typedef enum {
|
||||
METER_TYPE_NONE, // Nenhum medidor
|
||||
METER_TYPE_EVSE_ADE7758, // EVSE com ADE7758
|
||||
METER_TYPE_GRID_ORNO513, // Grid com ORNO 513
|
||||
METER_TYPE_GRID_ORNO516, // Grid com ORNO 516
|
||||
METER_TYPE_GRID_ZIGBEE // Grid com Zigbee
|
||||
} meter_type_t;
|
||||
|
||||
// Funções para inicializar e gerenciar o medidor EVSE (pode ser ADE7758)
|
||||
esp_err_t meter_manager_init_evse(meter_type_t evse_type); // Inicializa o medidor EVSE (ex: ADE7758)
|
||||
esp_err_t meter_manager_start_evse(meter_type_t evse_type); // Inicia o EVSE com o tipo especificado
|
||||
esp_err_t meter_manager_stop_evse(void); // Para o EVSE
|
||||
|
||||
// Funções para inicializar e gerenciar o medidor Grid (pode ser ORNO 513, ORNO 516 ou Zigbee)
|
||||
esp_err_t meter_manager_init_grid(meter_type_t grid_type); // Inicializa o medidor Grid (ORNO 513, ORNO 516, Zigbee)
|
||||
esp_err_t meter_manager_start_grid(meter_type_t grid_type); // Inicia o medidor Grid com o tipo especificado
|
||||
esp_err_t meter_manager_stop_grid(void); // Para o medidor Grid
|
||||
|
||||
// Funções para ler dados dos medidores
|
||||
esp_err_t meter_manager_read_current(meter_type_t meter_type, float *current); // Lê a corrente do medidor
|
||||
esp_err_t meter_manager_read_voltage(meter_type_t meter_type, float *voltage); // Lê a tensão do medidor
|
||||
|
||||
#endif // METER_MANAGER_H
|
||||
138
components/meter_manager/src/meter_manager.c
Executable file
138
components/meter_manager/src/meter_manager.c
Executable file
@@ -0,0 +1,138 @@
|
||||
#include "meter_manager.h"
|
||||
#include "esp_log.h"
|
||||
#include "meter_ade7758.h"
|
||||
#include "meter_orno513.h"
|
||||
#include "meter_orno516.h"
|
||||
#include "meter_zigbee.h"
|
||||
|
||||
static const char *TAG = "meter_manager";
|
||||
|
||||
// Variáveis para armazenar o tipo de medidor atual
|
||||
static meter_type_t current_meter_type = METER_TYPE_NONE;
|
||||
|
||||
esp_err_t meter_init(meter_type_t meter_type) {
|
||||
current_meter_type = meter_type;
|
||||
ESP_LOGI(TAG, "Initializing meter of type: %d", meter_type);
|
||||
|
||||
switch (current_meter_type) {
|
||||
case METER_TYPE_EVSE_ADE7758:
|
||||
return meter_ade7758_init(); // Inicializa o medidor ADE7758 (EVSE)
|
||||
case METER_TYPE_GRID_ORNO513:
|
||||
return meter_orno513_init(); // Inicializa o medidor ORNO 513 ou 516 (Grid)
|
||||
case METER_TYPE_GRID_ORNO516:
|
||||
return meter_init_orno516(); // Inicializa o medidor ORNO 513 ou 516 (Grid)
|
||||
case METER_TYPE_GRID_ZIGBEE:
|
||||
return meter_init_zigbee(); // Inicializa o medidor Zigbee (Grid)
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported meter type");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t meter_start(void) {
|
||||
if (current_meter_type == METER_TYPE_NONE) {
|
||||
ESP_LOGE(TAG, "Meter type is not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Starting meter");
|
||||
|
||||
switch (current_meter_type) {
|
||||
case METER_TYPE_EVSE_ADE7758:
|
||||
return meter_ade7758_start();
|
||||
case METER_TYPE_GRID_ORNO513:
|
||||
return meter_orno513_start();
|
||||
case METER_TYPE_GRID_ORNO516:
|
||||
return meter_start_orno516();
|
||||
case METER_TYPE_GRID_ZIGBEE:
|
||||
return meter_start_zigbee();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported meter type");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
void meter_stop(void) {
|
||||
if (current_meter_type == METER_TYPE_NONE) {
|
||||
ESP_LOGE(TAG, "Meter is not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stopping meter");
|
||||
|
||||
switch (current_meter_type) {
|
||||
case METER_TYPE_EVSE_ADE7758:
|
||||
meter_ade7758_stop();
|
||||
break;
|
||||
case METER_TYPE_GRID_ORNO513:
|
||||
meter_orno513_stop();
|
||||
break;
|
||||
case METER_TYPE_GRID_ORNO516:
|
||||
meter_stop_orno516();
|
||||
break;
|
||||
case METER_TYPE_GRID_ZIGBEE:
|
||||
meter_stop_zigbee();
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported meter type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool meter_is_running(void) {
|
||||
if (current_meter_type == METER_TYPE_NONE) {
|
||||
ESP_LOGE(TAG, "Meter is not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (current_meter_type) {
|
||||
case METER_TYPE_EVSE_ADE7758:
|
||||
return meter_ade7758_is_running();
|
||||
case METER_TYPE_GRID_ORNO513:
|
||||
return meter_orno513_is_running();
|
||||
case METER_TYPE_GRID_ORNO516:
|
||||
return meter_is_running_orno516();
|
||||
case METER_TYPE_GRID_ZIGBEE:
|
||||
return meter_is_running_zigbee();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported meter type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float meter_get_vrms_l1(void) {
|
||||
if (current_meter_type == METER_TYPE_NONE) return 0;
|
||||
switch (current_meter_type) {
|
||||
case METER_TYPE_EVSE_ADE7758:
|
||||
return meter_ade7758_get_vrms_l1();
|
||||
case METER_TYPE_GRID_ORNO513:
|
||||
return meter_orno513_get_vrms_l1();
|
||||
case METER_TYPE_GRID_ORNO516:
|
||||
return meter_get_vrms_l1_orno516();
|
||||
case METER_TYPE_GRID_ZIGBEE:
|
||||
return meter_get_vrms_l1_zigbee();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported meter type for reading vrms_l1");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue as funções `meter_get_*` para cada tipo de dado (corrente, potência, etc.)
|
||||
float meter_get_irms_l1(void) {
|
||||
if (current_meter_type == METER_TYPE_NONE) return 0;
|
||||
switch (current_meter_type) {
|
||||
case METER_TYPE_EVSE_ADE7758:
|
||||
return meter_ade7758_get_irms_l1();
|
||||
case METER_TYPE_GRID_ORNO513:
|
||||
return meter_orno513_get_irms_l1();
|
||||
case METER_TYPE_GRID_ORNO516:
|
||||
return meter_get_irms_l1_orno516();
|
||||
case METER_TYPE_GRID_ZIGBEE:
|
||||
return meter_get_irms_l1_zigbee();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported meter type for reading irms_l1");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// You should add the rest of the functions similarly as you progress
|
||||
Reference in New Issue
Block a user