lvx_file.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. //
  2. // The MIT License (MIT)
  3. //
  4. // Copyright (c) 2019 Livox. All rights reserved.
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. // SOFTWARE.
  23. //
  24. #include "lvx_file.h"
  25. #include <string.h>
  26. #include <time.h>
  27. #include <cmath>
  28. #include "lds.h"
  29. #include "rapidxml/rapidxml.hpp"
  30. #include "rapidxml/rapidxml_utils.hpp"
  31. namespace livox_ros {
  32. #define M_PI 3.14159265358979323846
  33. const uint32_t kMaxLvxFileHeaderLength = 16 * 1024;
  34. const char *kLvxHeaderSigStr = "livox_tech";
  35. const uint32_t kLvxHeaderMagicCode = 0xac0ea767;
  36. LvxFileHandle::LvxFileHandle()
  37. : file_ver_(kLvxFileV1),
  38. device_count_(0),
  39. cur_frame_index_(0),
  40. cur_offset_(0),
  41. data_start_offset_(0),
  42. size_(0),
  43. mode_(0),
  44. state_(0) {
  45. memset((void *)&public_header_, 0, sizeof(public_header_));
  46. memset((void *)&private_header_, 0, sizeof(private_header_));
  47. memset((void *)&private_header_v0_, 0, sizeof(private_header_v0_));
  48. }
  49. bool LvxFileHandle::ReadAndCheckHeader() {
  50. lvx_file_.seekg(0, std::ios::beg);
  51. lvx_file_.read((char *)(&public_header_), sizeof(public_header_));
  52. if (strcmp((const char *)public_header_.signature, kLvxHeaderSigStr)) {
  53. return false;
  54. }
  55. /**
  56. if (public_header_.magic_code != kLvxHeaderMagicCode) {
  57. return false;
  58. }
  59. */
  60. if (public_header_.version[1] > kLvxFileV1) {
  61. printf("Unkown lvx file version[%d.%d.%d.%d]\n", public_header_.version[0],
  62. public_header_.version[1], public_header_.version[2],
  63. public_header_.version[3]);
  64. return false;
  65. }
  66. file_ver_ = public_header_.version[1];
  67. printf("Livox file version[%d]\n", file_ver_);
  68. return true;
  69. }
  70. uint64_t LvxFileHandle::MiniFileSize() {
  71. if (file_ver_ == kLvxFileV1) {
  72. return (sizeof(LvxFilePublicHeader) + sizeof(LvxFilePrivateHeader) +
  73. sizeof(LvxFileDeviceInfo) + sizeof(FrameHeader) +
  74. sizeof(LvxFilePacket));
  75. } else {
  76. return (sizeof(LvxFilePublicHeader) + sizeof(LvxFilePrivateHeaderV0) +
  77. sizeof(LvxFileDeviceInfoV0) + sizeof(FrameHeaderV0) +
  78. sizeof(LvxFilePacketV0));
  79. }
  80. }
  81. uint64_t LvxFileHandle::PrivateHeaderOffset() {
  82. return sizeof(LvxFilePublicHeader);
  83. }
  84. uint64_t LvxFileHandle::DataStartOffset() {
  85. if (file_ver_ == kLvxFileV1) {
  86. return (sizeof(LvxFilePublicHeader) + sizeof(LvxFilePrivateHeader) +
  87. sizeof(LvxFileDeviceInfo) * private_header_.device_count);
  88. } else {
  89. return (sizeof(LvxFilePublicHeader) + sizeof(LvxFilePrivateHeaderV0) +
  90. sizeof(LvxFileDeviceInfoV0) * private_header_v0_.device_count);
  91. }
  92. }
  93. bool LvxFileHandle::AddAndCheckDeviceInfo() {
  94. lvx_file_.seekg(PrivateHeaderOffset(), std::ios::beg);
  95. if (file_ver_ == kLvxFileV1) {
  96. lvx_file_.read((char *)(&private_header_), sizeof(private_header_));
  97. device_count_ = private_header_.device_count;
  98. } else {
  99. lvx_file_.read((char *)(&private_header_v0_), sizeof(private_header_v0_));
  100. device_count_ = private_header_v0_.device_count;
  101. }
  102. if (!device_count_) {
  103. return false;
  104. }
  105. for (int i = 0; i < device_count_; i++) {
  106. LvxFileDeviceInfo device_info;
  107. if (file_ver_ == kLvxFileV1) {
  108. lvx_file_.read((char *)(&device_info), sizeof(LvxFileDeviceInfo));
  109. } else { /* device info v0 to v1 */
  110. LvxFileDeviceInfoV0 device_info_v0;
  111. lvx_file_.read((char *)(&device_info_v0), sizeof(LvxFileDeviceInfoV0));
  112. memcpy((void *)&device_info, (void *)&device_info_v0,
  113. &device_info.extrinsic_enable - device_info.lidar_broadcast_code);
  114. memcpy((void *)&device_info.roll, (void *)&device_info_v0.roll,
  115. sizeof(float) * 6);
  116. device_info.extrinsic_enable = 0;
  117. }
  118. AddDeviceInfo(device_info);
  119. }
  120. return true;
  121. }
  122. bool LvxFileHandle::PrepareDataRead() {
  123. lvx_file_.seekg(DataStartOffset(), std::ios::beg);
  124. FrameHeader frame_header; /* v0&v1 compatible */
  125. lvx_file_.read((char *)(&frame_header), sizeof(frame_header));
  126. if ((frame_header.current_offset != DataStartOffset()) ||
  127. (frame_header.frame_index != 0)) {
  128. return false;
  129. }
  130. /** reset the read position to the start offset of data erea */
  131. lvx_file_.seekg(DataStartOffset(), std::ios::beg);
  132. return true;
  133. }
  134. int LvxFileHandle::Open(const char *filename, std::ios_base::openmode mode) {
  135. if ((mode & std::ios::in) == std::ios::in) {
  136. state_ = kLvxFileOk;
  137. lvx_file_.open(filename, mode | std::ios_base::binary | std::ios_base::ate);
  138. if (!lvx_file_.is_open()) {
  139. state_ = kLvxFileNotExist;
  140. return state_;
  141. }
  142. size_ = lvx_file_.tellg();
  143. lvx_file_.seekg(0, std::ios::beg);
  144. printf("Filesize %lu\n", size_);
  145. if (size_ < MiniFileSize()) {
  146. state_ = kLvxFileSizeFault;
  147. return state_;
  148. }
  149. if (!ReadAndCheckHeader()) {
  150. state_ = kLvxFileHeaderFault;
  151. return state_;
  152. }
  153. if (!AddAndCheckDeviceInfo()) {
  154. state_ = kLvxFileDeviceInfoFault;
  155. return state_;
  156. }
  157. if (!PrepareDataRead()) {
  158. state_ = kLvxFileDataInfoFault;
  159. return state_;
  160. }
  161. } else {
  162. lvx_file_.open(filename, mode | std::ios_base::binary);
  163. if (!lvx_file_.is_open()) {
  164. state_ = kLvxFileNotExist;
  165. return state_;
  166. }
  167. }
  168. return state_;
  169. }
  170. bool LvxFileHandle::Eof() { return lvx_file_.eof(); }
  171. int LvxFileHandle::InitLvxFile() {
  172. time_t curtime = time(nullptr);
  173. char filename[30] = {0};
  174. tm *local_time = localtime(&curtime);
  175. strftime(filename, sizeof(filename), "%Y%m%d%H%M%S", local_time);
  176. return Open(filename, std::ios::out | std::ios::binary);
  177. }
  178. void LvxFileHandle::InitLvxFileHeader() {
  179. char write_buffer[kMaxLvxFileHeaderLength];
  180. cur_offset_ = 0;
  181. std::string signature = kLvxHeaderSigStr;
  182. memcpy(public_header_.signature, signature.c_str(), signature.size());
  183. public_header_.version[0] = 1;
  184. public_header_.version[1] = file_ver_; /* default version 1 */
  185. public_header_.version[2] = 0;
  186. public_header_.version[3] = 0;
  187. public_header_.magic_code = kLvxHeaderMagicCode;
  188. memcpy(&write_buffer[cur_offset_], (void *)&public_header_,
  189. sizeof(public_header_));
  190. cur_offset_ += sizeof(public_header_);
  191. if (file_ver_ == kLvxFileV1) {
  192. private_header_.device_count =
  193. static_cast<uint8_t>(device_info_list_.size());
  194. private_header_.frame_duration = frame_duration_;
  195. device_count_ = private_header_.device_count;
  196. memcpy(&write_buffer[cur_offset_], (void *)&private_header_,
  197. sizeof(private_header_));
  198. cur_offset_ += sizeof(private_header_);
  199. } else {
  200. private_header_v0_.device_count =
  201. static_cast<uint8_t>(device_info_list_.size());
  202. device_count_ = private_header_v0_.device_count;
  203. memcpy(&write_buffer[cur_offset_], (void *)&private_header_v0_,
  204. sizeof(private_header_v0_));
  205. cur_offset_ += sizeof(private_header_v0_);
  206. }
  207. for (int i = 0; i < device_count_; i++) {
  208. if (file_ver_ == kLvxFileV1) {
  209. memcpy(&write_buffer[cur_offset_], (void *)&device_info_list_[i],
  210. sizeof(LvxFileDeviceInfo));
  211. cur_offset_ += sizeof(LvxFileDeviceInfo);
  212. } else {
  213. LvxFileDeviceInfoV0 device_info_v0;
  214. memcpy((void *)&device_info_v0, (void *)&device_info_list_[i],
  215. &device_info_list_[i].extrinsic_enable -
  216. device_info_list_[i].lidar_broadcast_code);
  217. memcpy((void *)&device_info_v0.roll, (void *)&device_info_list_[i].roll,
  218. sizeof(float) * 6);
  219. memcpy(&write_buffer[cur_offset_], (void *)&device_info_v0,
  220. sizeof(device_info_v0));
  221. cur_offset_ += sizeof(device_info_v0);
  222. }
  223. }
  224. lvx_file_.write(&write_buffer[cur_offset_], cur_offset_);
  225. }
  226. void LvxFileHandle::SaveFrameToLvxFile(
  227. std::list<LvxFilePacket> &point_packet_list_temp) {
  228. uint64_t cur_pos = 0;
  229. FrameHeader frame_header = {0};
  230. std::unique_ptr<char[]> write_buffer(new char[kMaxFrameSize]);
  231. frame_header.current_offset = cur_offset_;
  232. frame_header.next_offset = cur_offset_ + sizeof(FrameHeader);
  233. for (auto iter : point_packet_list_temp) {
  234. frame_header.next_offset += iter.pack_size;
  235. }
  236. frame_header.frame_index = cur_frame_index_;
  237. memcpy(write_buffer.get() + cur_pos, (void *)&frame_header,
  238. sizeof(FrameHeader));
  239. cur_pos += sizeof(FrameHeader);
  240. for (auto iter : point_packet_list_temp) {
  241. if (cur_pos + iter.pack_size >= kMaxFrameSize) {
  242. lvx_file_.write((char *)write_buffer.get(), cur_pos);
  243. cur_pos = 0;
  244. memcpy(write_buffer.get() + cur_pos, (void *)&(iter), iter.pack_size);
  245. cur_pos += iter.pack_size;
  246. } else {
  247. memcpy(write_buffer.get() + cur_pos, (void *)&(iter), iter.pack_size);
  248. cur_pos += iter.pack_size;
  249. }
  250. }
  251. lvx_file_.write((char *)write_buffer.get(), cur_pos);
  252. cur_offset_ = frame_header.next_offset;
  253. cur_frame_index_++;
  254. }
  255. void LvxFileHandle::CloseLvxFile() {
  256. if (lvx_file_ && lvx_file_.is_open()) lvx_file_.close();
  257. }
  258. void LvxFileHandle::BasePointsHandle(LivoxEthPacket *data,
  259. LvxFilePacket &packet) {
  260. memcpy((void *)&packet, (void *)data, GetEthPacketLen(data->data_type));
  261. }
  262. int LvxFileHandle::GetDeviceInfo(uint8_t idx, LvxFileDeviceInfo *info) {
  263. if (idx < device_info_list_.size()) {
  264. *info = device_info_list_[idx];
  265. return 0;
  266. }
  267. return -1;
  268. }
  269. int LvxFileHandle::GetPacketsOfFrame(OutPacketBuffer *packets_of_frame) {
  270. if (!lvx_file_ || lvx_file_.eof()) {
  271. state_ = kLvxFileAtEnd;
  272. return kLvxFileAtEnd;
  273. }
  274. uint64_t tmp_size = lvx_file_.tellg();
  275. if (tmp_size >= size_) {
  276. printf("At the file end %lu\n", tmp_size);
  277. state_ = kLvxFileAtEnd;
  278. return kLvxFileAtEnd;
  279. }
  280. FrameHeader frame_header;
  281. FrameHeaderV0 frame_header_v0;
  282. uint64_t read_length;
  283. if (file_ver_ == kLvxFileV1) {
  284. lvx_file_.read((char *)&frame_header, sizeof(frame_header));
  285. if (!lvx_file_) {
  286. return kLvxFileReadFail;
  287. }
  288. if ((size_ < frame_header.current_offset) ||
  289. (frame_header.next_offset < frame_header.current_offset)) {
  290. return kLvxFileFrameHeaderError;
  291. }
  292. packets_of_frame->data_size = DataSizeOfFrame(frame_header);
  293. read_length = packets_of_frame->data_size;
  294. } else {
  295. lvx_file_.read((char *)&frame_header_v0, sizeof(frame_header_v0));
  296. if (!lvx_file_) {
  297. return kLvxFileReadFail;
  298. }
  299. if ((size_ < frame_header_v0.current_offset) ||
  300. (frame_header_v0.next_offset < frame_header_v0.current_offset)) {
  301. return kLvxFileFrameHeaderError;
  302. }
  303. packets_of_frame->data_size = DataSizeOfFrame(frame_header_v0);
  304. read_length = packets_of_frame->data_size;
  305. }
  306. lvx_file_.read((char *)(packets_of_frame->packet), read_length);
  307. if (lvx_file_) {
  308. return kLvxFileOk;
  309. } else {
  310. return kLvxFileReadFail;
  311. }
  312. }
  313. int LvxFileHandle::GetLvxFileReadProgress() {
  314. if (!size_) {
  315. return 0;
  316. }
  317. if (!lvx_file_.eof()) {
  318. return (lvx_file_.tellg() * 100ULL) / size_;
  319. } else {
  320. return 100;
  321. }
  322. }
  323. void ParseExtrinsicXml(DeviceItem &item, LvxFileDeviceInfo &info) {
  324. rapidxml::file<> extrinsic_param("extrinsic.xml");
  325. rapidxml::xml_document<> doc;
  326. doc.parse<0>(extrinsic_param.data());
  327. rapidxml::xml_node<> *root = doc.first_node();
  328. if ("Livox" == (std::string)root->name()) {
  329. for (rapidxml::xml_node<> *device = root->first_node(); device;
  330. device = device->next_sibling()) {
  331. if ("Device" == (std::string)device->name() &&
  332. (strncmp(item.info.broadcast_code, device->value(),
  333. kBroadcastCodeSize) == 0)) {
  334. memcpy(info.lidar_broadcast_code, device->value(), kBroadcastCodeSize);
  335. memset(info.hub_broadcast_code, 0, kBroadcastCodeSize);
  336. info.device_type = item.info.type;
  337. info.device_index = item.handle;
  338. for (rapidxml::xml_attribute<> *param = device->first_attribute();
  339. param; param = param->next_attribute()) {
  340. if ("roll" == (std::string)param->name()) {
  341. info.roll = static_cast<float>(atof(param->value()));
  342. }
  343. if ("pitch" == (std::string)param->name()) {
  344. info.pitch = static_cast<float>(atof(param->value()));
  345. }
  346. if ("yaw" == (std::string)param->name()) {
  347. info.yaw = static_cast<float>(atof(param->value()));
  348. }
  349. if ("x" == (std::string)param->name()) {
  350. info.x = static_cast<float>(atof(param->value()));
  351. }
  352. if ("y" == (std::string)param->name()) {
  353. info.y = static_cast<float>(atof(param->value()));
  354. }
  355. if ("z" == (std::string)param->name()) {
  356. info.z = static_cast<float>(atof(param->value()));
  357. }
  358. }
  359. }
  360. }
  361. }
  362. }
  363. } // namespace livox_ros