main.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <string>
  4. #include <vector>
  5. #include <map>
  6. #include <boost/interprocess/file_mapping.hpp>
  7. #include <boost/interprocess/mapped_region.hpp>
  8. #include <boost/filesystem.hpp>
  9. #include "tx01_msg.hpp"
  10. #include "tx01_data_frame.hpp"
  11. #include "tx01_telemetry_frame.hpp"
  12. #include "config.hpp"
  13. #include "crc.h"
  14. template <class T>
  15. inline static T load(const char *addr)
  16. {
  17. T t;
  18. memcpy(&t, addr, sizeof(T));
  19. return t;
  20. }
  21. struct adc_sample
  22. {
  23. uint32_t fl_time;
  24. int v;
  25. bool fired;
  26. };
  27. static std::vector<adc_sample> rm100_data[2];
  28. // dump raw data file for gnuplot, enabled by config file.
  29. static void dump_rm100_raw_data(int k)
  30. {
  31. std::ofstream out(std::string("rm100_raw_") + "01"[k] + ".dat");
  32. for (size_t i = 0; i < rm100_data[k].size(); i++)
  33. out << i << ' ' << rm100_data[k][i].v << '\n';
  34. }
  35. struct particle
  36. {
  37. size_t k;
  38. uint32_t fl_time;
  39. bool fired;
  40. };
  41. static void dump_particles(const std::vector<particle> particles, int id)
  42. {
  43. std::ofstream out(std::string("rm100_particles_") + "01"[id] + ".csv");
  44. out << "k,fl_time,fired\n";
  45. for (particle p: particles)
  46. out << p.k << ',' << p.fl_time << p.fired << '\n';
  47. }
  48. static std::vector<particle>
  49. adc_data_to_particles(const std::vector<adc_sample> &sample)
  50. {
  51. std::vector<particle> ret;
  52. const size_t crit = 5;
  53. if (sample.size() < crit)
  54. return ret;
  55. for (size_t i = 0; i < sample.size() - crit; i++) {
  56. bool ok = true;
  57. for (size_t j = 0; j < crit; j++)
  58. if (sample[i+j].v > 0 || sample[i+j].v < -10)
  59. ok = false;
  60. if (ok) {
  61. ret.push_back({i, sample[i].fl_time, sample[i].fired});
  62. i += crit - 1;
  63. }
  64. }
  65. return ret;
  66. }
  67. static void append_to_rm100_data(int rm100_id, const char *p, size_t sz,
  68. int fl_time, bool fired)
  69. {
  70. //std::cout << "appending " << sz << " bytes to rm100 " <<
  71. // rm100_id << '\n';
  72. std::size_t old_size = rm100_data[rm100_id].size();
  73. rm100_data[rm100_id].resize(old_size + sz);
  74. for (; old_size != rm100_data[rm100_id].size(); old_size++) {
  75. rm100_data[rm100_id][old_size].fl_time = fl_time;
  76. rm100_data[rm100_id][old_size].v = *p++;
  77. rm100_data[rm100_id][old_size].fired = fired;
  78. }
  79. }
  80. struct flight_data
  81. {
  82. uint32_t fl_time;
  83. double ils_height;
  84. double gps_height;
  85. };
  86. static bool fired = false;
  87. static flight_data current = {0, 0, 0};
  88. static std::map<uint32_t, flight_data> FDR;
  89. static void dump_particles_aggr(const std::vector<particle> particles,
  90. int id, uint32_t ts, uint32_t tw)
  91. {
  92. std::ofstream out(std::string("rm100_aggreated_") + "01"[id] + ".csv");
  93. out << "fl_time,cnt,gps_height,ils_height\n";
  94. size_t cnt = 0;
  95. uint32_t last_time = particles.rbegin()->fl_time;
  96. auto cmp = [](particle a, particle b) {
  97. return a.fl_time < b.fl_time;
  98. };
  99. auto first = particles.begin();
  100. while (first != particles.end() && !first->fired)
  101. ++first;
  102. std::vector<size_t> sum;
  103. for (uint32_t t0 = 0; t0 < last_time; t0 += ts) {
  104. auto a = std::lower_bound(first, particles.end(),
  105. particle{0, t0, 0}, cmp);
  106. auto b = std::lower_bound(first, particles.end(),
  107. particle{0, t0+tw, 0}, cmp);
  108. sum.push_back(b - a);
  109. }
  110. flight_data fd{0, 0, 0};
  111. for (size_t i = 0; i < sum.size(); i++) {
  112. auto cnt = sum[i];
  113. if (FDR.find(ts*i) != FDR.end())
  114. fd = FDR[ts*i];
  115. out << i * ts * 0.0001 <<
  116. ',' << cnt * 1. <<
  117. ',' << fd.gps_height << ',' << fd.ils_height << '\n';
  118. }
  119. }
  120. static void parse_and_record_flight_data(const char *buf, size_t sz)
  121. {
  122. const tx01_telemetry_frame *frame = (const tx01_telemetry_frame *) buf;
  123. uint16_t recv_crc = load<uint16_t>(&frame->payload[frame->len_payload]);
  124. uint16_t crc = crc16_ccitt(&buf[2],
  125. sizeof(frame) + frame->len_payload - 4);
  126. if (crc != recv_crc)
  127. return ;
  128. uint32_t fl_time = load<uint32_t>(&buf[7]);
  129. current.fl_time = fl_time;
  130. unsigned char frame_id = (unsigned char) buf[6];
  131. double height;
  132. switch (frame_id) {
  133. case 0x85:
  134. height = load<int32_t>(&buf[164]) * 0.00004656613;
  135. if (height >= -300 && height <= 100000)
  136. current.ils_height = height;
  137. break;
  138. case 0x87:
  139. height = load<int32_t>(&buf[168]) * 0.01;
  140. if (height >= -300 && height <= 100000)
  141. current.gps_height = height;
  142. break;
  143. }
  144. if (fl_time < 20000)
  145. fired = true;
  146. if (fired)
  147. FDR[fl_time] = current;
  148. if (conf_debug_dump_flight_data)
  149. std::cout << current.fl_time * 0.0001 << ' ' <<
  150. current.ils_height << ' ' << current.gps_height << ' ' <<
  151. fired << '\n';
  152. }
  153. static void process_flight_ctrl_frame(const char *first, size_t sz)
  154. {
  155. static union {
  156. char buf[512];
  157. tx01_telemetry_frame frame;
  158. } x;
  159. static size_t buf_tail = 0;
  160. const char *last = first + sz;
  161. while (first != last) {
  162. unsigned char byte = (unsigned char) *first;
  163. if (buf_tail == 0 && byte != 0x55) {
  164. first++;
  165. continue;
  166. }
  167. if (buf_tail == 1 && byte != 0xaa) {
  168. if (byte != 0x55)
  169. buf_tail = 0;
  170. first++;
  171. continue;
  172. }
  173. x.buf[buf_tail++] = *first++;
  174. if (buf_tail >= sizeof(x.frame) &&
  175. (sizeof(x.frame) + x.frame.len_payload + sizeof(uint16_t) ==
  176. buf_tail)) {
  177. parse_and_record_flight_data(x.buf, buf_tail);
  178. buf_tail = 0;
  179. }
  180. }
  181. }
  182. static int process_data_in_msg(const char *buf, size_t sz)
  183. {
  184. // std::cout << sz << '\n';
  185. // std::cout << (void *)buf << '\n';
  186. // std::cout << std::hex << 0 + (unsigned char)buf[0] << ' '
  187. // << 0 + (unsigned char)buf[1] << std::dec << '\n';
  188. const tx01_data_frame *frame = (const tx01_data_frame *) buf;
  189. if (frame->magic == 0xeb90) {
  190. switch (frame->channel_id) {
  191. case 9:
  192. case 10:
  193. case 11:
  194. case 12:
  195. append_to_rm100_data(0, frame->data,
  196. size_data_frame_content,
  197. current.fl_time, fired);
  198. break;
  199. case 13:
  200. case 14:
  201. case 15:
  202. case 16:
  203. append_to_rm100_data(1, frame->data,
  204. size_data_frame_content,
  205. current.fl_time, fired);
  206. break;
  207. case 17:
  208. case 18:
  209. case 19:
  210. case 20:
  211. case 21:
  212. case 22:
  213. case 23:
  214. process_flight_ctrl_frame(frame->data,
  215. size_data_frame_content);
  216. break;
  217. }
  218. }
  219. return 0;
  220. }
  221. static int process_telemetry_data(void *ptr, size_t sz)
  222. {
  223. //std::cout << sz << '\n';
  224. //std::cout << std::string((const char *)ptr, (const char *)ptr + sz);
  225. char *first = static_cast<char *>(ptr), *last = first + sz;
  226. while (first != last) {
  227. ptrdiff_t remain = last - first;
  228. if (remain < sizeof(tx01_msg_header))
  229. break;
  230. const tx01_msg_header *p_hdr = tx01_try_match_msg_header(first);
  231. if (!p_hdr) {
  232. ++first;
  233. continue;
  234. }
  235. // ignore incomplete msg at the tail
  236. if (last - first < p_hdr->size)
  237. break;
  238. const tx01_data_msg *p_msg = tx01_try_match_data_msg(p_hdr);
  239. if (p_msg != NULL)
  240. process_data_in_msg(p_msg->data,
  241. p_hdr->size - sizeof(tx01_data_msg) - 4);
  242. first += p_hdr->size;
  243. // std::cout << static_cast<void *>(first) << '\n';
  244. }
  245. for (int k = 0; k < 2; k++) {
  246. if (conf_debug_dump_adc_raw)
  247. dump_rm100_raw_data(0);
  248. auto particles = adc_data_to_particles(rm100_data[k]);
  249. dump_particles(particles, k);
  250. dump_particles_aggr(particles, k, (int)(conf_aggr_ts * 10000),
  251. (int)(conf_aggr_tav * 10000));
  252. }
  253. return 0;
  254. }
  255. int main(int argc, const char **argv)
  256. {
  257. using namespace std;
  258. using namespace boost::interprocess;
  259. using namespace boost::filesystem;
  260. const char *filename = "data.bin";
  261. if (argc > 1)
  262. filename = argv[1];
  263. path p = filename;
  264. size_t sz;
  265. try {
  266. sz = file_size(p);
  267. } catch (const filesystem_error &ex) {
  268. cerr << ex.what() << '\n';
  269. exit(1);
  270. }
  271. try {
  272. file_mapping fmap(filename, read_only);
  273. mapped_region region(fmap, read_only, 0, sz);
  274. return process_telemetry_data(region.get_address(), sz);
  275. } catch (const interprocess_exception &ex) {
  276. cerr << ex.what() << '\n';
  277. exit(1);
  278. }
  279. return 0;
  280. }