Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: UAVCAN UAVCAN_Subscriber
system_utils.hpp
00001 /* 00002 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #pragma once 00006 00007 #include <array> 00008 #include <cassert> 00009 #include <cctype> 00010 #include <fstream> 00011 #include <string> 00012 #include <vector> 00013 #include <cstdint> 00014 #include <algorithm> 00015 #include <utility> 00016 #include <uavcan_linux/exception.hpp> 00017 #include <uavcan/data_type.hpp> 00018 00019 namespace uavcan_linux 00020 { 00021 /** 00022 * This class can find and read machine ID from a text file, represented as 32-char (16-byte) long hexadecimal string, 00023 * possibly with separators (like dashes or colons). If the available ID is more than 16 bytes, extra bytes will be 00024 * ignored. A shorter ID will not be accepted as valid. 00025 * In order to be read, the ID must be located on the first line of the file and must not contain any whitespace 00026 * characters. 00027 * 00028 * Examples of valid ID: 00029 * 0123456789abcdef0123456789abcdef 00030 * 20CE0b1E-8C03-07C8-13EC-00242C491652 00031 */ 00032 class MachineIDReader 00033 { 00034 public: 00035 static constexpr int MachineIDSize = 16; 00036 00037 typedef std::array<std::uint8_t, MachineIDSize> MachineID; 00038 00039 static std::vector<std::string> getDefaultSearchLocations() 00040 { 00041 return 00042 { 00043 "/etc/machine-id", 00044 "/var/lib/dbus/machine-id", 00045 "/sys/class/dmi/id/product_uuid" 00046 }; 00047 } 00048 00049 private: 00050 const std::vector<std::string> search_locations_; 00051 00052 static std::vector<std::string> mergeLists(const std::vector<std::string>& a, const std::vector<std::string>& b) 00053 { 00054 std::vector<std::string> ab; 00055 ab.reserve(a.size() + b.size()); 00056 ab.insert(ab.end(), a.begin(), a.end()); 00057 ab.insert(ab.end(), b.begin(), b.end()); 00058 return ab; 00059 } 00060 00061 bool tryRead(const std::string& location, MachineID& out_id) const 00062 { 00063 /* 00064 * Reading the file 00065 */ 00066 std::string token; 00067 try 00068 { 00069 std::ifstream infile(location); 00070 infile >> token; 00071 } 00072 catch (std::exception&) 00073 { 00074 return false; 00075 } 00076 00077 /* 00078 * Preprocessing the input string - convert to lowercase, remove all non-hex characters, limit to 32 chars 00079 */ 00080 std::transform(token.begin(), token.end(), token.begin(), [](char x) { return std::tolower(x); }); 00081 token.erase(std::remove_if(token.begin(), token.end(), 00082 [](char x){ return (x < 'a' || x > 'f') && !std::isdigit(x); }), 00083 token.end()); 00084 00085 if (token.length() < (MachineIDSize * 2)) 00086 { 00087 return false; 00088 } 00089 token.resize(MachineIDSize * 2); // Truncating 00090 00091 /* 00092 * Parsing the string as hex bytes 00093 */ 00094 auto sym = std::begin(token); 00095 for (auto& byte : out_id) 00096 { 00097 assert(sym != std::end(token)); 00098 byte = std::stoi(std::string{*sym++, *sym++}, nullptr, 16); 00099 } 00100 00101 return true; 00102 } 00103 00104 public: 00105 /** 00106 * This class can use extra seach locations. If provided, they will be checked first, before default ones. 00107 */ 00108 MachineIDReader(const std::vector<std::string>& extra_search_locations = {}) 00109 : search_locations_(mergeLists(extra_search_locations, getDefaultSearchLocations())) 00110 { } 00111 00112 /** 00113 * Just like @ref readAndGetLocation(), but this one doesn't return location where this ID was obtained from. 00114 */ 00115 MachineID read() const { return readAndGetLocation().first; } 00116 00117 /** 00118 * This function checks available search locations and reads the ID from the first valid location. 00119 * It returns std::pair<> with ID and the file path where it was read from. 00120 * In case if none of the search locations turned out to be valid, @ref uavcan_linux::Exception will be thrown. 00121 */ 00122 std::pair<MachineID, std::string> readAndGetLocation() const 00123 { 00124 for (auto x : search_locations_) 00125 { 00126 auto out = MachineID(); 00127 if (tryRead(x, out)) 00128 { 00129 return {out, x}; 00130 } 00131 } 00132 throw Exception("Failed to read machine ID"); 00133 } 00134 }; 00135 00136 /** 00137 * This class computes unique ID for a UAVCAN node in a Linux application. 00138 * It takes the following inputs: 00139 * - Unique machine ID 00140 * - Node name string (e.g. "org.uavcan.linux_app.dynamic_node_id_server") 00141 * - Instance ID byte, e.g. node ID (optional) 00142 */ 00143 inline std::array<std::uint8_t, 16> makeApplicationID(const MachineIDReader::MachineID& machine_id, 00144 const std::string& node_name, 00145 const std::uint8_t instance_id = 0) 00146 { 00147 union HalfID 00148 { 00149 std::uint64_t num; 00150 std::uint8_t bytes[8]; 00151 00152 HalfID(std::uint64_t arg_num) : num(arg_num) { } 00153 }; 00154 00155 std::array<std::uint8_t, 16> out; 00156 00157 // First 8 bytes of the application ID are CRC64 of the machine ID in native byte order 00158 { 00159 uavcan::DataTypeSignatureCRC crc; 00160 crc.add(machine_id.data(), static_cast<unsigned>(machine_id.size())); 00161 HalfID half(crc.get()); 00162 std::copy_n(half.bytes, 8, out.begin()); 00163 } 00164 00165 // Last 8 bytes of the application ID are CRC64 of the node name and optionally node ID 00166 { 00167 uavcan::DataTypeSignatureCRC crc; 00168 crc.add(reinterpret_cast<const std::uint8_t*>(node_name.c_str()), static_cast<unsigned>(node_name.length())); 00169 crc.add(instance_id); 00170 HalfID half(crc.get()); 00171 std::copy_n(half.bytes, 8, out.begin() + 8); 00172 } 00173 00174 return out; 00175 } 00176 00177 }
Generated on Tue Jul 12 2022 17:17:34 by
1.7.2