add configuration request and decode
This commit is contained in:
parent
d44bbfe4f9
commit
8c9f5afaaf
@ -72,6 +72,18 @@ static const uint16_t register_input[] = {
|
||||
0x0158 // 30345 total reactive energy (in kVArh)
|
||||
};
|
||||
|
||||
/** SDM120 4xxxx holding register start addresses for the configuration types */
|
||||
static const uint16_t register_holding[] = {
|
||||
0x000c, // relay pulse width (60, 100, or 200 ms)
|
||||
0x0012, // network parity stop (0: 1 stop bit no parity, 1: one stop bit even parity, 2: one stop bit odd parity, 3: two stop bits no parity)
|
||||
0x0014, // meter slave address (1-247)
|
||||
0x001c, // baud rate (0: 2400 bps, 1: 4800 bps, 2: 9600 bps, 5: 1200 bps)
|
||||
0x0056, // pulse 1 output mode (1: import active energy, 2: import+export active energy, 4: export active energy, 5: import reactive energy, 6: import+export reactive energy, 8: export reactive energy)
|
||||
0xf900, // time of scroll display (0-30 s)
|
||||
0xf910, // pulse 1 output (0: 0.001 kWh/imp, 1: 0.01 kWh/imp, 2: 0.1 kWh/imp, 3: 1 kWh/imp)
|
||||
0xf920 // measurement mode (1: total=import, 2: total=import+export, 3: total=import-export)
|
||||
};
|
||||
|
||||
/** compute CRC for ModBus
|
||||
* @note ModBus uses ANSi/IBM 16-bits CRC (with normal polynomial 0x8005, reverse polynomial 0xA001, start value 0xfff)
|
||||
* @param[in] buffer data on which to compute the CRC for
|
||||
@ -128,18 +140,18 @@ void sensor_sdm120_setup(void)
|
||||
}
|
||||
|
||||
/** send request to electricity meter
|
||||
* @param[in] slave electricity meter slave device address
|
||||
* @param[in] meter_id electricity meter device id (ModBus salve address)
|
||||
* @param[in] function ModBus function: 0x03 read two 16 bits holding registers, 0x04 read two 16 bits input registers, 0x10 write two 16 bits holding registers
|
||||
* @param[in] address register start point address
|
||||
* @param[in] value value to store in holding register (if function 0x10 is used)
|
||||
* @return if request is correct and transmission started
|
||||
*/
|
||||
static bool sensor_sdm120_transmit_request(uint8_t slave, uint8_t function, uint16_t address, float value)
|
||||
static bool sensor_sdm120_transmit_request(uint8_t meter_id, uint8_t function, uint16_t address, float value)
|
||||
{
|
||||
if (tx_used!=0) { // transmission is ongoing
|
||||
return false;
|
||||
}
|
||||
if (slave==0) { // broadcast request are not supported
|
||||
if (meter_id==0) { // broadcast request are not supported
|
||||
return false;
|
||||
}
|
||||
if (function!=0x03 && function!=0x04 && function!=0x10) { // function not supported
|
||||
@ -150,7 +162,7 @@ static bool sensor_sdm120_transmit_request(uint8_t slave, uint8_t function, uint
|
||||
}
|
||||
uint8_t packet[11]; // buffer to build ModBus message (without error check)
|
||||
uint8_t packet_size = 0; // ModBus message size (without error check)
|
||||
packet[0] = slave; // set slave device address
|
||||
packet[0] = meter_id; // set slave device address
|
||||
packet[1] = function; // set function
|
||||
packet[2] = address>>8; // set high register address
|
||||
packet[3] = address; // set low register address
|
||||
@ -184,15 +196,21 @@ static bool sensor_sdm120_transmit_request(uint8_t slave, uint8_t function, uint
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sensor_sdm120_measurement_request(uint8_t slave, enum sensor_sdm120_measurement_type_t type)
|
||||
bool sensor_sdm120_measurement_request(uint8_t meter_id, enum sensor_sdm120_measurement_type_t type)
|
||||
{
|
||||
if (type>=SENSOR_SDM120_MAX) { // invalid type
|
||||
if (type>=SENSOR_SDM120_MEASUREMENT_MAX) { // invalid type
|
||||
return false;
|
||||
}
|
||||
return sensor_sdm120_transmit_request(slave, 0x04, register_input[type], 0);
|
||||
return sensor_sdm120_transmit_request(meter_id, 0x04, register_input[type], 0);
|
||||
}
|
||||
|
||||
|
||||
bool sensor_sdm120_configuration_request(uint8_t meter_id, enum sensor_sdm120_configuration_type_t type)
|
||||
{
|
||||
if (type>=SENSOR_SDM120_CONFIGURATION_MAX) { // invalid type
|
||||
return false;
|
||||
}
|
||||
return sensor_sdm120_transmit_request(meter_id, 0x03, register_holding[type], 0);
|
||||
}
|
||||
|
||||
float sensor_sdm120_measurement_decode(void)
|
||||
{
|
||||
@ -205,8 +223,14 @@ float sensor_sdm120_measurement_decode(void)
|
||||
if (rx_used<5) { // not a complete response (minimum is address, function, size/error, error check low, error check high)
|
||||
return NAN;
|
||||
}
|
||||
if (crc_modbus(rx_buffer,rx_used)==0 && (rx_buffer[1]&0x80)==0) { // no checksum error, no error condition
|
||||
// a complete message has been received
|
||||
if (crc_modbus(rx_buffer,rx_used)) { // checksum error, error check failed
|
||||
measurement = NAN;
|
||||
} else if (rx_buffer[1]&0x80) { // error condition received
|
||||
measurement = INFINITY; // indicate we received and error
|
||||
} else {
|
||||
switch (rx_buffer[1]) {
|
||||
case 0x03: // read 4xxx holding register response received
|
||||
case 0x04: // read 3xxxx input register response received
|
||||
if (rx_buffer[2]==0x04 && rx_used>=(4+5)) { // 2 registers received, corresponds to implemented request
|
||||
// convert big endian received float value to little endian return value
|
||||
@ -217,11 +241,11 @@ float sensor_sdm120_measurement_decode(void)
|
||||
convert[3] = rx_buffer[3];
|
||||
}
|
||||
break;
|
||||
case 0x03: // read 4xxx holding register response received
|
||||
break; // not supported currently
|
||||
case 0x10: // write 4xxx holding register response received
|
||||
measurement = (rx_buffer[4]<<8)+rx_buffer[5]; // number of registers written
|
||||
break; // not supported currently
|
||||
default: // unknown function response received
|
||||
measurement = INFINITY;
|
||||
break; // nothing to do
|
||||
}
|
||||
}
|
||||
@ -251,7 +275,7 @@ void USART_ISR(SENSOR_SDM120_USART)(void)
|
||||
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag, ignore received data
|
||||
} else if (rx_used<LENGTH(rx_buffer)) { // receiving response
|
||||
rx_buffer[rx_used++] = usart_recv(USART(SENSOR_SDM120_USART)); // put received byte in buffer (clears flag)
|
||||
if (rx_used==1 && rx_buffer[0]==0) { // this is wrong decoding because the signal is low on idle (and the 0 broadcast device address is not supported)
|
||||
if (rx_used==1 && rx_buffer[0]==0) { // this is wrong decoding because the signal is going low on idle, which is misinterpreted as start bit (and the 0 broadcast device address is not supported by this device)
|
||||
rx_used = 0; // reset buffer
|
||||
} else if (rx_used>=5 && (rx_buffer[1]&0x80)) { // error condition response received
|
||||
sensor_sdm120_measurement_received = true; // notify used response has been received
|
||||
@ -261,8 +285,7 @@ void USART_ISR(SENSOR_SDM120_USART)(void)
|
||||
sensor_sdm120_measurement_received = true; // notify used response has been receive
|
||||
}
|
||||
} else { // buffer full and unknown response received
|
||||
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag (reading measurement will clear buffer)
|
||||
//rx_used = 0; // clear buffer (not clearing the flag will restart this ISR)
|
||||
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag (wait for user to read measurement, this clears the buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
/** a measurement response has been received */
|
||||
extern volatile bool sensor_sdm120_measurement_received;
|
||||
|
||||
/** measurements offered by electricity meter */
|
||||
/** measurement types offered by electricity meter in 3xxx input registers */
|
||||
enum sensor_sdm120_measurement_type_t {
|
||||
SENSOR_SDM120_VOLTAGE = 0,
|
||||
SENSOR_SDM120_CURRENT,
|
||||
@ -38,18 +38,37 @@ enum sensor_sdm120_measurement_type_t {
|
||||
SENSOR_SDM120_ENERGY_REACTIVE_EXPORT,
|
||||
SENSOR_SDM120_ENERGY_ACTIVE_TOTAL,
|
||||
SENSOR_SDM120_ENERGY_REACTIVE_TOTAL,
|
||||
SENSOR_SDM120_MAX
|
||||
SENSOR_SDM120_MEASUREMENT_MAX
|
||||
};
|
||||
|
||||
/** configuration types for electricity meter in 4xxx holding registers */
|
||||
enum sensor_sdm120_configuration_type_t {
|
||||
SENSOR_SDM120_RELAY_PULSE_WIDTH = 0,
|
||||
SENSOR_SDM120_NETWORK_PARITY_STOP,
|
||||
SENSOR_SDM120_METER_ID,
|
||||
SENSOR_SDM120_BAUD_RATE,
|
||||
SENSOR_SDM120_PULSE_1_OUTPUT_MODE,
|
||||
SENSOR_SDM120_TIME_OF_SCROLL_DISPLAY,
|
||||
SENSOR_SDM120_PULSE_1_OUTPUT,
|
||||
SENSOR_SDM120_MEASUREMENT_MODE,
|
||||
SENSOR_SDM120_CONFIGURATION_MAX
|
||||
};
|
||||
|
||||
/** setup peripherals to communicate with electricity meter */
|
||||
void sensor_sdm120_setup(void);
|
||||
/** request measurement from electricity meter
|
||||
* @param[in] slave electricity meter slave device address
|
||||
* @param[in] mater_id electricity meter device ID
|
||||
* @param[in] type measurement type to request
|
||||
* @return if transmission started
|
||||
*/
|
||||
bool sensor_sdm120_measurement_request(uint8_t slave, enum sensor_sdm120_measurement_type_t type);
|
||||
bool sensor_sdm120_measurement_request(uint8_t meter_id, enum sensor_sdm120_measurement_type_t type);
|
||||
/** request configuration from electricity meter
|
||||
* @param[in] mater_id electricity meter device ID
|
||||
* @param[in] type configuration: type to request
|
||||
* @return if transmission started
|
||||
*/
|
||||
bool sensor_sdm120_configuration_request(uint8_t meter_id, enum sensor_sdm120_configuration_type_t type);
|
||||
/** decode received measurement
|
||||
* @return decoded measurement (NaN if invalid or no new measurement has been received)
|
||||
* @return decoded measurement or number of registers written, NaN if message has error or no new measurement has been received, infinity if an error or unknown message has been received
|
||||
*/
|
||||
float sensor_sdm120_measurement_decode(void);
|
||||
|
Loading…
Reference in New Issue
Block a user