libuav original
Dependents: UAVCAN UAVCAN_Subscriber
storage.hpp
00001 /* 00002 * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #ifndef UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_CENTRALIZED_STORAGE_HPP_INCLUDED 00006 #define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_CENTRALIZED_STORAGE_HPP_INCLUDED 00007 00008 #include <uavcan/build_config.hpp> 00009 #include <uavcan/debug.hpp> 00010 #include <uavcan/protocol/dynamic_node_id_server/storage_marshaller.hpp> 00011 #include <uavcan/protocol/dynamic_node_id_server/event.hpp> 00012 #include <uavcan/util/bitset.hpp> 00013 00014 namespace uavcan 00015 { 00016 namespace dynamic_node_id_server 00017 { 00018 namespace centralized 00019 { 00020 /** 00021 * This class transparently replicates its state to the storage backend, keeping the most recent state in memory. 00022 * Writes are slow, reads are instantaneous. 00023 */ 00024 class Storage 00025 { 00026 typedef BitSet<NodeID::Max + 1> OccupationMask ; 00027 typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeStatic, 00028 BitLenToByteLen<NodeID::Max + 1>::Result> 00029 OccupationMaskArray; 00030 00031 IStorageBackend& storage_; 00032 OccupationMask occupation_mask_; 00033 00034 static IStorageBackend::String getOccupationMaskKey() { return "occupation_mask"; } 00035 00036 static OccupationMask maskFromArray(const OccupationMaskArray& array) 00037 { 00038 OccupationMask mask; 00039 for (uint8_t byte = 0; byte < array.size(); byte++) 00040 { 00041 for (uint8_t bit = 0; bit < 8; bit++) 00042 { 00043 mask[byte * 8U + bit] = (array[byte] & (1U << bit)) != 0; 00044 } 00045 } 00046 return mask; 00047 } 00048 00049 static OccupationMaskArray maskToArray(const OccupationMask & mask) 00050 { 00051 OccupationMaskArray array; 00052 for (uint8_t byte = 0; byte < array.size(); byte++) 00053 { 00054 for (uint8_t bit = 0; bit < 8; bit++) 00055 { 00056 if (mask[byte * 8U + bit]) 00057 { 00058 array[byte] = static_cast<uint8_t>(array[byte] | (1U << bit)); 00059 } 00060 } 00061 } 00062 return array; 00063 } 00064 00065 public: 00066 Storage(IStorageBackend& storage) : 00067 storage_(storage) 00068 { } 00069 00070 /** 00071 * This method reads only the occupation mask from the storage. 00072 */ 00073 int init() 00074 { 00075 StorageMarshaller io(storage_); 00076 OccupationMaskArray array; 00077 io.get(getOccupationMaskKey(), array); 00078 occupation_mask_ = maskFromArray(array); 00079 return 0; 00080 } 00081 00082 /** 00083 * This method invokes storage IO. 00084 * Returned value indicates whether the entry was successfully appended. 00085 */ 00086 int add(const NodeID node_id, const UniqueID& unique_id) 00087 { 00088 if (!node_id.isUnicast()) 00089 { 00090 return -ErrInvalidParam; 00091 } 00092 00093 StorageMarshaller io(storage_); 00094 00095 // If next operations fail, we'll get a dangling entry, but it's absolutely OK. 00096 { 00097 uint32_t node_id_int = node_id.get(); 00098 int res = io.setAndGetBack(StorageMarshaller::convertUniqueIDToHex(unique_id), node_id_int); 00099 if (res < 0) 00100 { 00101 return res; 00102 } 00103 if (node_id_int != node_id.get()) 00104 { 00105 return -ErrFailure; 00106 } 00107 } 00108 00109 // Updating the mask in the storage 00110 OccupationMask new_occupation_mask = occupation_mask_; 00111 new_occupation_mask[node_id.get()] = true; 00112 OccupationMaskArray occupation_array = maskToArray(new_occupation_mask); 00113 00114 int res = io.setAndGetBack(getOccupationMaskKey(), occupation_array); 00115 if (res < 0) 00116 { 00117 return res; 00118 } 00119 if (occupation_array != maskToArray(new_occupation_mask)) 00120 { 00121 return -ErrFailure; 00122 } 00123 00124 // Updating the cached mask only if the storage was updated successfully 00125 occupation_mask_ = new_occupation_mask; 00126 00127 return 0; 00128 } 00129 00130 /** 00131 * Returns an invalid node ID if there's no such allocation. 00132 */ 00133 NodeID getNodeIDForUniqueID(const UniqueID& unique_id) const 00134 { 00135 StorageMarshaller io(storage_); 00136 uint32_t node_id = 0; 00137 io.get(StorageMarshaller::convertUniqueIDToHex(unique_id), node_id); 00138 return (node_id > 0 && node_id <= NodeID::Max) ? NodeID(static_cast<uint8_t>(node_id)) : NodeID(); 00139 } 00140 00141 bool isNodeIDOccupied(NodeID node_id) const { return occupation_mask_[node_id.get()]; } 00142 00143 uint8_t getSize() const { return static_cast<uint8_t>(occupation_mask_.count()); } 00144 }; 00145 00146 } 00147 } 00148 } 00149 00150 #endif // Include guard
Generated on Tue Jul 12 2022 17:17:34 by 1.7.2