Compare commits
3 Commits
adjustable
...
0.9.0
Author | SHA1 | Date | |
---|---|---|---|
2dc3daaf70 | |||
36a85d3737 | |||
2f9fa5ccc8 |
@ -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,42 +54,59 @@ 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];
|
||||||
|
}
|
||||||
|
else if (argc == 3 && strcmp(argv[1], "-d") == 0)
|
||||||
{
|
{
|
||||||
case 'd':
|
|
||||||
debug = 1;
|
debug = 1;
|
||||||
break;
|
device = argv[2];
|
||||||
case 'b':
|
}
|
||||||
baudrate = atol(optarg);
|
else if (argc == 4 && strcmp(argv[1], "-b") == 0)
|
||||||
break;
|
{
|
||||||
case 'r':
|
baudrate = atol(argv[2]);
|
||||||
retries = atoi(optarg);
|
device = argv[3];
|
||||||
break;
|
}
|
||||||
case 't':
|
else if (argc == 4 && strcmp(argv[1], "-r") == 0)
|
||||||
timeout = atoi(optarg);
|
{
|
||||||
break;
|
retries = atoi(argv[2]);
|
||||||
default:
|
device = argv[3];
|
||||||
fprintf(stderr,"usage: %s [-d] [-b BAUDRATE] [-r RETRIES] [-t TIMEOUT] device\n",
|
}
|
||||||
argv[0]);
|
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;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (optind >= argc) {
|
|
||||||
fprintf(stderr,"usage: %s [-d] [-b BAUDRATE] [-r RETRIES] [-t TIMEOUT] device\n",
|
|
||||||
argv[0]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
device = argv[optind];
|
|
||||||
|
|
||||||
if ((handle = mbus_context_serial(device)) == NULL)
|
if ((handle = mbus_context_serial(device)) == NULL)
|
||||||
{
|
{
|
||||||
@ -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");
|
||||||
|
@ -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
|
||||||
|
15
libmbus.spec
15
libmbus.spec
@ -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
|
@ -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) ||
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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,10 +503,22 @@ 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);
|
||||||
|
|
||||||
|
if (bcd_data[i-1]>>4 < 0xA)
|
||||||
|
{
|
||||||
|
val += ((bcd_data[i-1]>>4) & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
val = (val * 10) + ( bcd_data[i-1] & 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"))
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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):
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user