libmbus/mbus/mbus-protocol-aux.h

337 lines
9.9 KiB
C
Raw Normal View History

//------------------------------------------------------------------------------
// Copyright (C) 2011, Robert Johansson and contributors, Raditex AB
// All rights reserved.
//
// FreeSCADA
// http://www.FreeSCADA.com
// freescada@freescada.com
//
// 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_connect_serial(device);
* or
* mbus_handle = mbus_connect_tcp(host, port);
*
* ...
*
* 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);
* \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/mbus.h>
#include <mbus/mbus-protocol.h>
#include <mbus/mbus-serial.h>
#include <mbus/mbus-tcp.h>
#define MBUS_PROBE_NOTHING 0
#define MBUS_PROBE_SINGLE 1
#define MBUS_PROBE_COLLISION 2
#define MBUS_PROBE_ERROR -1
/**
* Unified MBus handle type encapsulating either Serial or TCP gateway.
*/
typedef struct _mbus_handle {
char is_serial; /**< _handle type (non zero for serial) */
union {
mbus_tcp_handle * m_tcp_handle; /**< TCP gateway handle */
mbus_serial_handle * m_serial_handle; /**< Serial gateway handle */
};
} 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) */
} mbus_record;
/**
* Connects to serial gateway and initializes MBus handle
*
* @param device Serial device (like /dev/ttyUSB0 or /dev/ttyS0)
*
* @return Initialized "unified" handler when successful, NULL otherwise;
*/
mbus_handle * mbus_connect_serial(const char * device);
/**
* Connects to TCP gateway and initializes MBus handle
*
* @param host Gateway host
* @param port Gateway port
*
* @return Initialized "unified" handler when successful, NULL otherwise;
*/
mbus_handle * mbus_connect_tcp(const char *host, int port);
/**
* Disconnects the "unified" handle.
*
* @param handle Initialized handle
*
* @return Zero when successful.
*/
int mbus_disconnect(mbus_handle * handle);
/**
* 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);
/**
* 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 secodary 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 data request frame 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 ping frame to given slave using "unified" handle
*
* @param handle Initialized handle
* @param address Address (0-255)
*
* @return Zero when successful.
*/
int mbus_send_ping_frame(mbus_handle *handle, int address);
/**
* 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, u_char *data);
/**
* Create/parse single counter from the variable data structure record
*
* @param data 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_data_variable_value_decode(mbus_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);
/**
* Iterate over secondary addresses, send a probe package to all addresses matching
* the given addresses mask.
*
* @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);
#endif // __MBUS_PROTOCOL_AUX_H__