mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-10 09:16:53 +00:00
WMBUS: better support for extended VIFs, decoding of function field
git-svn-id: https://svn.fhem.de/fhem/trunk@6688 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
342df28bf5
commit
6d2f1fda7f
@ -77,6 +77,7 @@ use constant {
|
|||||||
ERR_DECRYPTION_FAILED => 8,
|
ERR_DECRYPTION_FAILED => 8,
|
||||||
ERR_NO_AESKEY => 9,
|
ERR_NO_AESKEY => 9,
|
||||||
ERR_UNKNOWN_ENCRYPTION => 10,
|
ERR_UNKNOWN_ENCRYPTION => 10,
|
||||||
|
ERR_TOO_MANY_VIFE => 11,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -461,6 +462,7 @@ my %VIFInfo_FB = (
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# see 4.2.3, page 24
|
# see 4.2.3, page 24
|
||||||
my %validDeviceTypes = (
|
my %validDeviceTypes = (
|
||||||
0x00 => 'Other',
|
0x00 => 'Other',
|
||||||
@ -519,6 +521,14 @@ my %encryptionModes = (
|
|||||||
0x03 => 'reserved',
|
0x03 => 'reserved',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my %functionFieldTypes = (
|
||||||
|
0b00 => 'Instantaneous value',
|
||||||
|
0b01 => 'Maximum value',
|
||||||
|
0b10 => 'Minimum value',
|
||||||
|
0b11 => 'Value during error state',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
sub type2string($$) {
|
sub type2string($$) {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $type = shift;
|
my $type = shift;
|
||||||
@ -648,6 +658,8 @@ sub decodeBCD($$$) {
|
|||||||
my $val=0;
|
my $val=0;
|
||||||
my $mult=1;
|
my $mult=1;
|
||||||
|
|
||||||
|
#print "bcd:" . unpack("H*", $bcd) . "\n";
|
||||||
|
|
||||||
for (my $i = 0; $i < $digits/2; $i++) {
|
for (my $i = 0; $i < $digits/2; $i++) {
|
||||||
$byte = unpack('C',substr($bcd, $i, 1));
|
$byte = unpack('C',substr($bcd, $i, 1));
|
||||||
$val += ($byte & 0x0f) * $mult;
|
$val += ($byte & 0x0f) * $mult;
|
||||||
@ -667,41 +679,64 @@ sub decodeValueInformationBlock($$$) {
|
|||||||
my $vif;
|
my $vif;
|
||||||
my $bias;
|
my $bias;
|
||||||
my $exponent;
|
my $exponent;
|
||||||
my $vifInfoRef = \%VIFInfo;
|
my $vifInfoRef;
|
||||||
my $vifExtension = 0;
|
my $vifExtension = 0;
|
||||||
|
my $vifExtNo = 0;
|
||||||
|
my $isExtension;
|
||||||
|
|
||||||
$vif = unpack('C', $vib);
|
|
||||||
$offset = 1;
|
|
||||||
|
|
||||||
|
$dataBlockRef->{type} = '';
|
||||||
|
|
||||||
|
EXTENSION: while (1) {
|
||||||
|
$vif = unpack('C', substr($vib,$offset++,1));
|
||||||
|
$isExtension = $vif & VIF_EXTENSION_BIT;
|
||||||
#printf("vif: %x\n", $vif);
|
#printf("vif: %x\n", $vif);
|
||||||
my $isExtension = $vif & VIF_EXTENSION_BIT;
|
|
||||||
|
|
||||||
if ($isExtension) {
|
last EXTENSION if (defined $vifInfoRef);
|
||||||
|
last EXTENSION if (!$isExtension && $dataBlockRef->{type} eq "MANUFACTURER SPECIFIC");
|
||||||
|
|
||||||
|
|
||||||
|
$vifExtNo++;
|
||||||
|
if ($vifExtNo > 10) {
|
||||||
|
$dataBlockRef->{errormsg} = 'too many VIFE';
|
||||||
|
$dataBlockRef->{errorcode} = ERR_TOO_MANY_VIFE;
|
||||||
|
last EXTENSION;
|
||||||
|
}
|
||||||
|
|
||||||
# switch to extension codes
|
# switch to extension codes
|
||||||
$vifExtension = $vif;
|
$vifExtension = $vif;
|
||||||
if ($vifExtension == 0xFD) {
|
$vif &= ~VIF_EXTENSION_BIT;
|
||||||
|
#printf("vif ohne extension: %x\n", $vif);
|
||||||
|
if ($vif <= 0b01111011) {
|
||||||
|
# The unit and multiplier is taken from the table for primary VIF
|
||||||
|
$vifInfoRef = \%VIFInfo;
|
||||||
|
} elsif ($vif == 0x7D) {
|
||||||
$vifInfoRef = \%VIFInfo_FD;
|
$vifInfoRef = \%VIFInfo_FD;
|
||||||
} elsif ($vifExtension == 0xFB) {
|
} elsif ($vif == 0x7B) {
|
||||||
$vifInfoRef = \%VIFInfo_FB;
|
$vifInfoRef = \%VIFInfo_FB;
|
||||||
} elsif ($vifExtension == 0xFF) {
|
} elsif ($vif == 0x7C) {
|
||||||
|
# Plaintext VIF
|
||||||
|
my $vifLength = unpack('C', substr($vib,$offset++,1));
|
||||||
|
$dataBlockRef->{type} = "see unit";
|
||||||
|
$dataBlockRef->{unit} = unpack(sprintf("C%d",$vifLength), substr($vib, $offset, $vifLength));
|
||||||
|
$offset += $vifLength;
|
||||||
|
} elsif ($vif == 0x7F) {
|
||||||
# manufacturer specific data, can't be interpreted
|
# manufacturer specific data, can't be interpreted
|
||||||
$dataBlockRef->{type} = "MANUFACTURER SPECIFIC";
|
$dataBlockRef->{type} = "MANUFACTURER SPECIFIC";
|
||||||
$dataBlockRef->{unit} = "";
|
$dataBlockRef->{unit} = "";
|
||||||
return $offset;
|
|
||||||
} else {
|
} else {
|
||||||
$dataBlockRef->{type} = 'unknown';
|
$dataBlockRef->{type} = 'unknown';
|
||||||
$dataBlockRef->{errormsg} = "unknown VIFE " . sprintf("%x", $vifExtension) . " at offset $offset-1";
|
$dataBlockRef->{errormsg} = "unknown VIFE " . sprintf("%x", $vifExtension) . " at offset " . $offset-1;
|
||||||
$dataBlockRef->{errorcode} = ERR_UNKNOWN_VIFE;
|
$dataBlockRef->{errorcode} = ERR_UNKNOWN_VIFE;
|
||||||
}
|
}
|
||||||
$vif = unpack('C', substr($vib,$offset++,1));
|
last EXTENSION if (!$isExtension);
|
||||||
#printf("vife: %x\n", $vif);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$vif &= ~VIF_EXTENSION_BIT;
|
|
||||||
|
|
||||||
#printf("vif w/o ext: %x\n", $vif);
|
#printf("vif w/o ext: %x\n", $vif);
|
||||||
$dataBlockRef->{type} = '';
|
if (defined $vifInfoRef) {
|
||||||
VIFID: foreach my $vifType ( keys $vifInfoRef ) {
|
VIFID: foreach my $vifType ( keys $vifInfoRef ) {
|
||||||
|
|
||||||
#printf "vifType $vifType\n";
|
#printf "vifType $vifType\n";
|
||||||
@ -721,7 +756,7 @@ sub decodeValueInformationBlock($$$) {
|
|||||||
last VIFID;
|
last VIFID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ($dataBlockRef->{type} eq '') {
|
if ($dataBlockRef->{type} eq '') {
|
||||||
$dataBlockRef->{type} = 'unknown';
|
$dataBlockRef->{type} = 'unknown';
|
||||||
$dataBlockRef->{errormsg} = sprintf("in VIFExtension %x unknown VIF %x",$vifExtension, $vif);
|
$dataBlockRef->{errormsg} = sprintf("in VIFExtension %x unknown VIF %x",$vifExtension, $vif);
|
||||||
@ -773,6 +808,7 @@ sub decodeDataInformationBlock($$$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$dataBlockRef->{functionField} = $functionField;
|
$dataBlockRef->{functionField} = $functionField;
|
||||||
|
$dataBlockRef->{functionFieldText} = $functionFieldTypes{$functionField};
|
||||||
$dataBlockRef->{dataField} = $df;
|
$dataBlockRef->{dataField} = $df;
|
||||||
$dataBlockRef->{storageNo} = $storageNo;
|
$dataBlockRef->{storageNo} = $storageNo;
|
||||||
$dataBlockRef->{tariff} = $tariff;
|
$dataBlockRef->{tariff} = $tariff;
|
||||||
@ -834,7 +870,11 @@ sub decodePayload($$) {
|
|||||||
$offset += $self->decodeDataRecordHeader(substr($payload,$offset), $dataBlock);
|
$offset += $self->decodeDataRecordHeader(substr($payload,$offset), $dataBlock);
|
||||||
#printf("No. %d, type %x at offset %d\n", $dataBlockNo, $dataBlock->{dataField}, $offset-1);
|
#printf("No. %d, type %x at offset %d\n", $dataBlockNo, $dataBlock->{dataField}, $offset-1);
|
||||||
|
|
||||||
if ($dataBlock->{dataField} == DIF_NONE || $dataBlock->{dataField} == DIF_READOUT) {
|
if ($dataBlock->{dataField} == DIF_NONE) {
|
||||||
|
} elsif ($dataBlock->{dataField} == DIF_READOUT) {
|
||||||
|
$self->{errormsg} = "in datablock $dataBlockNo: unexpected DIF_READOUT";
|
||||||
|
$self->{errorcode} = ERR_UNKNOWN_DATAFIELD;
|
||||||
|
return 0;
|
||||||
} elsif ($dataBlock->{dataField} == DIF_BCD2) {
|
} elsif ($dataBlock->{dataField} == DIF_BCD2) {
|
||||||
$value = $self->decodeBCD(2, substr($payload,$offset,1));
|
$value = $self->decodeBCD(2, substr($payload,$offset,1));
|
||||||
$offset += 1;
|
$offset += 1;
|
||||||
@ -953,6 +993,8 @@ sub decodeApplicationLayer($) {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $applicationlayer = $self->removeCRC(substr($self->{msg},12));
|
my $applicationlayer = $self->removeCRC(substr($self->{msg},12));
|
||||||
|
|
||||||
|
#print unpack("H*", $applicationlayer) . "\n";
|
||||||
|
|
||||||
if ($self->{errorcode} != ERR_NO_ERROR) {
|
if ($self->{errorcode} != ERR_NO_ERROR) {
|
||||||
# CRC check failed
|
# CRC check failed
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user