Search code examples
arrayslogicbyteplcbytebuffer

String to int to byte array without advanced data types


this might be a difficult question, but I'm trying to do the following:

Take an input string i which i want to be a unix timestamp including miliseconds Convert this to an int64 byte array, but i can only do the operations using simpler structures, my largest available int is 32 bit, to expand a bit this is for a PLC to send some telegram to a database

Wanted input:
  "1707461225120" // int64 string 
Should return:
  [00, 00, 01, 8D, 8C, 9E, AA, A0] // 8 byte array

I dont really care what language for responses, i only care about the logical thinking to solve this, anything would be helpful, no advanced data types

I tried the following (want to convert string to int64 8 byte array), sorry if this is a weird language to adhere to, but its all i have, for responses i dont need the same format, i just need the general logic / math, no advanced data types

    byArray : Array[0..31] OF Byte; // temp array of characters in string
    byArrayO : Array[0..7] OF Byte; // temp memory before converting to output
    charCount : Int; // temp amount of characters in input string 16 bit int
    il : Int; // temp counter generic 16 bit int
    i : String; // input string
    o : Array[0..7] OF Byte; // output byte array

    // reset temp memory
    FOR #il := 0 TO 7 DO
        #o[#il] := 0;
        #byArrayO[#il] := 0;
    END_FOR;

    // Convert string to character array
    "STRING_TO_CHARS"(Chars => #byArray,
                      Cnt => #charCount,
                      pChars := 0,
                      Strg := #i); 
    
    // loop character array, here's what im doing wrong, but unsure how to solve this
    FOR #il := 0 TO #charCount - 2 DO // - 2 due to character count offset by 2
        // Function adds an int to a byte array
        "ADD_BYTE_ARRAY"(iAdd := (#byArray[#il] - 48) * 10 ** #il, // convert int char to int and offset
                        arr := #byArrayO); // array to add to
    END_FOR;
    
    #o := #byArrayO;

By this post https://stackoverflow.com/a/28201576/23369035 I need to tweak the add_byte_Array input to keep the memory of the old val value, but how would this be done with a byte array when i cant use int64?

Wanted input:
  "1707461225120"
Should return:
  [00, 00, 01, 8D, 8C, 9E, AA, A0]
What my code does:
   adds the characters in the string together one by one :/

Solution

  • I "Solved" my issue by making a way to multiply the byte array by an int32 value then adding the miliseconds

    MULT_BYTE_ARRAY
    
    // Multiply to byte array and carry over
    
    #carry := 0;
    FOR #i := #LEN TO 0 BY -1 DO
        #sum := BYTE_TO_UDINT(#arr[#i]) * #iMult + #carry;
        #carry := SHR(IN := #sum, N := 8);
        #arr[#i] := UDINT_TO_BYTE(#sum);
    END_FOR;
    
    ADD_BYTE_ARRAY
    
    // Add to byte array and carry over
    
    #carry := #iAdd;
    FOR #i := #LEN TO 0 BY -1 DO
        #sum := (#arr[#i] & 255) + #carry;
        #arr[#i] := UDINT_TO_BYTE(#sum);
        #carry := SHR(IN := #sum, N := 8);
    END_FOR;
    
    "ADD_BYTE_ARRAY"(iAdd := STRING_TO_UDINT(#i), // regular unix timestamp in
                     arr := #byArrayO); 
    
    "MULT_BYTE_ARRAY"(iMult := 1000,
                      arr := #byArrayO);
    

    After this i can add the ms using ADD_BYTE_ARRAY, works fine when you know there wont be any overflow