I have a PLC with some DATE_AND_TIME values (DT) that are periodically updated. The idea is use a OPC Tag for each one. But there is a problem with the format. The ignition date and time format is different from the Siemens one. SIEMENS Format is :
BYTE Contents BCD Code Limits
0 Year 90-99h (19__)
00-89h (20__)
1 Month 01-12 h
2 Day 01-31h
3 Hour 00-23h
4 Minute 00-59h
5 Second 00-59h
6 MSEC(high)
7 MSEC (low) 000-999h
The only solution I found is to put every byte in different tags and then generate a tag that is a String combining the diferent values. But this involves using 7 tags and some code for something that has to be simple. There is also the problem that doing this you need a function to transform from decimal to hex. Is there a easier and more direct solution?
Ok, thanks. But then there is an easy and standard way to tranform de values I recive in decimal into Hexadecimal? Because the only way I found is using some self made code.
If you have access to the plc programm there is a workaround. You can use the system functions DT_TOD and DT_DATE to convert a date into days and time of day. The DATE is an 16-bit value with the days since 1990-01-01 and TOD is a 32-bit value with the count of milliseconds since midnight. These value can easily be converted to a java date in Ignition.
I added a function to our plc programs that converts all DT values and stores them in a seperate datablock which is then read by Ignition.
Thank you Chi for your tips. But the problem is that I only have control over the ignition. For the PLC code I have to negotiate with the client, and so far he has been reluctant to change the code of them.
I did some digging in my bag of discarded solutions, so here is what i tried initially (not really nice but it works)
You need to get the plc data in two 32-bit tags (Driver format D). So when date is stored in datablock 50 at adress 0, the tags are [S7]DB50,D and [S7]DB50,D4.
Make an expression tag (e.g. S7DateVal) with following expression:
({[.]DB50DD0}<<32) + {[.]DB50DD4}
All of the above tags need to have INT8 as datatype.
Create an additional memory tag of type DATETIME with the same name added ‘DT’ at the end (S7DateValDT).
Put the following code in a tag change script:
val = newValue.value
val = val >> 4 # Ignore DayOfWeek
msec = ((val & 0xf00) / 256)*100
msec += ((val & 0xf0) / 16)*10
msec += (val & 0xf)
val = val >> 12
sec = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
min = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
hour = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
day = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
month = ((val & 0xf0) / 16)*10 + (val & 0xf) - 1 # Java month starts with 0
val = val >> 8
year = ((val & 0xf0) / 16)*10 + (val & 0xf)
if year<90:
year += 2000
else:
year += 1900
#print "%d %d %d %d %d %d %d" % (msec, sec, min, hour, day, month, year)
from java.util import Calendar
cal = Calendar.getInstance()
cal.set(year, month, day, hour, min, sec)
cal.set(Calendar.MILLISECOND, msec)
#print cal.getTime()
system.tag.write(event.tagPath.toStringFull()+'DT', cal.getTime())
Add the expression tag to the tag change script.
Now, on every change of your plc data the …DT tag will be updated.
Be aware the access to two seperate values might not be consistent, so don’t try this with fast changing values.
Since the last post in this thread, have there been any new features w.r.t. conversion between Siemens TOD and DATE formats and the standard (Ignition) DATETIME format?
I did some further checking on this and it looks like the following expression functions are in the works:
toHex() - takes a decimal number and returns a string representing the hex value
fromHex() - takes a hex string and returns the decimal number equivalent
No hard timeline on this but it is being worked on currently.
The script provided works perfectly for Ignition 7.9.10 but not on Ignition 8 when using a Gateway Event script. After talking with support, we were able to get it functioning by using a Tag Event Script on the expression tag “S7DateVal”. Please see below for the script used in Ignition 8.
val = currentValue.value
val = val >> 4 # Ignore DayOfWeek
msec = ((val & 0xf00) / 256)*100
msec += ((val & 0xf0) / 16)*10
msec += (val & 0xf)
val = val >> 12
sec = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
min = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
hour = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
day = ((val & 0xf0) / 16)*10 + (val & 0xf)
val = val >> 8
month = ((val & 0xf0) / 16)*10 + (val & 0xf) - 1 # Java month starts with 0
val = val >> 8
year = ((val & 0xf0) / 16)*10 + (val & 0xf)
if year<90:
year += 2000
else:
year += 1900
#print "%d %d %d %d %d %d %d" % (msec, sec, min, hour, day, month, year)
from java.util import Calendar
cal = Calendar.getInstance()
cal.set(year, month, day, hour, min, sec)
cal.set(Calendar.MILLISECOND, msec)
#print cal.getTime()
system.tag.write("**S7DateValDT PATH HERE**", cal.getTime())
It’s a DataType that has a value for reading date_and_time and a value for writing back to PLC. Might not be the best solution but it works (at least in my case).