AERA
test_mem.cpp
1 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
2 //_/_/
3 //_/_/ AERA
4 //_/_/ Autocatalytic Endogenous Reflective Architecture
5 //_/_/
6 //_/_/ Copyright (c) 2018-2025 Jeff Thompson
7 //_/_/ Copyright (c) 2018-2025 Kristinn R. Thorisson
8 //_/_/ Copyright (c) 2018-2025 Icelandic Institute for Intelligent Machines
9 //_/_/ Copyright (c) 2021 Arash Sheikhlar
10 //_/_/ http://www.iiim.is
11 //_/_/
12 //_/_/ Copyright (c) 2010-2012 Eric Nivel
13 //_/_/ Copyright (c) 2010 Thor List
14 //_/_/ Center for Analysis and Design of Intelligent Agents
15 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
16 //_/_/ http://cadia.ru.is
17 //_/_/
18 //_/_/ Part of this software was developed by Eric Nivel
19 //_/_/ in the HUMANOBS EU research project, which included
20 //_/_/ the following parties:
21 //_/_/
22 //_/_/ Autonomous Systems Laboratory
23 //_/_/ Technical University of Madrid, Spain
24 //_/_/ http://www.aslab.org/
25 //_/_/
26 //_/_/ Communicative Machines
27 //_/_/ Edinburgh, United Kingdom
28 //_/_/ http://www.cmlabs.com/
29 //_/_/
30 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
31 //_/_/ University of Lugano and SUPSI, Switzerland
32 //_/_/ http://www.idsia.ch/
33 //_/_/
34 //_/_/ Institute of Cognitive Sciences and Technologies
35 //_/_/ Consiglio Nazionale delle Ricerche, Italy
36 //_/_/ http://www.istc.cnr.it/
37 //_/_/
38 //_/_/ Dipartimento di Ingegneria Informatica
39 //_/_/ University of Palermo, Italy
40 //_/_/ http://diid.unipa.it/roboticslab/
41 //_/_/
42 //_/_/
43 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
44 //_/_/
45 //_/_/ Redistribution and use in source and binary forms, with or without
46 //_/_/ modification, is permitted provided that the following conditions
47 //_/_/ are met:
48 //_/_/ - Redistributions of source code must retain the above copyright
49 //_/_/ and collaboration notice, this list of conditions and the
50 //_/_/ following disclaimer.
51 //_/_/ - Redistributions in binary form must reproduce the above copyright
52 //_/_/ notice, this list of conditions and the following disclaimer
53 //_/_/ in the documentation and/or other materials provided with
54 //_/_/ the distribution.
55 //_/_/
56 //_/_/ - Neither the name of its copyright holders nor the names of its
57 //_/_/ contributors may be used to endorse or promote products
58 //_/_/ derived from this software without specific prior
59 //_/_/ written permission.
60 //_/_/
61 //_/_/ - CADIA Clause: The license granted in and to the software
62 //_/_/ under this agreement is a limited-use license.
63 //_/_/ The software may not be used in furtherance of:
64 //_/_/ (i) intentionally causing bodily injury or severe emotional
65 //_/_/ distress to any person;
66 //_/_/ (ii) invading the personal privacy or violating the human
67 //_/_/ rights of any person; or
68 //_/_/ (iii) committing or preparing for any act of war.
69 //_/_/
70 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
71 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
72 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
73 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
74 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
75 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
76 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
77 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
78 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
79 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
80 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
81 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
82 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
83 //_/_/ OF SUCH DAMAGE.
84 //_/_/
85 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
86 
87 #include "test_mem.h"
88 
89 using namespace std;
90 using namespace std::chrono;
91 using namespace r_code;
92 using namespace r_exec;
93 
94 template<class O, class S> TestMem<O, S>::TestMem()
95  : MemExec<O, S>() {
96  timeTickThread_ = 0;
97  lastInjectTime_ = Timestamp(seconds(0));
98  velocity_y_ = 0.0001;
99  force_y_ = 0.1;
100  next_velocity_y_ = .1;
101  next_position_y_ = 1;
102  next_theta_y_ = 1;
103  next_omega_y_ = .1;
104  position_y_ = NULL;
105  position_y_obj_ = NULL;
106  cart_position_y_obj_ = NULL;
107  position_property_ = NULL;
108  position_y_property_ = NULL;
109  velocity_y_property_ = NULL;
110  force_y_property_ = NULL;
111  theta_y_property_ = NULL;
112  omega_y_property_ = NULL;
113  primary_group_ = NULL;
114  ready_opcode_ = 0xFFFF;
115  set_velocity_y_opcode_ = 0xFFFF;
116  set_force_y_opcode_ = 0xFFFF;
117  move_y_plus_opcode_ = 0xFFFF;
118  move_y_minus_opcode_ = 0xFFFF;
119  lastCommandTime_ = Timestamp(seconds(0));
120 
121  for (int i = 0; i <= 9; ++i)
122  yEnt_[i] = NULL;
123  discretePositionObj_ = NULL;
124  discretePosition_ = NULL;
125  nextDiscretePosition_ = NULL;
126  babbleState_ = 0;
127 }
128 
129 float max_force = 20;
130 template<class O, class S> TestMem<O, S>::~TestMem() {
131  if (timeTickThread_)
132  delete timeTickThread_;
133 }
134 
135 template<class O, class S> bool TestMem<O, S>::load
136 (const vector<Code*> *objects, uint32 stdin_oid, uint32 stdout_oid,
137  uint32 self_oid) {
138  // Call the method in the parent class.
139  if (!MemExec<O, S>::load(objects, stdin_oid, stdout_oid, self_oid))
140  return false;
141 
142  // Find the opcodes we need.
143  ready_opcode_ = r_exec::GetOpcode("ready");
144  set_velocity_y_opcode_ = r_exec::GetOpcode("set_velocity_y");
145  set_force_y_opcode_ = r_exec::GetOpcode("set_force_y");
146  move_y_plus_opcode_ = r_exec::GetOpcode("move_y_plus");
147  move_y_minus_opcode_ = r_exec::GetOpcode("move_y_minus");
148 
149  // Find the objects we need.
150  position_property_ = S::find_object(objects, "position");
151  position_y_property_ = S::find_object(objects, "position_y");
152  velocity_y_property_ = S::find_object(objects, "velocity_y");
153  force_y_property_ = S::find_object(objects, "force_y");
154  theta_y_property_ = S::find_object(objects, "theta_y");
155  omega_y_property_ = S::find_object(objects, "omega_y");
156  primary_group_ = S::find_object(objects, "primary");
157 
158  // Find the entities we need.
159  for (int i = 0; i <= 9; ++i)
160  yEnt_[i] = S::find_object(objects, ("y" + to_string(i)).c_str());
161 
162  return true;
163 }
164 
165 template<class O, class S> Code* TestMem<O, S>::eject(Code *command) {
166  uint16 function = (command->code(CMD_FUNCTION).atom_ >> 8) & 0x000000FF;
167 
168  if (function == ready_opcode_) {
169  uint16 args_set_index = command->code(CMD_ARGS).asIndex();
170  if (command->code_size() >= 2 && command->code(args_set_index + 1).getDescriptor() == Atom::I_PTR &&
171  command->code(command->code(args_set_index + 1).asIndex()).getDescriptor() == Atom::STRING) {
172  string identifier = Utils::GetString(&command->code(command->code(args_set_index + 1).asIndex()));
173 
174  if (identifier == "ball") {
175  if (!(command->code_size() >= 3 && command->code(args_set_index + 2).getDescriptor() == Atom::R_PTR &&
176  command->references_size() > command->code(args_set_index + 2).asIndex())) {
177  cout << "WARNING: Cannot get the object for ready \"ball\"" << endl;
178  return NULL;
179  }
180  if (!velocity_y_property_) {
181  cout << "WARNING: Can't find the velocity_y property" << endl;
182  return NULL;
183  }
184  if (!position_y_property_) {
185  cout << "WARNING: Can't find the position_y property" << endl;
186  return NULL;
187  }
188 
189  Code* obj = command->get_reference(command->code(args_set_index + 2).asIndex());
190  if (!position_y_obj_) {
191  // This is the first call. Remember the object whose position we're reporting.
192  position_y_obj_ = obj;
193  startTimeTickThread();
194  }
195  else {
196  if (position_y_obj_ != obj)
197  // For now, don't allow tracking multiple objects.
198  return NULL;
199  }
200  return command;
201  }
202  if (identifier == "cart-pole") {
203  if (!(command->code_size() >= 3 && command->code(args_set_index + 2).getDescriptor() == Atom::R_PTR &&
204  command->references_size() > command->code(args_set_index + 2).asIndex())) {
205  cout << "WARNING: Cannot get the object for ready \"ball\"" << endl;
206  return NULL;
207  }
208  if (!velocity_y_property_) {
209  cout << "WARNING: Can't find the velocity_y property" << endl;
210  return NULL;
211  }
212  if (!position_y_property_) {
213  cout << "WARNING: Can't find the position_y property" << endl;
214  return NULL;
215  }
216  if (!force_y_property_) {
217  cout << "WARNING: Can't find the force_y property" << endl;
218  return NULL;
219  }
220  if (!omega_y_property_) {
221  cout << "WARNING: Can't find the omega_y property" << endl;
222  return NULL;
223  }
224  if (!theta_y_property_) {
225  cout << "WARNING: Can't find the theta_y property" << endl;
226  return NULL;
227  }
228  Code* obj = command->get_reference(command->code(args_set_index + 2).asIndex());
229  if (!cart_position_y_obj_) {
230  // This is the first call. Remember the object whose position we're reporting.
231  cart_position_y_obj_ = obj;
232  startTimeTickThread();
233  }
234 
235  else {
236  if (cart_position_y_obj_ != obj)
237  // For now, don't allow tracking multiple objects.
238  return NULL;
239  }
240  ofs.open("cart.out");
241  return command;
242  }
243  else {
244  cout << "WARNING: Ignoring unrecognized ready command identifier: " << identifier << endl;
245  return NULL;
246  }
247  }
248  }
249  else if (function == set_velocity_y_opcode_) {
250  if (!velocity_y_property_) {
251  cout << "WARNING: Can't find the velocity_y property" << endl;
252  return NULL;
253  }
254  if (!position_y_property_) {
255  cout << "WARNING: Can't find the position_y property" << endl;
256  return NULL;
257  }
258 
259  auto now = r_exec::Now();
260  lastCommandTime_ = now;
261  uint16 args_set_index = command->code(CMD_ARGS).asIndex();
262  Code* obj = command->get_reference(
263  command->code(args_set_index + 1).asIndex());
264  // Set up position_y_obj_ the same as the ready "ball" command.
265  if (!position_y_obj_) {
266  // This is the first call. Remember the object whose velocity we're setting.
267  position_y_obj_ = obj;
268  startTimeTickThread();
269  }
270  else {
271  if (position_y_obj_ != obj)
272  // For now, don't allow tracking the velocity of multiple objects.
273  return NULL;
274  }
275 
276  velocity_y_ = command->code(args_set_index + 2).asFloat();
277  // Let on_time_tick inject the new velocity_y.
278  return command;
279  }
280  else if (function == set_force_y_opcode_) {
281  if (!velocity_y_property_) {
282  cout << "WARNING: Can't find the velocity_y property" << endl;
283  return NULL;
284  }
285  if (!position_y_property_) {
286  cout << "WARNING: Can't find the position_y property" << endl;
287  return NULL;
288  }
289  if (!omega_y_property_) {
290  cout << "WARNING: Can't find the omega_y property" << endl;
291  return NULL;
292  }
293  if (!theta_y_property_) {
294  cout << "WARNING: Can't find the theta_y property" << endl;
295  return NULL;
296  }
297  if (!force_y_property_) {
298  cout << "WARNING: Can't find the force_y property" << endl;
299  return NULL;
300  }
301  auto now = r_exec::Now();
302  lastCommandTime_ = now;
303  uint16 args_set_index = command->code(CMD_ARGS).asIndex();
304  Code* obj = command->get_reference(
305  command->code(args_set_index + 1).asIndex());
306  // Set up position_y_obj_ the same as the ready "ball" command.
307  if (!cart_position_y_obj_) {
308  // This is the first call. Remember the object whose velocity we're setting.
309  cart_position_y_obj_ = obj;
310  startTimeTickThread();
311  }
312  else {
313  if (cart_position_y_obj_ != obj)
314  // For now, don't allow tracking the velocity of multiple objects.
315  return NULL;
316  }
317 
318  float desired_force = command->code(args_set_index + 2).asFloat();
319  if ((desired_force > max_force) || (desired_force < -max_force)) {
320  if (desired_force > max_force)
321  desired_force = max_force;
322  else if (desired_force < -max_force)
323  desired_force = -max_force;
324 
325  force_y_ = desired_force;
326 
327  uint16 AccCommand;
328  AccCommand = set_force_y_opcode_;
329  // Make (cmd set_force_y [obj: acc:] 1)
330  Code* cmdAcc = new r_exec::LObject(this);
331  cmdAcc->code(0) = Atom::Object(r_exec::GetOpcode("cmd"), 3);
332  cmdAcc->code(1) = Atom::DeviceFunction(AccCommand);
333  cmdAcc->code(2) = Atom::IPointer(4);
334  cmdAcc->code(3) = Atom::Float(1); // psln_thr.
335  cmdAcc->code(4) = Atom::Set(2);
336  cmdAcc->code(5) = Atom::RPointer(0); // obj
337  cmdAcc->code(6) = Atom::Float(force_y_);
338  cmdAcc->set_reference(0, cart_position_y_obj_);
339 
340  return cmdAcc;
341  }
342  else {
343  force_y_ = desired_force;
344  return command;
345  }
346  // Let on_time_tick inject the new force_y.
347  }
348  else if (function == move_y_plus_opcode_ ||
349  function == move_y_minus_opcode_) {
350  if (!position_property_) {
351  cout << "WARNING: Can't find the position property" << endl;
352  return NULL;
353  }
354  for (int i = 0; i <= 9; ++i) {
355  if (!yEnt_[i]) {
356  cout << "WARNING: Can't find the entities y0, y1, etc." << endl;
357  return NULL;
358  }
359  }
360 
361  auto now = r_exec::Now();
362 
363  uint16 args_set_index = command->code(CMD_ARGS).asIndex();
364  Code* obj = command->get_reference(
365  command->code(args_set_index + 1).asIndex());
366  if (!discretePositionObj_) {
367  // This is the first call. Remember the object whose position we're setting.
368  discretePositionObj_ = obj;
369  discretePosition_ = yEnt_[0];
370  startTimeTickThread();
371  }
372  else {
373  if (discretePositionObj_ != obj)
374  // For now, don't allow tracking multiple objects.
375  return NULL;
376  }
377 
378  if (nextDiscretePosition_)
379  // A previous move command is still pending execution.
380  return NULL;
381 
382  // nextDiscretePosition_ will become the position at the next sampling period.
383  lastCommandTime_ = now;
384  const int maxYPosition = 9;
385  if (function == move_y_plus_opcode_) {
386  for (int i = 0; i <= maxYPosition - 1; ++i) {
387  if (discretePosition_ == yEnt_[i])
388  nextDiscretePosition_ = yEnt_[i + 1];
389  }
390  }
391  else if (function == move_y_minus_opcode_) {
392  for (int i = 1; i <= maxYPosition; ++i) {
393  if (discretePosition_ == yEnt_[i])
394  nextDiscretePosition_ = yEnt_[i - 1];
395  }
396  }
397  // Let on_time_tick inject the new position.
398  return command;
399  }
400 
401  return NULL;
402 }
403 
404 template<class O, class S> void TestMem<O, S>::on_time_tick() {
405  auto now = r_exec::Now();
406  if (now <= lastInjectTime_ + S::get_sampling_period() * 8 / 10)
407  // Not enough time has elapsed to inject a new position.
408  return;
409 
410  if (position_y_obj_) {
411  // We are updating the continuous position_y_.
412  if (lastInjectTime_.time_since_epoch().count() == 0) {
413  // This is the first call, so leave the initial position.
414  }
415  else
416  position_y_ += velocity_y_ * duration_cast<microseconds>(now - lastInjectTime_).count();
417 
418  lastInjectTime_ = now;
419  // Inject the velocity and position.
420  // It seems that velocity_y needs SYNC_HOLD for building models.
421  S::inject_marker_value_from_io_device(
422  position_y_obj_, velocity_y_property_, Atom::Float(velocity_y_),
423  now, now + S::get_sampling_period(), r_exec::View::SYNC_HOLD);
424  S::inject_marker_value_from_io_device(
425  position_y_obj_, position_y_property_, Atom::Float(position_y_),
426  now, now + S::get_sampling_period());
427  }
428  if (cart_position_y_obj_) {
429  // We are updating the cart position_y_.
430  if (lastInjectTime_.time_since_epoch().count() == 0) {
431  // This is the first call, so leave the initial position.
432  }
433  else
434  {
435  auto DeltaK = 1e-6 * duration_cast<microseconds>(now - lastInjectTime_).count();
436  float current_position_y;
437  float current_velocity_y;
438  float current_theta_y;
439  float current_omega_y;
440 
441  current_position_y = next_position_y_;
442  current_velocity_y = next_velocity_y_;
443  current_theta_y = next_theta_y_;
444  current_omega_y = next_omega_y_;
445 
446  //next_velocity_y_ = (((1. / M) * force_y_) * DeltaK) + current_velocity_y;
447  next_velocity_y_ = (0.1 * force_y_) + current_velocity_y;
448  //next_position_y_ = (0.5 * ((1. / M) * force_y_) * DeltaK * DeltaK) + (current_velocity_y * DeltaK) + current_position_y;
449  next_position_y_ = (0.5e-2 * force_y_) + (0.1 * current_velocity_y) + current_position_y;
450  //next_omega_y_ = A*current_theta_y + B*force_y_ + current_omega_y;
451  next_omega_y_ = current_theta_y + 0.1 * force_y_ + current_omega_y;
452  //next_theta_y_ = A * force_y_ + B * current_theta_y + C * current_omega_y;
453  next_theta_y_ = 0.0371943 * force_y_ + 1.05042 * current_theta_y + 0.101675 * current_omega_y;
454  /* Calculate the constants of theta and omega equations
455  #include<iostream>
456  #include<string>
457  #include<algorithm>
458  using namespace std;
459  float max_force = 15; float d = 0; float m = .00001; float M = 1; float b = 1; float L = 100; float g = -10; float DeltaK = 0.1;
460  int main (){ float p = (-g / L);
461  float A_omg = (-g / L) * DeltaK; float B_omg = DeltaK / (M * L);
462  float A_th = ((-2 + exp(sqrt(p) * DeltaK) + exp(sqrt(p) * DeltaK)) / (2 * p));
463  float B_th = ((exp(-sqrt(p) * DeltaK) + exp(sqrt(p) * DeltaK)) / 2);
464  float C_th = ((-sqrt(p) * exp(-sqrt(p) * DeltaK) + sqrt(p) * exp(sqrt(p) * DeltaK)) / (2 * p));
465  cout << "P: " << p << endl; cout << "A_omega: " << A_omg << endl; cout << "B_omega: " << B_omg << endl;
466  cout << "A_theta: " << A_th << endl; cout << "B_theta: " << B_th << endl; cout << "C_theta: " << C_th << endl;
467  return 0;}
468  */
469  }
470  lastInjectTime_ = now;
471 
472 
473  S::inject_marker_value_from_io_device(
474  cart_position_y_obj_, force_y_property_, Atom::Float(force_y_),
475  now, now + S::get_sampling_period());
476  S::inject_marker_value_from_io_device(
477  cart_position_y_obj_, velocity_y_property_, Atom::Float(next_velocity_y_),
478  now, now + S::get_sampling_period());
479  S::inject_marker_value_from_io_device(
480  cart_position_y_obj_, position_y_property_, Atom::Float(next_position_y_),
481  now, now + S::get_sampling_period());
482  S::inject_marker_value_from_io_device(
483  cart_position_y_obj_, theta_y_property_, Atom::Float(next_theta_y_),
484  now, now + S::get_sampling_period());
485  S::inject_marker_value_from_io_device(
486  cart_position_y_obj_, omega_y_property_, Atom::Float(next_omega_y_),
487  now, now + S::get_sampling_period());
488 
489  ofs << next_theta_y_ << "," << next_omega_y_ << "," << next_position_y_ << "," << next_velocity_y_ << "," << force_y_ << endl;
490  }
491  if (discretePositionObj_) {
492  // We are updating the discretePosition_.
493  if (nextDiscretePosition_ &&
494  now >= lastCommandTime_ + S::get_sampling_period() * 4 / 10) {
495  // Enough time has elapsed from the move command to update the position.
496  discretePosition_ = nextDiscretePosition_;
497  // Clear nextDiscretePosition_ to allow another move command.
498  nextDiscretePosition_ = NULL;
499  }
500 
501  lastInjectTime_ = now;
502  S::inject_marker_value_from_io_device(
503  discretePositionObj_, position_property_, discretePosition_,
504  now, now + S::get_sampling_period());
505 
506  const microseconds babbleStopTime(3700000);
507  const int maxBabblePosition = 9;
508  if (now - Utils::GetTimeReference() < babbleStopTime) {
509  // Babble.
510  if (discretePosition_ == yEnt_[0])
511  // Reset to the expected value.
512  babbleState_ = 1;
513  else if (discretePosition_ == yEnt_[maxBabblePosition])
514  // Reset to the expected value.
515  babbleState_ = maxBabblePosition + 1;
516  else {
517  ++babbleState_;
518  if (babbleState_ >= maxBabblePosition * 2)
519  babbleState_ = 0;
520  }
521 
522  uint16 nextCommand;
523  if (babbleState_ >= 0 && babbleState_ <= maxBabblePosition - 1)
524  nextCommand = move_y_plus_opcode_;
525  else
526  nextCommand = move_y_minus_opcode_;
527 
528  // Inject (fact (goal (fact (cmd ...))))
529  Code *cmd = new r_exec::LObject(this);
530  cmd->code(0) = Atom::Object(r_exec::GetOpcode("cmd"), 3);
531  cmd->code(1) = Atom::DeviceFunction(nextCommand);
532  cmd->code(2) = Atom::IPointer(4);
533  cmd->code(3) = Atom::Float(1); // psln_thr.
534  cmd->code(4) = Atom::Set(1);
535  cmd->code(5) = Atom::RPointer(0); // obj
536  cmd->set_reference(0, discretePositionObj_);
537 
538  auto after = now + S::get_sampling_period() + 2 * Utils::GetTimeTolerance();
539  r_exec::Fact* factCmd = new r_exec::Fact(cmd, after, now + 2 * S::get_sampling_period(), 1, 1);
540  r_exec::Goal* goal = new r_exec::Goal(factCmd, S::get_self(), NULL, 1);
541  S::inject_fact_from_io_device(goal, after, now + S::get_sampling_period(), primary_group_);
542  }
543  }
544 }
545 
546 template<class O, class S> void
548  if (S::reduction_core_count_ == 0 && S::time_core_count_ == 0)
549  // We don't need a timeTickThread for diagnostic time.
550  return;
551  if (timeTickThread_)
552  // We already started the thread.
553  return;
554 
555  // We are running in real time. on_diagnostic_time_tick() will not be called.
556  // Set up a timer thread to call on_time_tick().
557  timeTickThread_ = Thread::New<_Thread>(timeTickRun, this);
558 }
559 
560 template<class O, class S> thread_ret thread_function_call
562  TestMem<O, S>* self = (TestMem *)args;
563 
564  auto sampling_period = _Mem::Get()->get_sampling_period();
565  auto tickTime = r_exec::Now();
566  // Call on_time_tick at the sampling period.
567  while (self->state_ == S::RUNNING) {
568  self->on_time_tick();
569 
570  tickTime += sampling_period;
571  Thread::Sleep(tickTime - r_exec::Now());
572  }
573 
574  thread_ret_val(0);
575 }
576 
577 // Instatiate this template class as needed by main(). (Needs C++11.)
TestMem::eject
r_code::Code * eject(r_code::Code *command) override
Definition: test_mem.cpp:165
TestMem
Definition: test_mem.h:99
r_exec::Goal
Definition: factory.h:517
r_exec::LObject
Definition: r_exec/object.h:195
r_code::Code
Definition: r_code/object.h:224
TestMem::load
bool load(const std::vector< r_code::Code * > *objects, uint32 stdin_oid, uint32 stdout_oid, uint32 self_oid) override
Definition: test_mem.cpp:136
TestMem::timeTickRun
static thread_ret thread_function_call timeTickRun(void *args)
Definition: test_mem.cpp:561
r_exec::Fact
Definition: factory.h:360
r_exec::MemExec
Definition: mem.h:979
TestMem::startTimeTickThread
void startTimeTickThread()
Definition: test_mem.cpp:547