AERA
video_screen_io_device.cpp
1 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
2 //_/_/
3 //_/_/ AERA
4 //_/_/ Autocatalytic Endogenous Reflective Architecture
5 //_/_/
6 //_/_/ Copyright (c) 2022-2025 Jeff Thompson
7 //_/_/ Copyright (c) 2022-2025 Icelandic Institute for Intelligent Machines
8 //_/_/ http://www.iiim.is
9 //_/_/
10 //_/_/ --- Open-Source BSD License, with CADIA Clause v 1.0 ---
11 //_/_/
12 //_/_/ Redistribution and use in source and binary forms, with or without
13 //_/_/ modification, is permitted provided that the following conditions
14 //_/_/ are met:
15 //_/_/ - Redistributions of source code must retain the above copyright
16 //_/_/ and collaboration notice, this list of conditions and the
17 //_/_/ following disclaimer.
18 //_/_/ - Redistributions in binary form must reproduce the above copyright
19 //_/_/ notice, this list of conditions and the following disclaimer
20 //_/_/ in the documentation and/or other materials provided with
21 //_/_/ the distribution.
22 //_/_/
23 //_/_/ - Neither the name of its copyright holders nor the names of its
24 //_/_/ contributors may be used to endorse or promote products
25 //_/_/ derived from this software without specific prior
26 //_/_/ written permission.
27 //_/_/
28 //_/_/ - CADIA Clause: The license granted in and to the software
29 //_/_/ under this agreement is a limited-use license.
30 //_/_/ The software may not be used in furtherance of:
31 //_/_/ (i) intentionally causing bodily injury or severe emotional
32 //_/_/ distress to any person;
33 //_/_/ (ii) invading the personal privacy or violating the human
34 //_/_/ rights of any person; or
35 //_/_/ (iii) committing or preparing for any act of war.
36 //_/_/
37 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
44 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
45 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
47 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
48 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
49 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
50 //_/_/ OF SUCH DAMAGE.
51 //_/_/
52 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
53 
54 #include "video_screen_io_device.h"
55 
56 using namespace std;
57 using namespace std::chrono;
58 using namespace r_code;
59 using namespace r_exec;
60 
61 namespace video_screen {
62 
63 template<class O, class S> VideoScreenIoDevice<O, S>::VideoScreenIoDevice()
64 : MemExec<O, S>() {
65  lastInjectTime_ = Timestamp(seconds(0));
66  video_screen_ = NULL;
67  ready_opcode_ = 0xFFFF;
68  move_opcode_ = 0xFFFF;
69  fovea_pattern_property_ = NULL;
70  eye_obj_ = NULL;
71  lastCommandTime_ = Timestamp(seconds(0));
72 }
73 
74 template<class O, class S> VideoScreenIoDevice<O, S>::~VideoScreenIoDevice() {
75  if (video_screen_)
76  delete video_screen_;
77 }
78 
79 template<class O, class S> bool VideoScreenIoDevice<O, S>::load
80  (const vector<Code*> *objects, uint32 stdin_oid, uint32 stdout_oid,
81  uint32 self_oid) {
82  // Call the method in the parent class.
83  if (!MemExec<O, S>::load(objects, stdin_oid, stdout_oid, self_oid))
84  return false;
85 
86  if (video_screen_)
87  // We don't expect this. load should only be called once.
88  delete video_screen_;
89  video_screen_ = new VideoScreen(64, 64);
90  if (!video_screen_->load(objects))
91  return false;
92 
93  // Find the opcodes we need.
94  ready_opcode_ = r_exec::GetOpcode("ready");
95  move_opcode_ = r_exec::GetOpcode("move");
96 
97  // Find the objects we need.
98  fovea_pattern_property_ = S::find_object(objects, "fovea_pattern");
99 
100  return true;
101 }
102 
103 template<class O, class S> Code* VideoScreenIoDevice<O, S>::eject(Code *command) {
104  uint16 function = (command->code(CMD_FUNCTION).atom_ >> 8) & 0x000000FF;
105 
106  if (function == ready_opcode_) {
107  uint16 args_set_index = command->code(CMD_ARGS).asIndex();
108  if (command->code_size() >= 2 && command->code(args_set_index + 1).getDescriptor() == Atom::I_PTR &&
109  command->code(command->code(args_set_index + 1).asIndex()).getDescriptor() == Atom::STRING) {
110  string identifier = Utils::GetString(&command->code(command->code(args_set_index + 1).asIndex()));
111 
112  if (identifier == "pong") {
113  if (!(command->code_size() >= 3 && command->code(args_set_index + 2).getDescriptor() == Atom::R_PTR &&
114  command->references_size() > command->code(args_set_index + 2).asIndex())) {
115  cout << "WARNING: Cannot get the object for ready \"pong\"" << endl;
116  return NULL;
117  }
118  if (!fovea_pattern_property_) {
119  cout << "WARNING: Can't find the fovea_pattern property" << endl;
120  return NULL;
121  }
122 
123  Code* obj = command->get_reference(command->code(args_set_index + 2).asIndex());
124  if (!eye_obj_) {
125  // This is the first call. Remember the eye we're controlling.
126  eye_obj_ = obj;
127  //startTimeTickThread();
128  }
129  else {
130  if (eye_obj_ != obj)
131  // For now, don't allow tracking multiple objects.
132  return NULL;
133  }
134  return command;
135  }
136  else {
137  cout << "WARNING: Ignoring unrecognized ready command identifier: " << identifier << endl;
138  return NULL;
139  }
140  }
141  }
142  else if (function == move_opcode_) {
143  auto now = r_exec::Now();
144  lastCommandTime_ = now;
145  uint16 args_set_index = command->code(CMD_ARGS).asIndex();
146  if (command->code(args_set_index).getAtomCount() < 3) {
147  cout << "WARNING: Not enough args for (cmd move [eye1 X Y])" << endl;
148  return NULL;
149  }
150 
151  Code* obj = command->get_reference(command->code(args_set_index + 1).asIndex());
152  // Set up eye_obj_ the same as the ready "pong" command.
153  if (!eye_obj_) {
154  // This is the first call. Remember the eye we're controlling.
155  //startTimeTickThread();
156  eye_obj_ = obj;
157  }
158  else {
159  if (eye_obj_ != obj)
160  // For now, don't allow tracking multiple objects.
161  return NULL;
162  }
163 
164  int delta_x = (int)command->code(args_set_index + 2).asFloat();
165  int delta_y = (int)command->code(args_set_index + 3).asFloat();
166 
167  int actual_delta_x;
168  int actual_delta_y;
169  video_screen_->move_eye(delta_x, delta_y, actual_delta_x, actual_delta_y);
170  if (actual_delta_x == delta_x && actual_delta_y == delta_y)
171  // Just return the requested command.
172  return command;
173  else {
174  // Moved by an amount different than the requested amount. Make a command from the actual values.
175  // Make (cmd set_force_y [obj: acc:] 1)
176  Code* actual_command = new r_exec::LObject(this);
177  actual_command->code(0) = Atom::Object(r_exec::GetOpcode("cmd"), 3);
178  actual_command->code(1) = Atom::DeviceFunction(move_opcode_);
179  actual_command->code(2) = Atom::IPointer(4);
180  actual_command->code(3) = Atom::Float(1); // psln_thr.
181  actual_command->code(4) = Atom::Set(3);
182  actual_command->code(5) = Atom::RPointer(0); // obj
183  actual_command->code(6) = Atom::Float(actual_delta_x);
184  actual_command->code(7) = Atom::Float(actual_delta_y);
185  actual_command->set_reference(0, eye_obj_);
186 
187  return actual_command;
188  }
189  }
190 
191  return NULL;
192 }
193 
194 template<class O, class S> void VideoScreenIoDevice<O, S>::on_time_tick() {
195  auto now = r_exec::Now();
196  if (now <= lastInjectTime_ + S::get_sampling_period() * 8 / 10)
197  // Not enough time has elapsed to inject a new measurement.
198  return;
199 
200  if (eye_obj_) {
201 #if 0
202  if (lastInjectTime_.time_since_epoch().count() == 0) {
203  // This is the first call, so leave the initial position.
204  }
205  else
206  position_y_ += velocity_y_ * duration_cast<microseconds>(now - lastInjectTime_).count();
207 #endif
208 
209  lastInjectTime_ = now;
210  // Inject the fovea value.
211  S::inject_marker_value_from_io_device(
212  eye_obj_, fovea_pattern_property_, video_screen_->get_fovea_pattern(),
213  now, now + S::get_sampling_period());
214  }
215 }
216 
217 // Instatiate this template class as needed by main(). (Needs C++11.)
218 template class VideoScreenIoDevice<r_exec::LObject, r_exec::MemStatic>;
219 template class VideoScreenIoDevice<r_exec::LObject, r_exec::MemVolatile>;
220 
221 }
video_screen::VideoScreen
Definition: video_screen.h:61
r_exec::LObject
Definition: r_exec/object.h:195
r_code::Code
Definition: r_code/object.h:224
video_screen::VideoScreenIoDevice::eject
r_code::Code * eject(r_code::Code *command) override
Definition: video_screen_io_device.cpp:103
video_screen::VideoScreenIoDevice
Definition: video_screen_io_device.h:63
video_screen::VideoScreenIoDevice::load
bool load(const std::vector< r_code::Code * > *objects, uint32 stdin_oid, uint32 stdout_oid, uint32 self_oid) override
Definition: video_screen_io_device.cpp:80
r_exec::MemExec
Definition: mem.h:979