Introduction
This TechTip is about using a Macro to generate a QR code to scan with a phone to access via FTP* the HMI to upload history files etc from it. As usual, we’ll break it down so you can see what we’re doing here.
*It’s worth noting that some browsers do not support parsing passwords etc in the address. As of today, Mozilla Firefox works ok.
Using with Mozilla Firefox


ftp://uploadhis:[email protected]/ read from QR code…. Press “Go”…

Macro
The required string is in the following format: “ftp://uploadhis:[email protected]/“
Declare variables
The first part, “ftp://uploadhis:” is fixed, so we’ll declare that in our macro:
char Text1[16] = "ftp://uploadhis:" // first part of the string, this is fixed and 16 characters long
Next is the ftp password, we are using the default of “111111” here.
char Text2[10] ="111111" // 2nd part of the string - ftp password
The other fixed characters (“@” “.” & “/”) are also defined.
char Text3[1] ="@" // the "@" character
char Dot[1] = "." // the "." dot character
char Slash[1] = "/" // the "/" forward slash character
The HMI IP address is stored in 4 consecutive LW registers, LW 9129-9132, 9129 is the first Octet, 9130, the second, etc. these are 16-bit numbers. So we’ll declare variables for each Octet as “short” data type.
short IPfirstOctDEC // IP address 1st Octet
short IPsecondOctDEC // IP address 2nd Octet
short IPthirdOctDEC // IP address 3rd Octet
short IPfourthOctDEC // IP address 4th Octet
Since the IP Octets could be 1, 2 or 3 digits, we’ll declare some variables to store the length of them
short IPfirstOctLength // Length of IP address 1st Octet
short IPsecondOctLength // Length of IP address 2nd Octet
short IPthirdOctLength // Length of IP address 3rd Octet
short IPfourthOctLength // Length of IP address 4th Octet
For concatenating our string, we’ll need to calculate the length of the new part we’re adding and use that as an offset, so we’ll need 2 variables for this
short length1 // length1 used for offset calculations
short length2 // length2 used for offset calculations
Once we have our final string, we’ll measure the length of that too.
short overalllength // Overall length of string
Since our output will be an ASCII string, we’ll need some ASCII (char) variables as destinations for a Decimal to ASCII conversion
char IPfirstOct[3] // IP address 1st Octet char
char IPsecondOct[3] // IP address 2nd Octet char
char IPthirdOct[3] // IP address 3rd Octet char
char IPfourthOct[3] // IP address 4th Octet char
Finally, a destination for the final string:
char OutputString[64] // Result output string
The Program
Now to the program itself. Having set up our variables, first off, we’ll clear “OutputString” and put the result into our destination, LW100.
FILL(OutputString[0], 0, 64) // clear OutputString
SetData(OutputString[0], "Local HMI", LW, 100,64) // Clear LW100
Then get the IP address from the HMI, one Octet at a time.
GetData(IPfirstOctDEC, "Local HMI", LW, 9129, 1) // Get IP address 1st Octet
etc.
Next, we’ll determine if the first Octet of the IP address is 1, 2 or 3 digits.
if IPfirstOctDEC > 99 then // If 1st Octet of IP is>than 99 then
IPfirstOctLength = 3 // 3 digits
else if IPfirstOctDEC > 9 then // if it is greater than 9 then it is
IPfirstOctLength = 2 // 2 digits
else
IPfirstOctLength = 1 // otherwise it's 1 digit
end if
As the IP address as read from the HMI LW is decimal, we’ll convert to ASCII and use the calculated length (IPfirstOctLength) to determine how many characters it will be.
DEC2ASCII(IPfirstOctDEC, IPfirstOct[0], IPfirstOctLength) //
// Convert the 1st Octet to ASCII for its calculated length of 1,2 or 3
We’ll repeat this for the other 3 Octets of the IP address.
Next, we’ll start building the string…
//"ftp://uploadhis:"
StringCat(Text1[0], OutputString[0]) // concat Text1 - "ftp://uploadhis:" into OutputString
length1 = StringLength(Text1[0]) // measure Text1 and put result into "length1"
//
//"ftp://uploadhis:password"
StringCat(Text2[0], OutputString[length1]) // offset Text2 (password)into outputstring by length of Text1 (length1)
length2 = StringLength(Text2[0]) + length1 // measure Text2 and add to length1 to give the next offset (length2)
Using length1 and length2 alternately, we will offset the point at which the required variable or value is inserted into “OutputString“.
And finally, we’ll measure “OutputString“, putting the result in “overalllength“.
// Calculate the length of "ftp://uploadhis:[email protected]"
overalllength = StringLength(OutputString[0])
And finally, putting in our ultimate destination, LW100.
SetData(OutputString[0], "Local HMI", LW, 100, overalllength) // set LW100 with the value of OutputString
The final, full macro is as follows:
macro_command main()
//
// This Macro generates a string using the HMI IP address and the FTP password to generate:
//
// ftp://uploadhis:[email protected]/
//
char Text1[16] = "ftp://uploadhis:" // first part of the string, this is fixed and 16 characters long
char Text2[10] ="111111" // 2nd part of the string - ftp password
char Text3[1] ="@" // the "@" character
char Dot[1] = "." // the "." dot character
char Slash[1] = "/" // the "/" forward slash character
// the HMI IP address is in 16 bit registers, i.e. "decimal"
short IPfirstOctDEC // IP address 1st Octet
short IPsecondOctDEC // IP address 2nd Octet
short IPthirdOctDEC // IP address 3rd Octet
short IPfourthOctDEC // IP address 4th Octet
// since each octet of the IP address can be 1,2 or 3 digits we will measure each Octet
short IPfirstOctLength // Length of IP address 1st Octet
short IPsecondOctLength // Length of IP address 2nd Octet
short IPthirdOctLength // Length of IP address 3rd Octet
short IPfourthOctLength // Length of IP address 4th Octet
// when concatenating the strings for our final string we'll use 2 offsets
short length1 // length1 used for offset calculations
short length2 // length2 used for offset calculations
// and calculate an overall length
short overalllength // Overall length of string
//
char IPfirstOct[3] // IP address 1st Octet char
char IPsecondOct[3] // IP address 2nd Octet char
char IPthirdOct[3] // IP address 3rd Octet char
char IPfourthOct[3] // IP address 4th Octet char
char OutputString[64] // Result output string
FILL(OutputString[0], 0, 64) // clear OutputString
SetData(OutputString[0], "Local HMI", LW, 100,64) // Clear LW100
GetData(IPfirstOctDEC, "Local HMI", LW, 9129, 1) // Get IP address 1st Octet
GetData(IPsecondOctDEC, "Local HMI", LW, 9130, 1) // Get IP address 2nd Octet
GetData(IPthirdOctDEC, "Local HMI", LW, 9131, 1) // Get IP address 3rd Octet
GetData(IPfourthOctDEC, "Local HMI", LW, 9132, 1) // Get IP address 4th Octet
if IPfirstOctDEC > 99 then // If 1st Octet of IP is > than 99 then it is
IPfirstOctLength = 3 // 3 digits
else if IPfirstOctDEC > 9 then // if it is greater than 9 then it is
IPfirstOctLength = 2 // 2 digits
else
IPfirstOctLength = 1 // otherwise it's 1 digit
end if
DEC2ASCII(IPfirstOctDEC, IPfirstOct[0], IPfirstOctLength) // Convert the 1st Octet to ASCII for its calculated length of 1,2 or 3
if IPsecondOctDEC > 99 then // If 2nd Octet of IP is > than 99 then it is
IPsecondOctLength = 3 // 3 digits
else if IPsecondOctDEC > 9 then // if it is greater than 9 then it is
IPsecondOctLength = 2 // 2 digits
else
IPsecondOctLength = 1 // otherwise it's 1 digit
end if
DEC2ASCII(IPsecondOctDEC, IPsecondOct[0], IPsecondOctLength) // Convert the 2nd Octet to ASCII for its calculated length of 1,2 or 3
if IPthirdOctDEC > 99 then // If 3rd Octet of IP is > than 99 then it is
IPthirdOctLength = 3 // 3 digits
else if IPthirdOctDEC > 9 then // if it is greater than 9 then it is
IPthirdOctLength = 2
else
IPthirdOctLength = 1 // otherwise it's 1 digit
end if
DEC2ASCII(IPthirdOctDEC, IPthirdOct[0], IPthirdOctLength) // Convert the 3rd Octet to ASCII for its calculated length of 1,2 or 3
if IPfourthOctDEC > 99 then // If 4th Octet of IP is > than 99 then it is
IPfourthOctLength = 3 // 3 digits
else if IPfourthOctDEC > 9 then // if it is greater than 9 then it is
IPfourthOctLength = 2
else
IPfourthOctLength = 1 // otherwise it's 1 digit
end if
DEC2ASCII(IPfourthOctDEC, IPfourthOct[0], IPfourthOctLength) // Convert the 4th Octet to ASCII for its calculated length of 1,2 or 3
// Build the string
//
//"ftp://uploadhis:"
StringCat(Text1[0], OutputString[0]) // concatenate Text1 - "ftp://uploadhis:" into OutputString
length1 = StringLength(Text1[0]) // measure Text1 and put result into "length1"
//
//"ftp://uploadhis:password"
StringCat(Text2[0], OutputString[length1]) // offset Text2 (password)into outputstring by length of Text1 (length1)
length2 = StringLength(Text2[0]) + length1 // measure Text2 and add to length1 to give the next offset (length2)
//
//"ftp://uploadhis:[email protected]"
StringCat(Text3[0], OutputString[length2]) // offset Text3 (@)into outputstring by length of Text1 (length2)
length1 = StringLength(Text3[0]) + length2 // measure Text3 and add to length2 to give the next offset (length1)
//
//"ftp://uploadhis:[email protected]"
StringCat(IPfirstOct[0], OutputString[length1]) // Put 1st Octet of IP into our string
length2 = StringLength(IPfirstOct[0]) + length1 // and calculate next offset
//
//"ftp://uploadhis:[email protected]"
StringCat(Dot[0], OutputString[length2]) // Put "Dot" into our string
length1 = StringLength(Dot[0]) + length2 // and calculate next offset
//
//"ftp://uploadhis:[email protected]"
StringCat(IPsecondOct[0], OutputString[length1]) // Put 2nd Octet of IP into our string
length2 = StringLength(IPsecondOct[0]) + length1 // and calculate next offset
//
//"ftp://uploadhis:[email protected]"
StringCat(Dot[0], OutputString[length2]) // Put "Dot" into our string
length1 = StringLength(Dot[0]) + length2 // and calculate next offset
//
//"ftp://uploadhis:[email protected]"
StringCat(IPthirdOct[0], OutputString[length1]) // Put 3rd Octet of IP into our string
length2 = StringLength(IPthirdOct[0]) + length1 // and calculate next offset
//
//"ftp://uploadhis:[email protected]"
StringCat(Dot[0], OutputString[length2]) // Put "Dot" into our string
length1 = StringLength(Dot[0]) + length2 // and calculate next offset
//
//"ftp://uploadhis:[email protected]"
StringCat(IPfourthOct[0], OutputString[length1]) // Put 4th Octet of IP into our string
length2 = StringLength(IPfourthOct[0]) + length1 // and calculate next offset
//
//"ftp://uploadhis:[email protected]/"
StringCat(Slash[0], OutputString[length2]) // Put some slash on the end
length1 = StringLength(Slash[0]) + length2 // and calculate next offset
//
// Calculate the length of "ftp://uploadhis:[email protected]"
overalllength = StringLength(OutputString[0])
// Set LW100 to Value of OutputString
// for length "overalllength"
SetData(OutputString[0], "Local HMI", LW, 100, overalllength) // set LW100 with the value of OutputString
end macro_command
As usual, we have a demo program for you to download and try here.