Hi,
after I gave up on C++ version of Gurux (on embedded platforms such as ESP32 cannot compile due to error: 'dynamic_cast' not permitted with -fno-rtti... impossibile to work around) I resumed working with ANSI C version. Anyway I'm happy with this cause I succeed to use findObjectByLN(), it works and I can look by LN also with che C version.
But I have the requirement to read up to 4 meters on the same serial. I hypothesized to:
1) cl_init() with meter 1 params -> read AV1 -> cache AV1 -> read meter1 registers -> cl_clear()
2) cl_init() with meter 2 params -> read AV2 -> cache AV2 -> read meter1 registers -> cl_clear()
3) cl_init() with meter 3 params -> read AV3 -> cache AV3 -> read meter1 registers -> cl_clear()
4) cl_init() with meter 4 params -> read AV4 -> cache AV4 -> read meter1 registers -> cl_clear()
And so:
1) cl_init() with meter 1 params -> load AV1 from cache AV1 -> read meter1 registers -> cl_clear()
etc.
And in case of same model of meter, AV could be the same.
Cannot (and don't want) save to (emulated...) EEPROM and use the serializer. Also, I don't want to read the AV every time because it's very very slow and I cannot have polling times of several minutes for all the meters.
Simply, I wish to deep copy settings.objects and reuse after. From the main program, from the Arduino IDE (that is C++ not ANSI C) I just tried a simple object copy:
After cl_clear() the objectArray copy contains previous size and capacity... but copy.data is gone. So I fear that i shallow copy happens, probably due to the multiple indirection due to the pointer of pointer...
If you know what you want to read the easiest way to handle this is if you define objects that you want to read and don't read the association view at all. Something like this:
gxRegister r;
//Replace logical name with the correct one.
const unsigned char ln[6] = { 0,0,0,0,0,255 };
if ((ret = INIT_OBJECT(r, DLMS_OBJECT_TYPE_REGISTER, ln)) == 0)
{
ret = com_read(BASE(r), 2);
//Handle error.
}
Hi Mikko,
I know, but unluckily I cannot in this way. I have to support various models of meters, I don't have the AV XML export of them all (...this would be the solution of all my problems :-p) or the meters themselves (I have only an L+G E650 for development purposes), and some of them works in SN mode but I knows the LN only... (it's a modbus protocol converter, so I have a mapping between modbus registers and OBIS codes... )
I can now deep copy and so load after and reuse after the AV... it "just work" but I notice a very strange issue. Data returned by obj_toString after com_read is corrupted... the index 2, the register itself, is correct but random values of indexes 3,4,5,6,7,8,9 are shown...). It happens simply copying and restoring AV as settings.objects... also without cl_clear. While indexes > 2 are correctly shown with original settings.objects.
I cannot make the serializer to compile :( Moreover, I would not use the EEPROM emulation because I found it's frail (eg. no wear leveling) and so small, totally inadeguate for this purpose. So i did the trick in this way:
1) Client.init() with a fake server number
2) for loop for every configured meter
3) Client.reuse() ** with real connection parameters
4) com_initializeConnection()
5) Client.GetObjects()
6) if objects list is empy, do com_getAssociationView() and com_readScalerAndUnits(), else do nothing
7) Client.findObjectByLN() for every configured LN
8) com_read() and so on
9) com_close()
In this way I can reuse only one client instance and share only one AV, with a simplest and lighter code. I don't need to store the AV because in case of reboot, it will be read again one time only.
Obviously, all the meters on the bus has to be identical!
You don't need to serialize all objects. You can also save only the list of Logical Names and Object types (Short Names in your case) and use that.
But collectors usually are powered all the time, so your idea is working well if all the meters are the same brand and usually, they are. :-)
Hi Andrea,
Hi Andrea,
If you know what you want to read the easiest way to handle this is if you define objects that you want to read and don't read the association view at all. Something like this:
gxRegister r;
//Replace logical name with the correct one.
const unsigned char ln[6] = { 0,0,0,0,0,255 };
if ((ret = INIT_OBJECT(r, DLMS_OBJECT_TYPE_REGISTER, ln)) == 0)
{
ret = com_read(BASE(r), 2);
//Handle error.
}
BR,
Mikko
Hi Mikko,
Hi Mikko,
I know, but unluckily I cannot in this way. I have to support various models of meters, I don't have the AV XML export of them all (...this would be the solution of all my problems :-p) or the meters themselves (I have only an L+G E650 for development purposes), and some of them works in SN mode but I knows the LN only... (it's a modbus protocol converter, so I have a mapping between modbus registers and OBIS codes... )
BR,
Andrea
Hi, I i did it...... or a
Hi, I i did it...... or a "sort of" :-p
objectArray* objects = DLMSClient.GetObjects();
objectArray copy = *objects;
copy.data = (gxObject **) malloc (sizeof(gxObject *) * objects->size);
for (int pos = 0; pos < objects->size; pos++) {
copy.data[pos] = (gxObject*) malloc (sizeof (gxObject));
*copy.data[pos] = *objects->data[pos];
}
I can now deep copy and so load after and reuse after the AV... it "just work" but I notice a very strange issue. Data returned by obj_toString after com_read is corrupted... the index 2, the register itself, is correct but random values of indexes 3,4,5,6,7,8,9 are shown...). It happens simply copying and restoring AV as settings.objects... also without cl_clear. While indexes > 2 are correctly shown with original settings.objects.
BR
Andrea
Hi,
Hi,
Do it like this:
objectArray* objects = DLMSClient.GetObjects();
objectArray *copy = (objectArray*) malloc (sizeof(objectArray));
oa_init(copy);
gxObject* it;
for (uint16_t pos = 0; pos < objects->size; ++pos)
{
oa_getByIndex(objects, pos, &it);
oa_push(copy, it);
}
BR,
Mikko
Hi, unlucily same problem I
Hi, unlucily same problem I had before copying the objects in my way: Just tried but the objects dont' survive to cl_clear()...
BR,
Andrea
Hi Andrea,
Hi Andrea,
Get the latest version and find com_readAllObject. Uncomment the code and it will read the association view and serialize objects to the EEPROM.
com_getAssociationView is also modified. It parses association view objects one at a time to reduce memory usage.
BR,
Mikko
BR,
Mikko
I cannot make the serializer
I cannot make the serializer to compile :( Moreover, I would not use the EEPROM emulation because I found it's frail (eg. no wear leveling) and so small, totally inadeguate for this purpose. So i did the trick in this way:
1) Client.init() with a fake server number
2) for loop for every configured meter
3) Client.reuse() ** with real connection parameters
4) com_initializeConnection()
5) Client.GetObjects()
6) if objects list is empy, do com_getAssociationView() and com_readScalerAndUnits(), else do nothing
7) Client.findObjectByLN() for every configured LN
8) com_read() and so on
9) com_close()
** I added this little method:
void GXDLMSClient::reuse(bool useLogicalNameReferencing, int clientAddress, int serverAddress, DLMS_AUTHENTICATION authentication, const char* password, DLMS_INTERFACE_TYPE interfaceType)
{
settings.useLogicalNameReferencing = useLogicalNameReferencing;
settings.clientAddress = clientAddress;
settings.serverAddress = serverAddress;
settings.authentication = authentication;
bb_addString(&settings.password, password);
}
In this way I can reuse only one client instance and share only one AV, with a simplest and lighter code. I don't need to store the AV because in case of reboot, it will be read again one time only.
Obviously, all the meters on the bus has to be identical!
BR,
Andrea
Hi,
Hi,
You don't need to serialize all objects. You can also save only the list of Logical Names and Object types (Short Names in your case) and use that.
But collectors usually are powered all the time, so your idea is working well if all the meters are the same brand and usually, they are. :-)
BR,
Mikko