Breaking Ints into Sints and Casting Them as Strings

Hello Everyone,

My title may look pretty silly, but that’s what I need to figure out how to do in FPMI. I am looking to convert an old RSView32 hmi, and the people before me thought it would be best to store string characters in integers. :angry: (It looks like Rockwell thought it was a good idea as well since RSView32 does all of this implicitly behind the scenes)

Well, enough griping…here is the chain of events I need to figure out how to do in FPMI:

First you need to break up each 16-bit Integer into two 8-bit Short Integers. Once you have your two Short Integers you cast those into standard ascii characters and concatenate them together. Thus each integer can hold 2 characters. I need to be able to do this for an array of Integers.

What would be the best way to pull this off in FPMI? I am using KepServerEx for my OPC server which supports advanced tags. Perhaps I could use that?

Thanks in advance.

–HandledException

I don’t think FactoryPMI has an ASCII lookup function (sounds like a reasonable feature request).

As a starting point, using the expression language…

your masked less significant int will be: {value}&255your second will be: {value}&65280)>>8(We just masked the 8 most significant bits by performing a logical AND with 1111111100000000, then shifted our result over 8 bits)

you might have to create your own ASCII_lookup table (dataSet), then use the lookup function like this:

lookup({ASCII}, {first or second value}, "default_no_match", 0, 1)

0 and 1 are the columns in your lookup table.

I’m not sure how you could dynamically apply this to a whole dataSet. You could step through a dataSet in code and do the manipulation.

[color=#FF4000]IMPORTANT EDIT[/color]: Don’t use this. It is unsafe. See the followup post here for a safe version.

Well the expression language has right shift (>>) and bitmask (&) operators, so you can use those to break up the 16bits (short) into 2 8bits (bytes). Converting those into a string would require the Python “chr” function, but you could use that in an expression too with the “runScript” function.

For example, suppose you had the short 16961, which would represent “BA” (66<<8 | 65)

You could turn that into “BA” with an expression like so:

runScript("chr(" + (16961 >> 8) + ")") + runScript("chr(" + (16961 & 0x00FF) + ")")

Tada!

Wow, your software keeps surprising me. Something I thought was going to be a huge p.i.t.a. turns out to be pretty simple. Horray for robust scripting languages and software!

I think I am going to make a global script for this, since I am going to need it in multiple places.

What would be the best way to construct an array of the values I need so I can loop through them easily in my script? Or maybe a List would work better?

Thanks for the great help.

–HandledException

Yeah, flexible and powerful scripting is really crucial.

A python list would be good if you’re going to do it all within scripting.

I can’t seem to get my global script for this to work. Could you perhaps take a look at it and see what I am doing wrong? Am I referencing it wrong somehow?

Module Hierarchy I am using:

-apps --legacy ---rsview32 ----strings
I am trying to bind the results to a dynamic property like so:

runscript("app.legacy.rsview32.strings.integerToString([" + {[dgpc]Overview/Sources/Row E/E1/Gradecode/Word1} + ", " + {[dgpc]Overview/Sources/Row E/E1/Gradecode/Word2} + ", " + {[dgpc]Overview/Sources/Row E/E1/Gradecode/Word3} + ", " + {[dgpc]Overview/Sources/Row E/E1/Gradecode/Word4} + ", " + {[dgpc]Overview/Sources/Row E/E1/Gradecode/Word5} + "])")
Thanks for your on-going help!

–HandledException
(script in question attached below)
app.legacy.rsview32.strings.fpkg.zip (843 Bytes)

Your script was actually called “Strings” with a capital S.
so…

app.legacy.rsview32.Strings.integerToString

Thanks for spotting that. I figured that it was something obvious, but just couldn’t find it…I needed a second set of eyes.

Now I am running into a more serious problem. Once I made that change and saved the project, the script runs, but I get an xml parsing exception (see attached text file) whenever I try to open the window again. :frowning:

Is it a problem with my script, FPMI, or both? I already lost a lot of work due to this, so if you could let me know what I need to do to remedy this it would be greatly appreciated.

–HandledException
XML Parsing Exception.txt (2.87 KB)

After troubleshooting this a bit more, it seems that the problem stemmed from the fact that my script could return multiple null characters to the string dynamic property. Once I modified the script so that it doesn’t return any nulls things seem to work fine.

Perhaps this could be added to the bug list? It permanently nukes your window if it happens…

–HandledException

PS I attached the modified script for anyone interested

**Edit Updated script export file
app.legacy.rsview32.Strings.zip (524 Bytes)

Indeed. I think this has already been fixed in the next major version, but I'll double-check.

Why am I not able to add this in my Module Editor??

I select “app” , then “Import Package or Script” and then I select the file I downloaded and extracted “app.legacy.rsview32.strings.fpkg” and then I get this:


java.util.NoSuchElementException
	at java.util.Vector.lastElement(Unknown Source)
	at com.sun.beans.ObjectHandler.lastExp(Unknown Source)
	at com.sun.beans.ObjectHandler.dequeueResult(Unknown Source)
	at java.beans.XMLDecoder.readObject(Unknown Source)
	at com.inductiveautomation.factorypmi.designer.tools.jython.ModuleEditor$11.actionPerformed(ModuleEditor.java:556)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
FactoryPMI v3.3.2 (build 2754)
Java: Sun Microsystems Inc. 1.6.0_04

Sorry about that. It looks like the xml got snipped out for whatever reason.

Let me know if this one doesn’t work for you…

–HandledException
app.legacy.rsview32.Strings.zip (868 Bytes)

Thanks for the script, works like a charm.

I have one question though. I tried using the code

runScript("chr(" + (16961 >> 8) + ")") +
runScript("chr(" + (16961 & 0x00FF) + ")")

Where “16961” was actually an SQLTag. Now I have this error

[quote]com.inductiveautomation.factorypmi.common.xmlserialization.SerializationException: Unexpected parsing error during deserialization.
at com.inductiveautomation.factorypmi.common.xmlserialization.deserialization.XMLDeserializer.deserialize(XMLDeserializer.java:150)
at com.inductiveautomation.factorypmi.application.model.WindowController.deserializeWindow(WindowController.java:619)
at com.inductiveautomation.factorypmi.application.model.WindowController._loadWindow(WindowController.java:324)
at com.inductiveautomation.factorypmi.application.model.WindowController.getWindow(WindowController.java:368)
at com.inductiveautomation.factorypmi.application.FPMIApp.openWindow(FPMIApp.java:836)
at com.inductiveautomation.factorypmi.application.FPMIApp.openWindow(FPMIApp.java:817)
at com.inductiveautomation.factorypmi.designer.model.ObjectHolder.openWindow(ObjectHolder.java:2204)
at com.inductiveautomation.factorypmi.designer.navtree.ProjectBrowserPanel.openItem(ProjectBrowserPanel.java:500)
at com.inductiveautomation.factorypmi.designer.navtree.ProjectBrowserPanel.mousePressed(ProjectBrowserPanel.java:486)
at java.awt.AWTEventMulticaster.mousePressed(Unknown Source)
at java.awt.AWTEventMulticaster.mousePressed(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x1b) was found in the element content of the document.
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at com.inductiveautomation.factorypmi.common.xmlserialization.deserialization.XMLDeserializer.deserialize(XMLDeserializer.java:143)
… 30 more
FactoryPMI v3.3.2 (build 2754)
Java: Sun Microsystems Inc. 1.6.0_04
[/quote]

And I am now unable to open the window in Designer and FIX IT… is there ANY way to recover all of the work that I put into this window? or do I cut my losses and start over? LOL

I feel your pain. :frowning:

Sorry to say, but I was unable to recover my window once I ran into that error. You might be able to open up the window’s xml and fix it, but I never tried that.

Was the SQL tag value a zero? I think that’s what caused my problem. The window serializer must not like it when there is a string value containing multiple null characters. The script I posted strips out all of the nulls though, so it shouldn’t happen anymore at least.

–HandledException

How would I go about looking at the window and fixing it in the XML?? I CAN export it. So i was curious if I could open the window with some sort of program and hunt through it line by line.

Yes, I HARD coded that CHAR line of code into the window. and there WERE some zero’s. Then when I saved and it tried to Serialize, it CRAPPED on the rug… :cry: :scratch:

It looks like it is saved/exported in binary. I don’t think there is much you can do unless someone from IA can offer some help…

–HandledException

Looks like I gave you guys a dangerous tool. Let me try to make it a bit safer for you:
Put this in your global script library under a module called “char”

def toChar(x): return chr(max(32, min(126, x>>8))) + chr(max(32, min(126, x&0x00FF)))
And then use expression bindings like this:

runScript("app.char.toChar("+{MyTag}+")")

Sorry for the issues. You can export and email to me any windows that got corrupted, and I can fix them for you.

Here is my window. Thanks for the fix, but it would be nice to understand this a bit more and be able to fix my own problems in the future LOL :wink: Unless this is going too far into the PROPRIETARY realm :stuck_out_tongue:
overview.fwin (113 KB)

Ok, here is the fixed file.

There is no big secret here. Its just that I’ve got the FactoryPMI Designer started up in a special mode that lets me hack the XML directly, so I can remove the invalid character. You could technically do this yourself by setting the “fpmi.debug=true” flag in the JNLP, but this is really tricky due to the architecture of Java Web-Start, and the fact that our JNLPs are generated dynamically. I’ve been thinking of some more end-user friendly way of enabling these special functions, even something as simple as holding down shift when you right click on things, or something along those lines of “hidden in plain sight” type methods of enabling these more esoteric functions. You could also just export the window and un-Base64/un-Gzip the XML, but this is a P.I.T.A.
overview_fixed.fwin (113 KB)

For those who are following this thread, here is the code module I ended up going with. It accepts a sequence of numbers (or a single one), tacks all of the results together, and returns a single string with all of the whitespace removed. This version also incorporates Carl’s nifty solution to mask all non-printable characters.

Seems to work pretty well…

Enjoy!

–HandledException
app.legacy.rsview32.Strings.zip (899 Bytes)