Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers file_server.hpp Source File

file_server.hpp

00001 /*
00002  * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_PROTOCOL_FILE_SERVER_HPP_INCLUDED
00006 #define UAVCAN_PROTOCOL_FILE_SERVER_HPP_INCLUDED
00007 
00008 #include <uavcan/build_config.hpp>
00009 #include <uavcan/debug.hpp>
00010 #include <uavcan/node/service_server.hpp>
00011 #include <uavcan/util/method_binder.hpp>
00012 // UAVCAN types
00013 #include <uavcan/protocol/file/GetInfo.hpp>
00014 #include <uavcan/protocol/file/GetDirectoryEntryInfo.hpp>
00015 #include <uavcan/protocol/file/Read.hpp>
00016 #include <uavcan/protocol/file/Write.hpp>
00017 #include <uavcan/protocol/file/Delete.hpp>
00018 
00019 namespace uavcan
00020 {
00021 /**
00022  * The file server backend should implement this interface.
00023  * Note that error codes returned by these methods are defined in uavcan.protocol.file.Error; these are
00024  * not the same as libuavcan-internal error codes defined in uavcan.error.hpp.
00025  */
00026 class UAVCAN_EXPORT IFileServerBackend
00027 {
00028 public:
00029     typedef protocol::file::Path::FieldTypes::path Path;
00030     typedef protocol::file::EntryType EntryType;
00031     typedef protocol::file::Error Error;
00032 
00033     /**
00034      * All read operations must return this number of bytes, unless end of file is reached.
00035      */
00036     enum { ReadSize = protocol::file::Read::Response::FieldTypes::data::MaxSize };
00037 
00038     /**
00039      * Shortcut for uavcan.protocol.file.Path.SEPARATOR.
00040      */
00041     static char getPathSeparator() { return static_cast<char>(protocol::file::Path::SEPARATOR); }
00042 
00043     /**
00044      * Backend for uavcan.protocol.file.GetInfo.
00045      * Refer to uavcan.protocol.file.EntryType for the list of available bit flags.
00046      * Implementation of this method is required.
00047      * On success the method must return zero.
00048      */
00049     virtual int16_t getInfo(const Path& path, uint64_t& out_size, EntryType& out_type) = 0;
00050 
00051     /**
00052      * Backend for uavcan.protocol.file.Read.
00053      * Implementation of this method is required.
00054      * @ref inout_size is set to @ref ReadSize; read operation is required to return exactly this amount, except
00055      * if the end of file is reached.
00056      * On success the method must return zero.
00057      */
00058     virtual int16_t read(const Path& path, const uint64_t offset, uint8_t* out_buffer, uint16_t& inout_size) = 0;
00059 
00060     // Methods below are optional.
00061 
00062     /**
00063      * Backend for uavcan.protocol.file.Write.
00064      * Implementation of this method is NOT required; by default it returns uavcan.protocol.file.Error.NOT_IMPLEMENTED.
00065      * On success the method must return zero.
00066      */
00067     virtual int16_t write(const Path& path, const uint64_t offset, const uint8_t* buffer, const uint16_t size)
00068     {
00069         (void)path;
00070         (void)offset;
00071         (void)buffer;
00072         (void)size;
00073         return Error::NOT_IMPLEMENTED;
00074     }
00075 
00076     /**
00077      * Backend for uavcan.protocol.file.Delete. ('delete' is a C++ keyword, so 'remove' is used instead)
00078      * Implementation of this method is NOT required; by default it returns uavcan.protocol.file.Error.NOT_IMPLEMENTED.
00079      * On success the method must return zero.
00080      */
00081     virtual int16_t remove(const Path& path)
00082     {
00083         (void)path;
00084         return Error::NOT_IMPLEMENTED;
00085     }
00086 
00087     /**
00088      * Backend for uavcan.protocol.file.GetDirectoryEntryInfo.
00089      * Refer to uavcan.protocol.file.EntryType for the list of available bit flags.
00090      * Implementation of this method is NOT required; by default it returns uavcan.protocol.file.Error.NOT_IMPLEMENTED.
00091      * On success the method must return zero.
00092      */
00093     virtual int16_t getDirectoryEntryInfo(const Path& directory_path, const uint32_t entry_index,
00094                                           EntryType& out_type, Path& out_entry_full_path)
00095     {
00096         (void)directory_path;
00097         (void)entry_index;
00098         (void)out_type;
00099         (void)out_entry_full_path;
00100         return Error::NOT_IMPLEMENTED;
00101     }
00102 
00103     virtual ~IFileServerBackend() { }
00104 };
00105 
00106 /**
00107  * Basic file server implements only the following services:
00108  *      uavcan.protocol.file.GetInfo
00109  *      uavcan.protocol.file.Read
00110  * Also see @ref IFileServerBackend.
00111  */
00112 class BasicFileServer
00113 {
00114     typedef MethodBinder<BasicFileServer*,
00115         void (BasicFileServer::*)(const protocol::file::GetInfo::Request&, protocol::file::GetInfo::Response&)>
00116             GetInfoCallback;
00117 
00118     typedef MethodBinder<BasicFileServer*,
00119         void (BasicFileServer::*)(const protocol::file::Read::Request&, protocol::file::Read::Response&)>
00120             ReadCallback;
00121 
00122     ServiceServer<protocol::file::GetInfo, GetInfoCallback> get_info_srv_;
00123     ServiceServer<protocol::file::Read, ReadCallback> read_srv_;
00124 
00125     void handleGetInfo(const protocol::file::GetInfo::Request& req, protocol::file::GetInfo::Response& resp)
00126     {
00127         resp.error.value = backend_.getInfo(req.path.path, resp.size, resp.entry_type);
00128     }
00129 
00130     void handleRead(const protocol::file::Read::Request& req, protocol::file::Read::Response& resp)
00131     {
00132         uint16_t inout_size = resp.data.capacity();
00133 
00134         resp.data.resize(inout_size);
00135 
00136         resp.error.value = backend_.read(req.path.path, req.offset, resp.data.begin(), inout_size);
00137 
00138         if (resp.error.value != protocol::file::Error::OK)
00139         {
00140             inout_size = 0;
00141         }
00142 
00143         if (inout_size > resp.data.capacity())
00144         {
00145             UAVCAN_ASSERT(0);
00146             resp.error.value = protocol::file::Error::UNKNOWN_ERROR;
00147         }
00148         else
00149         {
00150             resp.data.resize(inout_size);
00151         }
00152     }
00153 
00154 protected:
00155     IFileServerBackend& backend_;       ///< Derived types can use it
00156 
00157 public:
00158     BasicFileServer(INode& node, IFileServerBackend& backend)
00159         : get_info_srv_(node)
00160         , read_srv_(node)
00161         , backend_(backend)
00162     { }
00163 
00164     int start()
00165     {
00166         int res = get_info_srv_.start(GetInfoCallback(this, &BasicFileServer::handleGetInfo));
00167         if (res < 0)
00168         {
00169             return res;
00170         }
00171 
00172         res = read_srv_.start(ReadCallback(this, &BasicFileServer::handleRead));
00173         if (res < 0)
00174         {
00175             return res;
00176         }
00177 
00178         return 0;
00179     }
00180 };
00181 
00182 /**
00183  * Full file server implements all file services:
00184  *      uavcan.protocol.file.GetInfo
00185  *      uavcan.protocol.file.Read
00186  *      uavcan.protocol.file.Write
00187  *      uavcan.protocol.file.Delete
00188  *      uavcan.protocol.file.GetDirectoryEntryInfo
00189  * Also see @ref IFileServerBackend.
00190  */
00191 class FileServer : protected BasicFileServer
00192 {
00193     typedef MethodBinder<FileServer*,
00194         void (FileServer::*)(const protocol::file::Write::Request&, protocol::file::Write::Response&)>
00195             WriteCallback;
00196 
00197     typedef MethodBinder<FileServer*,
00198         void (FileServer::*)(const protocol::file::Delete::Request&, protocol::file::Delete::Response&)>
00199             DeleteCallback;
00200 
00201     typedef MethodBinder<FileServer*,
00202         void (FileServer::*)(const protocol::file::GetDirectoryEntryInfo::Request&,
00203                              protocol::file::GetDirectoryEntryInfo::Response&)>
00204             GetDirectoryEntryInfoCallback;
00205 
00206     ServiceServer<protocol::file::Write, WriteCallback> write_srv_;
00207     ServiceServer<protocol::file::Delete, DeleteCallback> delete_srv_;
00208     ServiceServer<protocol::file::GetDirectoryEntryInfo, GetDirectoryEntryInfoCallback> get_directory_entry_info_srv_;
00209 
00210     void handleWrite(const protocol::file::Write::Request& req, protocol::file::Write::Response& resp)
00211     {
00212         resp.error.value = backend_.write(req.path.path, req.offset, req.data.begin(), req.data.size());
00213     }
00214 
00215     void handleDelete(const protocol::file::Delete::Request& req, protocol::file::Delete::Response& resp)
00216     {
00217         resp.error.value = backend_.remove(req.path.path);
00218     }
00219 
00220     void handleGetDirectoryEntryInfo(const protocol::file::GetDirectoryEntryInfo::Request& req,
00221                                      protocol::file::GetDirectoryEntryInfo::Response& resp)
00222     {
00223         resp.error.value = backend_.getDirectoryEntryInfo(req.directory_path.path, req.entry_index,
00224                                                           resp.entry_type, resp.entry_full_path.path);
00225     }
00226 
00227 public:
00228     FileServer(INode& node, IFileServerBackend& backend)
00229         : BasicFileServer(node, backend)
00230         , write_srv_(node)
00231         , delete_srv_(node)
00232         , get_directory_entry_info_srv_(node)
00233     { }
00234 
00235     int start()
00236     {
00237         int res = BasicFileServer::start();
00238         if (res < 0)
00239         {
00240             return res;
00241         }
00242 
00243         res = write_srv_.start(WriteCallback(this, &FileServer::handleWrite));
00244         if (res < 0)
00245         {
00246             return res;
00247         }
00248 
00249         res = delete_srv_.start(DeleteCallback(this, &FileServer::handleDelete));
00250         if (res < 0)
00251         {
00252             return res;
00253         }
00254 
00255         res = get_directory_entry_info_srv_.start(
00256             GetDirectoryEntryInfoCallback(this, &FileServer::handleGetDirectoryEntryInfo));
00257         if (res < 0)
00258         {
00259             return res;
00260         }
00261 
00262         return 0;
00263     }
00264 };
00265 
00266 }
00267 
00268 #endif // Include guard