Initial commit: Livox SDK2 source (excluding build artifacts)

This commit is contained in:
gardentech
2026-08-26 01:38:14 +09:00
commit 34a9a52cd4
221 changed files with 54102 additions and 0 deletions
+363
View File
@@ -0,0 +1,363 @@
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "file_manager.h"
#ifdef WIN32
#include <direct.h>
#else
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <string>
#include <map>
#include "base/logging.h"
namespace livox {
namespace lidar {
constexpr uint16_t kLengthOfTimeInFilename = 19;
constexpr bool kFOk = 0;
#ifdef WIN32
uint64_t GetDirTotalSize(const std::string& dir_name) {
uint64_t total_size = 0;
WIN32_FIND_DATAA data;
HANDLE sh = NULL;
sh = FindFirstFileA((dir_name +"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE ) {
LOG_ERROR("get directory stat error");
return 0;
}
do {
// skip current and parent
if (std::string(data.cFileName).compare(".") != 0 && std::string(data.cFileName).compare("..") != 0)
{
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
// directory, then search it recursievly
total_size += GetDirTotalSize(dir_name +"\\"+ data.cFileName);
} else {
// otherwise get object size and add it to directory size
total_size += (__int64) (data.nFileSizeHigh * (MAXDWORD ) + data.nFileSizeLow);
}
}
} while (FindNextFileA(sh, &data));
FindClose(sh);
return total_size;
}
bool GetFileNames(const std::string& dir_name, std::multimap<std::string, std::string> &filenames) {
uint64_t total_size = 0;
WIN32_FIND_DATAA data;
HANDLE sh = NULL;
sh = FindFirstFileA((dir_name +"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE ) {
LOG_ERROR("get directory stat error");
return false;
}
do {
// skip current and parent
if (std::string(data.cFileName).compare(".") == 0 || std::string(data.cFileName).compare("..") == 0) {
continue;
}
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
// directory, then search it recursievly
GetFileNames(dir_name +"\\"+ data.cFileName, filenames);
} else {
// otherwise get file name and add it to std::map<std::string, std::string> &filenames
if(!StoreFileName(data.cFileName, filenames)) {
LOG_ERROR("StoreFileName {} failed", data.cFileName);
}
}
} while (FindNextFileA(sh, &data));
FindClose(sh);
return true;
}
bool ChangeHiddenFiles(const std::string& dir_name) {
uint64_t total_size = 0;
WIN32_FIND_DATAA data;
HANDLE sh = NULL;
sh = FindFirstFileA((dir_name +"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE ) {
LOG_ERROR("get directory stat error");
return 0;
}
do {
// skip current and parent
if (std::string(data.cFileName).compare(".") != 0 && std::string(data.cFileName).compare("..") != 0)
{
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
// directory, then search it recursievly
ChangeHiddenFiles(dir_name +"\\"+ data.cFileName);
} else {
// otherwise get file name and change it to normal file name
char first_element = '.';
if (data.cFileName[0] != first_element) {
continue;
}
std::string filename(data.cFileName);
if (filename.empty()) {
continue;
}
if(access((dir_name + "\\" + filename).c_str(), kFOk) != 0) {
LOG_WARN("The file to be renamed : {} does not exist ", filename);
continue;
}
std::string file_name_cut = filename.substr(1);
if(access((dir_name + "\\" + file_name_cut).c_str(), kFOk) == 0) {
if (remove((dir_name + "\\" + file_name_cut).c_str()) != 0) {
LOG_WARN("Failed to remove the existing file: {}. errno: {}", file_name_cut, errno);
}
}
if (rename((dir_name + "\\" + filename).c_str(), (dir_name + "\\" + file_name_cut).c_str()) != 0) {
LOG_WARN("Rename hidden file {} failed. errno: {}", filename, errno);
}
}
}
} while (FindNextFileA(sh, &data));
FindClose(sh);
return true;
}
#else
uint64_t GetDirTotalSize(const std::string& dir_name) {
struct stat dir_stat;
if (stat(dir_name.c_str(), &dir_stat) != EXIT_SUCCESS) {
LOG_ERROR("get directory stat error");
return 0;
}
if (S_ISREG(dir_stat.st_mode)) {
return dir_stat.st_size;
}
if (!S_ISDIR(dir_stat.st_mode)) {
LOG_WARN("unknown directory type: {}", dir_name);
return 0;
}
uint64_t total_size = 0;
DIR *dirp = opendir(dir_name.c_str());
if (!dirp) {
LOG_ERROR("opendir: {} failed", dir_name);
return 0;
}
struct dirent *dp = nullptr;
while ((dp = readdir(dirp)) != nullptr) {
// ignore . and ..
if (strcmp(".", dp -> d_name) == EXIT_SUCCESS || strcmp("..", dp -> d_name) == EXIT_SUCCESS) {
continue;
}
std::string sub_dir_name = dir_name;
sub_dir_name.append("/").append(dp -> d_name);
total_size += GetDirTotalSize(sub_dir_name.c_str());
}
closedir(dirp);
return total_size;
}
bool GetFileNames(const std::string& dir_name, std::multimap<std::string, std::string> &filenames) {
DIR *dirp = opendir(dir_name.c_str());
if (!dirp) {
LOG_ERROR("opendir: {} failed", dir_name);
return false;
}
struct dirent *dp = nullptr;
while ((dp = readdir(dirp)) != nullptr) {
if (strcmp(dp->d_name, ".") == 0 ||
strcmp(dp->d_name, "..") == 0 ||
dp->d_type == DT_LNK) {
continue;
}
if (dp->d_type == DT_REG) {
if (dp->d_name[0] == '.') {
continue;
}
if(!StoreFileName(dp->d_name, filenames)) {
LOG_ERROR("StoreFileName {} failed", dp->d_name);
}
} else if (dp->d_type == DT_DIR) {
std::string sub_dir_name = dir_name;
sub_dir_name.append("/").append(dp -> d_name);
GetFileNames(sub_dir_name, filenames);
}
}
closedir(dirp);
return true;
}
bool ChangeHiddenFiles(const std::string& dir_name) {
if (dir_name.empty()) {
return false;
}
DIR *dirp = opendir(dir_name.c_str());
if (!dirp) {
LOG_ERROR("opendir: {} failed", dir_name);
return false;
}
struct dirent *dp = nullptr;
while ((dp = readdir(dirp)) != nullptr) {
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
continue;
} else if (dp->d_type == DT_REG) {
char first_element = '.';
if (dp->d_name[0] != first_element) {
continue;
}
std::string filename(dp->d_name);
if (filename.empty()) {
continue;
}
if(access((dir_name + "/" + filename).c_str(), kFOk) != 0) {
LOG_WARN("The file to be renamed : {} does not exist ", filename);
continue;
}
std::string file_name_cut = filename.substr(1);
if(access((dir_name + "/" + file_name_cut).c_str(), kFOk) == 0) {
if (remove((dir_name + "/" + file_name_cut).c_str()) != 0) {
LOG_WARN("Failed to remove the existing file: {}. errno: {}", file_name_cut, errno);
}
}
if (rename((dir_name + "/" + filename).c_str(), (dir_name + "/" + file_name_cut).c_str()) != 0) {
LOG_WARN("Rename hidden file {} failed. errno: {}", filename, errno);
}
} else if (dp->d_type == DT_LNK) {
continue;
} else if (dp->d_type == DT_DIR) {
std::string sub_dir_name = dir_name;
sub_dir_name.append("/");
sub_dir_name.append(dp -> d_name);
ChangeHiddenFiles(sub_dir_name);
}
}
closedir(dirp);
return true;
}
bool DeleteHidFiles(const std::string& dir_name) {
DIR *dirp = opendir(dir_name.c_str());
if (!dirp) {
LOG_ERROR("opendir: {} failed", dir_name);
return false;
}
struct dirent *dp = nullptr;
while ((dp = readdir(dirp)) != nullptr) {
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
continue;
} else if (dp->d_type == DT_REG) {
char first_element = '.';
if (dp->d_name[0] != first_element) {
continue;
}
std::string filename(dp->d_name);
remove((dir_name + "/" + filename).c_str());
} else if (dp->d_type == DT_LNK) {
continue;
} else if (dp->d_type == DT_DIR) {
std::string sub_dir_name = dir_name;
sub_dir_name.append("/");
sub_dir_name.append(dp -> d_name);
DeleteHidFiles(sub_dir_name);
}
}
closedir(dirp);
return true;
}
#endif
bool ChangeCurrentFileName(const std::string& dir_name, std::string file_name) {
if (file_name.empty()) {
return false;
}
if (file_name.at(0) != '.') {
return false;
}
if(access((dir_name + "/" + file_name).c_str(), kFOk) != 0) {
LOG_WARN("The file to be renamed : {} does not exist ", file_name);
return false;
}
std::string file_name_cut = file_name.substr(1);
if(access((dir_name + "/" + file_name_cut).c_str(), kFOk) == 0) {
if (remove((dir_name + "/" + file_name_cut).c_str()) != 0) {
LOG_WARN("Failed to remove the existing file: {}. errno: {}", file_name_cut, errno);
}
}
if (rename((dir_name + "/" + file_name).c_str(), (dir_name + "/" + file_name_cut).c_str()) != 0) {
LOG_WARN("Rename hidden file {} failed. errno: {}", file_name, errno);
return false;
}
return true;
}
bool StoreFileName(const char* filename, std::multimap<std::string, std::string> &filenames) {
std::string str_filename(filename);
if (str_filename.empty()) {
return false;
}
std::string record_time = str_filename.substr(0, kLengthOfTimeInFilename);
filenames.insert(std::make_pair(record_time, str_filename));
return true;
}
bool MakeDirecotory(std::string dir) {
int flag = -1;
#ifdef WIN32
flag = mkdir(dir.c_str());
#else
flag = mkdir(dir.c_str(), 0777);
#endif // WIN32
return (flag == 0);
}
bool IsDirectoryExits(std::string dir) {
return access(dir.c_str(), 0) == EXIT_SUCCESS;
}
} // namespace lidar
} // namespace livox
+50
View File
@@ -0,0 +1,50 @@
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#ifndef LIVOX_FILE_MANAGER_
#define LIVOX_FILE_MANAGER_
#include <string>
#include <vector>
#include <map>
namespace livox {
namespace lidar {
uint64_t GetDirTotalSize(const std::string& dir_name);
bool GetFileNames(const std::string& dir_name, std::multimap<std::string, std::string>& files_name);
bool ChangeHiddenFiles(const std::string& dir_name);
bool ChangeCurrentFileName(const std::string& dir_name, std::string file_name);
bool StoreFileName(const char* filename, std::multimap<std::string, std::string>& files_name);
bool DeleteHidFiles(const std::string& dir_name);
bool MakeDirecotory(std::string dir);
bool IsDirectoryExits(std::string dir);
} // namespace lidar
} // namespace livox
#endif // LIVOX_FILE_MANAGER_
+209
View File
@@ -0,0 +1,209 @@
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "logger_handler.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include "base/logging.h"
#include "command_handler/command_impl.h"
#include "device_manager.h"
#include "livox_lidar_def.h"
#include "file_manager.h"
namespace livox {
namespace lidar {
std::string GetCurFormatTime() {
std::time_t t = std::time(nullptr);
std::stringstream format_time;
format_time << std::put_time(std::localtime(&t), "%Y-%m-%d_%H-%M-%S");
return format_time.str();
}
void LoggerHandler::Init() {
is_stop_write_.store(false);
thread_ptr_ = std::make_shared<std::thread>(&LoggerHandler::SaveToFile, this);
}
void LoggerHandler::Destory() {
if (thread_ptr_) {
is_stop_write_.store(true);
thread_ptr_->join();
thread_ptr_ = nullptr;
}
for (auto &file: current_files_) {
auto& fp = file.second.fp;
if (fp) {
std::fclose(fp);
fp = nullptr;
}
}
}
void LoggerHandler::SaveToFile() {
while (!is_stop_write_.load()) {
Write();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void LoggerHandler::StoreLogBag(DeviceLoggerFilePushRequest* req, uint8_t flag) {
LOG_INFO("Transform Data Length : {}", req->data_length);
WriteBuffer write_buff {};
write_buff.log_type = req->log_type;
write_buff.flag = flag;
write_buff.file_index = req->file_index;
write_buff.data_length = req->data_length;
write_buff.trans_index = req->trans_index;
write_buff.data_ptr.reset(new uint8_t[req->data_length], [] (uint8_t * buff) { delete[] buff;});
memcpy(write_buff.data_ptr.get(), req->data, write_buff.data_length);
{
std::lock_guard<std::mutex> lock(queue_mutex_);
queue_.push(std::move(write_buff));
}
}
void LoggerHandler::CreateFile(const WriteBuffer& write_buff) {
std::string current_time_str = GetCurFormatTime();
uint8_t log_type = write_buff.log_type;
log_branch_path_[log_type] = log_root_path_ + (log_root_path_.back() == '/' ? "" : "/") + "type_" + std::to_string(log_type);
if (!IsDirectoryExits(log_branch_path_[log_type])) {
if (!MakeDirecotory(log_branch_path_[log_type])) {
LOG_ERROR("Can't Create Dir {}", log_branch_path_[log_type]);
return;
}
}
// The handling of the four given scenarios has already been included.
if (current_files_[log_type].fp) {
if ((current_files_[log_type].trans_index + 1) != write_buff.trans_index) {
LOG_WARN("The terminal command to end the {}rd log file has been lost.", current_files_[log_type].file_index);
}
std::fclose(current_files_[log_type].fp);
current_files_[log_type].fp = nullptr;
ChangeCurrentFileName(log_branch_path_[log_type], current_files_[log_type].file_name);
}
std::string file_path = log_branch_path_[log_type] + "/" +
"." + current_time_str + "_" + serial_num_ +
"_" + std::to_string(log_type) + "_" + std::to_string(write_buff.file_index) + ".dat";
LOG_INFO("file path : {}", file_path);
current_files_[log_type].fp = std::fopen(file_path.c_str(), "ab");
if (current_files_[log_type].fp) {
std::fwrite(write_buff.data_ptr.get(), 1, write_buff.data_length, current_files_[log_type].fp);
std::fflush(current_files_[log_type].fp);
}
current_files_[log_type].flag = write_buff.flag;
current_files_[log_type].file_index = write_buff.file_index;
current_files_[log_type].trans_index = write_buff.trans_index;
current_files_[log_type].file_name = "." + current_time_str + "_" + serial_num_ +
"_" + std::to_string(log_type) + "_" + std::to_string(write_buff.file_index) + ".dat";
LOG_INFO("Create File index: {}", (int)write_buff.file_index);
}
void LoggerHandler::WriteFile(const WriteBuffer& write_buff) {
uint8_t log_type = write_buff.log_type;
//check file index is equal
if (current_files_[log_type].file_index != write_buff.file_index) {
LOG_WARN("Log Type: {}, File Index error: last file index: {}, current file index: {}",
(int)log_type,
current_files_[log_type].file_index,
write_buff.file_index);
return;
}
if (current_files_[log_type].trans_index + 1 != write_buff.trans_index && write_buff.trans_index != 1) {
LOG_WARN("Log Type: {}, Trans Index error: last trans index: {}, current trans index: {}",
(int)log_type,
current_files_[log_type].trans_index,
write_buff.trans_index);
}
if (current_files_[log_type].fp) {
std::fwrite(write_buff.data_ptr.get(), 1, write_buff.data_length, current_files_[log_type].fp);
std::fflush(current_files_[log_type].fp);
} else {
LOG_ERROR("There is an issue with the lidar firmware, the starting file command is not sent from lidar. trans_index: {}", write_buff.trans_index);
}
current_files_[log_type].flag = write_buff.flag;
current_files_[log_type].trans_index = write_buff.trans_index;
}
void LoggerHandler::StopFile(const WriteBuffer& write_buff) {
uint8_t log_type = write_buff.log_type;
if (current_files_[log_type].flag == static_cast<uint8_t>(Flag::kEndFile) &&
current_files_[log_type].trans_index + 1 != write_buff.trans_index) {
LOG_ERROR("There is an issue with the lidar firmware. Multiple terminal commands to close the log files with discontinuous trans_index.");
}
if (current_files_[log_type].fp) {
std::fclose(current_files_[log_type].fp);
current_files_[log_type].fp = nullptr;
ChangeCurrentFileName(log_branch_path_[log_type], current_files_[log_type].file_name);
}
current_files_[log_type].fp = nullptr;
current_files_[log_type].flag = write_buff.flag;
current_files_[log_type].trans_index = write_buff.trans_index;
}
void LoggerHandler::Write() {
std::queue<WriteBuffer> queue;
{
std::lock_guard<std::mutex> lock(queue_mutex_);
queue.swap(queue_);
}
while (!queue.empty()) {
WriteBuffer& write_buff = queue.front();
if (write_buff.trans_index < current_files_[write_buff.log_type].trans_index &&
write_buff.flag != static_cast<uint8_t>(Flag::kCreateFile)) {
continue;
}
if(write_buff.flag == static_cast<uint8_t>(Flag::kCreateFile)) {
CreateFile(write_buff);
}
if(write_buff.flag == static_cast<uint8_t>(Flag::kEndFile)) {
StopFile(write_buff);
}
if(write_buff.flag == static_cast<uint8_t>(Flag::kTransferData)) {
WriteFile(write_buff);
}
queue.pop();
}
}
} // namespace lidar
} // namespace livox
+102
View File
@@ -0,0 +1,102 @@
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#ifndef LIVOX_LOGGER_HANDLER_
#define LIVOX_LOGGER_HANDLER_
#include <string>
#include <algorithm>
#include <map>
#include <queue>
#include <mutex>
#include <thread>
#include <stdio.h>
#include "base/io_thread.h"
#include "base/noncopyable.h"
#include "command_handler/command_impl.h"
#include "comm/comm_port.h"
#include "comm/define.h"
namespace livox {
namespace lidar {
class LoggerHandler {
public:
struct CurrentFileInfo {
uint8_t flag {0};
uint8_t file_index {0};
uint32_t trans_index {0};
std::FILE* fp {nullptr};
std::string file_name {""};
};
struct WriteBuffer {
uint8_t log_type;
uint8_t flag {0};
uint8_t file_index {0};
uint16_t data_length {0};
uint32_t trans_index {0};
std::shared_ptr<uint8_t> data_ptr = std::make_shared<uint8_t>(0);
};
public:
explicit LoggerHandler(std::string log_root_path, std::string serial_num) :
log_root_path_(log_root_path),
serial_num_(serial_num),
is_stop_write_(false),
thread_ptr_(nullptr) {
};
~LoggerHandler() {
Destory();
}
void Init();
void Destory();
void StoreLogBag(DeviceLoggerFilePushRequest* req, uint8_t flag);
void CreateFile(const WriteBuffer& write_buff);
void WriteFile(const WriteBuffer& write_buff);
void StopFile(const WriteBuffer& write_buff);
void Write();
void SaveToFile();
private:
std::string log_root_path_;
std::map <uint8_t, std::string> log_branch_path_;
std::string serial_num_;
std::map <uint8_t, CurrentFileInfo> current_files_;
std::mutex queue_mutex_;
std::queue<WriteBuffer> queue_;
std::atomic<bool> is_stop_write_;
std::shared_ptr<std::thread> thread_ptr_;
};
} // namespace lidar
} // namespace livox
#endif // LIVOX_LOGGER_HANDLER_
+378
View File
@@ -0,0 +1,378 @@
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "logger_manager.h"
#include "file_manager.h"
#include "command_handler/general_command_handler.h"
#include "base/logging.h"
#include "comm/protocol.h"
#include "comm/generate_seq.h"
#include <map>
#include <iomanip>
#include <chrono>
#include <iostream>
#include <condition_variable>
#ifdef WIN32
#include<winsock2.h>
#else
#include <sys/socket.h>
#endif
namespace livox {
namespace lidar {
constexpr uint16_t kMaxExceptionLogCachSizeMb = 200;
constexpr uint16_t kExceptionLogCacheRatio = 1;
constexpr uint16_t kRealtimeLogCacheRatio = 3;
LoggerManager::LoggerManager()
: log_enable_(false),
log_cycle_delete_enable_(false),
log_root_path_("./"),
max_realtimelog_cache_size_(150 * 1024 * 1024),
max_exceptionlog_cache_size_(50 * 1024 * 1024),
comm_port_(nullptr),
cycle_delete_thread_(nullptr),
cond_(false),
is_destroy_(false) {
}
LoggerManager& LoggerManager::GetInstance() {
static LoggerManager logger_manager;
return logger_manager;
}
bool LoggerManager::Init(std::shared_ptr<LivoxLidarLoggerCfg> lidar_logger_cfg_ptr) {
if (lidar_logger_cfg_ptr == nullptr ||
lidar_logger_cfg_ptr->lidar_log_enable == false) {
log_enable_.store(false);
return true;
}
// Do not enable the log when the allocated space is equal to 0 MB and greater than 1000 TB
if (lidar_logger_cfg_ptr->lidar_log_cache_size == 0 || lidar_logger_cfg_ptr->lidar_log_cache_size > 1000000000) {
log_enable_.store(false);
return true;
}
comm_port_.reset(new CommPort());
log_enable_.store(lidar_logger_cfg_ptr->lidar_log_enable);
// Only 200 MB of exception log space will be allocated.
if (lidar_logger_cfg_ptr->lidar_log_cache_size >
kMaxExceptionLogCachSizeMb * (kExceptionLogCacheRatio + kRealtimeLogCacheRatio) / kExceptionLogCacheRatio) {
max_exceptionlog_cache_size_ = kMaxExceptionLogCachSizeMb * 1024 * 1024;
max_realtimelog_cache_size_ = (lidar_logger_cfg_ptr->lidar_log_cache_size - kMaxExceptionLogCachSizeMb) * 1024 * 1024;
} else {
max_realtimelog_cache_size_ = (lidar_logger_cfg_ptr->lidar_log_cache_size * kRealtimeLogCacheRatio /
(kExceptionLogCacheRatio + kRealtimeLogCacheRatio)) * 1024 * 1024;
max_exceptionlog_cache_size_ = (lidar_logger_cfg_ptr->lidar_log_cache_size * kExceptionLogCacheRatio /
(kExceptionLogCacheRatio + kRealtimeLogCacheRatio)) * 1024 * 1024;
}
if (!InitLoggerSavePath(lidar_logger_cfg_ptr->lidar_log_path)) {
LOG_ERROR("Init logger save path failed");
return false;
}
if (!ChangeHiddenFiles(lidar_logger_cfg_ptr->lidar_log_path)) {
LOG_ERROR("Change hidden files to normal files failed");
}
log_cycle_delete_enable_.store(true);
cycle_delete_thread_ = std::make_shared<std::thread>(&LoggerManager::CycleDelete, this);
return true;
}
bool LoggerManager::GetLogEnable() {
return log_enable_.load();
}
bool LoggerManager::InitLoggerSavePath(std::string log_root_path) {
std::string log_root_dir = log_root_path + (log_root_path.back() == '/' ? "" : "/") + "lidar_log/";
if (access(log_root_dir.c_str(), 0) != EXIT_SUCCESS) {
if (!MakeDirecotory(log_root_dir)) {
LOG_ERROR("Can't Create Dir {}", log_root_dir);
return false;
}
}
log_root_path_ = log_root_dir;
return true;
}
void LoggerManager::AddDevice(const uint32_t handle, const DetectionData* detection_data) {
if (devices_info_.find(handle) == devices_info_.end()) {
devices_info_[handle].sn = detection_data->sn;
devices_info_[handle].dev_type = detection_data->dev_type;
std::string lidar_ip = std::to_string(detection_data->lidar_ip[0]) + "." +
std::to_string(detection_data->lidar_ip[1]) + "." +
std::to_string(detection_data->lidar_ip[2]) + "." +
std::to_string(detection_data->lidar_ip[3]);
devices_info_[handle].lidar_ip = lidar_ip;
devices_info_[handle].cmd_port = detection_data->cmd_port;
}
}
void LoggerManager::RemoveDevice(const uint32_t handle) {
if (devices_info_.find(handle) != devices_info_.end()) {
devices_info_.erase(handle);
}
}
livox_status LoggerManager::StartLogger(const uint32_t handle, const LivoxLidarLogType log_type,
LivoxLidarLoggerCallback cb, void* client_data) {
if (log_enable_.load() == false) {
LOG_INFO("Disable logger.");
return kLivoxLidarStatusSuccess;
}
LOG_INFO("Start Logger handler: {}, log_type: {}", handle, log_type);
EnableDeviceLoggerRequest enable_req = {};
enable_req.log_type = static_cast<uint8_t>(log_type);
enable_req.enable = true;
return GeneralCommandHandler::GetInstance().SendLoggerCommand(handle,
kCommandIDLidarCollectionLog, (uint8_t*)&enable_req, sizeof(EnableDeviceLoggerRequest),
MakeCommandCallback<LivoxLidarLoggerResponse>(cb, client_data));
}
void LoggerManager::Handler(uint32_t handle, uint16_t lidar_port, uint8_t *buf, uint32_t buf_size) {
if (!log_enable_.load()) {
return;
}
if (buf == nullptr || buf_size == 0) {
return;
}
CommPacket packet;
memset(&packet, 0, sizeof(packet));
if (!(comm_port_->ParseCommStream((uint8_t*)buf, buf_size, &packet))) {
LOG_INFO("Parse GeneralCommandHandler Command Stream failed.");
return;
}
if (packet.cmd_id != kCommandIDLidarPushLog) {
return;
}
auto data = static_cast<DeviceLoggerFilePushRequest*>((void *)packet.data);
uint8_t flag = data->flag;
if (flag & 1) {
DeviceLoggerFilePushReponse response = {};
response.ret_code = 0x00;
response.log_type = data->log_type;
response.file_index = data->file_index;
response.trans_index = data->trans_index;
GeneralCommandHandler::GetInstance().SendLoggerCommand(handle, kCommandIDLidarPushLog,
(uint8_t*)&response, sizeof(DeviceLoggerFilePushReponse),
MakeCommandCallback<DeviceLoggerFilePushReponse>(nullptr, nullptr)); //Send ACK
}
if (flag & (1 << 1)) {
OnLoggerCreate(handle, data);
return;
}
if (flag & (1 << 2)) {
OnLoggerStopped(handle, data);
return;
}
OnLoggerTransfer(handle, data);
}
void LoggerManager::OnLoggerCreate(const uint32_t handle, DeviceLoggerFilePushRequest* data) {
if (handlers_.find(handle) == handlers_.end()) {
if (devices_info_.find(handle) != devices_info_.end()) {
auto serial_num = devices_info_[handle].sn;
handlers_[handle] = std::make_shared<LoggerHandler>(log_root_path_, serial_num);
handlers_[handle]->Init();
}
}
auto & handler = handlers_[handle];
handler->StoreLogBag(data, static_cast<uint8_t>(Flag::kCreateFile));
}
void LoggerManager::OnLoggerStopped(const uint32_t handle, DeviceLoggerFilePushRequest* data) {
if (handlers_.find(handle) == handlers_.end()) {
LOG_INFO("LogType: {} Stop! File doesn't create", (int)data->log_type);
return;
}
auto & handler = handlers_[handle];
handler->StoreLogBag(data, static_cast<uint8_t>(Flag::kEndFile));
{
std::lock_guard<std::mutex> lock(mutex_);
cond_ = true;
cv_.notify_one();
}
}
void LoggerManager::OnLoggerTransfer(const uint32_t handle, DeviceLoggerFilePushRequest* data) {
if (handlers_.find(handle) == handlers_.end()) {
LOG_ERROR("LogType : {} File doesn't create", (int)data->log_type);
return;
}
auto & handler = handlers_[handle];
handler->StoreLogBag(data, static_cast<uint8_t>(Flag::kTransferData));
}
void LoggerManager::CycleDelete() {
std::string realtime_log_save_path_ = log_root_path_ + (log_root_path_.back() == '/' ? "" : "/") + "type_0";
std::string exception_log_save_path_ = log_root_path_ + (log_root_path_.back() == '/' ? "" : "/") + "type_1";
while (log_cycle_delete_enable_.load()) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait_for(lock, std::chrono::seconds(600), [&]{ return cond_; });
if (IsDirectoryExits(realtime_log_save_path_) && (GetDirTotalSize(realtime_log_save_path_) > max_realtimelog_cache_size_)) {
if (!GetFileNames(realtime_log_save_path_, realtime_files_)) {
LOG_ERROR("Can not get filenames in this directory: {}", realtime_log_save_path_);
}
while (GetDirTotalSize(realtime_log_save_path_) > max_realtimelog_cache_size_ && realtime_files_.begin() != realtime_files_.end()) {
remove((realtime_log_save_path_ + "/" + realtime_files_.begin()->second).c_str());
realtime_files_.erase(realtime_files_.begin());
}
realtime_files_.clear();
}
if (IsDirectoryExits(exception_log_save_path_) && GetDirTotalSize(exception_log_save_path_) > max_exceptionlog_cache_size_) {
if (!GetFileNames(exception_log_save_path_, exception_files_)) {
LOG_ERROR("Can not get filenames in this directory: {}", exception_log_save_path_);
}
while (GetDirTotalSize(exception_log_save_path_) > max_exceptionlog_cache_size_ && exception_files_.begin() != exception_files_.end()) {
remove((exception_log_save_path_ + "/" + exception_files_.begin()->second).c_str());
exception_files_.erase(exception_files_.begin());
}
exception_files_.clear();
}
cond_ = false;
}
}
void LoggerManager::StopAllLogger() {
if (!log_enable_.load()) {
return;
}
for (auto it = devices_info_.begin(); it != devices_info_.end(); ++it) {
const uint32_t handle = it->first;
StopLogger(handle, kLivoxLidarRealTimeLog, nullptr, nullptr);
}
}
livox_status LoggerManager::StopLogger(const uint32_t handle, const LivoxLidarLogType log_type,
LivoxLidarLoggerCallback cb, void* client_data) {
LOG_INFO("Stop Logger handler: {}, log_type: {}", handle, log_type);
EnableDeviceLoggerRequest enable_req = {};
enable_req.log_type = log_type;
enable_req.enable = false;
return GeneralCommandHandler::GetInstance().SendLoggerCommand(handle,
kCommandIDLidarCollectionLog, (uint8_t*)&enable_req, sizeof(EnableDeviceLoggerRequest),
MakeCommandCallback<LivoxLidarLoggerResponse>(cb, client_data));
}
void LoggerManager::LoggerStopCallback(livox_status status, uint32_t handle, LivoxLidarLoggerResponse* response, void* client_data) {
if (status != kLivoxLidarStatusSuccess) {
LOG_ERROR("Lidar:{} stop logger failed, the status:{}", handle, status);
if (client_data) {
LoggerManager* manager = static_cast<LoggerManager*>(client_data);
manager->StopLogger(handle, kLivoxLidarRealTimeLog, LoggerManager::LoggerStopCallback, client_data);
}
return;
}
if (response == nullptr) {
LOG_ERROR("Lidar:{} stop logger failed, the response is nullptr.", handle);
LoggerManager* manager = static_cast<LoggerManager*>(client_data);
manager->StopLogger(handle, kLivoxLidarRealTimeLog, LoggerManager::LoggerStopCallback, client_data);
return;
}
if (response->ret_code != 0) {
LOG_ERROR("Lidar:{} stop logger failed, the ret_code:{}.", handle, response->ret_code);
LoggerManager* manager = static_cast<LoggerManager*>(client_data);
manager->StopLogger(handle, kLivoxLidarRealTimeLog, LoggerManager::LoggerStopCallback, client_data);
return;
}
LOG_INFO("The lidar:{} stop logger succ.\n", handle);
LoggerManager* manager = static_cast<LoggerManager*>(client_data);
manager->RemoveDevice(handle);
}
void LoggerManager::Destory() {
if(is_destroy_) {
return;
}
log_cycle_delete_enable_.store(false);
{
std::lock_guard<std::mutex> lock(mutex_);
cond_ = true;
cv_.notify_one();
}
if (cycle_delete_thread_) {
cycle_delete_thread_->join();
cycle_delete_thread_ = nullptr;
}
for (auto it = handlers_.begin(); it != handlers_.end(); ++it) {
it->second->Destory();
}
if (!handlers_.empty()) {
handlers_.clear();
}
StopAllLogger();
if (log_enable_.load()) {
ChangeHiddenFiles(log_root_path_);
}
log_enable_.store(false);
is_destroy_.store(true);
}
LoggerManager::~LoggerManager() {
Destory();
}
} // namespace lidar
} // namespace livox
+122
View File
@@ -0,0 +1,122 @@
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#ifndef LIVOX_LOGGER_MANAGER_H_
#define LIVOX_LOGGER_MANAGER_H_
#include <functional>
#include <memory>
#include <mutex>
#include <condition_variable>
#include "livox_lidar_def.h"
#include "livox_lidar_api.h"
#include "logger_handler.h"
#include "base/io_thread.h"
#include "comm/define.h"
#include "base/network/network_util.h"
namespace livox {
namespace lidar {
#pragma pack(1)
typedef enum {
kLidarLoggerCreate,
kLidarLoggerStop,
kLidarUnknown
} LogState;
struct LogInfo {
LogInfo() {
this->log_state = LogState::kLidarUnknown;
this->total_log_size = 0;
}
LogState log_state;
uint64_t total_log_size;
};
#pragma pack()
class LoggerManager {
private:
LoggerManager();
LoggerManager(const LoggerManager& other) = delete;
LoggerManager& operator=(const LoggerManager& other) = delete;
public:
typedef std::chrono::steady_clock::time_point TimePoint;
~LoggerManager();
static LoggerManager& GetInstance();
bool Init(std::shared_ptr<LivoxLidarLoggerCfg> lidar_logger_cfg_ptr);
bool GetLogEnable();
void AddDevice(const uint32_t handle, const DetectionData* detection_data);
void RemoveDevice(const uint32_t handle);
void Destory();
livox_status StartLogger(const uint32_t handle, const LivoxLidarLogType log_type, LivoxLidarLoggerCallback cb, void* client_data);
livox_status StopLogger(const uint32_t handle, const LivoxLidarLogType log_type, LivoxLidarLoggerCallback cb, void* client_data);
void Handler(uint32_t handle, uint16_t lidar_port, uint8_t *buf, uint32_t buf_size);
static void LoggerStopCallback(livox_status status, uint32_t handle, LivoxLidarLoggerResponse* response, void* client_data);
private:
bool InitLoggerSavePath(std::string log_root_path);
void CreateDeviceDir(const uint32_t handle, const LidarDeviceInfo& device_info);
void OnLoggerCreate(const uint32_t handle, DeviceLoggerFilePushRequest* data);
void OnLoggerStopped(const uint32_t handle, DeviceLoggerFilePushRequest* data);
void OnLoggerTransfer(const uint32_t handle, DeviceLoggerFilePushRequest* data);
void CycleDelete();
void StopAllLogger();
private:
std::atomic<bool> log_enable_;
std::atomic<bool> log_cycle_delete_enable_;
std::string log_root_path_;
uint64_t max_realtimelog_cache_size_;
uint64_t max_exceptionlog_cache_size_;
std::unique_ptr<CommPort> comm_port_;
std::shared_ptr<std::thread> cycle_delete_thread_;
bool cond_;
std::mutex mutex_;
std::condition_variable cv_;
std::map<uint32_t, LidarDeviceInfo> devices_info_;
std::map<uint32_t, std::shared_ptr<LoggerHandler>> handlers_;
std::multimap<std::string, std::string> realtime_files_;
std::multimap<std::string, std::string> exception_files_;
std::atomic<bool> is_destroy_;
};
} // namespace lidar
} // namespace livox
#endif // LIVOX_LOGGER_MANAGER_H_