|  |  |  | #include <future>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "catch2/catch.hpp"
 | 
					
						
							|  |  |  | #include "selfdrive/loggerd/loggerd.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int random_int(int min, int max) {
 | 
					
						
							|  |  |  |   std::random_device dev;
 | 
					
						
							|  |  |  |   std::mt19937 rng(dev());
 | 
					
						
							|  |  |  |   std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);
 | 
					
						
							|  |  |  |   return dist(rng);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int get_synced_frame_id(LoggerdState *s, CameraType cam_type, int start_frame_id) {
 | 
					
						
							|  |  |  |   int frame_id = start_frame_id;
 | 
					
						
							|  |  |  |   while (!sync_encoders(s, cam_type, frame_id)) {
 | 
					
						
							|  |  |  |     ++frame_id;
 | 
					
						
							|  |  |  |     usleep(0);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  |   return frame_id;
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("sync_encoders") {
 | 
					
						
							|  |  |  |   const int max_waiting = GENERATE(1, 2, 3);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int test_cnt = 0; test_cnt < 10; ++test_cnt) {
 | 
					
						
							|  |  |  |     LoggerdState s{.max_waiting = max_waiting};
 | 
					
						
							|  |  |  |     std::vector<int> start_frames;
 | 
					
						
							|  |  |  |     std::vector<std::future<int>> futures;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < max_waiting; ++i) {
 | 
					
						
							|  |  |  |       int start_frame_id = random_int(0, 20);
 | 
					
						
							|  |  |  |       start_frames.push_back(start_frame_id);
 | 
					
						
							|  |  |  |       futures.emplace_back(std::async(std::launch::async, get_synced_frame_id, &s, (CameraType)i, start_frame_id));
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // get results
 | 
					
						
							|  |  |  |     int synced_frame_id = 0;
 | 
					
						
							|  |  |  |     for (int i = 0; i < max_waiting; ++i) {
 | 
					
						
							|  |  |  |       if (i == 0) {
 | 
					
						
							|  |  |  |         synced_frame_id = futures[i].get();
 | 
					
						
							|  |  |  |         // require synced_frame_id equal start_frame_id if max_waiting == 1
 | 
					
						
							|  |  |  |         if (max_waiting == 1) {
 | 
					
						
							|  |  |  |           REQUIRE(synced_frame_id == start_frames[0]);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |       } else {
 | 
					
						
							|  |  |  |         REQUIRE(futures[i].get() == synced_frame_id);
 | 
					
						
							|  |  |  |       }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int MAX_SEGMENT_CNT = 100;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::pair<int, uint32_t> encoder_thread(LoggerdState *s) {
 | 
					
						
							|  |  |  |   int cur_seg = 0;
 | 
					
						
							|  |  |  |   uint32_t frame_id = s->start_frame_id;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (cur_seg < MAX_SEGMENT_CNT) {
 | 
					
						
							|  |  |  |     ++frame_id;
 | 
					
						
							|  |  |  |     if (trigger_rotate_if_needed(s, cur_seg, frame_id)) {
 | 
					
						
							|  |  |  |       cur_seg = s->rotate_segment;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     util::sleep_for(0);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return {cur_seg, frame_id};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("trigger_rotate") {
 | 
					
						
							|  |  |  |   const int encoders = GENERATE(1, 2, 3);
 | 
					
						
							|  |  |  |   const int start_frame_id = random_int(0, 20);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LoggerdState s{
 | 
					
						
							|  |  |  |       .max_waiting = encoders,
 | 
					
						
							|  |  |  |       .start_frame_id = start_frame_id,
 | 
					
						
							|  |  |  |   };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::vector<std::future<std::pair<int, uint32_t>>> futures;
 | 
					
						
							|  |  |  |   for (int i = 0; i < encoders; ++i) {
 | 
					
						
							|  |  |  |     futures.emplace_back(std::async(std::launch::async, encoder_thread, &s));
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (s.rotate_segment < MAX_SEGMENT_CNT) {
 | 
					
						
							|  |  |  |     rotate_if_needed(&s);
 | 
					
						
							|  |  |  |     util::sleep_for(10);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (auto &f : futures) {
 | 
					
						
							|  |  |  |     auto [encoder_seg, frame_id] = f.get();
 | 
					
						
							|  |  |  |     REQUIRE(encoder_seg == MAX_SEGMENT_CNT);
 | 
					
						
							|  |  |  |     REQUIRE(frame_id == start_frame_id + encoder_seg * (SEGMENT_LENGTH * MAIN_FPS));
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | }
 |