Sporadic Task will be run at a specific time - real-time

I have a sporadic task that print something. I want to run this task at specified time i.e. 4:40PM.
I have an idea to create cyclic task, that checks time and when the time is equal to my specified time, this cyclic task realeases the barrier of sporadic task. But how to check if my specified time (represented as Unix timestamp or String) is equal to time at now? How to convert my specified time to Ada.Real_Time.Time according to Ravenscar Profile?
How can I achieve that in Ada?
Here is my code:
sprinkler.ads
pragma Profile(Ravenscar);
with GNATCOLL.Ravenscar.Simple_Cyclic_Task;
with GNATCOLL.Ravenscar.Simple_Sporadic_Task;
package Sprinkler is
Counter : Integer := 0;
MyTime : String := "4:45";
procedure My_Cyclic_Operation;
package My_Cyclic_Task is new GNATCOLL.Ravenscar.Simple_Cyclic_Task
(Task_Priority => 10,
Phase => 0,
Period => 1000,
Cyclic_Operation => My_Cyclic_Operation);
procedure My_Sporadic_Operation;
package My_Sporadic_Task is new GNATCOLL.Ravenscar.Simple_Sporadic_Task
(Task_Priority => 10,
Minimum_Interelease_Time => 1_000,
Protocol_Ceiling => 15,
Sporadic_Operation => My_Sporadic_Operation);
end Sprinkler;
sprinkler.adb
pragma Profile(Ravenscar);
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
package body Sprinkler is
procedure My_Cyclic_Operation is
begin
-- Here I want to run My_Sporadic_Operation when time at now is equal to my specified time
null;
end My_Cyclic_Operation;
procedure My_Sporadic_Operation is
begin
Put_Line("Sporadic at specified time!");
end;
end Sprinkler;

The GNATCOLL.Ravenscar packages obey the restrictions of the Ravenscar profile, but they can be compiled into a partition that has an unrestricted profile. So, unless you’re compiling for a system that only supports Ravenscar, you can (with a small error because the calls take finite time)
convert your 4:40 pm to Ada.Calendar.Time
subtract Ada.Calendar.Clock to obtain a Duration
use Ada.Real_Time.To_Time_Span to convert to Time_Span

Related

How to get a date in yyyy-MM-dd'T'HH: mm: ss.SSSZ format

I want to get the current time, and format it in the following way:
yyyy-MM-dd'T'HH:mm:ss.SSSZ
(where SSS is the milliseconds and Z the time zone)
the code so far I have it as follows:
formatted_date() ->
{{Y,M,D},{H,Min,S}} = erlang:localtime(),
{Ms, _, _} = os:timestamp(),
{Days, {Hours, _,_}} = calendar:time_difference(erlang:universaltime(), erlang:localtime()),
Difference = 24*Days + Hours,
Tz = [case Difference < 0 of
true ->
$-;
false ->
$+
end | io_lib:format("~2..0B00",[Difference])],
io_lib:format("[~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B.~3..0B ~5.s]",
[Y, M, D, H, Min, S, Ms, Tz]).
The fact is that it always returns the same Ms, therefore, I think that I am not doing it well, and in other questions I only see how to obtain the total time in milliseconds, but not how to format it in this way.
Thank you.
The easiest way is to use the library function calendar:system_time_to_rfc3339/2 - it seems to fulfil all your requirements.
> calendar:system_time_to_rfc3339(os:system_time(millisecond), [{unit, millisecond}]).
"2021-03-03T18:42:08.497+05:30"
This function was added in Erlang/OTP 21.0, which was released in June 2018.
The reason your code always gets the same value for Ms is that the first value in the tuple returned by os:timestamp/0 is megaseconds, not milliseconds; the three values are megaseconds, seconds and microseconds. This comes from a time when Erlang did not support large integers, so splitting up the timestamp was necessary. These days you can just call os:system_time/1 or a number of other functions, depending on what kind of time you need, and get the result in a single integer.

Dynamic Event to release pallet types with specified ID to the time of a dbase

I would like to use the loop trough my dbase and create_mydynamicevent in MAIN for different process flows. So by means of my dynamic event I will release the type of pallets (id) to specified times which I insert into my source block. Because of that I can use my create_mydynamicevent function for different processes. My question is either what is wrong at the myDE and should I also adapt the create_dynamicevent function in Main?
Agent Type: Pallet: agent.typeID = pallet types
n = number of pallets I would like to release to the specified time of the dbase
flowchart Agent Type = Pallet
My Dynamic event and wait block are in my custom flowchart Agent Type "Store_and_Pick"
Main to create the dynamic event:
List< Tuple > amounts =selectFrom( tor77_kunde1 ).list();
for( Tuple tup : amounts ) {
Date today=date();
Date future=tup.get(tor77_kunde1.picktime);
long diff = future.getTime() - today.getTime();
int n =tup.get(tor77_kunde1.n);
process.create_MyDynamicEvent(diff, MILLISECOND, n);
process1.create_MyDynamicEvent(diff, MILLISECOND, n);
}

Ruby: dealing with booleans: How to address not using military time for a clock Class

TDD
gem 'minitest', '~> 5.2'
require 'minitest/autorun'
require 'minitest/pride'
require_relative 'clock'
class ClockTest < Minitest::Test
def test_start_at_6
clock = Clock.new
assert_equal 6, clock.time
end
def test_passage_of_time
clock = Clock.new
clock.wait
assert_equal 7, clock.time
3.times { clock.wait }
assert_equal 10, clock.time
end
def test_clocks_are_not_military_time
clock = Clock.new
8.times { clock.wait }
assert_equal 2, clock.time
end
end
CODE
class Clock
attr_reader :time
def initialize
#time = 6
end
def wait(time = 1)
#time += time
end
def not_military_time
#time += (time - 10)
end
end
Can anyone guide me into figuring out how to address that the clocks are not in military time? It's coming as Expected : 2 , Actual : 14. I feel like there needs to be some of subtraction going in order to address the clock saying 2 instead of 14.
I know what I have in the code does not work, but am I on the right track?
If you look through all of the tests you'll see that apart from test_start_at_6 each test essentially calls wait some number of times and then checks for the right time in clock.time.
If you look at your code, clock.time is generated by attr_reader and so all it will ever do is return the current value of #time. So this leaves you with wait as a place to implement the behaviour needed to make the tests pass.
One other thing to notice is that you're currently overcomplicating the wait method. It's never called with any parameters and so the time parameter isn't needed. So to start simplify that to just:
def wait
#time += 1
end
Next, step away from the code and make a little list showing for each current time what the next time needs to be after wait is called. You can then think about how to change wait so that it matches that required behaviour.
In terms of whether to use an if or a case statement, everything that you could achieve using a case statement can also be done with an if as an alternative. It's best to think about the most common use of a case statement which is for checking the same variable for various possible values. i.e. the case statement
case #time
when 1
puts "One o'clock"
when 2
puts "Two o'clock"
else
puts "Later!"
end
is the same as:
if #time == 1
puts "One o'clock"
elsif #time == 2
puts "Two o'clock"
else
puts "Later!"
end
Often when you're just working out what some logic needs to be you'll write it as an if statement and then once it's working realise that it can more elegantly be expressed as a case statement. In this exercise an if should be fine.

Change system time of Beckhoff controller by programming

For the last couple of hours, I am facing problems with changing system date and time by structured-text programming. I have used function block FB_LocalSystemTime where I can read the system time. But I could not find any function or function block to write new system time. I have checked NT_SetLocalTime, that also did not work. Do you have any idea how can I do that?
For further information: I have included the sample code like:
/**
Declaration Part
**/
fbLocalSystemTime:FB_localSystemTime;
fbSetLocalTime:NT_SetLocalTime;
newTime:TIMESTRUCT:=(wHour:=5);
/**
DEFINITION PART
**/
fbLocalSystemTime(); /*This gives system time */
fbSetLocalTime.TIMESTR:=newTimne; /* New time to set */
fbSetLocalTime.START:=TRUE;
fbSetLocalTime(); /** This does NOT set the system time which I guess should set **/
I understand the question, but unfortunately I don't have much experience with beckhoff plcs. Have you tried calling their support line? This should be a non application specific question that should be easy for them to help you with.
You may consider using FB_LocalSystemTime in the way indicated below. This will synchronize the local PLC time with the system with the given AMS ID passed to the parameter sNetID. If you do not pass sNetID parameter local OS system will be used as reference for setting the local PLC time. The time will be synchronized on rising edge of the signal bEnable and then in the interval given by the parameter dwCycle
VAR
{attribute 'hide'}
LocalSysTime : FB_LocalSystemTime;
SynchNodeAmsId : STRING := '10.10.10.1.1.1';
END_VAR
LocalSysTime(
sNetID:= SynchNodeAmsId,
bEnable:= TRUE,
dwCycle:= 60,
dwOpt:= ,
tTimeout:= ,
bValid=> ,
systemTime=> ,
tzID=> );
You are correct. You should be using NT_SetLocalTime.
If you open the function block fbSetLocalTime(), you will realize your function block returns an error with error ID 1862.
The definition of the errors can be found here: https://infosys.beckhoff.com/english.php?content=../content/1033/tcplclib_tc2_utilities/18014398544490635.html&id=
1862 means error in win32 system.
This is because TIMESTRUCT consists of Year, Month, Week, etc, but you only initialize the Hour as 5. This means that other things will become 0. The Year needs to be between 1970 and 2106, and there are many things to follow, shown below:
After you use a valid TIMESTRUCT variable, your code should be able to execute without problem and your computer system will be changed.
Had a similiar problem, using TwinCat3. Sometimes it works to change local system time, sometimes not.
I use a small state machine to solve that (also there could be a more advanced solution) - just write 3 times the new time....
Here is an code example:
VAR
nState : BYTE := 0; //local state machine
ntSetLocalTime : Tc2_Utilities.NT_SetLocalTime;
tTimestructSet : Tc2_Utilities.TIMESTRUCT; // time to set
nErrId : UDINT;
nRetryCnt : BYTE := 0;
and the state machine:
CASE nState OF
0: //wait for change
bBusy := FALSE;
nRetryCnt := 0;
1: //trigger change
bBusy := TRUE;
ntSetLocalTime(
NETID:= '',
TIMESTR:= tTimestructSet,
START:= TRUE,
TMOUT:= ,
BUSY=> ,
ERR=> ,
ERRID=> );
nState := 2; //wait for writing
2: //wait till written
ntSetLocalTime(
START:= FALSE,
ERRID => nErrId);
IF NOT ntSetLocalTime.BUSY THEN
nState := 3;
END_IF
3: //retry and after some retries go back to init
nRetryCnt := nRetryCnt + 1;
IF nRetryCnt >=3 THEN
nState := 0;
ELSE
nState := 1;
END_IF
END_CASE
Otherwise you could call Beckhoff hotline, in most cases they have a really good support.

in UVM RAL, a reg defined as no reset value, but set/update a '0' data on it won't trigger bus transaction

In ral file, I have something like:
class ral_reg_AAA_0 extends uvm_reg;
rand uvm_reg_field R2Y;
constraint R2Y_default {
}
function new(string name = "AAA_0");
super.new(name, 32,build_coverage(UVM_NO_COVERAGE));
endfunction: new
virtual function void build();
this.R2Y = uvm_reg_field::type_id::create("R2Y",,get_full_name());
this.R2Y.configure(this, 12, 4, "RW", 0, 12'h0, 0, 1, 1);
endfunction: build
`uvm_object_utils(ral_reg_AAA_0)
endclass : ral_reg_AAA_0
You can find R2Y is set to has_reset = 0, in real RTL, it's 'X' value by default
but if I use set/update mechanism to write this reg, if write data is 0, which is equal to reset value in R2Y (even has_reset = 0), seems like RAL will treat m_mirror == m_desired so there won't be a bus transaction for this reg access.
like
env.regmodel.AAA_0.R2Y.set(0);
env.regmodel.AAA_0.update(status,UVM_FRONTDOOR);
Does that make sense? I thought no matter which value I set to these kind of regs, there should be always bus transaction happening.
PS: mirrored and desired values are 2-state vectors, and even reg fields are set as 'no reset' value, m_mirrored initial value for a reg field is still 0. if RTL reset value is "x", for instance, there are 10 regs in design, I want to randomly pick up any number of them to write them with random value (of course, 0 is also a legal value), seems I will miss those '0' value register setting in this case.
I am using a workaround for now, flush all regs to be 0 value with a 'write' ral method, it can meet my expectation with some extra overhead on bus
The internal representations of the mirrored and desired values are 2-state vectors and are stored on a per field basis. This means that when created, your R2Y field's mirrored value is 0. By setting the desired value to 0, the values are still the same, which is why no bus transaction is started. If you want to force a bus transaction, just use the write(...) method:
env.regmodel.AAA_0.write(status, 0); // this will write the value '0' to the register
If you still want to use set(...) to play with the register fields, then you could try something like:
env.regmodel.AAA_0.R2Y.set(0);
env.regmodel.AAA_0.write(status, env.regmodel.AAA_0.get());