507 lines
15 KiB
C
Executable File
507 lines
15 KiB
C
Executable File
//------------------------------------------------------------------------------
|
|
// Copyright (C) 2011, Robert Johansson and contributors, Raditex AB
|
|
// All rights reserved.
|
|
//
|
|
// rSCADA
|
|
// http://www.rSCADA.se
|
|
// info@rscada.se
|
|
//
|
|
// Contributors:
|
|
// Large parts of this file was contributed by Tomas Menzl.
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* @file mbus-protocol-aux.h
|
|
*
|
|
* @brief Auxiliary functions to the Freescada libmbus library
|
|
*
|
|
* The idea is to simplify the basic task of querying MBus slaves and
|
|
* the data processing.
|
|
* Typical use might be (in oversimplified "pseudocode"):
|
|
* \verbatim
|
|
* mbus_handle = mbus_context_serial(device);
|
|
* or
|
|
* mbus_handle = mbus_context_tcp(host, port);
|
|
*
|
|
* mbus_context_set_option(mbus_handle,option,value); // optional
|
|
*
|
|
* mbus_connect(mbus_handle);
|
|
*
|
|
* ...
|
|
*
|
|
* mbus_read_slave(mbus_handle, addresses, &reply);
|
|
* mbus_frame_data_parse(reply, &frameData);
|
|
* // check the header / record type (fixed/variable)
|
|
*
|
|
* // for fixed use mbus_data_fixed_medium and 2x mbus_parse_fixed_record
|
|
* mbus_data_fixed_medium
|
|
* mbusRecord = mbus_parse_fixed_record() // first record
|
|
* // process mbusRecord
|
|
* mbusRecord = mbus_parse_fixed_record() // second record
|
|
* // process mbusRecord
|
|
*
|
|
* // for variable use mbus_parse_variable_record
|
|
* for each record
|
|
* mbusRecord = mbus_parse_variable_record(record)
|
|
* // process mbusRecord
|
|
*
|
|
* ...
|
|
*
|
|
* mbus_disconnect(mbus_handle);
|
|
* mbus_context_free(mbus_handle);
|
|
* \endverbatim
|
|
*
|
|
* Note that the quantity values are partially "normalized". For example energy
|
|
* is in Wh even when originally used "decimal" prefixes like MWh. This seems to
|
|
* be sensible as it make easier any processing of a dataset with huge
|
|
* fluctuation (no need to lookup/convert the prefixes). Also the potential
|
|
* conversion to desired units is pretty easy.
|
|
*
|
|
* On the other hand we acknowledge that use of certain units are expected so we
|
|
* do not convert all units to Si (i.e. no conversion from J to Wh or Bar to Pa.)
|
|
*/
|
|
|
|
#ifndef __MBUS_PROTOCOL_AUX_H__
|
|
#define __MBUS_PROTOCOL_AUX_H__
|
|
|
|
#include "mbus-protocol.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define MBUS_PROBE_NOTHING 0
|
|
#define MBUS_PROBE_SINGLE 1
|
|
#define MBUS_PROBE_COLLISION 2
|
|
#define MBUS_PROBE_ERROR -1
|
|
|
|
#define MBUS_FRAME_PURGE_S2M 2
|
|
#define MBUS_FRAME_PURGE_M2S 1
|
|
#define MBUS_FRAME_PURGE_NONE 0
|
|
|
|
/**
|
|
* Unified MBus handle type encapsulating either Serial or TCP gateway.
|
|
*/
|
|
typedef struct _mbus_handle {
|
|
int fd;
|
|
int max_data_retry;
|
|
int max_search_retry;
|
|
char purge_first_frame;
|
|
char is_serial; /**< _handle type (non zero for serial) */
|
|
int (*open) (struct _mbus_handle *handle);
|
|
int (*close) (struct _mbus_handle *handle);
|
|
int (*send) (struct _mbus_handle *handle, mbus_frame *frame);
|
|
int (*recv) (struct _mbus_handle *handle, mbus_frame *frame);
|
|
void (*free_auxdata) (struct _mbus_handle *handle);
|
|
void (*recv_event) (unsigned char src_type, const char *buff, size_t len);
|
|
void (*send_event) (unsigned char src_type, const char *buff, size_t len);
|
|
void (*scan_progress) (struct _mbus_handle *handle, const char *mask);
|
|
void (*found_event) (struct _mbus_handle *handle, mbus_frame *frame);
|
|
void *auxdata;
|
|
} mbus_handle;
|
|
|
|
/**
|
|
* MBus slave address type (primary/secodary address)
|
|
*/
|
|
typedef struct _mbus_address {
|
|
char is_primary; /**< Address type (non zero for primary) */
|
|
union {
|
|
int primary; /**< Primary address (for slaves shall be from 1 to 250) */
|
|
char * secondary; /**< Secondary address (shall be 16 digits) */
|
|
};
|
|
} mbus_address;
|
|
|
|
|
|
/**
|
|
* _string type
|
|
*
|
|
* In general support binary strings (octet string, non zero terminated)
|
|
* but so far almost all strings are zero terminated ("texts").
|
|
*/
|
|
typedef struct _mbus_string {
|
|
char * value; /**< Buffer */
|
|
int size; /**< _size */
|
|
} mbus_string;
|
|
|
|
|
|
/**
|
|
* Quantity value type union
|
|
*/
|
|
typedef union _mbus_value {
|
|
double real_val; /**< Numerical */
|
|
mbus_string str_val; /**< Text/binary */
|
|
} mbus_value;
|
|
|
|
|
|
/**
|
|
* Single measured quantity record type
|
|
*/
|
|
typedef struct _mbus_record {
|
|
mbus_value value; /**< Quantity value */
|
|
char is_numeric; /**< Quantity value type (nonzero is numeric) */
|
|
char *unit; /**< Quantity unit (e.g. Wh) */
|
|
char *function_medium; /**< Quantity medium or function (e.g. Electricity) */
|
|
char *quantity; /**< Quantity type (e.g. Energy) */
|
|
int device; /**< Quantity device */
|
|
long tariff; /**< Quantity tariff */
|
|
long storage_number; /**< Quantity storage number */
|
|
} mbus_record;
|
|
|
|
/**
|
|
* MBus handle option enumeration
|
|
*/
|
|
typedef enum _mbus_context_option {
|
|
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_PURGE_FIRST_FRAME /**< option controls the echo cancelation for mbus_recv_frame */
|
|
} mbus_context_option;
|
|
|
|
/**
|
|
* Event register functions
|
|
*/
|
|
//
|
|
// Event register functions
|
|
//
|
|
void mbus_register_recv_event(mbus_handle *handle, void (*event)(unsigned char src_type, const char *buff, size_t len));
|
|
void mbus_register_send_event(mbus_handle *handle, void (*event)(unsigned char src_type, const char *buff, size_t len));
|
|
void mbus_register_scan_progress(mbus_handle *handle, void (*event)(mbus_handle *handle, const char *mask));
|
|
void mbus_register_found_event(mbus_handle *handle, void (*event)(mbus_handle *handle, mbus_frame *frame));
|
|
|
|
/**
|
|
* Allocate and initialize M-Bus serial context.
|
|
*
|
|
* @param device Serial device (like /dev/ttyUSB0 or /dev/ttyS0)
|
|
*
|
|
* @return Initialized "unified" handler when successful, NULL otherwise;
|
|
*/
|
|
mbus_handle * mbus_context_serial(const char *device);
|
|
|
|
/**
|
|
* Allocate and initialize M-Bus TCP context.
|
|
*
|
|
* @param host Gateway host
|
|
* @param port Gateway port
|
|
*
|
|
* @return Initialized "unified" handler when successful, NULL otherwise;
|
|
*/
|
|
mbus_handle * mbus_context_tcp(const char *host, uint16_t port);
|
|
|
|
/**
|
|
* Deallocate memory used by M-Bus context.
|
|
*
|
|
* @param handle Initialized handle
|
|
*
|
|
*/
|
|
void mbus_context_free(mbus_handle * handle);
|
|
|
|
/**
|
|
* Connect to serial bus or TCP gateway depending on context.
|
|
*
|
|
* @param handle Initialized handle
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_connect(mbus_handle * handle);
|
|
|
|
/**
|
|
* Disconnects the "unified" handle.
|
|
*
|
|
* @param handle Initialized handle
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_disconnect(mbus_handle * handle);
|
|
|
|
/**
|
|
* Set option of a M-Bus context.
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param option option to set
|
|
* @param value value to set
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_context_set_option(mbus_handle * handle, mbus_context_option option, long value);
|
|
|
|
/**
|
|
* Receives a frame using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param frame Received frame
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_recv_frame(mbus_handle * handle, mbus_frame *frame);
|
|
|
|
/**
|
|
* Used for handling collisions. Blocks as long as receiving frames or corrupted data.
|
|
*
|
|
* @param handle Initialized handle
|
|
*
|
|
* @return Zero when nothing received, one otherwise.
|
|
*/
|
|
int mbus_purge_frames(mbus_handle * handle);
|
|
|
|
/**
|
|
* Sends frame using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param frame Frame to send
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_frame(mbus_handle * handle, mbus_frame *frame);
|
|
|
|
/**
|
|
* Sends secondary address selection frame using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param secondary_addr_str Secondary address
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_select_frame(mbus_handle * handle, const char *secondary_addr_str);
|
|
|
|
/**
|
|
* Sends application reset to given slave using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address (0-255)
|
|
* @param subcode Subcode (0-255) or no subcode (-1)
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_application_reset_frame(mbus_handle * handle, int address, int subcode);
|
|
|
|
/**
|
|
* Sends switch baudrate frame using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address (0-255)
|
|
* @param baudrate Baudrate (300,600,1200,2400,4800,9600,19200,38400)
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_switch_baudrate_frame(mbus_handle * handle, int address, long baudrate);
|
|
|
|
/**
|
|
* Sends request frame (REQ_UD2) to given slave using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address (0-255)
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_request_frame(mbus_handle * handle, int address);
|
|
|
|
/**
|
|
* Sends user data frame (SND_UD) to given slave using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address (0-255)
|
|
* @param data User data
|
|
* @param data_size Byte count of user data
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_user_data_frame(mbus_handle * handle, int address, const unsigned char *data, size_t data_size);
|
|
|
|
/**
|
|
* Sends a request and read replies until no more records available
|
|
* or limit is reached.
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address (0-255)
|
|
* @param reply pointer to an mbus frame for the reply
|
|
* @param max_frames limit of frames to readout (0 = no limit)
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_sendrecv_request(mbus_handle *handle, int address, mbus_frame *reply, int max_frames);
|
|
|
|
/**
|
|
* Sends ping frame to given slave using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address (0-255)
|
|
* @param purge_response Response flag (=0 don't receive response, >0 purge response)
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_send_ping_frame(mbus_handle *handle, int address, char purge_response);
|
|
|
|
/**
|
|
* Select slave by secondary address using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param mask Address/mask to select
|
|
*
|
|
* @return See MBUS_PROBE_* constants
|
|
*/
|
|
int mbus_select_secondary_address(mbus_handle * handle, const char *mask);
|
|
|
|
/**
|
|
* Probe/address slave by secondary address using "unified" handle
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param mask Address/mask to probe
|
|
* @param matching_addr Matched address (the buffer has tobe at least 16 bytes)
|
|
*
|
|
* @return See MBUS_PROBE_* constants
|
|
*/
|
|
int mbus_probe_secondary_address(mbus_handle * handle, const char *mask, char *matching_addr);
|
|
|
|
/**
|
|
* Read data from given slave using "unified" handle and address types
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param address Address of the slave
|
|
* @param reply Reply from the slave
|
|
*
|
|
* @return Zero when successful.
|
|
*/
|
|
int mbus_read_slave(mbus_handle *handle, mbus_address *address, mbus_frame *reply);
|
|
|
|
|
|
/**
|
|
* Allocate new data record. Use #mbus_record_free when finished.
|
|
*
|
|
* @return pointer to the new record, NULL when failed
|
|
*/
|
|
mbus_record * mbus_record_new();
|
|
|
|
/**
|
|
* Destructor for mbus_record
|
|
*
|
|
* @param rec record to be freed
|
|
*/
|
|
void mbus_record_free(mbus_record *rec);
|
|
|
|
|
|
/**
|
|
* Create/parse single counter from the fixed data structure
|
|
*
|
|
* @param statusByte status byte
|
|
* @param medium_unit_byte medium/unit byte
|
|
* @param data pointer to the data counter (4 bytes)
|
|
*
|
|
* @return Newly allocated record if succesful, NULL otherwise. Later on need to use #mbus_record_free
|
|
*/
|
|
mbus_record *mbus_parse_fixed_record(char statusByte, char medium_unit_byte, unsigned char *data);
|
|
|
|
|
|
/**
|
|
* Create/parse single counter from the variable data structure record
|
|
*
|
|
* @param record record data to be parsed
|
|
*
|
|
* @return Newly allocated record if succesful, NULL otherwise. Later on need to use #mbus_record_free
|
|
*/
|
|
mbus_record * mbus_parse_variable_record(mbus_data_record *record);
|
|
|
|
|
|
|
|
/**
|
|
* Get normalized counter value for a fixed counter
|
|
*
|
|
* Get "normalized" value and unit of the counter
|
|
*
|
|
* @param medium_unit_byte medium/unit byte of the fixed counter
|
|
* @param medium_value raw counter value
|
|
* @param unit_out units of the counter - use free when done
|
|
* @param value_out resulting counter value
|
|
* @param quantity_out parsed quantity, when done use "free"
|
|
*
|
|
* @return zero when OK
|
|
*/
|
|
int mbus_data_fixed_normalize(int medium_unit_byte, long medium_value, char **unit_out, double *value_out, char **quantity_out);
|
|
|
|
|
|
|
|
/**
|
|
* Decode value of a variable data structure
|
|
*
|
|
* @param record record to be decoded
|
|
* @param value_out_real numerical counter value output (when numerical)
|
|
* @param value_out_str string counter value output (when string, NULL otherwise), when finished use "free *value_out_str"
|
|
* @param value_out_str_size string counter value size
|
|
*
|
|
* @return zero when OK
|
|
*/
|
|
int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, char **value_out_str, int *value_out_str_size);
|
|
|
|
/**
|
|
* Decode units and normalize value using VIF/VIFE (used internally by mbus_vib_unit_normalize)
|
|
*
|
|
* @param vif VIF (including standard extensions)
|
|
* @param value already parsed "raw" numerical value
|
|
* @param unit_out parsed unit, when done use "free"
|
|
* @param value_out normalized value
|
|
* @param quantity_out parsed quantity, when done use "free"
|
|
*
|
|
* @return zero when OK
|
|
*/
|
|
int mbus_vif_unit_normalize(int vif, double value, char **unit_out, double *value_out, char **quantity_out);
|
|
|
|
/**
|
|
* Decode units and normalize value from VIB
|
|
*
|
|
* @param vib mbus value information block of the variable record
|
|
* @param value already parsed "raw" numerical value
|
|
* @param unit_out parsed unit, when done use "free"
|
|
* @param value_out normalized value
|
|
* @param quantity_out parsed quantity, when done use "free"
|
|
*
|
|
* @return zero when OK
|
|
*/
|
|
int mbus_vib_unit_normalize(mbus_value_information_block *vib, double value, char **unit_out, double *value_out, char ** quantity_out);
|
|
|
|
/**
|
|
* Generate XML for normalized variable-length data
|
|
*
|
|
* @param data variable-length data
|
|
*
|
|
* @return string with XML
|
|
*/
|
|
char * mbus_data_variable_xml_normalized(mbus_data_variable *data);
|
|
|
|
/**
|
|
* Return a string containing an XML representation of the normalized M-BUS frame data.
|
|
*
|
|
* @param data M-Bus frame data
|
|
*
|
|
* @return string with XML
|
|
*/
|
|
char * mbus_frame_data_xml_normalized(mbus_frame_data *data);
|
|
|
|
/**
|
|
* Iterate over secondary addresses, send a probe package to all addresses matching
|
|
* the given addresses mask.
|
|
*
|
|
* @param handle Initialized handle
|
|
* @param pos current address
|
|
* @param addr_mask address mask to
|
|
*
|
|
* @return zero when OK
|
|
*/
|
|
int mbus_scan_2nd_address_range(mbus_handle * handle, int pos, char *addr_mask);
|
|
|
|
/**
|
|
* Convert a buffer with hex values into a buffer with binary values.
|
|
*
|
|
* @param dst destination buffer with binary values
|
|
* @param dst_len byte count of destination buffer
|
|
* @param src source buffer with hex values
|
|
* @param src_len byte count of source buffer
|
|
*
|
|
* @return byte count of successful converted values
|
|
*/
|
|
size_t mbus_hex2bin(unsigned char * dst, size_t dst_len, const unsigned char * src, size_t src_len);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // __MBUS_PROTOCOL_AUX_H__
|