main.cc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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)
  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, size_t win_size)
  91. {
  92. std::ofstream out(std::string("rm100_aggreated_") + "01"[id] + ".csv");
  93. out << "fl_time,cnt,gps_height,ils_height\n";
  94. uint32_t t0 = 0;
  95. size_t cnt = 0;
  96. std::vector<size_t> sum;
  97. for (particle p: particles)
  98. if (p.fired) {
  99. while (t0 + ts < p.fl_time) {
  100. sum.push_back(cnt);
  101. cnt = 0;
  102. t0 += ts;
  103. }
  104. cnt++;
  105. }
  106. cnt = 0;
  107. flight_data fd{0, 0, 0};
  108. for (size_t i = 0; i < sum.size(); i++) {
  109. cnt += sum[i];
  110. if (win_size < i)
  111. cnt -= sum[i-win_size-1];
  112. if (win_size <= i) {
  113. if (FDR.find(ts*(i-win_size)) != FDR.end())
  114. fd = FDR[ts*(i-win_size)];
  115. out << (i-win_size) * ts * 0.0001 <<
  116. ',' << cnt * 1. / win_size <<
  117. ',' << fd.gps_height << ',' << fd.ils_height << '\n';
  118. }
  119. }
  120. }
  121. static void parse_and_record_flight_data(const char *buf, size_t sz)
  122. {
  123. const tx01_telemetry_frame *frame = (const tx01_telemetry_frame *) buf;
  124. uint16_t recv_crc = load<uint16_t>(&frame->payload[frame->len_payload]);
  125. uint16_t crc = crc16_ccitt(&buf[2],
  126. sizeof(frame) + frame->len_payload - 4);
  127. if (crc != recv_crc)
  128. return ;
  129. uint32_t fl_time = load<uint32_t>(&buf[7]);
  130. current.fl_time = fl_time;
  131. unsigned char frame_id = (unsigned char) buf[6];
  132. double height;
  133. switch (frame_id) {
  134. case 0x85:
  135. height = load<int32_t>(&buf[164]) * 0.00004656613;
  136. if (height >= -300 && height <= 100000)
  137. current.ils_height = height;
  138. break;
  139. case 0x87:
  140. height = load<int32_t>(&buf[168]) * 0.1;
  141. if (height >= -300 && height <= 100000)
  142. current.gps_height = height;
  143. break;
  144. }
  145. if (fl_time < 20000)
  146. fired = true;
  147. if (fired)
  148. FDR[fl_time] = current;
  149. if (conf_debug_dump_flight_data)
  150. std::cout << current.fl_time * 0.0001 << ' ' <<
  151. current.ils_height << ' ' << current.gps_height << ' ' <<
  152. fired << '\n';
  153. }
  154. static void process_flight_ctrl_frame(const char *first, size_t sz)
  155. {
  156. static union {
  157. char buf[512];
  158. tx01_telemetry_frame frame;
  159. } x;
  160. static size_t buf_tail = 0;
  161. const char *last = first + sz;
  162. while (first != last) {
  163. unsigned char byte = (unsigned char) *first;
  164. if (buf_tail == 0 && byte != 0x55) {
  165. first++;
  166. continue;
  167. }
  168. if (buf_tail == 1 && byte != 0xaa) {
  169. if (byte != 0x55)
  170. buf_tail = 0;
  171. first++;
  172. continue;
  173. }
  174. x.buf[buf_tail++] = *first++;
  175. if (buf_tail >= sizeof(x.frame) &&
  176. (sizeof(x.frame) + x.frame.len_payload + sizeof(uint16_t) ==
  177. buf_tail)) {
  178. parse_and_record_flight_data(x.buf, buf_tail);
  179. buf_tail = 0;
  180. }
  181. }
  182. }
  183. static int process_data_in_msg(const char *buf, size_t sz)
  184. {
  185. // std::cout << sz << '\n';
  186. // std::cout << (void *)buf << '\n';
  187. // std::cout << std::hex << 0 + (unsigned char)buf[0] << ' '
  188. // << 0 + (unsigned char)buf[1] << std::dec << '\n';
  189. const tx01_data_frame *frame = (const tx01_data_frame *) buf;
  190. if (frame->magic == 0xeb90) {
  191. switch (frame->channel_id) {
  192. case 9:
  193. case 10:
  194. case 11:
  195. case 12:
  196. append_to_rm100_data(0, frame->data,
  197. size_data_frame_content,
  198. current.fl_time, fired);
  199. break;
  200. case 13:
  201. case 14:
  202. case 15:
  203. case 16:
  204. append_to_rm100_data(1, frame->data,
  205. size_data_frame_content,
  206. current.fl_time, fired);
  207. break;
  208. case 17:
  209. case 18:
  210. case 19:
  211. case 20:
  212. case 21:
  213. case 22:
  214. case 23:
  215. process_flight_ctrl_frame(frame->data,
  216. size_data_frame_content);
  217. break;
  218. }
  219. }
  220. return 0;
  221. }
  222. static int process_telemetry_data(void *ptr, size_t sz)
  223. {
  224. //std::cout << sz << '\n';
  225. //std::cout << std::string((const char *)ptr, (const char *)ptr + sz);
  226. char *first = static_cast<char *>(ptr), *last = first + sz;
  227. while (first != last) {
  228. ptrdiff_t remain = last - first;
  229. if (remain < sizeof(tx01_msg_header))
  230. break;
  231. const tx01_msg_header *p_hdr = tx01_try_match_msg_header(first);
  232. if (!p_hdr) {
  233. ++first;
  234. continue;
  235. }
  236. // ignore incomplete msg at the tail
  237. if (last - first < p_hdr->size)
  238. break;
  239. const tx01_data_msg *p_msg = tx01_try_match_data_msg(p_hdr);
  240. if (p_msg != NULL)
  241. process_data_in_msg(p_msg->data,
  242. p_hdr->size - sizeof(tx01_data_msg) - 4);
  243. first += p_hdr->size;
  244. // std::cout << static_cast<void *>(first) << '\n';
  245. }
  246. for (int k = 0; k < 2; k++) {
  247. if (conf_debug_dump_adc_raw)
  248. dump_rm100_raw_data(0);
  249. auto particles = adc_data_to_particles(rm100_data[k]);
  250. dump_particles(particles, k);
  251. dump_particles_aggr(particles, k, (int)(conf_aggr_ts * 10000 + 0.5),
  252. (int)(conf_aggr_tav/conf_aggr_ts + 0.5));
  253. }
  254. return 0;
  255. }
  256. int main(int argc, const char **argv)
  257. {
  258. using namespace std;
  259. using namespace boost::interprocess;
  260. using namespace boost::filesystem;
  261. const char *filename = "data.bin";
  262. if (argc > 1)
  263. filename = argv[1];
  264. path p = filename;
  265. size_t sz;
  266. try {
  267. sz = file_size(p);
  268. } catch (const filesystem_error &ex) {
  269. cerr << ex.what() << '\n';
  270. exit(1);
  271. }
  272. try {
  273. file_mapping fmap(filename, read_only);
  274. mapped_region region(fmap, read_only, 0, sz);
  275. return process_telemetry_data(region.get_address(), sz);
  276. } catch (const interprocess_exception &ex) {
  277. cerr << ex.what() << '\n';
  278. exit(1);
  279. }
  280. return 0;
  281. }