3 Commits

Author SHA1 Message Date
2dc3daaf70 Prepare new release 0.9.0 2019-02-22 19:08:04 +01:00
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
8 changed files with 107 additions and 76 deletions

View File

@ -11,7 +11,6 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <mbus/mbus.h> #include <mbus/mbus.h>
static int debug = 0; static int debug = 0;
@ -55,43 +54,60 @@ main(int argc, char **argv)
{ {
mbus_handle *handle; mbus_handle *handle;
char *device; char *device;
int address, retries = 0, timeout = 0; int address, retries = 0;
long baudrate = 9600; long baudrate = 9600;
int opt, ret; int ret;
while ((opt = getopt(argc, argv, "db:r:t:")) != -1) if (argc == 2)
{ {
switch (opt) device = argv[1];
{
case 'd':
debug = 1;
break;
case 'b':
baudrate = atol(optarg);
break;
case 'r':
retries = atoi(optarg);
break;
case 't':
timeout = atoi(optarg);
break;
default:
fprintf(stderr,"usage: %s [-d] [-b BAUDRATE] [-r RETRIES] [-t TIMEOUT] device\n",
argv[0]);
return 0;
}
} }
else if (argc == 3 && strcmp(argv[1], "-d") == 0)
if (optind >= argc) { {
fprintf(stderr,"usage: %s [-d] [-b BAUDRATE] [-r RETRIES] [-t TIMEOUT] device\n", debug = 1;
argv[0]); device = argv[2];
}
else if (argc == 4 && strcmp(argv[1], "-b") == 0)
{
baudrate = atol(argv[2]);
device = argv[3];
}
else if (argc == 4 && strcmp(argv[1], "-r") == 0)
{
retries = atoi(argv[2]);
device = argv[3];
}
else if (argc == 5 && strcmp(argv[1], "-d") == 0 && strcmp(argv[2], "-b") == 0)
{
debug = 1;
baudrate = atol(argv[3]);
device = argv[4];
}
else if (argc == 5 && strcmp(argv[1], "-d") == 0 && strcmp(argv[2], "-r") == 0)
{
debug = 1;
retries = atoi(argv[3]);
device = argv[4];
}
else if (argc == 6 && strcmp(argv[1], "-b") == 0 && strcmp(argv[3], "-r") == 0)
{
baudrate = atol(argv[2]);
retries = atoi(argv[4]);
device = argv[5];
}
else if (argc == 7 && strcmp(argv[1], "-d") == 0 && strcmp(argv[2], "-b") == 0 && strcmp(argv[4], "-r") == 0)
{
debug = 1;
baudrate = atol(argv[3]);
retries = atoi(argv[5]);
device = argv[6];
}
else
{
fprintf(stderr,"usage: %s [-d] [-b BAUDRATE] [-r RETRIES] device\n", argv[0]);
return 0; return 0;
} }
device = argv[optind];
if ((handle = mbus_context_serial(device)) == NULL) if ((handle = mbus_context_serial(device)) == NULL)
{ {
fprintf(stderr,"Scan failed: Could not initialize M-Bus context: %s\n", mbus_error_str()); fprintf(stderr,"Scan failed: Could not initialize M-Bus context: %s\n", mbus_error_str());
@ -116,12 +132,6 @@ main(int argc, char **argv)
return 1; return 1;
} }
if (mbus_context_set_option(handle, MBUS_OPTION_TIMEOUT_OFFSET, timeout) == -1)
{
fprintf(stderr,"Failed to set timeout offset\n");
return 1;
}
if (mbus_serial_set_baudrate(handle, baudrate) == -1) if (mbus_serial_set_baudrate(handle, baudrate) == -1)
{ {
fprintf(stderr,"Failed to set baud rate.\n"); fprintf(stderr,"Failed to set baud rate.\n");

View File

@ -10,7 +10,7 @@ dnl ----------------------------------------------------------------------------
LT_CONFIG_LTDL_DIR([libltdl]) LT_CONFIG_LTDL_DIR([libltdl])
AC_INIT([libmbus], [0.8.0], [info@rscada.se], [libmbus], [http://www.rscada.se/libmbus/]) AC_INIT([libmbus], [0.9.0], [info@rscada.se], [libmbus], [http://www.rscada.se/libmbus/])
AC_CONFIG_AUX_DIR([libltdl/config]) AC_CONFIG_AUX_DIR([libltdl/config])
AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AM_INIT_AUTOMAKE([-Wall -Werror foreign])
@ -18,7 +18,7 @@ AM_PROG_LIBTOOL
# fix for automake 1.11 & 1.12 # fix for automake 1.11 & 1.12
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LDFLAGS="$LDFLAGS -version-info 0:8:0" LDFLAGS="$LDFLAGS -version-info 0:9:0"
dnl ---------------------- dnl ----------------------
dnl dnl

View File

@ -11,10 +11,10 @@
Summary: Open source M-bus (Meter-Bus) library Summary: Open source M-bus (Meter-Bus) library
Name: libmbus Name: libmbus
Version: 0.8.0 Version: 0.9.0
Release: 1 Release: 1
Source: http://www.rscada.se/public-dist/%{name}-%{version}.tar.gz Source: https://github.com/rscada/%{name}/archive/%{version}.tar.gz
URL: http://www.rscada.se/libmbus/ URL: https://github.com/rscada/libmbus/
License: BSD License: BSD
Vendor: Raditex Control AB Vendor: Raditex Control AB
Packager: Stefan Wahren <info@lategoodbye.de> Packager: Stefan Wahren <info@lategoodbye.de>
@ -68,9 +68,8 @@ rm -rf "%buildroot"
%{_bindir}/mbus-serial-* %{_bindir}/mbus-serial-*
%{_bindir}/mbus-tcp-* %{_bindir}/mbus-tcp-*
%{_libdir}/libmbus.so* %{_libdir}/libmbus.so*
# man pages doesn't exist in this version %{_mandir}/man1/libmbus.1
# %{_mandir}/man1/libmbus.1 %{_mandir}/man1/mbus-*
# %{_mandir}/man1/mbus-*
%files devel %files devel
%defattr (-,root,root) %defattr (-,root,root)
@ -80,5 +79,9 @@ rm -rf "%buildroot"
%{_libdir}/pkgconfig/libmbus.pc %{_libdir}/pkgconfig/libmbus.pc
%changelog %changelog
* Fri Feb 22 2019 Stefan Wahren <info@lategoodbye.de> - 0.9.0-1
- switch to github repo
- enable man pages
* Fri Mar 29 2013 Stefan Wahren <info@lategoodbye.de> - 0.8.0-1 * Fri Mar 29 2013 Stefan Wahren <info@lategoodbye.de> - 0.8.0-1
- Initial package based on the last official release - Initial package based on the last official release

View File

@ -1519,7 +1519,6 @@ mbus_context_serial(const char *device)
handle->max_data_retry = 3; handle->max_data_retry = 3;
handle->max_search_retry = 1; handle->max_search_retry = 1;
handle->timeout_offset = 0;
handle->is_serial = 1; handle->is_serial = 1;
handle->purge_first_frame = MBUS_FRAME_PURGE_M2S; handle->purge_first_frame = MBUS_FRAME_PURGE_M2S;
handle->auxdata = serial_data; handle->auxdata = serial_data;
@ -1568,7 +1567,6 @@ mbus_context_tcp(const char *host, uint16_t port)
handle->max_data_retry = 3; handle->max_data_retry = 3;
handle->max_search_retry = 1; handle->max_search_retry = 1;
handle->timeout_offset = 0;
handle->is_serial = 0; handle->is_serial = 0;
handle->purge_first_frame = MBUS_FRAME_PURGE_M2S; handle->purge_first_frame = MBUS_FRAME_PURGE_M2S;
handle->auxdata = tcp_data; handle->auxdata = tcp_data;
@ -1654,13 +1652,6 @@ mbus_context_set_option(mbus_handle * handle, mbus_context_option option, long v
return 0; return 0;
} }
break; break;
case MBUS_OPTION_TIMEOUT_OFFSET:
if ((value >= 0) && (value <= 100))
{
handle->timeout_offset = value;
return 0;
}
break;
case MBUS_OPTION_PURGE_FIRST_FRAME: case MBUS_OPTION_PURGE_FIRST_FRAME:
if ((value == MBUS_FRAME_PURGE_NONE) || if ((value == MBUS_FRAME_PURGE_NONE) ||
(value == MBUS_FRAME_PURGE_M2S) || (value == MBUS_FRAME_PURGE_M2S) ||

View File

@ -87,7 +87,6 @@ typedef struct _mbus_handle {
int fd; int fd;
int max_data_retry; int max_data_retry;
int max_search_retry; int max_search_retry;
unsigned int timeout_offset;
char purge_first_frame; char purge_first_frame;
char is_serial; /**< _handle type (non zero for serial) */ char is_serial; /**< _handle type (non zero for serial) */
int (*open) (struct _mbus_handle *handle); int (*open) (struct _mbus_handle *handle);
@ -155,8 +154,7 @@ typedef struct _mbus_record {
typedef enum _mbus_context_option { typedef enum _mbus_context_option {
MBUS_OPTION_MAX_DATA_RETRY, /**< option defines the maximum attempts of data request retransmission */ MBUS_OPTION_MAX_DATA_RETRY, /**< option defines the maximum attempts of data request retransmission */
MBUS_OPTION_MAX_SEARCH_RETRY, /**< option defines the maximum attempts of search request retransmission */ MBUS_OPTION_MAX_SEARCH_RETRY, /**< option defines the maximum attempts of search request retransmission */
MBUS_OPTION_PURGE_FIRST_FRAME, /**< option controls the echo cancelation for mbus_recv_frame */ MBUS_OPTION_PURGE_FIRST_FRAME /**< option controls the echo cancelation for mbus_recv_frame */
MBUS_OPTION_TIMEOUT_OFFSET, /**< option defines the additional timeout offset */
} mbus_context_option; } mbus_context_option;
/** /**

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"))

View File

@ -72,10 +72,13 @@ mbus_serial_connect(mbus_handle *handle)
// between the end of a master send telegram and the beginning of the response telegram of the slave shall be // between the end of a master send telegram and the beginning of the response telegram of the slave shall be
// between 11 bit times and (330 bit times + 50ms). // between 11 bit times and (330 bit times + 50ms).
// //
// For 2400Bd this means (330 + 11) / 2400 + 0.05 = 188.75 ms (added 11 bit periods to receive first byte). // Nowadays the usage of USB to serial adapter is very common, which could
// I.e. timeout of 0.2s seems appropriate for 2400Bd. // result in additional delay of 100 ms in worst case.
//
// For 2400Bd this means (330 + 11) / 2400 + 0.15 = 292 ms (added 11 bit periods to receive first byte).
// I.e. timeout of 0.3s seems appropriate for 2400Bd.
term->c_cc[VTIME] = (cc_t) 2 + handle->timeout_offset; // Timeout in 1/10 sec term->c_cc[VTIME] = (cc_t) 3; // Timeout in 1/10 sec
cfsetispeed(term, B2400); cfsetispeed(term, B2400);
cfsetospeed(term, B2400); cfsetospeed(term, B2400);
@ -113,51 +116,48 @@ mbus_serial_set_baudrate(mbus_handle *handle, long baudrate)
{ {
case 300: case 300:
speed = B300; speed = B300;
serial_data->t.c_cc[VTIME] = (cc_t) 12; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 13; // Timeout in 1/10 sec
break; break;
case 600: case 600:
speed = B600; speed = B600;
serial_data->t.c_cc[VTIME] = (cc_t) 6; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 8; // Timeout in 1/10 sec
break; break;
case 1200: case 1200:
speed = B1200; speed = B1200;
serial_data->t.c_cc[VTIME] = (cc_t) 4; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 5; // Timeout in 1/10 sec
break; break;
case 2400: case 2400:
speed = B2400; speed = B2400;
serial_data->t.c_cc[VTIME] = (cc_t) 2; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 3; // Timeout in 1/10 sec
break; break;
case 4800: case 4800:
speed = B4800; speed = B4800;
serial_data->t.c_cc[VTIME] = (cc_t) 2; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 3; // Timeout in 1/10 sec
break; break;
case 9600: case 9600:
speed = B9600; speed = B9600;
serial_data->t.c_cc[VTIME] = (cc_t) 1; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 2; // Timeout in 1/10 sec
break; break;
case 19200: case 19200:
speed = B19200; speed = B19200;
serial_data->t.c_cc[VTIME] = (cc_t) 1; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 2; // Timeout in 1/10 sec
break; break;
case 38400: case 38400:
speed = B38400; speed = B38400;
serial_data->t.c_cc[VTIME] = (cc_t) 1; // Timeout in 1/10 sec serial_data->t.c_cc[VTIME] = (cc_t) 2; // Timeout in 1/10 sec
break; break;
default: default:
return -1; // unsupported baudrate return -1; // unsupported baudrate
} }
// Add timeout offset for additional delay
serial_data->t.c_cc[VTIME] += handle->timeout_offset;
// Set input baud rate // Set input baud rate
if (cfsetispeed(&(serial_data->t), speed) != 0) if (cfsetispeed(&(serial_data->t), speed) != 0)
{ {

View File

@ -1,5 +1,14 @@
Release notes for libmbus Release notes for libmbus
Version 0.9.0 (2019-02-22):
Added support for negative BCD numbers (type A) and date time CP48 (type I),
new program (set primary address), extended XML output (storage number,
tariff, device), echo cancelation and better retry handling. Also this version
has countless bug fixes.
Many thanks to all contributers
Version 0.8.0 (2012-06-18): Version 0.8.0 (2012-06-18):
-------------------------- --------------------------