libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers storage.hpp Source File

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