TechTip: Using a Macro On a Weintek HMI to Generate a QR Code For The History Upload Address

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

Scan the QR Code Generated by Macro to give the URL for FTP access to the HMI

ftp://uploadhis:[email protected]/ read from QR code…. Press “Go”…
Access to the HMI to download logs etc.

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.