Is it possible to cast quickfix messages into specific classes in order to have intellisense guide? - quickfix

I´m pretty new in quickfix, but according to official doc, even in the case you are typing (in the way of assigning a type) the message you want to send. You have to know in advance which are the available fields. I was expecting to find something more programming friendly. Creating a new OrderCancelRequest, would create an instance where you have a pack of acknowledged variables-properties and IDE would help you to know what field must be provided.
In fact
Type Safe Messages And Fields
void sendOrderCancelRequest()
{
FIX41::OrderCancelRequest message(
FIX::OrigClOrdID("123"),
FIX::ClOrdID("321"),
FIX::Symbol("LNUX"),
FIX::Side(FIX::Side_BUY));
message.set(FIX::Text("Cancel My Order!"));
FIX::Session::sendToTarget(message, SenderCompID("TW"), TargetCompID("TARGET"));
}
and Type Safe Field Only
void sendOrderCancelRequest()
{
FIX::Message message;
FIX::Header header& = message.getHeader();
header.setField(FIX::BeginString("FIX.4.2"));
header.setField(FIX::SenderCompID(TW));
header.setField(FIX::TargetCompID("TARGET"));
header.setField(FIX::MsgType(FIX::MsgType_OrderCancelRequest));
message.setField(FIX::OrigClOrdID("123"));
message.setField(FIX::ClOrdID("321"));
message.setField(FIX::Symbol("LNUX"));
message.setField(FIX::Side(FIX::Side_BUY));
message.setField(FIX::Text("Cancel My Order!"));
FIX::Session::sendToTarget(message);
}
Shows not too much difference. In both cases you have to know which are valid tags to be provided. Maybe, in the second example, the compiler allows you to provide wrong fields, not sure. But at the end, you have to consult which are the available fields to kind of message you want to send (it´s similar to receive, cracking does not help too much, in onMessage you have to know which are the available fields)
So, summarizing. Is it possible to find any smarter way to work with quickfix in order to have more help from the IDE-context? I was thinking about a kind of direct message-class maping.
Thanks a lot for your help. Maybe it´s due to I´m new with quickfix, but I have the feeling that using it oblies you to know messages available fields at the end.

Related

Possibility of a multilanguage 'source' name with Twincat Eventlogger

Roald has written an excellent guide for the Twincat Eventlogger.
https://roald87.github.io/twincat/2020/11/03/twincat-eventlogger-plc-part.html
https://roald87.github.io/twincat/2021/01/20/twincat-eventlogger-hmi-part.html
For us this is exactly what we want, there is however 1 thing I haven't figured out. How to get the sourcename of the alarm in multiple languages in the HMI. params::sourceName gives the path in the software (example: MAIN.fbConveyor1.Cylinder1) This path can be customized when initializing the alarm (as Roald has shown). This doesn't work in my case, since I would like to define a generic alarm (example: "Cilinder not retracted within maximum time") that is instantiated multiple times.
I was thinking of using the source as a way to show the operator where the alarm occurs. We use this way (path) already for saving machine settings among other things. The machines we build are installed all over the world, so multilanguage is a must.
Beckhoff does support multilanguage alarm names (when defined), but the source is not defined, but dynamically generated.
Anyone have an idea how this problem can be solved?
If I understand your question correctly, then being able to parameterize the event text with information of the source of the problem should help you out.
If you define the event text as Cylinder {0} has not retracted in time. then you can add the arguments of that text during runtime.
IF bRaiseAlarm THEN
bRaiseAlarm := FALSE;
fbAlarm.ipArguments.Clear().AddString('Alice');
fbAlarm.Raise(0);
END_IF
However, since this also stated in the articles you mentioned, I am unsure if this would solve your problem.
'Alice' in this example, can be hard to localize. The following options come to my mind.
The string can be based on an ENUM. Enums can have textlist support, so if you add your translations there, that should allow multilingual output. However... this does require a lot of setup, placing translations inside your code, and making sure the PLC application is aware of the language that the parameter should use.
Use tags to mark the source device, as tags can be language invariant. It is not the most user-friendly method, but it could work for you. It would become something like: "Cylinder 'AA.1123' did not retract in time.". 'AA.1123' as a tag would have to be stored inside your PLC code as a string. You will have to trust that your operator can relate the tag back to the actual source.
Hopefully, this helped, or else please help me understand the problem better.

NodeId as string in ModelCompiler OPC UA

I am trying to develop a OPC UA server on my own, but since I am quite a newbie in coding, it is quite hard for me.
I have started from the QuickstartApplication found here: https://github.com/OPCFoundation/UA-.NET-Legacy
in particular I edit the ModelDesign.xml file to customize it as I wish
https://github.com/OPCFoundation/UA-.NET-Legacy/blob/master/ComIOP/Common/Common/ModelDesign.xml
I would like to define some nodes with NodeId as string (all the NodeId in the ModelDesign.xml in the example are numeric)
Following this xsd, I have found "StringId" and "NumericId" that look like what was looking for
https://github.com/OPCFoundation/UA-ModelCompiler/blob/master/ModelCompiler/UA%20Model%20Design.xsd
but changing their value in ModelDesign.xml does nothing about the NodeId. There is no error, just the compiler assigns new NodeIds (all numeric) as if it does not consider the changes I have made.
As a compiler, I am using the ModelCompiler found on GitHub
https://github.com/OPCFoundation/UA-ModelCompiler
Can somebody help me, please? How can I customize the NodeId of the nodes?
Thank you
Edo
the best suggestion that I can offer at this stage is to clone the UA-.NETStandard and run the NetCoreConsoleServer in
UA-.NETStandard/SampleApplications/Samples/NetCoreConsoleServer
through the debugger. The boiler node manager, if my memory serves me well, uses stringIDs. The Interface INodeIdFactory in ISystemContext.cs offers some insight in how ID's are generated.
IMHO, the model designer has no switch to enforce string ID's as you know. So you'll need to programmatically allocate stringID's rather than numeric ID's to nodes upon server boot. I haven't figured it out yet either.
So, you may set breakpoints in the BoilerNodeManager.cs and see how the nodeID is actually constructed.

Metabase/Clojure error: Unfreezable type: class org.postgresql.jdbc.PgArray

Anyone knows something about this error in Metabase (or a similar one in any Clojure program)?
Unfreezable type: class org.postgresql.jdbc.PgArray
It happens regularly, but not always, when I use a postgresql array type (i.e. TEXT[]) in a question => it probably depends on the exact data in the pgArray somehow, but I wasn't able to figure out how.
There is a workaround to get rid of it: retype/cast all pgArrays to TEXT (or VARCHAR). But I would really like to understand why this is happening. Thx for any insights.
Metabase uses a library called Nippy:
https://github.com/metabase/metabase/blob/master/project.clj#L61
Nippy provides fast serialization of common types. The error "Unfreezable type":
https://github.com/ptaoussanis/nippy/blob/master/src/taoensso/nippy.clj#L720
occurs when Nippy comes across data of a type it doesn't know how to serialize. PgArray, as a bespoke Postgres array type, is evidently one of those.
Providing serialization guidance to Nippy is not hard. Maybe make an issue for the Metabase folks with your details asking if they can do this?

Using boost's socket.async_send_to()

I've been stuck on this for a while now. I am trying to send the following:
boost::shared_ptr<uint8_t[]> m_data
over the wire using:
_socket.async_send_to(boost::asio::buffer(m_data), m_remote_endpoint,
boost::bind(&UDPServer::handle_send, this, message,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
I get the error "no instance of overloaded function boost::asio::buffer matches the argument list boost::shared_ptr<uint8_t[]>"
m_data is filled in another function.
I suspect this is because I actually have to use the key word new on m_data. But I can't quite figure out how to do it. I've tried a few different variations. Can anybody offer me some insight here? This is probably more a question of how to dereference a shared pointer then anything. Thanks in advance!
boost::asio::buffer has an impressive lists of consttructors, but neither of them takes shared_ptr<[]> (possibly an oversight form lib authors).
In your case, you simply need to derefence shared ptr, for example, by calling get on it.

Required fields within repeating groups FIX

So I am trying to generate repeating groups in a FIX message, but I need a method to determine which fields are required for each repeating group so I don't have to hard code everything. For some reason, the quickfix DataDictionary class's method
isRequiredField((java.lang.String msgType, int field)
does not work for required fields within repeating groups. For example
isRequiredField("V", 269)
gives false, even thought it is required. The Fix 4.2 XML also has it as required so why does the isRequiredField method return false?
I think you need getGroup(java.lang.String msg, int field), where field is the tag for the group's counter field.
That will give you a DataDictionary.GroupInfo object, and on that you can call getDataDictionary().isRequiredField(msgType,field) (use the same message type).
I think that'll work, anyway. The docs aren't explicitly clear on this.
But why are you doing this?
To be honest, I'm not sure why you think you need to do this. There's simply no need to dynamically query which fields are required. When receiving, the engine checks the required/not-required for you. When you're sending, you have to set values to all the required fields anyway (you can't dynamically do that!).
Unless you are writing some kind of DD-analysis tool, I think you're spending your time investigating a red herring.