Closed yel-best closed 9 months ago
This is the float format conversion issue because your slave uses the custom float format representation. The esp-modbus currently does not support conversion of other float or U32 formats. This will be addressed as planned to support all available types of float and U32.
There are 4 combinations of 32-bit float representation in modbus devices: Little-Endian Big-Endian Big-Endian byte swap Little-Endian byte swap - supported by esp-modbus
The fix should be performed here.
// the macro to fix endianess of the float value with format BADC (change the offsets as per your device format)
#define _XFER_4_FLOAT(dst, src) { \
*(uint8_t *)((uint8_t*)dst + 3) = *(uint8_t *)(src + 0); \
*(uint8_t *)((uint8_t*)dst + 2) = *(uint8_t *)(src + 1); \
*(uint8_t *)((uint8_t*)dst + 0) = *(uint8_t *)(src + 2); \
*(uint8_t *)((uint8_t*)dst + 1) = *(uint8_t *)(src + 3) ; \
}
static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
uint8_t* value_ptr, uint8_t *type)
{
MB_MASTER_CHECK((name != NULL),
ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
MB_MASTER_CHECK((type != NULL),
ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
esp_err_t error = ESP_ERR_INVALID_RESPONSE;
mb_param_request_t request ;
mb_parameter_descriptor_t reg_info = { 0 };
error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, ®_info);
if ((error == ESP_OK) && (cid == reg_info.cid)) {
// Send request to read characteristic data
error = mbc_serial_master_send_request(&request, value_ptr);
if (error == ESP_OK) {
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
} else {
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
}
// Set the type of parameter found in the table
*type = reg_info.param_type;
if ((( reg_info.param_type == PARAM_TYPE_FLOAT)
|| (reg_info.param_type == PARAM_TYPE_U32))
&& (reg_info.param_size == 4)) {
// Fix endianess for FLOAT and U32 according to your slave manual
float dest_val = 0;
_XFER_4_FLOAT(&dest_val, value_ptr);
ESP_LOGW(TAG, "Convert %"PRIx32" = %"PRIx32, *(uint32_t*)value_ptr, *(uint32_t*)&dest_val);
*(uint32_t*)value_ptr = (uint32_t)dest_val;
}
} else {
This is the float format conversion issue because your slave uses the custom float format representation. The esp-modbus currently does not support conversion of other float or U32 formats. This will be addressed as planned to support all available types of float and U32.
There are 4 combinations of 32-bit float representation in modbus devices: Little-Endian Big-Endian Big-Endian byte swap Little-Endian byte swap - supported by esp-modbus
The fix should be performed here.
// the macro to fix endianess of the float value with format BADC (change the offsets as per your device format) #define _XFER_4_FLOAT(dst, src) { \ *(uint8_t *)((uint8_t*)dst + 3) = *(uint8_t *)(src + 0); \ *(uint8_t *)((uint8_t*)dst + 2) = *(uint8_t *)(src + 1); \ *(uint8_t *)((uint8_t*)dst + 0) = *(uint8_t *)(src + 2); \ *(uint8_t *)((uint8_t*)dst + 1) = *(uint8_t *)(src + 3) ; \ } static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, uint8_t* value_ptr, uint8_t *type) { MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor."); MB_MASTER_CHECK((type != NULL), ESP_ERR_INVALID_ARG, "type pointer is incorrect."); esp_err_t error = ESP_ERR_INVALID_RESPONSE; mb_param_request_t request ; mb_parameter_descriptor_t reg_info = { 0 }; error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, ®_info); if ((error == ESP_OK) && (cid == reg_info.cid)) { // Send request to read characteristic data error = mbc_serial_master_send_request(&request, value_ptr); if (error == ESP_OK) { ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s", __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error)); } else { ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s", __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error)); } // Set the type of parameter found in the table *type = reg_info.param_type; if ((( reg_info.param_type == PARAM_TYPE_FLOAT) || (reg_info.param_type == PARAM_TYPE_U32)) && (reg_info.param_size == 4)) { // Fix endianess for FLOAT and U32 according to your slave manual float dest_val = 0; _XFER_4_FLOAT(&dest_val, value_ptr); ESP_LOGW(TAG, "Convert %"PRIx32" = %"PRIx32, *(uint32_t*)value_ptr, *(uint32_t*)&dest_val); *(uint32_t*)value_ptr = (uint32_t)dest_val; } } else {
thank you very much for your help
When I merge your code into the project, the running results are as follows
W (3153) MB_CONTROLLER_MASTER: Convert b000450e = e45b000
The value I got through modbus is B0 00 45 0E
Float of slave the actual result should be 45 0E B0 00
I think the _XFER_4_FLOAT function needs to be adjusted, but I don’t understand this function very well. Can you help me with the answer?
thk
This is the float format conversion issue because your slave uses the custom float format representation. The esp-modbus currently does not support conversion of other float or U32 formats. This will be addressed as planned to support all available types of float and U32. There are 4 combinations of 32-bit float representation in modbus devices: Little-Endian Big-Endian Big-Endian byte swap Little-Endian byte swap - supported by esp-modbus The fix should be performed here.
// the macro to fix endianess of the float value with format BADC (change the offsets as per your device format) #define _XFER_4_FLOAT(dst, src) { \ *(uint8_t *)((uint8_t*)dst + 3) = *(uint8_t *)(src + 0); \ *(uint8_t *)((uint8_t*)dst + 2) = *(uint8_t *)(src + 1); \ *(uint8_t *)((uint8_t*)dst + 0) = *(uint8_t *)(src + 2); \ *(uint8_t *)((uint8_t*)dst + 1) = *(uint8_t *)(src + 3) ; \ } static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, uint8_t* value_ptr, uint8_t *type) { MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor."); MB_MASTER_CHECK((type != NULL), ESP_ERR_INVALID_ARG, "type pointer is incorrect."); esp_err_t error = ESP_ERR_INVALID_RESPONSE; mb_param_request_t request ; mb_parameter_descriptor_t reg_info = { 0 }; error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, ®_info); if ((error == ESP_OK) && (cid == reg_info.cid)) { // Send request to read characteristic data error = mbc_serial_master_send_request(&request, value_ptr); if (error == ESP_OK) { ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s", __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error)); } else { ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s", __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error)); } // Set the type of parameter found in the table *type = reg_info.param_type; if ((( reg_info.param_type == PARAM_TYPE_FLOAT) || (reg_info.param_type == PARAM_TYPE_U32)) && (reg_info.param_size == 4)) { // Fix endianess for FLOAT and U32 according to your slave manual float dest_val = 0; _XFER_4_FLOAT(&dest_val, value_ptr); ESP_LOGW(TAG, "Convert %"PRIx32" = %"PRIx32, *(uint32_t*)value_ptr, *(uint32_t*)&dest_val); *(uint32_t*)value_ptr = (uint32_t)dest_val; } } else {
thank you very much for your help
When I merge your code into the project, the running results are as follows
W (3153) MB_CONTROLLER_MASTER: Convert b000450e = e45b000
The value I got through modbus is B0 00 45 0E
Float of slave the actual result should be 45 0E B0 00
I think the _XFER_4_FLOAT function needs to be adjusted, but I don’t understand this function very well. Can you help me with the answer?
thk
I tried to adjust the following function and the result is as follows
#define _XFER_4_FLOAT(dst, src) { \
*(uint8_t *)((uint8_t*)dst + 3) = *(uint8_t *)(src + 1); \
*(uint8_t *)((uint8_t*)dst + 2) = *(uint8_t *)(src + 0); \
*(uint8_t *)((uint8_t*)dst + 0) = *(uint8_t *)(src + 2); \
*(uint8_t *)((uint8_t*)dst + 1) = *(uint8_t *)(src + 3); \
}
before fixing
*(uint8_t *)((uint8_t*)dst + 3) = *(uint8_t *)(src + 0); \
*(uint8_t *)((uint8_t*)dst + 2) = *(uint8_t *)(src + 1); \
After modification
*(uint8_t *)((uint8_t*)dst + 3) = *(uint8_t *)(src + 1); \
*(uint8_t *)((uint8_t*)dst + 2) = *(uint8_t *)(src + 0); \
This will make my conversion results correct, I don't know if this is correct
W (9683) MB_CONTROLLER_MASTER: Convert 4000450e = 450e4000
But I also found that if I add this code, the result obtained by _XFER_4_FLOAT (uint32_t)value_ptr = (uint32_t)dest_val; 450ea000 will be converted to IEEE 754 Converter. How should I do it? 450f0000 = float: 2288
It seems that the original value conversion cannot be used after modification. I hope you can give me some opinions. Thank you.
`> After I modify the esp-modbus lib code according to your instructions, the subsequent compilation will prompt that the file needs to be deleted, otherwise the compilation cannot pass. It means that I have modified the package. How should I solve it? Does it mean that I should not modify the package directly? Solved in my business code?
Please just move the changed code of modbus component from managed_components
into components folder. After this you will be able to compile it without any issues and make changes as needed.
But I also found that if I add this code, the result obtained by _XFER_4_FLOAT (uint32_t)value_ptr = (uint32_t)dest_val; 450ea000 will be converted to IEEE 754 Converter. How should I do it? 450f0000 = float: 2288
After your modification the result looks good to me. Please carefully read the manual for your device to correctly convert this, I guess you just need to adjust the point position and your result is 228.8V?
You also can add the PARAM_TYPE_FLOAT_CDAB
enumeration value and then use it in object dictionary to handle your custom float type. In this case this conversion will be performed only for the custom values and regular functionality will be unchanged. This is how the conversion functionality will be performed in future update of the library.
After I modify the esp-modbus lib code according to your instructions, the subsequent compilation will prompt that the file needs to be deleted, otherwise the compilation cannot pass. It means that I have modified the package. How should I solve it? Does it mean that I should not modify the package directly? Solved in my business code?
Please just move the changed code of modbus component from
managed_components
into components folder. After this you will be able to compile it without any issues and make changes as needed.But I also found that if I add this code, the result obtained by _XFER_4_FLOAT (uint32_t)value_ptr = (uint32_t)dest_val; 450ea000 will be converted to IEEE 754 Converter. How should I do it? 450f0000 = float: 2288
After your modification the result looks good to me. Please carefully read the manual for your device to correctly convert this, I guess you just need to adjust the point position and your result is 228.8V?
Yes, that's right. After adjustment, the result is the 228.8V I want. Now I can get the correct result for me
But I also have another issue, in a separate issue, about compilation errors after mixing other components
Can you take a look at it for me?
https://github.com/espressif/esp-modbus/issues/52
Thx
yes, this problem has been solved. I hope to use the new v2.0 earlier. I hope these problems can be solved from the package. Thank you for your support. 😄
esp-idf version: 5.1.2 esp-modbus version: 1.0.12
In my master example, make the following adjustments:
Read the voltage value of the electric meter. The result of the value should be float. After I made the above definition and ran it, the output result through the console is as follows:
I (503) MASTER_TEST: Characteristic #0 Volts (V) value = -158790234117799422060857917440.000000 (0xf000450d) read successful. I (513) MASTER_TEST: MB readings stored: for Volts with value: -158790234117799422060857917440.000000
The result is an exception and the hexadecimal result read is (0xf000450d)
The hex code is incorrect, the correct one should be (0x450df000)
Please help me find out what is the reason. I have read the idf-modbus document many times, but I still can’t figure out why the order is reversed. I cannot get the data in the correct order from the read results, and it is done with 2 bytes. Displacement conversion, if it is bytes order, it should be swapped in the order of 1 byte.
This problem bothered me for a weekend, 😢
thx