mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-02-01 14:42:00 +00:00
Restructuring and cleaning out unnecessary files
This commit is contained in:
181
lib/HanReader/src/Aidon.h
Normal file
181
lib/HanReader/src/Aidon.h
Normal file
@@ -0,0 +1,181 @@
|
||||
// Aidon.h
|
||||
|
||||
#ifndef _AIDON_h
|
||||
#define _AIDON_h
|
||||
|
||||
|
||||
enum class Aidon
|
||||
{
|
||||
List1 = 0x01,
|
||||
List1PhaseShort = 0x09,
|
||||
List1PhaseLong = 0xff, // TODO: Need sample
|
||||
List3PhaseShort = 0x0D,
|
||||
List3PhaseLong = 0x12
|
||||
};
|
||||
|
||||
enum class Aidon_List1
|
||||
{
|
||||
ListSize,
|
||||
IGN_0,
|
||||
ActiveImportPower_OBIS,
|
||||
ActiveImportPower,
|
||||
IGN_1,
|
||||
ActiveImportPowerInt8,
|
||||
ActiveImportPowerEnum
|
||||
};
|
||||
|
||||
|
||||
enum class Aidon_List1Phase
|
||||
{
|
||||
ListSize,
|
||||
IGN_0,
|
||||
ListVersionIdentifier_OBIS,
|
||||
ListVersionIdentifier,
|
||||
IGN_1,
|
||||
MeterID_OBIS,
|
||||
MeterID,
|
||||
IGN_2,
|
||||
MeterType_OBIS,
|
||||
MeterType,
|
||||
IGN_3,
|
||||
ActiveImportPower_OBIS,
|
||||
ActiveImportPower,
|
||||
IGN_4,
|
||||
ActiveImportPowerInt8,
|
||||
ActiveImportPowerEnum,
|
||||
IGN_5,
|
||||
ActiveExportPower_OBIS,
|
||||
ActiveExportPower,
|
||||
IGN_6,
|
||||
ActiveExportPowerInt8,
|
||||
ActiveExportPowerEnum,
|
||||
IGN_7,
|
||||
ReactiveImportPower_OBIS,
|
||||
ReactiveImportPower,
|
||||
IGN_8,
|
||||
ReactiveImportPowerInt8,
|
||||
ReactiveImportPowerEnum,
|
||||
IGN_9,
|
||||
ReactiveExportPower_OBIS,
|
||||
ReactiveExportPower,
|
||||
IGN_10,
|
||||
ReactiveExportPowerInt8,
|
||||
ReactiveExportPowerEnum,
|
||||
IGN_11,
|
||||
CurrentL1_OBIS,
|
||||
CurrentL1,
|
||||
IGN_12,
|
||||
CurrentL1Int8,
|
||||
CurrentL1Enum,
|
||||
IGN_13,
|
||||
VoltageL1_OBIS,
|
||||
VoltageL1,
|
||||
IGN_14,
|
||||
VoltageL1Int8,
|
||||
VoltageL1Enum,
|
||||
};
|
||||
|
||||
enum class Aidon_List3Phase
|
||||
{
|
||||
ListSize,
|
||||
IGN_0,
|
||||
ListVersionIdentifier_OBIS,
|
||||
ListVersionIdentifier,
|
||||
IGN_1,
|
||||
MeterID_OBIS,
|
||||
MeterID,
|
||||
IGN_2,
|
||||
MeterType_OBIS,
|
||||
MeterType,
|
||||
IGN_3,
|
||||
ActiveImportPower_OBIS,
|
||||
ActiveImportPower,
|
||||
IGN_4,
|
||||
ActiveImportPowerInt8,
|
||||
ActiveImportPowerEnum,
|
||||
IGN_5,
|
||||
ActiveExportPower_OBIS,
|
||||
ActiveExportPower,
|
||||
IGN_6,
|
||||
ActiveExportPowerInt8,
|
||||
ActiveExportPowerEnum,
|
||||
IGN_7,
|
||||
ReactiveImportPower_OBIS,
|
||||
ReactiveImportPower,
|
||||
IGN_8,
|
||||
ReactiveImportPowerInt8,
|
||||
ReactiveImportPowerEnum,
|
||||
IGN_9,
|
||||
ReactiveExportPower_OBIS,
|
||||
ReactiveExportPower,
|
||||
IGN_10,
|
||||
ReactiveExportPowerInt8,
|
||||
ReactiveExportPowerEnum,
|
||||
IGN_11,
|
||||
CurrentL1_OBIS,
|
||||
CurrentL1,
|
||||
IGN_12,
|
||||
CurrentL1Int8,
|
||||
CurrentL1Enum,
|
||||
IGN_13,
|
||||
CurrentL2_OBIS,
|
||||
CurrentL2,
|
||||
IGN_14,
|
||||
CurrentL2Int8,
|
||||
CurrentL2Enum,
|
||||
IGN_15,
|
||||
CurrentL3_OBIS,
|
||||
CurrentL3,
|
||||
IGN_16,
|
||||
CurrentL3Int8,
|
||||
CurrentL3Enum,
|
||||
IGN_17,
|
||||
VoltageL1_OBIS,
|
||||
VoltageL1,
|
||||
IGN_18,
|
||||
VoltageL1Int8,
|
||||
VoltageL1Enum,
|
||||
IGN_19,
|
||||
VoltageL2_OBIS,
|
||||
VoltageL2,
|
||||
IGN_20,
|
||||
VoltageL2Int8,
|
||||
VoltageL2Enum,
|
||||
IGN_21,
|
||||
VoltageL3_OBIS,
|
||||
VoltageL3,
|
||||
IGN_22,
|
||||
VoltageL3Int8,
|
||||
VoltageL3Enum,
|
||||
IGN_23,
|
||||
Timestamp_OBIS,
|
||||
Timestamp,
|
||||
IGN_24,
|
||||
CumulativeActiveImportEnergy_OBIS,
|
||||
CumulativeActiveImportEnergy,
|
||||
IGN_25,
|
||||
CumulativeActiveImportEnergyInt8,
|
||||
CumulativeActiveImportEnergyEnum,
|
||||
IGN_26,
|
||||
CumulativeActiveExportEnergy_OBIS,
|
||||
CumulativeActiveExportEnergy,
|
||||
IGN_27,
|
||||
CumulativeActiveExportEnergyInt8,
|
||||
CumulativeActiveExportEnergyEnum,
|
||||
IGN_28,
|
||||
CumulativeReactiveImportEnergy_OBIS,
|
||||
CumulativeReactiveImportEnergy,
|
||||
IGN_29,
|
||||
CumulativeReactiveImportEnergyInt8,
|
||||
CumulativeReactiveImportEnergyEnum,
|
||||
IGN_30,
|
||||
CumulativeReactiveExportEnergy_OBIS,
|
||||
CumulativeReactiveExportEnergy,
|
||||
IGN_31,
|
||||
CumulativeReactiveExportEnergyInt8,
|
||||
CumulativeReactiveExportEnergyEnum
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
37
lib/HanReader/src/Crc16.cpp
Normal file
37
lib/HanReader/src/Crc16.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "Crc16.h"
|
||||
|
||||
Crc16Class::Crc16Class()
|
||||
{
|
||||
unsigned short value;
|
||||
unsigned short temp;
|
||||
for (unsigned short i = 0; i < 256; ++i)
|
||||
{
|
||||
value = 0;
|
||||
temp = i;
|
||||
for (byte j = 0; j < 8; ++j)
|
||||
{
|
||||
if (((value ^ temp) & 0x0001) != 0)
|
||||
{
|
||||
value = (ushort)((value >> 1) ^ polynomial);
|
||||
}
|
||||
else
|
||||
{
|
||||
value >>= 1;
|
||||
}
|
||||
temp >>= 1;
|
||||
}
|
||||
table[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short Crc16Class::ComputeChecksum(byte *data, int start, int length)
|
||||
{
|
||||
ushort fcs = 0xffff;
|
||||
for (int i = start; i < (start + length); i++)
|
||||
{
|
||||
byte index = (fcs ^ data[i]) & 0xff;
|
||||
fcs = (ushort)((fcs >> 8) ^ table[index]);
|
||||
}
|
||||
fcs ^= 0xffff;
|
||||
return fcs;
|
||||
}
|
||||
23
lib/HanReader/src/Crc16.h
Normal file
23
lib/HanReader/src/Crc16.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef _CRC16_h
|
||||
#define _CRC16_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
class Crc16Class
|
||||
{
|
||||
public:
|
||||
Crc16Class();
|
||||
unsigned short ComputeChecksum(byte *data, int start, int length);
|
||||
protected:
|
||||
private:
|
||||
const unsigned short polynomial = 0x8408;
|
||||
unsigned short table[256];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
154
lib/HanReader/src/DlmsReader.cpp
Normal file
154
lib/HanReader/src/DlmsReader.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "DlmsReader.h"
|
||||
|
||||
DlmsReader::DlmsReader()
|
||||
{
|
||||
//this->Clear();
|
||||
}
|
||||
|
||||
void DlmsReader::Clear()
|
||||
{
|
||||
this->position = 0;
|
||||
this->dataLength = 0;
|
||||
this->destinationAddressLength = 0;
|
||||
this->sourceAddressLength = 0;
|
||||
this->frameFormatType = 0;
|
||||
}
|
||||
|
||||
bool DlmsReader::Read(byte data)
|
||||
{
|
||||
if (position == 0 && data != 0x7E)
|
||||
{
|
||||
// we haven't started yet, wait for the start flag (no need to capture any data yet)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have completed reading of one package, so clear and be ready for the next
|
||||
if (dataLength > 0 && position >= dataLength + 2)
|
||||
Clear();
|
||||
|
||||
// Check if we're about to run into a buffer overflow
|
||||
if (position >= DLMS_READER_BUFFER_SIZE)
|
||||
Clear();
|
||||
|
||||
// Check if this is a second start flag, which indicates the previous one was a stop from the last package
|
||||
if (position == 1 && data == 0x7E)
|
||||
{
|
||||
// just return, we can keep the one byte we had in the buffer
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have started, so capture every byte
|
||||
buffer[position++] = data;
|
||||
|
||||
if (position == 1)
|
||||
{
|
||||
// This was the start flag, we're not done yet
|
||||
return false;
|
||||
}
|
||||
else if (position == 2)
|
||||
{
|
||||
// Capture the Frame Format Type
|
||||
frameFormatType = (byte)(data & 0xF0);
|
||||
if (!IsValidFrameFormat(frameFormatType))
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == 3)
|
||||
{
|
||||
// Capture the length of the data package
|
||||
dataLength = ((buffer[1] & 0x0F) << 8) | buffer[2];
|
||||
return false;
|
||||
}
|
||||
else if (destinationAddressLength == 0)
|
||||
{
|
||||
// Capture the destination address
|
||||
destinationAddressLength = GetAddress(3, destinationAddress, 0, DLMS_READER_MAX_ADDRESS_SIZE);
|
||||
if (destinationAddressLength > 3)
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (sourceAddressLength == 0)
|
||||
{
|
||||
// Capture the source address
|
||||
sourceAddressLength = GetAddress(3 + destinationAddressLength, sourceAddress, 0, DLMS_READER_MAX_ADDRESS_SIZE);
|
||||
if (sourceAddressLength > 3)
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == 4 + destinationAddressLength + sourceAddressLength + 2)
|
||||
{
|
||||
// Verify the header checksum
|
||||
ushort headerChecksum = GetChecksum(position - 3);
|
||||
if (headerChecksum != Crc16.ComputeChecksum(buffer, 1, position - 3))
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == dataLength + 1)
|
||||
{
|
||||
// Verify the data package checksum
|
||||
ushort checksum = this->GetChecksum(position - 3);
|
||||
if (checksum != Crc16.ComputeChecksum(buffer, 1, position - 3))
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == dataLength + 2)
|
||||
{
|
||||
// We're done, check the stop flag and signal we're done
|
||||
if (data == 0x7E)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DlmsReader::IsValidFrameFormat(byte frameFormatType)
|
||||
{
|
||||
return frameFormatType == 0xA0;
|
||||
}
|
||||
|
||||
int DlmsReader::GetRawData(byte *dataBuffer, int start, int length)
|
||||
{
|
||||
if (dataLength > 0 && position == dataLength + 2)
|
||||
{
|
||||
int headerLength = 3 + destinationAddressLength + sourceAddressLength + 2;
|
||||
int bytesWritten = 0;
|
||||
for (int i = headerLength + 1; i < dataLength - 1; i++)
|
||||
{
|
||||
dataBuffer[i + start - headerLength - 1] = buffer[i];
|
||||
bytesWritten++;
|
||||
}
|
||||
return bytesWritten;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DlmsReader::GetAddress(int addressPosition, byte* addressBuffer, int start, int length)
|
||||
{
|
||||
int addressBufferPos = start;
|
||||
for (int i = addressPosition; i < position; i++)
|
||||
{
|
||||
addressBuffer[addressBufferPos++] = buffer[i];
|
||||
|
||||
// LSB=1 means this was the last address byte
|
||||
if ((buffer[i] & 0x01) == 0x01)
|
||||
break;
|
||||
|
||||
// See if we've reached last byte, try again when we've got more data
|
||||
else if (i == position - 1)
|
||||
return 0;
|
||||
}
|
||||
return addressBufferPos - start;
|
||||
}
|
||||
|
||||
ushort DlmsReader::GetChecksum(int checksumPosition)
|
||||
{
|
||||
return (ushort)(buffer[checksumPosition + 2] << 8 |
|
||||
buffer[checksumPosition + 1]);
|
||||
}
|
||||
42
lib/HanReader/src/DlmsReader.h
Normal file
42
lib/HanReader/src/DlmsReader.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef _DLMSREADER_h
|
||||
#define _DLMSREADER_h
|
||||
|
||||
#include "Crc16.h"
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#define DLMS_READER_BUFFER_SIZE 512
|
||||
#define DLMS_READER_MAX_ADDRESS_SIZE 5
|
||||
|
||||
class DlmsReader
|
||||
{
|
||||
public:
|
||||
DlmsReader();
|
||||
bool Read(byte data);
|
||||
int GetRawData(byte *buffer, int start, int length);
|
||||
|
||||
protected:
|
||||
Crc16Class Crc16;
|
||||
|
||||
private:
|
||||
byte buffer[DLMS_READER_BUFFER_SIZE];
|
||||
int position;
|
||||
int dataLength;
|
||||
byte frameFormatType;
|
||||
byte destinationAddress[DLMS_READER_MAX_ADDRESS_SIZE];
|
||||
byte destinationAddressLength;
|
||||
byte sourceAddress[DLMS_READER_MAX_ADDRESS_SIZE];
|
||||
byte sourceAddressLength;
|
||||
|
||||
void Clear();
|
||||
int GetAddress(int addressPosition, byte* buffer, int start, int length);
|
||||
unsigned short GetChecksum(int checksumPosition);
|
||||
bool IsValidFrameFormat(byte frameFormatType);
|
||||
void WriteBuffer();
|
||||
};
|
||||
|
||||
#endif
|
||||
288
lib/HanReader/src/HanReader.cpp
Normal file
288
lib/HanReader/src/HanReader.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
#include "HanReader.h"
|
||||
|
||||
HanReader::HanReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HanReader::setup(HardwareSerial *hanPort, Stream *debugPort)
|
||||
{
|
||||
han = hanPort;
|
||||
bytesRead = 0;
|
||||
debug = debugPort;
|
||||
if (debug) debug->println("MBUS serial setup complete");
|
||||
}
|
||||
|
||||
void HanReader::setup(HardwareSerial *hanPort)
|
||||
{
|
||||
setup(hanPort, NULL);
|
||||
}
|
||||
|
||||
bool HanReader::read(byte data)
|
||||
{
|
||||
if (reader.Read(data))
|
||||
{
|
||||
bytesRead = reader.GetRawData(buffer, 0, 512);
|
||||
if (debug)
|
||||
{
|
||||
debug->print("Got valid DLMS data (");
|
||||
debug->print(bytesRead);
|
||||
debug->println(" bytes):");
|
||||
debugPrint(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
/*
|
||||
Data should start with E6 E7 00 0F
|
||||
and continue with four bytes for the InvokeId
|
||||
*/
|
||||
if (bytesRead < 9)
|
||||
{
|
||||
if (debug) debug->println("Invalid HAN data: Less than 9 bytes received");
|
||||
return false;
|
||||
}
|
||||
else if (
|
||||
buffer[0] != 0xE6 ||
|
||||
buffer[1] != 0xE7 ||
|
||||
buffer[2] != 0x00 ||
|
||||
buffer[3] != 0x0F
|
||||
)
|
||||
{
|
||||
if (debug) debug->println("Invalid HAN data: Start should be E6 E7 00 0F");
|
||||
return false;
|
||||
}
|
||||
|
||||
listSize = getInt(0, buffer, 0, bytesRead);
|
||||
if (debug) debug->print("HAN data is valid, listSize: ");
|
||||
if (debug) debug->println(listSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HanReader::debugPrint(byte *buffer, int start, int length)
|
||||
{
|
||||
for (int i = start; i < start + length; i++)
|
||||
{
|
||||
if (buffer[i] < 0x10)
|
||||
debug->print("0");
|
||||
debug->print(buffer[i], HEX);
|
||||
debug->print(" ");
|
||||
if ((i - start + 1) % 16 == 0)
|
||||
debug->println("");
|
||||
else if ((i - start + 1) % 4 == 0)
|
||||
debug->print(" ");
|
||||
|
||||
yield(); // Let other get some resources too
|
||||
}
|
||||
debug->println("");
|
||||
}
|
||||
|
||||
bool HanReader::read()
|
||||
{
|
||||
if (han->available())
|
||||
{
|
||||
byte newByte = han->read();
|
||||
return read(newByte);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int HanReader::getListSize()
|
||||
{
|
||||
return listSize;
|
||||
}
|
||||
|
||||
time_t HanReader::getPackageTime()
|
||||
{
|
||||
int packageTimePosition = dataHeader
|
||||
+ (compensateFor09HeaderBug ? 1 : 0);
|
||||
|
||||
return getTime(buffer, packageTimePosition, bytesRead);
|
||||
}
|
||||
|
||||
time_t HanReader::getTime(int objectId)
|
||||
{
|
||||
return getTime(objectId, buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
int HanReader::getInt(int objectId)
|
||||
{
|
||||
return getInt(objectId, buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
String HanReader::getString(int objectId)
|
||||
{
|
||||
return getString(objectId, buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
|
||||
int HanReader::findValuePosition(int dataPosition, byte *buffer, int start, int length)
|
||||
{
|
||||
// The first byte after the header gives the length
|
||||
// of the extended header information (variable)
|
||||
int headerSize = dataHeader + (compensateFor09HeaderBug ? 1 : 0);
|
||||
int firstData = headerSize + buffer[headerSize] + 1;
|
||||
|
||||
for (int i = start + firstData; i<length; i++)
|
||||
{
|
||||
if (dataPosition-- == 0)
|
||||
return i;
|
||||
else if (buffer[i] == 0x00) // null
|
||||
i += 0;
|
||||
else if (buffer[i] == 0x0A) // String
|
||||
i += buffer[i + 1] + 1;
|
||||
else if (buffer[i] == 0x09) // byte array
|
||||
i += buffer[i + 1] + 1;
|
||||
else if (buffer[i] == 0x01) // array (1 byte for reading size)
|
||||
i += 1;
|
||||
else if (buffer[i] == 0x02) // struct (1 byte for reading size)
|
||||
i += 1;
|
||||
else if (buffer[i] == 0x10) // int16 value (2 bytes)
|
||||
i += 2;
|
||||
else if (buffer[i] == 0x12) // uint16 value (2 bytes)
|
||||
i += 2;
|
||||
else if (buffer[i] == 0x06) // uint32 value (4 bytes)
|
||||
i += 4;
|
||||
else if (buffer[i] == 0x0F) // int8 value (1 bytes)
|
||||
i += 1;
|
||||
else if (buffer[i] == 0x16) // enum (1 bytes)
|
||||
i += 1;
|
||||
else
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
debug->print("Unknown data type found: 0x");
|
||||
debug->println(buffer[i], HEX);
|
||||
}
|
||||
return 0; // unknown data type found
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
debug->print("Passed the end of the data. Length was: ");
|
||||
debug->println(length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
time_t HanReader::getTime(int dataPosition, byte *buffer, int start, int length)
|
||||
{
|
||||
// TODO: check if the time is represented always as a 12 byte string (0x09 0x0C)
|
||||
int timeStart = findValuePosition(dataPosition, buffer, start, length);
|
||||
timeStart += 1;
|
||||
return getTime(buffer, start + timeStart, length - timeStart);
|
||||
}
|
||||
|
||||
time_t HanReader::getTime(byte *buffer, int start, int length)
|
||||
{
|
||||
int pos = start;
|
||||
int dataLength = buffer[pos++];
|
||||
|
||||
if (dataLength == 0x0C)
|
||||
{
|
||||
int year = buffer[pos] << 8 |
|
||||
buffer[pos + 1];
|
||||
|
||||
int month = buffer[pos + 2];
|
||||
int day = buffer[pos + 3];
|
||||
int hour = buffer[pos + 5];
|
||||
int minute = buffer[pos + 6];
|
||||
int second = buffer[pos + 7];
|
||||
|
||||
return toUnixTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Date format not supported
|
||||
return (time_t)0L;
|
||||
}
|
||||
}
|
||||
|
||||
int HanReader::getInt(int dataPosition, byte *buffer, int start, int length)
|
||||
{
|
||||
int valuePosition = findValuePosition(dataPosition, buffer, start, length);
|
||||
|
||||
if (valuePosition > 0)
|
||||
{
|
||||
int value = 0;
|
||||
int bytes = 0;
|
||||
switch (buffer[valuePosition++])
|
||||
{
|
||||
case 0x10:
|
||||
bytes = 2;
|
||||
break;
|
||||
case 0x12:
|
||||
bytes = 2;
|
||||
break;
|
||||
case 0x06:
|
||||
bytes = 4;
|
||||
break;
|
||||
case 0x02:
|
||||
bytes = 1;
|
||||
break;
|
||||
case 0x01:
|
||||
bytes = 1;
|
||||
break;
|
||||
case 0x0F:
|
||||
bytes = 1;
|
||||
break;
|
||||
case 0x16:
|
||||
bytes = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = valuePosition; i < valuePosition + bytes; i++)
|
||||
{
|
||||
value = value << 8 | buffer[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String HanReader::getString(int dataPosition, byte *buffer, int start, int length)
|
||||
{
|
||||
int valuePosition = findValuePosition(dataPosition, buffer, start, length);
|
||||
if (valuePosition > 0)
|
||||
{
|
||||
String value = String("");
|
||||
for (int i = valuePosition + 2; i < valuePosition + buffer[valuePosition + 1] + 2; i++)
|
||||
{
|
||||
value += String((char)buffer[i]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return String("");
|
||||
}
|
||||
|
||||
time_t HanReader::toUnixTime(int year, int month, int day, int hour, int minute, int second)
|
||||
{
|
||||
byte daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
long secondsPerMinute = 60;
|
||||
long secondsPerHour = secondsPerMinute * 60;
|
||||
long secondsPerDay = secondsPerHour * 24;
|
||||
|
||||
long time = (year - 1970) * secondsPerDay * 365L;
|
||||
|
||||
for (int yearCounter = 1970; yearCounter<year; yearCounter++)
|
||||
if ((yearCounter % 4 == 0) && ((yearCounter % 100 != 0) || (yearCounter % 400 == 0)))
|
||||
time += secondsPerDay;
|
||||
|
||||
if (month > 2 && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))
|
||||
time += secondsPerDay;
|
||||
|
||||
for (int monthCounter = 1; monthCounter<month; monthCounter++)
|
||||
time += daysInMonth[monthCounter - 1] * secondsPerDay;
|
||||
|
||||
time += (day - 1) * secondsPerDay;
|
||||
time += hour * secondsPerHour;
|
||||
time += minute * secondsPerMinute;
|
||||
time += second;
|
||||
|
||||
return (time_t)time;
|
||||
}
|
||||
52
lib/HanReader/src/HanReader.h
Normal file
52
lib/HanReader/src/HanReader.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef _HANREADER_h
|
||||
#define _HANREADER_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "DlmsReader.h"
|
||||
|
||||
|
||||
class HanReader
|
||||
{
|
||||
public:
|
||||
const uint dataHeader = 8;
|
||||
bool compensateFor09HeaderBug = false;
|
||||
|
||||
HanReader();
|
||||
void setup(HardwareSerial *hanPort);
|
||||
void setup(HardwareSerial *hanPort, Stream *debugPort);
|
||||
bool read();
|
||||
bool read(byte data);
|
||||
int getListSize();
|
||||
time_t getPackageTime();
|
||||
int getInt(int objectId);
|
||||
String getString(int objectId);
|
||||
time_t getTime(int objectId);
|
||||
|
||||
private:
|
||||
Stream *debug;
|
||||
HardwareSerial *han;
|
||||
byte buffer[512];
|
||||
int bytesRead;
|
||||
DlmsReader reader;
|
||||
int listSize;
|
||||
|
||||
int findValuePosition(int dataPosition, byte *buffer, int start, int length);
|
||||
|
||||
time_t getTime(int dataPosition, byte *buffer, int start, int length);
|
||||
time_t getTime(byte *buffer, int start, int length);
|
||||
int getInt(int dataPosition, byte *buffer, int start, int length);
|
||||
String getString(int dataPosition, byte *buffer, int start, int length);
|
||||
|
||||
time_t toUnixTime(int year, int month, int day, int hour, int minute, int second);
|
||||
|
||||
void debugPrint(byte *buffer, int start, int length);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
57
lib/HanReader/src/Kaifa.h
Normal file
57
lib/HanReader/src/Kaifa.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef _KAIFA_h
|
||||
#define _KAIFA_h
|
||||
|
||||
enum class Kaifa : byte {
|
||||
List1 = 0x01,
|
||||
List1PhaseShort = 0x09,
|
||||
List3PhaseShort = 0x0D,
|
||||
List1PhaseLong = 0x0E,
|
||||
List3PhaseLong = 0x12
|
||||
};
|
||||
|
||||
enum class Kaifa_List1 {
|
||||
ListSize,
|
||||
ActivePowerImported
|
||||
};
|
||||
|
||||
enum class Kaifa_List3Phase {
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID,
|
||||
MeterType,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower,
|
||||
CurrentL1,
|
||||
CurrentL2,
|
||||
CurrentL3,
|
||||
VoltageL1,
|
||||
VoltageL2,
|
||||
VoltageL3,
|
||||
MeterClock,
|
||||
CumulativeActiveImportEnergy,
|
||||
CumulativeActiveExportEnergy,
|
||||
CumulativeReactiveImportEnergy,
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
enum class Kaifa_List1Phase {
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID,
|
||||
MeterType,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower,
|
||||
CurrentL1,
|
||||
VoltageL1,
|
||||
MeterClock,
|
||||
CumulativeActiveImportEnergy,
|
||||
CumulativeActiveExportEnergy,
|
||||
CumulativeReactiveImportEnergy,
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
#endif
|
||||
88
lib/HanReader/src/Kamstrup.h
Normal file
88
lib/HanReader/src/Kamstrup.h
Normal file
@@ -0,0 +1,88 @@
|
||||
// Kamstrup.h
|
||||
|
||||
#ifndef _KAMSTRUP_h
|
||||
#define _KAMSTRUP_h
|
||||
|
||||
|
||||
enum class Kamstrup
|
||||
{
|
||||
List3PhaseShort = 0x19,
|
||||
List3PhaseLong = 0x23,
|
||||
List1PhaseShort = 0x11,
|
||||
List1PhaseLong = 0x1B
|
||||
};
|
||||
|
||||
enum class Kamstrup_List3Phase
|
||||
{
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID_OBIS,
|
||||
MeterID,
|
||||
MeterType_OBIS,
|
||||
MeterType,
|
||||
ActiveImportPower_OBIS,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower_OBIS,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower_OBIS,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower_OBIS,
|
||||
ReactiveExportPower,
|
||||
CurrentL1_OBIS,
|
||||
CurrentL1,
|
||||
CurrentL2_OBIS,
|
||||
CurrentL2,
|
||||
CurrentL3_OBIS,
|
||||
CurrentL3,
|
||||
VoltageL1_OBIS,
|
||||
VoltageL1,
|
||||
VoltageL2_OBIS,
|
||||
VoltageL2,
|
||||
VoltageL3_OBIS,
|
||||
VoltageL3,
|
||||
MeterClock_OBIS,
|
||||
MeterClock,
|
||||
CumulativeActiveImportEnergy_OBIS,
|
||||
CumulativeActiveImportEnergy,
|
||||
CumulativeActiveExportEnergy_OBIS,
|
||||
CumulativeActiveExportEnergy,
|
||||
CumulativeReactiveImportEnergy_OBIS,
|
||||
CumulativeReactiveImportEnergy,
|
||||
CumulativeReactiveExportEnergy_OBIS,
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
enum class Kamstrup_List1Phase
|
||||
{
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID_OBIS,
|
||||
MeterID,
|
||||
MeterType_OBIS,
|
||||
MeterType,
|
||||
ActiveImportPower_OBIS,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower_OBIS,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower_OBIS,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower_OBIS,
|
||||
ReactiveExportPower,
|
||||
CurrentL1_OBIS,
|
||||
CurrentL1,
|
||||
VoltageL1_OBIS,
|
||||
VoltageL1,
|
||||
MeterClock_OBIS,
|
||||
MeterClock,
|
||||
CumulativeActiveImportEnergy_OBIS,
|
||||
CumulativeActiveImportEnergy,
|
||||
CumulativeActiveExportEnergy_OBIS,
|
||||
CumulativeActiveExportEnergy,
|
||||
CumulativeReactiveImportEnergy_OBIS,
|
||||
CumulativeReactiveImportEnergy,
|
||||
CumulativeReactiveExportEnergy_OBIS,
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user