Community discussions

MikroTik App
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Can't turn code into a function

Wed May 31, 2023 7:51 pm

Hi all. I'm trying to convert the code into a function. This code in the specified line swaps these characters in each pair of characters. But when I try to make it into a local function, I get nothing. The function neither prints nor returns a result. The source code is this:
:local number "8350000048F0"
:local len [:len $number]
:local tmpNum [:toarray ""]
:local realNum [:toarray ""]
:local result

:local counter 0
while ( $counter<$len ) do={
    :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
    :set $counter ($counter + 1)
};

:local counter 0
while ( $counter<$len ) do={
    :if ( ($counter % 2) = 0) do={
        :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
    } else={
        :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
    }
  :set $counter ($counter + 1)
};

:foreach num in=$realNum do={
        :set result ($result.$num)
    }

:put $result
Here's one way I'm trying to make a function out of it.
:local number
:local reverseNumber do={
:local number
:local len [:len $number]
:local tmpNum [:toarray ""]
:local realNum [:toarray ""]
:local result

:local counter 0
while ( $counter<$len ) do={
    :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
    :set $counter ($counter + 1)
};

:local counter 0
while ( $counter<$len ) do={
    :if ( ($counter % 2) = 0) do={
        :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
    } else={
        :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
    }
  :set $counter ($counter + 1)
};

:put $realNum
:foreach num in=$realNum do={
        :set result ($result.$num)
    }

:return $result
}

:set $number "8350000048F0"
$reverseNumber $number

:local result [$reverseNumber $number]
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Wed May 31, 2023 8:31 pm

Several problems. Main one is you need to use $1 to capture the 1st argument to the function and assign it to a "number" inside your function – no need for ":local number XXXX" if your using a function. Personally, I'd make the function itself global. Although you can keep it :local, but then entire block need to be enclosed in { } to keep the local function available to locals INSIDE same block (which is the 2nd problem since the local function is no longer available when you get to calling it... since not in same block).

So assuming we make the function a global, looks like this:

:global reverseNumber do={
    :local number [:tostr $1]
    :local len [:len $number]
    :local tmpNum [:toarray ""]
    :local realNum [:toarray ""]
    :local result

    :local counter 0
    while ( $counter<$len ) do={
        :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
        :set $counter ($counter + 1)
    };

    :local counter 0
    while ( $counter<$len ) do={
        :if ( ($counter % 2) = 0) do={
            :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
        } else={
            :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
        }
    :set $counter ($counter + 1)
    };

    :put $realNum
    :foreach num in=$realNum do={
            :set result ($result.$num)
        }

    :return $result
}

# test code for reverseNumber
{
:local numberarg "8350000048F0"
$reverseNumber $numberarg

:local result [$reverseNumber $numberarg]
:put $result
}
I left the ":put" inside the function, which may be for debugging. Also you might want to avoid using variable names that match commands, although that shouldn't break anything here but not a good idea...
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Wed May 31, 2023 8:40 pm

Main one is you need to use $1 to capture the 1st argument to the function and assign it to a "number" inside your function – no need for ":local number XXXX" if your using a function. Personally, I'd make the function itself global.
I think I'm beginning to understand. What if I want to use a named variable?

And another clarification, if I want to transfer the result of a function to an array, then I also have to use $result or can I write [$reverseNumber $numberarg] to the array right away?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function  [SOLVED]

Wed May 31, 2023 8:46 pm

Any named variable you provide, become a local to the function. No need to declare anything. So basically if you remove the first line of the function, you can just use "$reverseNumber number=ABCDEF".

For completeness, you can make the function local, but then all code using it need to be in same block like:
{
    :local reverseNumber do={
        :local len [:len $number]
        :local tmpNum [:toarray ""]
        :local realNum [:toarray ""]
        :local result

        :local counter 0
        while ( $counter<$len ) do={
            :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
            :set $counter ($counter + 1)
        };

        :local counter 0
        while ( $counter<$len ) do={
            :if ( ($counter % 2) = 0) do={
                :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
            } else={
                :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
            }
        :set $counter ($counter + 1)
        };

        :put $realNum
        :foreach num in=$realNum do={
                :set result ($result.$num)
            }

        :return $result
    }


    {
    :local numberarg "8350000048F0"
    $reverseNumber number=$numberarg

    :local result [$reverseNumber number=$numberarg]
    :put $result
    }
}
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Wed May 31, 2023 8:55 pm

And another clarification, if I want to transfer the result of a function to an array, then I also have to use $result or can I write [$reverseNumber $numberarg] to the array right away?
Well, just skip the last part of your function and return $realNum (which is an array type). Or you can add a 2nd parameter that does takes "as-array" like so:


    :global reverseNumber do={
        :local number $1
        :local len [:len $number]
        :local tmpNum [:toarray ""]
        :local realNum [:toarray ""]
        :local result

        :local counter 0
        while ( $counter<$len ) do={
            :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
            :set $counter ($counter + 1)
        };

        :local counter 0
        while ( $counter<$len ) do={
            :if ( ($counter % 2) = 0) do={
                :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
            } else={
                :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
            }
        :set $counter ($counter + 1)
        };

        :if ($2 = "as-array") do={
             :return $realNum
        } else={
            :foreach num in=$realNum do={
                :set result ($result.$num)
            }
            :return $result
        }
    }
For example,
{
:local rv [$reverseNumber ABCD as-array] 
:put $rv 
:put [:typeof $rv]
:set rv [$reverseNumber ABCD]
:put $rv 
:put [:typeof $rv]} 
}

# Output:
B;A;D;C
array
BADC
str

 
optio
Forum Veteran
Forum Veteran
Posts: 945
Joined: Mon Dec 26, 2022 2:57 pm

Re: Can't turn code into a function

Wed May 31, 2023 9:00 pm

@DyadyaGenya
From question on this thread and viewtopic.php?t=196458, are you aware of ROS script documentation existence? See: https://wiki.mikrotik.com/wiki/Manual:S ... #Functions and https://help.mikrotik.com/docs/display/ROS/Scripting maybe it helps.

P.S.
You can use only local functions in script instead global, this complicates a bit calling them from another local functions, but you don't need to unset them when your script finish if you don't want leave them to hang in Environment. To call local function from other local function simply pass as argument variable, ex: [$funct1 funct2=$funct2], then you can call $funct2 inside $funct1 and you can go nested like that, function context must have nested local function variable passed from argument.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Wed May 31, 2023 9:34 pm

are you aware of ROS script documentation existence? See: https://wiki.mikrotik.com/wiki/Manual:S ... #Functions and https://help.mikrotik.com/docs/display/ROS/Scripting maybe it helps.
I watched them. They are very short and do not give a complete picture. If I had not looked at these instructions, I would not have been able to write the version of the code shown in the header. Luckily, Amm0 some things were explained to me.
 
optio
Forum Veteran
Forum Veteran
Posts: 945
Joined: Mon Dec 26, 2022 2:57 pm

Re: Can't turn code into a function

Wed May 31, 2023 9:49 pm

I watched them. They are very short and do not give a complete picture. If I had not looked at these instructions, I would not have been able to write the version of the code shown in the header. Luckily, Amm0 some things were explained to me.
Documentation doesn't contain all possible examples of script features but you can get a clue what else can be possible to do depending on experience in development/scripting and some experimenting.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Thu Jun 01, 2023 12:49 am

Sorry for this self-quotation, but my page is full of examples of how to code...

(please DO NOT post directly on the list, but in the various linked topics)
viewtopic.php?t=177551
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Thu Jun 01, 2023 1:25 am

You have to divide the process into parts to do something useful, this also helps you to create functions....

Function to convert a PDU SMSCenter part to real number

Step 1) we have aldeady the length of the PDU, 48, and the PDU itself from this:
viewtopic.php?t=196458#p1005348
07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72
*** done ***

Step 2) check if the length and the PDU corresponding:

partial code

:local length ($item->"length")
:local pdu    ($item->"PDU")
:local skip   (2 + ([:tonum "0x$[:pick $pdu 0 2]"] * 2))
:if ($length = (([:len $pdu] - $skip) / 2)) do={:put "OK"} else={:put "KO"}
48 is the length of SMS part, that start just after the SMSCenter number, so must be skipped the first two and the length specified on first two...
07912180958739F1 040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72

Working function:
{
:local SMScheckPDU do={
    :local length $1
    :local pdu    $2
    :local skip   (2 + ([:tonum "0x$[:pick $pdu 0 2]"] * 2))
    :if ($length = (([:len $pdu] - $skip) / 2)) do={:return "OK"} else={:return "KO"}
}

:put [$SMScheckPDU 48 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72]
}


Step 3) pick only the smsc number part

example code

{
:local pdu     07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72
:local rawSMSC [:pick $pdu 2 (2 + ([:tonum "0x$[:pick $pdu 0 2]"] * 2))] 
:put $rawSMSC
}
912180958739F1

Working function
{
:local rawSMSC do={:return [:pick $1 2 (2 + ([:tonum "0x$[:pick $1 0 2]"] * 2))]}
:put [$rawSMSC 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72]
}

Step 4a) Identify the type of number represented, to be developed later,
actually "91" is the international numbering format, so if is "91", the number is on deci-decimal format to be reversed, and is starting with "+"
91 + and 2180958739F1

Step 4b) reverse the number
from + and 2180958739F1 to +12085978931
The F is just a pad character when the number of digits in the phone is odd.
Each pair of deci-decimal must be swapped for obtain the right number.

example code

{
:local rawSMSC "2180958739F1"
:local lenSMSC [:len $rawSMSC]
:local currPos 0
:local smsc    ""
:while (($lenSMSC + 1) > $currPos) do={
    :set smsc "$smsc$[:pick $rawSMSC ($currPos + 1) ($currPos + 2)]$[:pick $rawSMSC $currPos ($currPos + 1)]"
    :set currPos ($currPos + 2)
}
:put $smsc
}
now you have + and 12085978931F, what remains to be done is the next point (except the step 4a)


Step 5) Create a function that providing the raw SMSCenter value, provide correct number (except the step 4a, for now).
Working code:

extract SMSC number directly from the PDU code

{
:local SMSCfromPDU do={
    :local pdu    [:tostr $1]
    :local length [:tonum "0$2"]
    :local skip   (2 + ([:tonum "0x$[:pick $pdu 0 2]"] * 2))
    :if ($length > 0) do={
        :if ($length != (([:len $pdu] - $skip) / 2)) do={:return "ERROR: Provided Length does not match SMS PDU part"}
    }
    :local smsc ""
    :local type [:pick $pdu 2 4]
    :if ($type = "91") do={
        :set smsc "+"
        :local SMSCraw [:pick $pdu 4 $skip]
        :local lenSMSC [:len $SMSCraw]
        :local currPos 0
        :while (($lenSMSC + 1) > $currPos) do={
            :set smsc "$smsc$[:pick $SMSCraw ($currPos + 1) ($currPos + 2)]$[:pick $SMSCraw $currPos ($currPos + 1)]"
            :set currPos ($currPos + 2)
        }
        :if ($smsc~"F\$") do={:set smsc [:pick $smsc 0 ([:len $smsc] - 1)]}
        :return $smsc
    }
    :return "ERROR: Unexpected SMSC number type (0x$type)"
}

:put [$SMSCfromPDU 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72 48]
}
The length is optional, if specified the validity of the PDU is calculated.

+1912085978931
Last edited by rextended on Fri Jun 02, 2023 3:59 am, edited 2 times in total.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Thu Jun 01, 2023 10:27 pm

Step 1) we have aldeady the length of the PDU, 48, and the PDU itself from this:
To be honest, I did not think that this topic would turn into a topic for creating a number processing function in the SMS body. But good. you use the number 48. But I still do not understand why, if it is not used in all steps. Only at the very end, when you need to print the result.
And of course you have a simple and short function. But I deliberately did not post all the code in this thread, because I doubted some of the data, such as encrypting the length of the number. But in general, my function also easily turns an encrypted number from SMS into a regular one. We use different algorithms. I try to work more with arrays. I am learning to work with arrays. I don't know which way is better. Surely each method has its own merits.

And I'm wondering what is "KO" in your code?
 
optio
Forum Veteran
Forum Veteran
Posts: 945
Joined: Mon Dec 26, 2022 2:57 pm

Re: Can't turn code into a function

Fri Jun 02, 2023 12:26 am

easily turns an encrypted number from SMS into a regular one. We use different algorithms.
FYI https://www.geeksforgeeks.org/differenc ... -encoding/
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Fri Jun 02, 2023 2:48 am

Step 1) we have aldeady the length of the PDU, 48, and the PDU itself from this:
But good. you use the number 48. But I still do not understand why, if it is not used in all steps. Only at the very end, when you need to print the result.
For me you have serious problems of understanding...
Do one thing at a time, you're just messing around...
Where do you think 48 (decimal) comes from?
+CMGL: 0,1,,48\r\n07912180958739F1040B917120069876F0000091405[…]0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72
You still haven't figured out what the individual values are for and you keep talking about encrypted text messages...

And of course you have a simple and short function. But I deliberately did not post all the code in this thread, because I doubted some of the data, such as encrypting the length of the number. But in general, my function also easily turns an encrypted number from SMS into a regular one. We use different algorithms. I try to work more with arrays. I am learning to work with arrays. I don't know which way is better. Surely each method has its own merits.
Doing multiple loops, using arrays, and calculating odd/even again is just a waste of time.
Nothing is perfect, but for decrypting the SMSCenter mine is better,
instead of using a loop to convert single characters into an array of characters, then do another loop where you put two tests, if the number is even or the number is odd, etc...

And I'm wondering what is "KO" in your code?
Seriously? Where do you live? I understand the language issues, but maybe in your country "KO" is not the opposite of "OK"....



If all this is reduced to using loops and even and odd checks that make no sense, just to practice (unnecessarily and in the wrong way) with arrays I'm not going to help you anymore.
Here on the forum I write code for everyone, and having to cripple a procedure just to use the arrays unnecessarily, I don't teach the others anything, and you don't want to learn.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Fri Jun 02, 2023 3:06 pm

You still haven't figured out what the individual values are for and you keep talking about encrypted text messages...
I understand now. Thank you. Only now I don’t understand why, after I started working at the beginning of the garden, I need to run to the end of the garden, if in the end I need to plow the entire garden. Perhaps I did not understand your algorithm, but at the moment it looks like this. At the same time, we have almost all the data to do the work gradually step by step from the beginning of the garden.
Seriously? Where do you live? I understand the language issues, but maybe in your country "KO" is not the opposite of "OK"....
we almost never use this word. Only those who work with tourists and some programmers. The rest, if they are told "OK", can answer "Ob". This is the name of the manufacturer of feminine hygiene products. And since I'm not exactly a programmer, I'm not very familiar with the terms and accepted abbreviations. There were thoughts that "KO" is an abbreviation for "Company".
Doing multiple loops, using arrays, and calculating odd/even again is just a waste of time.
Nothing is perfect, but for decrypting the SMSCenter mine is better,
instead of using a loop to convert single characters into an array of characters, then do another loop where you put two tests, if the number is even or the number is odd, etc...
Again, in this situation, I just learned to write a function. An additional condition was the desire to do it using arrays. But this desire is not necessary.
In this case, your method only works with 12-digit numbers. My method is not so strictly limited. It can process both a number with more characters and a number with fewer characters. I mean, it's more versatile.
I feel embarrassed in this debate, because you have done a lot for this society, and I am only a beginner. But sometimes the older ones should help the younger ones not in everything, but only in what the younger ones ask, and not do all the work instead of them. Otherwise, neither these juniors, nor others who will follow them, will learn anything new, but will only know what you know.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Fri Jun 02, 2023 4:05 pm

In this case, your method only works with 12-digit numbers. My method is not so strictly limited. It can process both a number with more characters and a number with fewer characters. I mean, it's more versatile.
What would be the function limited to 12 characters only?
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Fri Jun 02, 2023 7:02 pm

What would be the function limited to 12 characters only?
Phone translation. We don't know what other numbers are. You voiced some yesterday in another topic, but I have not had time to deal with them yet.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Fri Jun 02, 2023 8:46 pm

What would be the function limited to 12 characters only?
Phone translation. We don't know what other numbers are. You voiced some yesterday in another topic, but I have not had time to deal with them yet.
But you didn't explain why the function should be work only with 12 telephone digits
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Sat Jun 03, 2023 7:08 pm

But you didn't explain why the function should be work only with 12 telephone digits
I apologize for the confusion. In your case, the length of the phone number can vary, and the current implementation of the function only works with 12-digit numbers. If you need to handle phone numbers of different lengths, you can modify the function to accommodate them. You may need to adjust the logic and consider the specific requirements for handling shorter or longer phone numbers.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Sat Jun 03, 2023 7:53 pm

But where is it written in the function that accepts only 12 numbers?
You keep insisting, but there is no logic in what you write...
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Sat Jun 03, 2023 11:39 pm

You keep insisting, but there is no logic in what you write...
I don't know who doesn't understand whom and why. Maybe even chatGPT can't handle the translation. Let's point by point. Short messages. I'm talking about your version of the function. It's clear?
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 5:38 pm

I again cannot translate the code into a function. Here's the code. It has several global functions. I don't think it's necessary to list them here.
:global hex2num
:global num2bin

:local pair "A8";
:local sign "";
:local tZone "";
:local UTC [ $num2bin [ $hex2num $pair] ]
:if (:len $UTC < 8) do={
    :set sign "+";
    :set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 )
    :put ($sign.$tZone);
} else={
    :set sign "-";
    :put $UTC; 
    :set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 )
    :put ($sign.$tZone);
}
And this is how I try to make a function out of it.
:local getUTC do={
:local pair $1;
:local sign "";
:local tZone "";
:put $pair;
:local UTC [ $num2bin [ $hex2num $pair] ]
    :if (:len $UTC < 8) do={
        :set sign "+";
        :put $pair;
        :set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 )
        :return ($sign.$tZone);
        :put ($sign.$tZone);
    } else={
        :set sign "-";
        :put $pair;
        :put $UTC; 
        :set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 )
        :return ($sign.$tZone);
    }
}

:local num "A8";
:put [ $getUTC $num ] ;
I use the put command in the function body for debugging. In this case, only the sign is returned in "return".
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 5:51 pm

You don't need to list the functions here, but you don't need to use them either....

viewtopic.php?t=196747#p1006044

excerpt from code

[…]
    # BEGIN TIMEZONE section
    :local tza [:tonum "0x$[:pick $pdu ($skip + 1) ($skip + 2)]"]
    :local tzb [:tonum "0x$[:pick $pdu $skip       ($skip + 1)]"]
    :local tzs "+" ; :if (($tza & 0x8) = 0x8) do={:set tzs "-"}
    :set tza ($tza & 0x7)
    :local tzmin ((($tza * 10) + $tzb) * 15)
    :set ($return->"tzminutes") [:tonum "$tzs$tzmin"]
    :local tzhou ($tzmin / 60) ; :if ($tzhou < 10) do={:set tzhou "0$tzhou"}
    :set   tzmin ($tzmin % 60) ; :if ($tzmin < 10) do={:set tzmin "0$tzmin"}
    :set ($return->"timezone") "GMT$tzs$tzhou:$tzmin"
    :set skip ($skip + 2)
    # END TIMEZONE section
[…]

Just create a function...

TimeZone PDU to GMT code

{
:local tzpdutogmt do={
    :local input $1
    :local tza [:tonum "0x$[:pick $input 1 2]"]
    :local tzb [:tonum   "$[:pick $input 0 1]"]
    :local tzs "+" ; :if (($tza & 8) = 8) do={:set tzs "-"}
    :set tza ($tza & 7)
    :local tzmin ((($tza * 10) + $tzb) * 15)
    :local tzhou ($tzmin / 60) ; :if ($tzhou < 10) do={:set tzhou "0$tzhou"}
    :set   tzmin ($tzmin % 60) ; :if ($tzmin < 10) do={:set tzmin "0$tzmin"}
    :return "GMT$tzs$tzhou:$tzmin"
}

:put [$tzpdutogmt "8A"]
}

Result:
GMT-07:00
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 6:26 pm

You don't need to list the functions here, but you don't need to use them either....
You have a good function, but I want mine.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 6:37 pm

I understand you want yours, but they've already figured out that (2 + 2) is 4,
and you don't need to do (((2 / 2) * 2) + (16 / 8)) to get the same result...

explained function code

{
:local tzpdutogmt do={
    :local input $1 ; # read passed parameter, on example "8A"
    :local tza [:tonum "0x$[:pick $input 1 2]"] ; # put A on tza (and converted from hex because the value can be from 0 to F)
    :local tzb [:tonum   "$[:pick $input 0 1]"] ; # and 8 on tzb (not converted because is a decimal number from 0 to 9)
                                                  # because on PDU the values are inverted
    # tza = 10, tzb = 8

    :local tzs "+" ; # default is positive TimeZone

    :if (($tza & 8) = 8) do={:set tzs "-"}
    # if tza has the "8" bit set (1xxx) is a negative timezone

    :set tza ($tza & 7)
    # remove the 8th bit for obtain only the TimeZone data

    # tza = 2, tzb = 8

    :local tzmin ((($tza * 10) + $tzb) * 15)
    # since the values of tza is 10 time the value of tzb, is multiplied ( 2 * 10 = 20)
    # and is added to tzb (20 + 8 = 28). At this point we have the GMT difference: 28 times 15 minutes (each 1 on PDU are 15 minutes)
    # 28 * 15 = 420

    # can be simply returned also the +/- minutes, with :return [:tonum "$tzs$tzmin"]


    :local tzhou ($tzmin / 60) ; :if ($tzhou < 10) do={:set tzhou "0$tzhou"}
    # 420 minutes are (420 / 60) 7 hours, added a 0 on front for formatting if the number is less than 9

    :set   tzmin ($tzmin % 60) ; :if ($tzmin < 10) do={:set tzmin "0$tzmin"}
    # 420 minutes are perfectly divisible for 60, so no rest, added a 0 on front for formatting if the number is less than 9

    :return "GMT$tzs$tzhou:$tzmin"
    # at this point is returned the string GMT-07:00.
}

:put [$tzpdutogmt "8A"]
}
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 6:55 pm

You don't need to list the functions here, but you don't need to use them either....
You have a good function, but I want mine.



:local getUTC do={
:local pair $1; <<= useless ; everywhere
:local sign "";
:local tZone "";
:put $pair;# ignored, debug
# critical error: num2bin is undefined the wanted use of num2bin (must already exist) is undeclared
# critical error: hex2num is undefined the wanted use of hex2num (must already exist) is undeclared
:local UTC [ $num2bin [ $hex2num $pair] ] <<== useless conversion to binary, useless external function to convert one hex to one decimal
:if (:len $UTC < 8) do={ <<== why do not check simply if [:tonum "0x$pair"] is > of 127?
:set sign "+"; <<== error, define sign when is declared for skip this useless passage
:put $pair; # ignored, debug
:set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 ) <<== error, useless repeated, move outside if/else
# formula is wrong: if the timezone, for example, is 4h and 30m = 18 times 15 minutes,
# 18 / 4 = 4,5 and RouterOS do not suport decimal division.

:return ($sign.$tZone); <<== error, useless repeated, move outside if/else
:put ($sign.$tZone); # ignored, debug
} else={
:set sign "-";
:put $pair; # ignored, debug
:put $UTC;# ignored, debug
:set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 ) <<== error, useless repeated, move outside if/else
:return ($sign.$tZone); <<== error, useless repeated, move outside if/else
}
}
Last edited by rextended on Mon Jun 05, 2023 7:56 pm, edited 2 times in total.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 7:10 pm

It has several global functions. I don't think it's necessary to list them here.
Not need to list here the code here... but the globals must be declared in your new function with ":global hex2num" etc. That's at least one issue with your code.

Also, I get your idea to modularize the code...but just beware if you go down this way that :local functions can only call globals or locals defined with a local function – you cannot call a local function in higher scope. This puts a damper on the ability to modularize using :local functions. Currently, seems you're using :globals for your helper functions, which is fine. But all these oddities is why you see @rextended use slightly more monolithic functions...
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 7:32 pm

Yes, because I don't think you often find the TZ encoding scheme like the PDU in SMS...
So, creating a standalone function is useless.
Instead a function like "invertnibble" can come in handy in multiple cases, for multiple parts, not only for PDU.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 7:37 pm

Not need to list here the code here... but the globals must be declared in your new function with ":global hex2num" etc. That's at least one issue with your code.
This goes without saying. I thought that it would be superfluous to indicate here, because I showed that in the code from which I make the function, these global functions are declared.
Also, I get your idea to modularize the code...but just beware if you go down this way that :local functions can only call globals or locals defined with a local function – you cannot call a local function in higher scope. This puts a damper on the ability to modularize using :local functions. Currently, seems you're using :globals for your helper functions, which is fine. But all these oddities is why you see @rextended use slightly more monolithic functions...
I only use local functions when I'm trying to write a function. When I see that it works, I make it global. Otherwise, I would have to restart the script with the global function every time.
If you need for debugging, I can give here the code of the two global functions mentioned above.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 7:45 pm

Not need to list here the code here... but the globals must be declared in your new function with ":global hex2num" etc. That's at least one issue with your code.
This goes without saying. I thought that it would be superfluous to indicate here, because I showed that in the code from which I make the function, these global functions are declared.
Perhaps bad word choice – "defined" meaning it has code vs "declared" mean code is somewhere else... Regardless, in your $getUTC function, you need

:local getUTC do={
:local pair $1;
:local sign "";
:local tZone "";
:global num2bin
:global hex2num

:put $pair;
:local UTC [ $num2bin [ $hex2num $pair] ]
# ...
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 7:52 pm

@ammo, fixed the comments



or simply instead of converting uselessly the number on bit (just for count the number of bit), and the need to call uselessly other 2 function,
simply check if the number is > of 127 (on binary 1111111)
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 8:03 pm

:local pair $1; <<= useless ; everywhere
You mean useless? Wasn't it necessary to declare this variable? Or do you mean that I needed to use $1 everywhere? If so, then I just left the variable as it is in the source code. Later I planned to shorten the code.
:put $pair;# ignored, debug
Is debugging ignored in this place or do you think that nothing will be displayed here?
:if (:len $UTC < 8) do={ <<== why do not check simply if [:tonum "0x$pair"] is > of 127?
You forget, I just started to get acquainted with beats. What is 127? And what is the worse option if I check the length of the segment, and do not compare it with some number 127?
[/color]:local UTC [ $num2bin [ $hex2num $pair] ] <<== useless conversion to binary, useless external function to convert one hex to one decimal
Why useless? You offered me to make some kind of array so that I could learn to work with bits. But I found several functions from third-party authors and several functions built into Mikrotik for working with beats. Based on this knowledge, I work. I have already asked you about functions that transform the display of numbers. I found your advice to create an array too expensive. If you know of other built-in functions, please tell me. I already saw one of those that I found myself. This is the zeroing of the first bit. Perhaps there are others. But in your code, I don't understand it.
:set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 ) <<== error, useless repeated, move outside if/else
# formula is wrong: if the timezone, for example, is 4h and 30m = 18 times 15 minutes,

Maybe the formula is wrong. In another topic, I was interested in the formula for calculating the time zone. This is the only formula I can understand that I have found. The PDU instructions are written for very educated and highly specialized specialists. But in that comment, you pointed out that there are other time zones, with the addition of 30 minutes, that I didn't know about. And they just hinted at the formula for how such time zones are calculated. The formula I use is transparent. I assume that you understand its operation. And I think you can similarly formulate the correct formula.

:set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 ) <<== error, useless repeated, move outside if/else

Why move out? After all, it uses a global function that is available at all levels.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 8:08 pm

useless ; everywhere
Did you notice the ; between "useless" and "everywhere"?
Last edited by rextended on Mon Jun 05, 2023 8:14 pm, edited 2 times in total.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 8:10 pm


Perhaps bad word choice – "defined" meaning it has code vs "declared" mean code is somewhere else... Regardless, in your $getUTC function, you need

:local getUTC do={
:local pair $1;
:local sign "";
:local tZone "";
:global num2bin
:global hex2num

:put $pair;
:local UTC [ $num2bin [ $hex2num $pair] ]
# ...
Is it necessary to declare global functions inside a local one?

And about the use of terms... Sometimes a translator translates the same word in different ways, but I don't know how to translate it more correctly in English.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 8:11 pm

Did you notice the ; between "useless" and "everywhere"?
I noticed, but I don't understand. That's why I'm asking you what it means.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 8:14 pm

I recommend you write some unit test function to call your function with the some of various PDU formats & see what breaks. Post the test function and results. ;)
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 8:15 pm

Did you notice the ; between "useless" and "everywhere"?
I noticed, but I don't understand. That's why I'm asking you what it means.
Do not put ; at the end of each line, is useless.

Is debugging ignored in this place or do you think that nothing will be displayed here?
I simply ignore that line, is for debug

Is debugging ignored in this place or do you think that nothing will be displayed here?
beats -> bit on your translator, no problem, I understand.
127 is 7 times "1" on binary, so 128 is the first number with the 8th "1" on "10000000", so instead to calc the length, calc if the value is > or <= of 127....
If is <= 127 the timezone is positive, if is > 127 is negative.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 8:16 pm

Is it necessary to declare global functions inside a local one?
Yes. That why it gets kinda annoying to have a lot of little functions. ;)
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 8:23 pm

:set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 ) <<== error, useless repeated, move outside if/else
Why move out? After all, it uses a global function that is available at all levels.
I already wrote it to you in another case, don't repeat the same instructions unnecessarily inside the cycles

wrong code

    :if (:len $UTC < 8) do={
        :set sign "+";
        :set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 )
        :return ($sign.$tZone);
    } else={
        :set sign "-";
        :set tZone ( [ $num2hex ( [:tonum ("0x".$pair ) ] & 0x7F) ]/4 )
        :return ($sign.$tZone);
    }

correct code

    :if ([:tonum "0x$pair"] > 127) do={:set sign "-"} else={:set sign "+"}
    :set tZone ([$num2hex ([:tonum "0x$pair"] & 0x7F)] / 4)
    :return "$sign$tZone"
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 9:20 pm

I recommend you write some unit test function to call your function with the some of various PDU formats & see what breaks. Post the test function and results. ;)
I don't quite understand what you are suggesting. I understand that you are proposing to do some tests, but I did not understand which ones.
Yes. That why it gets kinda annoying to have a lot of little functions. ;)
It's uncommon and sad.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 9:23 pm

I already wrote it to you in another case, don't repeat the same instructions unnecessarily inside the cycles
Now it's clear))) But this is only a starting option, I usually shorten it when I see that everything is working. I also use this starting option because I do a lot of debug printouts on the screen to be sure that everything is transferred and all conditions are taken into account.
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Mon Jun 05, 2023 9:27 pm

# formula is wrong: if the timezone, for example, is 4h and 30m = 18 times 15 minutes,
# 18 / 4 = 4,5 and RouterOS do not suport decimal division.
Can you explain the correct algorithm in simple words? And preferably in another topic, so that it is in the right place.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4325
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 9:39 pm

# formula is wrong: if the timezone, for example, is 4h and 30m = 18 times 15 minutes,
# 18 / 4 = 4,5 and RouterOS do not suport decimal division.
Can you explain the correct algorithm in simple words? And preferably in another topic, so that it is in the right place.
Well, what he means is there no fractions returned, only integers, when dividing in RouterOS so 18/4=4...
:put (18 / 4)
4

And since the PDU use a unit of time in 15 minutes (e.g. quarter of an hour), you kinda need to / 4.

The lack of floats follows that the RouterOS variables act like most Bourne/bash/etc variables & function. e.g. In linux /bin/sh, "echo $((18/4))" will also output 4 although the value is really 4,5 (or 4 1/2 or 4.5 depending on locale)
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Mon Jun 05, 2023 10:31 pm

# formula is wrong: if the timezone, for example, is 4h and 30m = 18 times 15 minutes,
# 18 / 4 = 4,5 and RouterOS do not suport decimal division.
Can you explain the correct algorithm in simple words? And preferably in another topic, so that it is in the right place.
On the follow example, is supposed GMT-07:00
1) Read from PDU "8A"
2) Split the string, but read first the last, because on PDU the characters are inverted.
I call the variables x and y for not confuse "A" with a.
x = A, y = 8
A on bit are 1010, and the GSM rule say "if the first bit is 1, the timezone is negative", so, is negative.
now for obtain the second number, the 1st bit must be subtracted for have the right number
A (1010 binary) - 1st bit (1000 binary) = 0010
0010 binary is = 2, so we put 2 on x
since "2" and "8" must be considered literally decimal (like the phone number) and not 0x28,
2 is on decimal position, and 8 are the units, so the string x + y give the correct number for calculate how many 15 minutes are involved.
"negative sign" + "2" + "8" = "-28" and converted to number.... is -28...
At this point you have the correct timezone -28 times 15 minutes = -420 minutes.
and for convert minuntes on hours:minutes
-420 / 60 = -7
and do not remain any minutes, because 60 * -7 is exactly -420.

If, for example, we have on PDU 22 (India +05:30), is the same:
x = 2, y = 2, timezone is positive, because x (0010) <= 7 (0111)
so, "positive" + "2" + "2" = +22 = 22 times 15 = 330 minutes = 5 hours and ½ hour = 5 hours and 30 minutes

If, for example, we have on PDU 83 (Central Australia +09:30), is the same:
x = 3, y = 8, timezone is positive, because x (0011) <= 7 (0111)
so, "positive" + "3" + "8" = +38 = 38 times 15 = 570 minutes = 9 hours and ½ hour = 9 hours and 30 minutes

If, for example, we have on PDU 49 (America/St Johns -03:30), is the same:
x = 9, y = 4, timezone is NEGATIVE, because x (1001) > 7 (0111)
x = x - (1000) = 1
so, "negative" + "1" + "4" = -14 = -14 times 15 = -210 minutes = -3 hours and ½ hour = -3 hours and 30 minutes


Actuallu the timezones go from -11 (Pacific/Niue and Pacific/Pago_Pago) to +14 (Pacific/Kiritimati) and can end only with :00 or :30 or :45, but actually... every year something change....
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Tue Jun 06, 2023 6:19 pm

If, for example, we have on PDU 22 (India +05:30), is the same:
x = 2, y = 2, timezone is positive, because x (0010) <= 7 (0111)
so, "positive" + "2" + "2" = +22 = 22 times 15 = 330 minutes = 5 hours and ½ hour = 5 hours and 30 minutes

If, for example, we have on PDU 83 (Central Australia +09:30), is the same:
x = 3, y = 8, timezone is positive, because x (0011) <= 7 (0111)
so, "positive" + "3" + "8" = +38 = 38 times 15 = 570 minutes = 9 hours and ½ hour = 9 hours and 30 minutes

If, for example, we have on PDU 49 (America/St Johns -03:30), is the same:
x = 9, y = 4, timezone is NEGATIVE, because x (1001) > 7 (0111)
x = x - (1000) = 1
so, "negative" + "1" + "4" = -14 = -14 times 15 = -210 minutes = -3 hours and ½ hour = -3 hours and 30 minutes
Honestly, I don’t understand how it was calculated if Mikrotik doesn’t understand fractions
That is, 330 min/60=5.5, or 570 min/60=9.5, or 210/60=3.5.

Although the formula itself and the algorithm are clear. I will read how you can divide and get fractions in Mikrotik.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12558
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Can't turn code into a function

Tue Jun 06, 2023 6:39 pm

Honestly, I don’t understand how it was calculated if Mikrotik doesn’t understand fractions
That is, 330 min/60=5.5, or 570 min/60=9.5, or 210/60=3.5.

Although the formula itself and the algorithm are clear. I will read how you can divide and get fractions in Mikrotik.
simple, just read at least once the formula that I have put under your nose dozens of times....
viewtopic.php?t=196637#p1006390

and also with explanations...
viewtopic.php?t=196637#p1006397


570 minutes = 570 / 60 = 9 hours ( because 570 / 60 is 9,5, but MikroTik do not calc the decimal part)
570 minutes = 570 % 60 = 30 minutes (because subtracting 60 from 570 until the rest is less than 60, produce 30 minutes)

-210 / 60 = -3 (hours)
-210 % 60 = -30 (minutes)
 
DyadyaGenya
Member Candidate
Member Candidate
Topic Author
Posts: 222
Joined: Mon May 08, 2023 10:34 pm

Re: Can't turn code into a function

Wed Jun 07, 2023 12:52 am

simple, just read at least once the formula that I have put under your nose dozens of times....
viewtopic.php?t=196637#p1006390

and also with explanations...
viewtopic.php?t=196637#p1006397


570 minutes = 570 / 60 = 9 hours ( because 570 / 60 is 9,5, but MikroTik do not calc the decimal part)
570 minutes = 570 % 60 = 30 minutes (because subtracting 60 from 570 until the rest is less than 60, produce 30 minutes)

-210 / 60 = -3 (hours)
-210 % 60 = -30 (minutes)
Only after these explanations did I understand your formula. Everything is really easy and simple.

Who is online

Users browsing this forum: No registered users and 7 guests