10 Commits

Author SHA1 Message Date
36a85d3737 Add product string of Hydrometer Sharky 775 2019-02-20 22:01:47 +01:00
2f9fa5ccc8 Implement negative BCD number (Type A)
According to W4B21021.pdf Appendix A a hex code Fh in the MSD
position signals a negative BCD number.
2019-02-20 22:01:47 +01:00
027f6fb689 prevent multiple calls to disconnect for serial and tcp (#137)
* prevent multiple calls to disconnect for serial and tcp
2018-03-28 19:53:17 +02:00
de4a899b9d Merge pull request #136 from Apollon77/iso-dates
make generated timestamps conform to ISO definition
2018-03-28 17:09:56 +02:00
2a2fbc372a make generated timestamps conform to ISO definition 2018-03-28 14:26:06 +02:00
6d3bb00d97 Merge pull request #134 from lategoodbye/set-primary-address
Add binary to set primary address
2018-03-26 11:15:40 +02:00
84c43fe7a3 Add new program to set primary address 2018-03-21 21:44:50 +01:00
73d58a9f7d Implement mbus_set_primary_address()
This function sends a frame to change primary address of a slave.
2018-03-21 21:40:58 +01:00
ab8919136d Update LICENSE
See #129
2017-08-27 12:10:13 +02:00
2680079db4 Move license into separate file
See: https://github.com/rscada/libmbus/issues/129
2017-08-16 19:31:49 +02:00
12 changed files with 404 additions and 81 deletions

1
.gitignore vendored
View File

@ -52,6 +52,7 @@ bin/mbus-serial-request-data-multi-reply
bin/mbus-serial-scan bin/mbus-serial-scan
bin/mbus-serial-scan-secondary bin/mbus-serial-scan-secondary
bin/mbus-serial-select-secondary bin/mbus-serial-select-secondary
bin/mbus-serial-set-address
bin/mbus-serial-switch-baudrate bin/mbus-serial-switch-baudrate
bin/mbus-tcp-raw-send bin/mbus-tcp-raw-send
bin/mbus-tcp-request-data bin/mbus-tcp-request-data

16
COPYING
View File

@ -20,19 +20,5 @@ Contributers:
* Pelle van der Heide * Pelle van der Heide
* James Michael DuPont * James Michael DuPont
* Uwe Grohnwaldt * Uwe Grohnwaldt
* Markus Bergkvist * Markus Bergkvist
LICENSE (the BSD license):
Copyright (c) 2010-2012, Raditex Control AB
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the Raditex Control AB nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

29
LICENSE Normal file
View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2010-2012, Raditex Control AB
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -17,7 +17,8 @@ bin_PROGRAMS = mbus-tcp-scan mbus-tcp-request-data mbus-tcp-request-data-multi
mbus-tcp-select-secondary mbus-tcp-scan-secondary \ mbus-tcp-select-secondary mbus-tcp-scan-secondary \
mbus-serial-scan mbus-serial-request-data mbus-serial-request-data-multi-reply \ mbus-serial-scan mbus-serial-request-data mbus-serial-request-data-multi-reply \
mbus-serial-select-secondary mbus-serial-scan-secondary \ mbus-serial-select-secondary mbus-serial-scan-secondary \
mbus-serial-switch-baudrate mbus-tcp-raw-send mbus-tcp-application-reset mbus-serial-switch-baudrate mbus-tcp-raw-send mbus-tcp-application-reset \
mbus-serial-set-address
# tcp # tcp
mbus_tcp_scan_LDFLAGS = -L$(top_builddir)/mbus mbus_tcp_scan_LDFLAGS = -L$(top_builddir)/mbus
@ -73,6 +74,10 @@ mbus_serial_switch_baudrate_LDFLAGS = -L$(top_builddir)/mbus
mbus_serial_switch_baudrate_LDADD = -lmbus -lm mbus_serial_switch_baudrate_LDADD = -lmbus -lm
mbus_serial_switch_baudrate_SOURCES = mbus-serial-switch-baudrate.c mbus_serial_switch_baudrate_SOURCES = mbus-serial-switch-baudrate.c
mbus_serial_set_address_LDFLAGS = -L$(top_builddir)/mbus
mbus_serial_set_address_LDADD = -lmbus -lm
mbus_serial_set_address_SOURCES = mbus-serial-set-address.c
# man pages # man pages
dist_man_MANS = libmbus.1 \ dist_man_MANS = libmbus.1 \
mbus-tcp-scan.1 \ mbus-tcp-scan.1 \

View File

@ -10,6 +10,8 @@ the communication with M-Bus devices.
B<mbus-serial-switch-baudrate> [-b BAUDRATE] device address target-baudrate B<mbus-serial-switch-baudrate> [-b BAUDRATE] device address target-baudrate
B<mbus-serial-set-address> [-d] [-b BAUDRATE] device mbus-address new-primary-address
B<mbus-serial-scan> [-d] [-b BAUDRATE] [-r RETRIES] device B<mbus-serial-scan> [-d] [-b BAUDRATE] [-r RETRIES] device
B<mbus-tcp-scan> [-d] [-r RETRIES] host port B<mbus-tcp-scan> [-d] [-r RETRIES] host port

View File

@ -0,0 +1,2 @@
.so man1/libmbus.1

View File

@ -0,0 +1,229 @@
//------------------------------------------------------------------------------
// Copyright (C) 2011, Robert Johansson, Raditex AB
// All rights reserved.
//
// rSCADA
// http://www.rSCADA.se
// info@rscada.se
//
//------------------------------------------------------------------------------
#include <string.h>
#include <stdio.h>
#include <mbus/mbus.h>
static int debug = 0;
//
// init slave to get really the beginning of the records
//
static int
init_slaves(mbus_handle *handle)
{
if (debug)
printf("%s: debug: sending init frame #1\n", __PRETTY_FUNCTION__);
if (mbus_send_ping_frame(handle, MBUS_ADDRESS_NETWORK_LAYER, 1) == -1)
{
return 0;
}
//
// resend SND_NKE, maybe the first get lost
//
if (debug)
printf("%s: debug: sending init frame #2\n", __PRETTY_FUNCTION__);
if (mbus_send_ping_frame(handle, MBUS_ADDRESS_NETWORK_LAYER, 1) == -1)
{
return 0;
}
return 1;
}
//------------------------------------------------------------------------------
// set primary address
//------------------------------------------------------------------------------
int
main(int argc, char **argv)
{
mbus_handle *handle = NULL;
mbus_frame reply;
char *device, *old_address_str, *xml_result;
int old_address, new_address;
long baudrate = 9600;
int ret;
if (argc == 4)
{
device = argv[1];
old_address_str = argv[2];
new_address = atoi(argv[3]);
}
else if (argc == 5 && strcmp(argv[1], "-d") == 0)
{
device = argv[2];
old_address_str = argv[3];
new_address = atoi(argv[4]);
debug = 1;
}
else if (argc == 6 && strcmp(argv[1], "-b") == 0)
{
baudrate = atol(argv[2]);
device = argv[3];
old_address_str = argv[4];
new_address = atoi(argv[5]);
}
else if (argc == 7 && strcmp(argv[1], "-d") == 0 && strcmp(argv[2], "-b") == 0)
{
baudrate = atol(argv[3]);
device = argv[4];
old_address_str = argv[5];
new_address = atoi(argv[6]);
debug = 1;
}
else
{
fprintf(stderr, "usage: %s [-d] [-b BAUDRATE] device mbus-address new-primary-address\n", argv[0]);
fprintf(stderr, " optional flag -d for debug printout\n");
fprintf(stderr, " optional flag -b for selecting baudrate\n");
return 0;
}
if (mbus_is_primary_address(new_address) == 0)
{
fprintf(stderr, "Invalid new primary address\n");
return -1;
}
switch (new_address)
{
case MBUS_ADDRESS_NETWORK_LAYER:
case MBUS_ADDRESS_BROADCAST_REPLY:
case MBUS_ADDRESS_BROADCAST_NOREPLY:
fprintf(stderr, "Invalid new primary address\n");
return -1;
}
if ((handle = mbus_context_serial(device)) == NULL)
{
fprintf(stderr, "Could not initialize M-Bus context: %s\n", mbus_error_str());
return 1;
}
if (debug)
{
mbus_register_send_event(handle, &mbus_dump_send_event);
mbus_register_recv_event(handle, &mbus_dump_recv_event);
}
if (mbus_connect(handle) == -1)
{
fprintf(stderr,"Failed to setup connection to M-bus gateway\n");
mbus_context_free(handle);
return 1;
}
if (mbus_serial_set_baudrate(handle, baudrate) == -1)
{
fprintf(stderr,"Failed to set baud rate.\n");
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
if (init_slaves(handle) == 0)
{
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
if (mbus_send_ping_frame(handle, new_address, 0) == -1)
{
fprintf(stderr, "Verification failed. Could not send ping frame: %s\n", mbus_error_str());
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
if (mbus_recv_frame(handle, &reply) != MBUS_RECV_RESULT_TIMEOUT)
{
fprintf(stderr, "Verification failed. Got a response from new address\n");
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
if (mbus_is_secondary_address(old_address_str))
{
// secondary addressing
ret = mbus_select_secondary_address(handle, old_address_str);
if (ret == MBUS_PROBE_COLLISION)
{
fprintf(stderr, "%s: Error: The address mask [%s] matches more than one device.\n", __PRETTY_FUNCTION__, old_address_str);
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
else if (ret == MBUS_PROBE_NOTHING)
{
fprintf(stderr, "%s: Error: The selected secondary address does not match any device [%s].\n", __PRETTY_FUNCTION__, old_address_str);
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
else if (ret == MBUS_PROBE_ERROR)
{
fprintf(stderr, "%s: Error: Failed to select secondary address [%s].\n", __PRETTY_FUNCTION__, old_address_str);
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
// else MBUS_PROBE_SINGLE
old_address = MBUS_ADDRESS_NETWORK_LAYER;
}
else
{
// primary addressing
old_address = atoi(old_address_str);
}
if (mbus_set_primary_address(handle, old_address, new_address) == -1)
{
fprintf(stderr, "Failed to send set primary address frame: %s\n", mbus_error_str());
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
memset(&reply, 0, sizeof(mbus_frame));
ret = mbus_recv_frame(handle, &reply);
if (ret == MBUS_RECV_RESULT_TIMEOUT)
{
fprintf(stderr, "No reply from device\n");
mbus_disconnect(handle);
mbus_context_free(handle);
return 1;
}
else if (mbus_frame_type(&reply) != MBUS_FRAME_TYPE_ACK)
{
fprintf(stderr, "Unknown reply:\n");
mbus_frame_print(&reply);
}
else
{
printf("Set primary address of device to %d\n", new_address);
}
mbus_disconnect(handle);
mbus_context_free(handle);
return 0;
}

View File

@ -154,17 +154,17 @@ mbus_variable_vif vif_table[] = {
{ 0x56, 1.0e3, "kg/h", "Mass flow" }, { 0x56, 1.0e3, "kg/h", "Mass flow" },
{ 0x57, 1.0e4, "kg/h", "Mass flow" }, { 0x57, 1.0e4, "kg/h", "Mass flow" },
/* E101 10nn Flow Temperature <EFBFBD>C (0.001<EFBFBD>C to 1<EFBFBD>C) */ /* E101 10nn Flow Temperature °C (0.001°C to 1°C) */
{ 0x58, 1.0e-3, "<EFBFBD>C", "Flow temperature" }, { 0x58, 1.0e-3, "°C", "Flow temperature" },
{ 0x59, 1.0e-2, "<EFBFBD>C", "Flow temperature" }, { 0x59, 1.0e-2, "°C", "Flow temperature" },
{ 0x5A, 1.0e-1, "<EFBFBD>C", "Flow temperature" }, { 0x5A, 1.0e-1, "°C", "Flow temperature" },
{ 0x5B, 1.0e0, "<EFBFBD>C", "Flow temperature" }, { 0x5B, 1.0e0, "°C", "Flow temperature" },
/* E101 11nn Return Temperature <EFBFBD>C (0.001<EFBFBD>C to 1<EFBFBD>C) */ /* E101 11nn Return Temperature °C (0.001°C to 1°C) */
{ 0x5C, 1.0e-3, "<EFBFBD>C", "Return temperature" }, { 0x5C, 1.0e-3, "°C", "Return temperature" },
{ 0x5D, 1.0e-2, "<EFBFBD>C", "Return temperature" }, { 0x5D, 1.0e-2, "°C", "Return temperature" },
{ 0x5E, 1.0e-1, "<EFBFBD>C", "Return temperature" }, { 0x5E, 1.0e-1, "°C", "Return temperature" },
{ 0x5F, 1.0e0, "<EFBFBD>C", "Return temperature" }, { 0x5F, 1.0e0, "°C", "Return temperature" },
/* E110 00nn Temperature Difference K (mK to K) */ /* E110 00nn Temperature Difference K (mK to K) */
{ 0x60, 1.0e-3, "K", "Temperature difference" }, { 0x60, 1.0e-3, "K", "Temperature difference" },
@ -172,11 +172,11 @@ mbus_variable_vif vif_table[] = {
{ 0x62, 1.0e-1, "K", "Temperature difference" }, { 0x62, 1.0e-1, "K", "Temperature difference" },
{ 0x63, 1.0e0, "K", "Temperature difference" }, { 0x63, 1.0e0, "K", "Temperature difference" },
/* E110 01nn External Temperature <EFBFBD>C (0.001<EFBFBD>C to 1<EFBFBD>C) */ /* E110 01nn External Temperature °C (0.001°C to 1°C) */
{ 0x64, 1.0e-3, "<EFBFBD>C", "External temperature" }, { 0x64, 1.0e-3, "°C", "External temperature" },
{ 0x65, 1.0e-2, "<EFBFBD>C", "External temperature" }, { 0x65, 1.0e-2, "°C", "External temperature" },
{ 0x66, 1.0e-1, "<EFBFBD>C", "External temperature" }, { 0x66, 1.0e-1, "°C", "External temperature" },
{ 0x67, 1.0e0, "<EFBFBD>C", "External temperature" }, { 0x67, 1.0e0, "°C", "External temperature" },
/* E110 10nn Pressure bar (1mbar to 1000mbar) */ /* E110 10nn Pressure bar (1mbar to 1000mbar) */
{ 0x68, 1.0e-3, "bar", "Pressure" }, { 0x68, 1.0e-3, "bar", "Pressure" },
@ -608,29 +608,29 @@ mbus_variable_vif vif_table[] = {
{ 0x256, 1.0e0, "Reserved", "Reserved" }, { 0x256, 1.0e0, "Reserved", "Reserved" },
{ 0x257, 1.0e0, "Reserved", "Reserved" }, { 0x257, 1.0e0, "Reserved", "Reserved" },
/* E101 10nn Flow Temperature 10(nn-3) <EFBFBD>F 0.001<EFBFBD>F to 1<EFBFBD>F */ /* E101 10nn Flow Temperature 10(nn-3) °F 0.001°F to 1°F */
{ 0x258, 1.0e-3, "<EFBFBD>F", "Flow temperature" }, { 0x258, 1.0e-3, "°F", "Flow temperature" },
{ 0x259, 1.0e-2, "<EFBFBD>F", "Flow temperature" }, { 0x259, 1.0e-2, "°F", "Flow temperature" },
{ 0x25A, 1.0e-1, "<EFBFBD>F", "Flow temperature" }, { 0x25A, 1.0e-1, "°F", "Flow temperature" },
{ 0x25B, 1.0e0, "<EFBFBD>F", "Flow temperature" }, { 0x25B, 1.0e0, "°F", "Flow temperature" },
/* E101 11nn Return Temperature 10(nn-3) <EFBFBD>F 0.001<EFBFBD>F to 1<EFBFBD>F */ /* E101 11nn Return Temperature 10(nn-3) °F 0.001°F to 1°F */
{ 0x25C, 1.0e-3, "<EFBFBD>F", "Return temperature" }, { 0x25C, 1.0e-3, "°F", "Return temperature" },
{ 0x25D, 1.0e-2, "<EFBFBD>F", "Return temperature" }, { 0x25D, 1.0e-2, "°F", "Return temperature" },
{ 0x25E, 1.0e-1, "<EFBFBD>F", "Return temperature" }, { 0x25E, 1.0e-1, "°F", "Return temperature" },
{ 0x25F, 1.0e0, "<EFBFBD>F", "Return temperature" }, { 0x25F, 1.0e0, "°F", "Return temperature" },
/* E110 00nn Temperature Difference 10(nn-3) <EFBFBD>F 0.001<EFBFBD>F to 1<EFBFBD>F */ /* E110 00nn Temperature Difference 10(nn-3) °F 0.001°F to 1°F */
{ 0x260, 1.0e-3, "<EFBFBD>F", "Temperature difference" }, { 0x260, 1.0e-3, "°F", "Temperature difference" },
{ 0x261, 1.0e-2, "<EFBFBD>F", "Temperature difference" }, { 0x261, 1.0e-2, "°F", "Temperature difference" },
{ 0x262, 1.0e-1, "<EFBFBD>F", "Temperature difference" }, { 0x262, 1.0e-1, "°F", "Temperature difference" },
{ 0x263, 1.0e0, "<EFBFBD>F", "Temperature difference" }, { 0x263, 1.0e0, "°F", "Temperature difference" },
/* E110 01nn External Temperature 10(nn-3) <EFBFBD>F 0.001<EFBFBD>F to 1<EFBFBD>F */ /* E110 01nn External Temperature 10(nn-3) °F 0.001°F to 1°F */
{ 0x264, 1.0e-3, "<EFBFBD>F", "External temperature" }, { 0x264, 1.0e-3, "°F", "External temperature" },
{ 0x265, 1.0e-2, "<EFBFBD>F", "External temperature" }, { 0x265, 1.0e-2, "°F", "External temperature" },
{ 0x266, 1.0e-1, "<EFBFBD>F", "External temperature" }, { 0x266, 1.0e-1, "°F", "External temperature" },
{ 0x267, 1.0e0, "<EFBFBD>F", "External temperature" }, { 0x267, 1.0e0, "°F", "External temperature" },
/* E110 1nnn Reserved */ /* E110 1nnn Reserved */
{ 0x268, 1.0e0, "Reserved", "Reserved" }, { 0x268, 1.0e0, "Reserved", "Reserved" },
@ -642,19 +642,19 @@ mbus_variable_vif vif_table[] = {
{ 0x26E, 1.0e0, "Reserved", "Reserved" }, { 0x26E, 1.0e0, "Reserved", "Reserved" },
{ 0x26F, 1.0e0, "Reserved", "Reserved" }, { 0x26F, 1.0e0, "Reserved", "Reserved" },
/* E111 00nn Cold / Warm Temperature Limit 10(nn-3) <EFBFBD>F 0.001<EFBFBD>F to 1<EFBFBD>F */ /* E111 00nn Cold / Warm Temperature Limit 10(nn-3) °F 0.001°F to 1°F */
{ 0x270, 1.0e-3, "<EFBFBD>F", "Cold / Warm Temperature Limit" }, { 0x270, 1.0e-3, "°F", "Cold / Warm Temperature Limit" },
{ 0x271, 1.0e-2, "<EFBFBD>F", "Cold / Warm Temperature Limit" }, { 0x271, 1.0e-2, "°F", "Cold / Warm Temperature Limit" },
{ 0x272, 1.0e-1, "<EFBFBD>F", "Cold / Warm Temperature Limit" }, { 0x272, 1.0e-1, "°F", "Cold / Warm Temperature Limit" },
{ 0x273, 1.0e0, "<EFBFBD>F", "Cold / Warm Temperature Limit" }, { 0x273, 1.0e0, "°F", "Cold / Warm Temperature Limit" },
/* E111 01nn Cold / Warm Temperature Limit 10(nn-3) <EFBFBD>C 0.001<EFBFBD>C to 1<EFBFBD>C */ /* E111 01nn Cold / Warm Temperature Limit 10(nn-3) °C 0.001°C to 1°C */
{ 0x274, 1.0e-3, "<EFBFBD>C", "Cold / Warm Temperature Limit" }, { 0x274, 1.0e-3, "°C", "Cold / Warm Temperature Limit" },
{ 0x275, 1.0e-2, "<EFBFBD>C", "Cold / Warm Temperature Limit" }, { 0x275, 1.0e-2, "°C", "Cold / Warm Temperature Limit" },
{ 0x276, 1.0e-1, "<EFBFBD>C", "Cold / Warm Temperature Limit" }, { 0x276, 1.0e-1, "°C", "Cold / Warm Temperature Limit" },
{ 0x277, 1.0e0, "<EFBFBD>C", "Cold / Warm Temperature Limit" }, { 0x277, 1.0e0, "°C", "Cold / Warm Temperature Limit" },
/* E111 1nnn cumul. count max power <EFBFBD> 10(nnn-3) W 0.001W to 10000W */ /* E111 1nnn cumul. count max power § 10(nnn-3) W 0.001W to 10000W */
{ 0x278, 1.0e-3, "W", "Cumul count max power" }, { 0x278, 1.0e-3, "W", "Cumul count max power" },
{ 0x279, 1.0e-3, "W", "Cumul count max power" }, { 0x279, 1.0e-3, "W", "Cumul count max power" },
{ 0x27A, 1.0e-1, "W", "Cumul count max power" }, { 0x27A, 1.0e-1, "W", "Cumul count max power" },
@ -730,7 +730,7 @@ mbus_variable_vif fixed_table[] = {
{ 0x36, 1.0e1, "m^3/h", "Volume flow" }, { 0x36, 1.0e1, "m^3/h", "Volume flow" },
{ 0x37, 1.0e2, "m^3/h", "Volume flow" }, { 0x37, 1.0e2, "m^3/h", "Volume flow" },
{ 0x38, 1.0e-3, "<EFBFBD>C", "Temperature" }, { 0x38, 1.0e-3, "°C", "Temperature" },
{ 0x39, 1.0e0, "Units for H.C.A.", "H.C.A." }, { 0x39, 1.0e0, "Units for H.C.A.", "H.C.A." },
@ -886,7 +886,7 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real,
else // normal integer else // normal integer
{ {
result = mbus_data_int_decode(record->data, 2, &value_out_int); result = mbus_data_int_decode(record->data, 2, &value_out_int);
*value_out_real = value_out_int; *value_out_real = value_out_int;
} }
break; break;
@ -904,12 +904,12 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real,
((record->drh.vib.vif == 0xFD) && (vife == 0x70))) ((record->drh.vib.vif == 0xFD) && (vife == 0x70)))
{ {
mbus_data_tm_decode(&time, record->data, 4); mbus_data_tm_decode(&time, record->data, 4);
if ((*value_out_str = (char*) malloc(20)) == NULL) if ((*value_out_str = (char*) malloc(21)) == NULL)
{ {
MBUS_ERROR("Unable to allocate memory"); MBUS_ERROR("Unable to allocate memory");
return -1; return -1;
} }
*value_out_str_size = snprintf(*value_out_str, 20, "%04d-%02d-%02dT%02d:%02d:%02d", *value_out_str_size = snprintf(*value_out_str, 21, "%04d-%02d-%02dT%02d:%02d:%02dZ",
(time.tm_year + 1900), (time.tm_year + 1900),
(time.tm_mon + 1), (time.tm_mon + 1),
time.tm_mday, time.tm_mday,
@ -921,7 +921,7 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real,
else // normal integer else // normal integer
{ {
result = mbus_data_int_decode(record->data, 4, &value_out_int); result = mbus_data_int_decode(record->data, 4, &value_out_int);
*value_out_real = value_out_int; *value_out_real = value_out_int;
} }
break; break;
@ -939,12 +939,12 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real,
((record->drh.vib.vif == 0xFD) && (vife == 0x70))) ((record->drh.vib.vif == 0xFD) && (vife == 0x70)))
{ {
mbus_data_tm_decode(&time, record->data, 6); mbus_data_tm_decode(&time, record->data, 6);
if ((*value_out_str = (char*) malloc(20)) == NULL) if ((*value_out_str = (char*) malloc(21)) == NULL)
{ {
MBUS_ERROR("Unable to allocate memory"); MBUS_ERROR("Unable to allocate memory");
return -1; return -1;
} }
*value_out_str_size = snprintf(*value_out_str, 20, "%04d-%02d-%02dT%02d:%02d:%02d", *value_out_str_size = snprintf(*value_out_str, 21, "%04d-%02d-%02dT%02d:%02d:%02dZ",
(time.tm_year + 1900), (time.tm_year + 1900),
(time.tm_mon + 1), (time.tm_mon + 1),
time.tm_mday, time.tm_mday,
@ -1286,7 +1286,7 @@ mbus_parse_variable_record(mbus_data_record *data)
MBUS_ERROR("%s: memory allocation error\n", __PRETTY_FUNCTION__); MBUS_ERROR("%s: memory allocation error\n", __PRETTY_FUNCTION__);
return NULL; return NULL;
} }
record->storage_number = mbus_data_record_storage_number(data); record->storage_number = mbus_data_record_storage_number(data);
record->tariff = mbus_data_record_tariff(data); record->tariff = mbus_data_record_tariff(data);
record->device = mbus_data_record_device(data); record->device = mbus_data_record_device(data);
@ -1981,6 +1981,33 @@ mbus_send_user_data_frame(mbus_handle * handle, int address, const unsigned char
return retval; return retval;
} }
//------------------------------------------------------------------------------
// send a request from master to slave in order to change the primary address
//------------------------------------------------------------------------------
int
mbus_set_primary_address(mbus_handle * handle, int old_address, int new_address)
{
/* primary address record, see chapter 6.4.2 */
unsigned char buffer[3] = { 0x01, 0x7A, new_address };
if (mbus_is_primary_address(new_address) == 0)
{
MBUS_ERROR("%s: invalid address %d\n", __PRETTY_FUNCTION__, new_address);
return -1;
}
switch (new_address)
{
case MBUS_ADDRESS_NETWORK_LAYER:
case MBUS_ADDRESS_BROADCAST_REPLY:
case MBUS_ADDRESS_BROADCAST_NOREPLY:
MBUS_ERROR("%s: invalid address %d\n", __PRETTY_FUNCTION__, new_address);
return -1;
}
return mbus_send_user_data_frame(handle, old_address, buffer, sizeof(buffer));
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// send a request from master to slave and collect the reply (replies) // send a request from master to slave and collect the reply (replies)
// from the slave. // from the slave.
@ -2304,7 +2331,7 @@ mbus_probe_secondary_address(mbus_handle *handle, const char *mask, char *matchi
if (addr == NULL) if (addr == NULL)
{ {
// show error message, but procede with scan // show error message, but procede with scan
MBUS_ERROR("Failed to generate secondary address from M-Bus reply frame: %s\n", MBUS_ERROR("Failed to generate secondary address from M-Bus reply frame: %s\n",
mbus_error_str()); mbus_error_str());
return MBUS_PROBE_NOTHING; return MBUS_PROBE_NOTHING;
} }

View File

@ -307,6 +307,17 @@ int mbus_send_request_frame(mbus_handle * handle, int address);
*/ */
int mbus_send_user_data_frame(mbus_handle * handle, int address, const unsigned char *data, size_t data_size); int mbus_send_user_data_frame(mbus_handle * handle, int address, const unsigned char *data, size_t data_size);
/**
* Sends frame to change primary address of given slave using "unified" handle
*
* @param handle Initialized handle
* @param old_address Old Address (0-255)
* @param new_address New Address (0-250)
*
* @return Zero when successful.
*/
int mbus_set_primary_address(mbus_handle * handle, int old_address, int new_address);
/** /**
* Sends a request and read replies until no more records available * Sends a request and read replies until no more records available
* or limit is reached. * or limit is reached.

View File

@ -461,9 +461,9 @@ mbus_data_bcd_encode(unsigned char *bcd_data, size_t bcd_data_size, int value)
int v0, v1, v2, x1, x2; int v0, v1, v2, x1, x2;
size_t i; size_t i;
if (bcd_data && bcd_data_size && (value >= 0)) if (bcd_data && bcd_data_size)
{ {
v2 = value; v2 = abs(value);
for (i = 0; i < bcd_data_size; i++) for (i = 0; i < bcd_data_size; i++)
{ {
@ -477,6 +477,11 @@ mbus_data_bcd_encode(unsigned char *bcd_data, size_t bcd_data_size, int value)
bcd_data[bcd_data_size-1-i] = (x2 << 4) | x1; bcd_data[bcd_data_size-1-i] = (x2 << 4) | x1;
} }
if (value < 0)
{
bcd_data[bcd_data_size-1] |= 0xF0;
}
return 0; return 0;
} }
@ -498,8 +503,20 @@ mbus_data_bcd_decode(unsigned char *bcd_data, size_t bcd_data_size)
{ {
for (i = bcd_data_size; i > 0; i--) for (i = bcd_data_size; i > 0; i--)
{ {
val = (val * 10) + ((bcd_data[i-1]>>4) & 0xF); val = (val * 10);
val = (val * 10) + ( bcd_data[i-1] & 0xF);
if (bcd_data[i-1]>>4 < 0xA)
{
val += ((bcd_data[i-1]>>4) & 0xF);
}
val = (val * 10) + ( bcd_data[i-1] & 0xF);
}
// hex code Fh in the MSD position signals a negative BCD number
if (bcd_data[bcd_data_size-1]>>4 == 0xF)
{
val *= -1;
} }
return val; return val;
@ -1088,6 +1105,9 @@ mbus_data_product_name(mbus_data_variable_header *header)
case 0x28: case 0x28:
strcpy(buff,"ABB F95 Typ US770"); strcpy(buff,"ABB F95 Typ US770");
break; break;
case 0x2F:
strcpy(buff,"Hydrometer Sharky 775");
break;
} }
} }
else if (manufacturer == mbus_manufacturer_id("JAN")) else if (manufacturer == mbus_manufacturer_id("JAN"))
@ -3739,7 +3759,7 @@ mbus_hex_dump(const char *label, const char *buff, size_t len)
{ {
time_t rawtime; time_t rawtime;
struct tm * timeinfo; struct tm * timeinfo;
char timestamp[21]; char timestamp[22];
size_t i; size_t i;
if (label == NULL || buff == NULL) if (label == NULL || buff == NULL)
@ -3748,7 +3768,7 @@ mbus_hex_dump(const char *label, const char *buff, size_t len)
time ( &rawtime ); time ( &rawtime );
timeinfo = gmtime ( &rawtime ); timeinfo = gmtime ( &rawtime );
strftime(timestamp,20,"%Y-%m-%d %H:%M:%S",timeinfo); strftime(timestamp,21,"%Y-%m-%d %H:%M:%SZ",timeinfo);
fprintf(stderr, "[%s] %s (%03zu):", timestamp, label, len); fprintf(stderr, "[%s] %s (%03zu):", timestamp, label, len);
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
@ -3767,6 +3787,7 @@ mbus_data_error_print(int error)
return -1; return -1;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// //
// XML RELATED FUNCTIONS // XML RELATED FUNCTIONS
@ -3886,7 +3907,7 @@ mbus_data_variable_record_xml(mbus_data_record *record, int record_cnt, int fram
char str_encoded[768]; char str_encoded[768];
size_t len = 0; size_t len = 0;
struct tm * timeinfo; struct tm * timeinfo;
char timestamp[21]; char timestamp[22];
long tariff; long tariff;
if (record) if (record)
@ -3942,7 +3963,7 @@ mbus_data_variable_record_xml(mbus_data_record *record, int record_cnt, int fram
if (record->timestamp > 0) if (record->timestamp > 0)
{ {
timeinfo = gmtime (&(record->timestamp)); timeinfo = gmtime (&(record->timestamp));
strftime(timestamp,20,"%Y-%m-%dT%H:%M:%S",timeinfo); strftime(timestamp,21,"%Y-%m-%dT%H:%M:%SZ",timeinfo);
len += snprintf(&buff[len], sizeof(buff) - len, len += snprintf(&buff[len], sizeof(buff) - len,
" <Timestamp>%s</Timestamp>\n", timestamp); " <Timestamp>%s</Timestamp>\n", timestamp);
} }

View File

@ -191,7 +191,13 @@ mbus_serial_disconnect(mbus_handle *handle)
return -1; return -1;
} }
if (handle->fd < 0)
{
return -1;
}
close(handle->fd); close(handle->fd);
handle->fd = -1;
return 0; return 0;
} }
@ -374,4 +380,3 @@ mbus_serial_recv_frame(mbus_handle *handle, mbus_frame *frame)
return MBUS_RECV_RESULT_OK; return MBUS_RECV_RESULT_OK;
} }

View File

@ -127,7 +127,13 @@ mbus_tcp_disconnect(mbus_handle *handle)
return -1; return -1;
} }
if (handle->fd < 0)
{
return -1;
}
close(handle->fd); close(handle->fd);
handle->fd = -1;
return 0; return 0;
} }
@ -262,4 +268,3 @@ mbus_tcp_set_timeout_set(double seconds)
return 0; return 0;
} }