3 #include "library/movie.hpp"
11 //std::ofstream debuglog("movie-debugging-log", std::ios::out | std::ios::app);
15 uint64_t find_next_sync(controller_frame_vector
& movie
, uint64_t after
)
17 if(after
>= movie
.size())
21 } while(after
< movie
.size() && !movie
[after
].sync());
25 bool movies_compatible(controller_frame_vector
& old_movie
, controller_frame_vector
& new_movie
,
26 uint64_t frame
, const uint32_t* polls
, const std::string
& old_projectid
,
27 const std::string
& new_projectid
)
29 //Project IDs have to match.
30 if(old_projectid
!= new_projectid
)
32 //Types have to match.
33 if(old_movie
.get_types() != new_movie
.get_types())
35 const port_type_set
& pset
= new_movie
.get_types();
36 //If new movie is before first frame, anything with same project_id is compatible.
39 //Scan both movies until frame syncs are seen. Out of bounds reads behave as all neutral but frame
41 uint64_t syncs_seen
= 0;
42 uint64_t frames_read
= 0;
43 while(syncs_seen
< frame
- 1) {
44 controller_frame oldc
= old_movie
.blank_frame(true), newc
= new_movie
.blank_frame(true);
45 if(frames_read
< old_movie
.size())
46 oldc
= old_movie
[frames_read
];
47 if(frames_read
< new_movie
.size())
48 newc
= new_movie
[frames_read
];
50 return false; //Mismatch.
55 //We increment the counter one time too many.
57 //Current frame. We need to compare each control up to poll counter.
58 uint64_t readable_old_subframes
= 0, readable_new_subframes
= 0;
59 uint64_t oldlen
= find_next_sync(old_movie
, frames_read
);
60 uint64_t newlen
= find_next_sync(new_movie
, frames_read
);
61 if(frames_read
< oldlen
)
62 readable_old_subframes
= oldlen
- frames_read
;
63 if(frames_read
< newlen
)
64 readable_new_subframes
= newlen
- frames_read
;
65 //Then rest of the stuff.
66 for(unsigned i
= 0; i
< pset
.indices(); i
++) {
67 uint32_t p
= polls
[i
] & 0x7FFFFFFFUL
;
69 for(uint32_t j
= 0; j
< p
; j
++) {
70 if(j
< readable_old_subframes
)
71 ov
= old_movie
[j
+ frames_read
].axis2(i
);
72 if(j
< readable_new_subframes
)
73 nv
= new_movie
[j
+ frames_read
].axis2(i
);
82 void movie::set_all_DRDY() throw()
84 pollcounters
.set_all_DRDY();
87 std::string
movie::rerecord_count() throw(std::bad_alloc
)
92 void movie::rerecord_count(const std::string
& count
) throw(std::bad_alloc
)
97 std::string
movie::project_id() throw(std::bad_alloc
)
102 void movie::project_id(const std::string
& id
) throw(std::bad_alloc
)
107 bool movie::readonly_mode() throw()
112 void movie::set_controls(controller_frame controls
) throw()
114 current_controls
= controls
;
117 uint32_t movie::count_changes(uint64_t first_subframe
) throw()
119 return movie_data
.subframe_count(first_subframe
);
122 controller_frame
movie::get_controls() throw()
125 return current_controls
;
126 controller_frame c
= movie_data
.blank_frame(false);
127 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
128 if(current_frame
== 0)
130 //Otherwise find the last valid frame of input.
131 uint32_t changes
= count_changes(current_frame_first_subframe
);
133 return c
; //End of movie.
134 if(pollcounters
.get_polls(0, 0, 1)) {
136 c
.axis3(0, 0, 1, movie_data
[current_frame_first_subframe
].axis3(0, 0, 1));
137 c
.axis3(0, 0, 2, movie_data
[current_frame_first_subframe
].axis3(0, 0, 2));
138 c
.axis3(0, 0, 3, movie_data
[current_frame_first_subframe
].axis3(0, 0, 3));
140 for(size_t i
= 0; i
< movie_data
.get_types().indices(); i
++) {
141 uint32_t polls
= pollcounters
.get_polls(i
);
142 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
143 c
.axis2(i
, movie_data
[current_frame_first_subframe
+ index
].axis2(i
));
148 uint64_t movie::get_current_frame() throw()
150 return current_frame
;
153 uint64_t movie::get_lag_frames() throw()
158 uint64_t movie::get_frame_count() throw()
160 return frames_in_movie
;
163 void movie::next_frame() throw(std::bad_alloc
)
165 //Adjust lag count. Frame 0 MUST NOT be considered lag.
166 //If we don't have valid pflag handler, use the legacy behaviour.
167 unsigned pflag
= pflag_handler
? pflag_handler
->get_pflag() : 2;
168 if(current_frame
&& pflag
== 0)
170 else if(pflag
< 2 && pflag_handler
)
171 pflag_handler
->set_pflag(0);
173 //If all poll counters are zero for all real controls, this frame is lag.
174 bool this_frame_lag
= !pollcounters
.has_polled();
175 //Oh, frame 0 must not be considered lag.
176 if(current_frame
&& this_frame_lag
) {
178 lag_frames
++; //Legacy compat. behaviour.
179 //debuglog << "Frame " << current_frame << " is lag" << std::endl << std::flush;
181 //If in read-write mode, write a dummy record for the frame. Force sync flag.
182 //As index should be movie_data.size(), it is correct afterwards.
183 movie_data
.append(current_controls
.copy(true));
188 //Reset the poll counters and DRDY flags.
189 pollcounters
.clear();
191 //Increment the current frame counter and subframe counter. Note that first subframe is undefined for
192 //frame 0 and 0 for frame 1.
194 current_frame_first_subframe
= current_frame_first_subframe
+
195 count_changes(current_frame_first_subframe
);
197 current_frame_first_subframe
= 0;
201 bool movie::get_DRDY(unsigned port
, unsigned controller
, unsigned ctrl
) throw(std::logic_error
)
203 return pollcounters
.get_DRDY(port
, controller
, ctrl
);
206 short movie::next_input(unsigned port
, unsigned controller
, unsigned ctrl
) throw(std::bad_alloc
, std::logic_error
)
208 pollcounters
.clear_DRDY(port
, controller
, ctrl
);
211 //In readonly mode...
212 //If at the end of the movie, return released / neutral (but also record the poll)...
213 if(current_frame_first_subframe
>= movie_data
.size()) {
214 pollcounters
.increment_polls(port
, controller
, ctrl
);
217 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
218 if(current_frame
== 0)
220 //Otherwise find the last valid frame of input.
221 uint32_t changes
= count_changes(current_frame_first_subframe
);
222 uint32_t polls
= pollcounters
.increment_polls(port
, controller
, ctrl
);
223 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
224 //debuglog << "Frame=" << current_frame << " Subframe=" << polls << " control=" << controlindex << " value=" << movie_data[current_frame_first_subframe + index](controlindex) << " fetchrow=" << current_frame_first_subframe + index << std::endl << std::flush;
225 return movie_data
[current_frame_first_subframe
+ index
].axis3(port
, controller
, ctrl
);
228 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
229 //Also, frame 0 must not be added to movie file.
230 if(current_frame
== 0)
232 //If at movie end, insert complete input with frame sync set (this is the first subframe).
233 if(current_frame_first_subframe
>= movie_data
.size()) {
234 movie_data
.append(current_controls
.copy(true));
235 //current_frame_first_subframe should be movie_data.size(), so it is right.
236 pollcounters
.increment_polls(port
, controller
, ctrl
);
238 //debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << movie_data[current_frame_first_subframe](controlindex) << " fetchrow=" << current_frame_first_subframe << std::endl << std::flush;
239 return movie_data
[current_frame_first_subframe
].axis3(port
, controller
, ctrl
);
241 short new_value
= current_controls
.axis3(port
, controller
, ctrl
);
242 //Fortunately, we know this frame is the last one in movie_data.
243 uint32_t pollcounter
= pollcounters
.get_polls(port
, controller
, ctrl
);
244 uint64_t fetchrow
= movie_data
.size() - 1;
245 if(current_frame_first_subframe
+ pollcounter
< movie_data
.size()) {
246 //The index is within existing size. Change the value and propagate to all subsequent
248 for(uint64_t i
= current_frame_first_subframe
+ pollcounter
; i
< movie_data
.size(); i
++)
249 movie_data
[i
].axis3(port
, controller
, ctrl
, new_value
);
250 fetchrow
= current_frame_first_subframe
+ pollcounter
;
251 } else if(new_value
!= movie_data
[movie_data
.size() - 1].axis3(port
, controller
, ctrl
)) {
252 //The index is not within existing size and value does not match. We need to create a new
253 //subframes(s), copying the last subframe.
254 while(current_frame_first_subframe
+ pollcounter
>= movie_data
.size())
255 movie_data
.append(movie_data
[movie_data
.size() - 1].copy(false));
256 fetchrow
= current_frame_first_subframe
+ pollcounter
;
257 movie_data
[current_frame_first_subframe
+ pollcounter
].axis3(port
, controller
, ctrl
,
260 pollcounters
.increment_polls(port
, controller
, ctrl
);
261 //debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << new_value << " fetchrow=" << fetchrow << std::endl << std::flush;
266 movie::movie() throw(std::bad_alloc
)
273 current_frame_first_subframe
= 0;
275 pflag_handler
= NULL
;
279 void movie::load(const std::string
& rerecs
, const std::string
& project_id
, controller_frame_vector
& input
)
280 throw(std::bad_alloc
, std::runtime_error
)
282 if(input
.size() > 0 && !input
[0].sync())
283 throw std::runtime_error("First subframe MUST have frame sync flag set");
286 for(size_t i
= 0; i
< input
.size(); i
++)
291 _project_id
= project_id
;
293 current_frame_first_subframe
= 0;
294 pollcounters
= pollcounter_vector(input
.get_types());
297 //This is to force internal type of current_controls to become correct.
298 current_controls
= input
.blank_frame(false);
301 controller_frame_vector
movie::save() throw(std::bad_alloc
)
306 void movie::commit_reset(long delay
) throw(std::bad_alloc
)
308 if(readonly
|| delay
< 0)
310 //If this frame is lagged, we need to write entry for it.
311 if(!pollcounters
.has_polled()) {
312 movie_data
.append(current_controls
.copy(true));
314 //Current_frame_first_subframe is correct.
316 //Also set poll counters on reset cycles to avoid special cases elsewhere.
317 pollcounters
.increment_polls(0, 0, 1);
318 //Current frame is always last in rw mode.
319 movie_data
[current_frame_first_subframe
].axis3(0, 0, 1, 1);
320 movie_data
[current_frame_first_subframe
].axis3(0, 0, 2, delay
/ 10000);
321 movie_data
[current_frame_first_subframe
].axis3(0, 0, 3, delay
% 10000);
324 unsigned movie::next_poll_number()
326 return pollcounters
.max_polls() + 1;
329 void movie::readonly_mode(bool enable
) throw(std::bad_alloc
)
331 bool was_in_readonly
= readonly
;
333 if(was_in_readonly
&& !readonly
) {
335 //Transitioning to readwrite mode, we have to adjust the length of the movie data.
336 if(current_frame
== 0) {
337 //WTF... At before first frame. Blank the entiere movie.
342 //Fun special case: Current frame is not in movie (current_frame_first_subframe >= movie_data.size()).
343 //In this case, we have to extend the movie data.
344 if(current_frame_first_subframe
>= movie_data
.size()) {
345 //Yes, this will insert one extra frame... But we will lose it later if it is not needed.
346 while(frames_in_movie
< current_frame
) {
347 movie_data
.append(movie_data
.blank_frame(true));
350 current_frame_first_subframe
= movie_data
.size() - 1;
353 //We have to take the part up to furthest currently readable subframe. Also, we need to propagate
354 //forward values with smaller poll counters.
355 uint64_t next_frame_first_subframe
= current_frame_first_subframe
+
356 count_changes(current_frame_first_subframe
);
357 uint64_t max_readable_subframes
= current_frame_first_subframe
+ pollcounters
.max_polls();
358 if(max_readable_subframes
> next_frame_first_subframe
)
359 max_readable_subframes
= next_frame_first_subframe
;
361 movie_data
.resize(max_readable_subframes
);
362 next_frame_first_subframe
= max_readable_subframes
;
363 //Propagate RESET. This always has poll count of 0 or 1, which always behaves like 1.
364 for(uint64_t j
= current_frame_first_subframe
+ 1; j
< next_frame_first_subframe
; j
++) {
365 movie_data
[j
].axis3(0, 0, 1, movie_data
[current_frame_first_subframe
].axis3(0, 0, 1));
366 movie_data
[j
].axis3(0, 0, 2, movie_data
[current_frame_first_subframe
].axis3(0, 0, 2));
367 movie_data
[j
].axis3(0, 0, 3, movie_data
[current_frame_first_subframe
].axis3(0, 0, 3));
369 //Then the other buttons.
370 for(size_t i
= 4; i
< movie_data
.get_types().indices(); i
++) {
371 uint32_t polls
= pollcounters
.get_polls(i
);
372 polls
= polls
? polls
: 1;
373 for(uint64_t j
= current_frame_first_subframe
+ polls
; j
< next_frame_first_subframe
; j
++)
374 movie_data
[j
].axis2(i
, movie_data
[current_frame_first_subframe
+ polls
- 1].axis2(i
));
376 frames_in_movie
= current_frame
- ((current_frame_first_subframe
>= movie_data
.size()) ? 1 : 0);
380 //Save state of movie code.
381 void movie::save_state(std::string
& proj_id
, uint64_t& curframe
, uint64_t& lagframes
, std::vector
<uint32_t>& pcounters
)
382 throw(std::bad_alloc
)
384 pollcounters
.save_state(pcounters
);
385 proj_id
= _project_id
;
386 curframe
= current_frame
;
387 lagframes
= lag_frames
;
390 //Restore state of movie code. Throws if state is invalid. Flag gives new state of readonly flag.
391 size_t movie::restore_state(uint64_t curframe
, uint64_t lagframe
, const std::vector
<uint32_t>& pcounters
, bool ro
,
392 controller_frame_vector
* old_movie
, const std::string
& old_projectid
) throw(std::bad_alloc
,
395 if(!pollcounters
.check(pcounters
))
396 throw std::runtime_error("Wrong number of poll counters");
397 if(old_movie
&& !movies_compatible(*old_movie
, movie_data
, curframe
, &pcounters
[0], old_projectid
,
399 throw std::runtime_error("Save is not from this movie");
400 uint64_t tmp_firstsubframe
= 0;
401 for(uint64_t i
= 1; i
< curframe
; i
++)
402 tmp_firstsubframe
= tmp_firstsubframe
+ count_changes(tmp_firstsubframe
);
403 //Checks have passed, copy the data.
405 current_frame
= curframe
;
406 current_frame_first_subframe
= tmp_firstsubframe
;
407 lag_frames
= lagframe
;
408 pollcounters
.load_state(pcounters
);
413 long movie::get_reset_status() throw()
415 if(current_frame
== 0 || current_frame_first_subframe
>= movie_data
.size())
416 return -1; //No resets out of range.
417 if(!movie_data
[current_frame_first_subframe
].axis3(0, 0, 1))
418 return -1; //Not a reset.
419 //Also set poll counters on reset cycles to avoid special cases elsewhere.
420 pollcounters
.increment_polls(0, 0, 1);
421 long hi
= movie_data
[current_frame_first_subframe
].axis3(0, 0, 2);
422 long lo
= movie_data
[current_frame_first_subframe
].axis3(0, 0, 3);
423 return hi
* 10000 + lo
;
426 uint64_t movie::frame_subframes(uint64_t frame
) throw()
428 if(frame
< cached_frame
)
430 uint64_t p
= cached_subframe
;
431 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
432 p
= p
+ count_changes(p
);
433 cached_frame
= frame
;
435 return count_changes(p
);
438 void movie::clear_caches() throw()
444 controller_frame
movie::read_subframe(uint64_t frame
, uint64_t subframe
) throw()
446 if(frame
< cached_frame
)
448 uint64_t p
= cached_subframe
;
449 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
450 p
= p
+ count_changes(p
);
451 cached_frame
= frame
;
453 uint64_t max
= count_changes(p
);
455 return movie_data
.blank_frame(true);
459 return movie_data
[p
+ subframe
];
462 void movie::reset_state() throw()
466 current_frame_first_subframe
= 0;
467 pollcounters
.clear();
472 void movie::fast_save(uint64_t& _frame
, uint64_t& _ptr
, uint64_t& _lagc
, std::vector
<uint32_t>& _counters
)
474 pollcounters
.save_state(_counters
);
475 _frame
= current_frame
;
476 _ptr
= current_frame_first_subframe
;
480 void movie::fast_load(uint64_t& _frame
, uint64_t& _ptr
, uint64_t& _lagc
, std::vector
<uint32_t>& _counters
)
483 current_frame
= _frame
;
484 current_frame_first_subframe
= (_ptr
<= movie_data
.size()) ? _ptr
: movie_data
.size();
486 pollcounters
.load_state(_counters
);
487 readonly_mode(false);
490 void movie::set_pflag_handler(poll_flag
* handler
)
492 pflag_handler
= handler
;
495 movie::poll_flag::~poll_flag()