Files
oopt-tai/tools/framework/examples/basic/basic.hpp
2020-01-04 11:11:19 -08:00

223 lines
9.3 KiB
C++

#ifndef __BASIC_HPP__
#define __BASIC_HPP__
#include "platform.hpp"
#include <atomic>
namespace tai::basic {
const uint8_t BASIC_NUM_MODULE = 1;
const uint8_t BASIC_NUM_NETIF = 1;
const uint8_t BASIC_NUM_HOSTIF = 2;
// the same object ID format as examples/stub is used
const uint8_t OBJECT_TYPE_SHIFT = 48;
class Platform : public tai::Platform {
public:
Platform(const tai_service_method_table_t * services);
tai_status_t create(tai_object_type_t type, tai_object_id_t module_id, uint32_t attr_count, const tai_attribute_t * const attr_list, tai_object_id_t *id);
tai_status_t remove(tai_object_id_t id);
tai_object_type_t get_object_type(tai_object_id_t id);
tai_object_id_t get_module_id(tai_object_id_t id);
};
class Module;
class NetIf;
class HostIf;
using S_Module = std::shared_ptr<Module>;
using S_NetIf = std::shared_ptr<NetIf>;
using S_HostIf = std::shared_ptr<HostIf>;
// The FSM for state handling of the hardware
//
// It is not mandatory to implement FSM to use the TAI library framework.
// You can see that examples/stub doesn't implement it.
//
// The TAI library framework defines 4 FSM states, INIT, WAITING_CONFIGURATION, READY and END.
// The FSM starts with INIT and stops when it reaches to END
// The TAI library framework doesn't have any assumption on how to transit between these states.
//
// You need to implement FSM::cb(FSMState state) which returns fsm_callback for handling every states other than END.
// ( If FSM::cb(FSMState state) returns nullptr, the state goes to END )
// The callback returns the next state which the FSM transit.
//
// When the framework want to transit to another state (described in basic.cpp when this happens),
// the framework triggers an event. This event can be captured through eventfd.
// `int tai::FSM::get_event_fd()` returns the event fd and `FSMState tai::FSM::next_state()` returns
// the next state which the framework is requesting to transite.
//
// In typical case, the callback respects what the framework is requesting, and return the next state promptly.
//
// If needed, you can define additional states and implement fsm_callbacks for them.
//
// You can implement FSM::state_change_cb() which returns fsm_state_change_callback.
// This callback will get called everytime when the FSM state changes.
//
// In this example, a FSM is created per module and shared among module and its netif/hostif.
// A FSM is fed to a constructor of Object.
//
// set_module/set_netif/set_hostif are implemented to enable the access to TAI objects from FSM
// it is not mandatory and required by the framework, but you will find it necessary most of the time to do meaningful stuff
class FSM : public tai::FSM {
// requirements to inherit tai::FSM
public:
bool configured();
private:
fsm_state_change_callback state_change_cb();
fsm_callback cb(FSMState state);
// methods/fields specific to this example
public:
FSM(tai::Location loc) : m_loc(loc), m_module(nullptr), m_netif(nullptr), m_hostif{} {}
int set_module(S_Module module);
int set_netif(S_NetIf netif);
int set_hostif(S_HostIf hostif, int index);
tai_status_t remove_module();
tai_status_t remove_netif();
tai_status_t remove_hostif(int index);
tai_status_t set_tx_dis(const tai_attribute_t* const attribute);
tai_status_t get_tx_dis(tai_attribute_t* const attribute);
tai::Location location() {
return m_loc;
}
private:
FSMState _state_change_cb(FSMState current, FSMState next, void* user);
FSMState _init_cb(FSMState current, void* user);
FSMState _waiting_configuration_cb(FSMState current, void* user);
FSMState _ready_cb(FSMState current, void* user);
S_Module m_module;
S_NetIf m_netif;
S_HostIf m_hostif[BASIC_NUM_HOSTIF];
std::atomic<bool> m_no_transit;
tai::Location m_loc;
};
using S_FSM = std::shared_ptr<FSM>;
template<tai_object_type_t T>
class Object : public tai::Object<T> {
public:
Object(uint32_t count, const tai_attribute_t *list, S_FSM fsm) : tai::Object<T>(count, list, fsm, reinterpret_cast<void*>(fsm.get()), std::bind(&Object::setter, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), std::bind(&Object::getter, this, std::placeholders::_1, std::placeholders::_2)) {}
tai_object_id_t id() const {
return m_id;
}
protected:
tai_object_id_t m_id;
private:
tai_status_t setter(const tai_attribute_t* const attribute, FSMState* fsm, void* const user) {
auto meta = tai_metadata_get_attr_metadata(T, attribute->id);
m_config[attribute->id] = std::make_shared<Attribute>(meta, *attribute);
return TAI_STATUS_SUCCESS;
}
tai_status_t getter(tai_attribute_t* const attribute, void* const user) {
auto it = m_config.find(attribute->id);
auto meta = tai_metadata_get_attr_metadata(T, attribute->id);
if ( it != m_config.end() ) {
return tai_metadata_deepcopy_attr_value(meta, it->second->raw(), attribute);
}
if ( meta == nullptr || meta->isreadonly ) {
return TAI_STATUS_ATTR_NOT_SUPPORTED_0;
} else if ( meta->defaultvaluetype == TAI_DEFAULT_VALUE_TYPE_NONE ) {
return tai_metadata_clear_attr_value(meta, attribute);
} else if ( meta->defaultvalue != NULL ) {
tai_attribute_t in = {attribute->id, *meta->defaultvalue};
return tai_metadata_deepcopy_attr_value(meta, &in, attribute);
}
return TAI_STATUS_UNINITIALIZED;
}
std::map<tai_attr_id_t, S_Attribute> m_config;
};
class Module : public Object<TAI_OBJECT_TYPE_MODULE> {
public:
// 4th argument to the Object constructor is a user context which is passed in getter()/setter() callbacks
// getter()/setter() callbacks is explained in basic.hpp
Module(uint32_t count, const tai_attribute_t *list, S_FSM fsm) : m_fsm(fsm), Object(count, list, fsm) {
std::string loc;
for ( auto i = 0; i < count; i++ ) {
if ( list[i].id == TAI_MODULE_ATTR_LOCATION ) {
loc = std::string(list[i].value.charlist.list, list[i].value.charlist.count);
break;
}
}
if ( loc == "" ) {
throw Exception(TAI_STATUS_MANDATORY_ATTRIBUTE_MISSING);
}
auto i = std::stoi(loc);
m_id = static_cast<tai_object_id_t>(uint64_t(TAI_OBJECT_TYPE_MODULE) << OBJECT_TYPE_SHIFT | i);
if ( i >= BASIC_NUM_MODULE ) {
throw Exception(TAI_STATUS_INVALID_PARAMETER);
}
}
S_FSM fsm() {
return m_fsm;
}
private:
S_FSM m_fsm;
};
class NetIf : public Object<TAI_OBJECT_TYPE_NETWORKIF> {
public:
NetIf(S_Module module, uint32_t count, const tai_attribute_t *list) : Object(count, list, module->fsm()) {
int index = -1;
for ( auto i = 0; i < count; i++ ) {
if ( list[i].id == TAI_NETWORK_INTERFACE_ATTR_INDEX ) {
index = list[i].value.u32;
break;
}
}
if ( index < 0 ) {
throw Exception(TAI_STATUS_MANDATORY_ATTRIBUTE_MISSING);
}
if ( index >= BASIC_NUM_NETIF ) {
throw Exception(TAI_STATUS_INVALID_PARAMETER);
}
m_id = static_cast<tai_object_id_t>(uint64_t(TAI_OBJECT_TYPE_NETWORKIF) << OBJECT_TYPE_SHIFT | (module->id() & 0xff) << 8 | index);
}
};
class HostIf : public Object<TAI_OBJECT_TYPE_HOSTIF> {
public:
HostIf(S_Module module, uint32_t count, const tai_attribute_t *list) : Object(count, list, module->fsm()) {
int index = -1;
for ( auto i = 0; i < count; i++ ) {
if ( list[i].id == TAI_HOST_INTERFACE_ATTR_INDEX ) {
index = list[i].value.u32;
break;
}
}
if ( index < 0 ) {
throw Exception(TAI_STATUS_MANDATORY_ATTRIBUTE_MISSING);
}
if ( index >= BASIC_NUM_HOSTIF ) {
throw Exception(TAI_STATUS_INVALID_PARAMETER);
}
m_id = static_cast<tai_object_id_t>(uint64_t(TAI_OBJECT_TYPE_HOSTIF) << OBJECT_TYPE_SHIFT | (module->id() & 0xff) << 8 | index);
}
};
};
#ifdef TAI_EXPOSE_PLATFORM
using tai::basic::Platform;
#endif
#endif // __BASIC_HPP__