pool_ptr pool(context_t& context, const std::string& name) { auto pool = context.config().component_group("postgres").get(name); if(!pool) { throw error_t(std::errc::argument_out_of_domain, "postgres component with name '{}' not found", name); } return context.repository().get<pool_t>("postgres", context, name, pool->args()); }
// I2C Slave mode void i2c_interrupt(void) { // Test if there is really an interrupt switch (status_reg) { // SLAVE TRANSMITTER MODE case DATA_TX: // Slave TX callback ctx.data_cb(TX, &data_reg); break; // SLAVE RECEIVER MODE case ADDR_MATCH: break; // Data has been received on SLA+W; ACK has been returned. case DATA_RX: // Slave RX callback ctx.data_cb(RX, &data_reg); break; // Data has been received on general call;ACK has been returned. case DATA_RXGC: // Slave RX general call callback ctx.data_cb(RXGC, &data_reg); break; // OTHER case STOP_CATCHED: ctx.data_cb = idle; ctx.data_cb(END, &data_reg); default: break; } }
/* compute the current binary context */ void ContextTree::getContext(const history_t &h, context_t &context) const { context.clear(); for (size_t i=0; i < m_depth; ++i) { context.push_back(h[h.size()-i-1]); } }
/** * Unicorn trait for service creation. * Trait to create unicorn service by name. All instances are cached by name as it is done in storage. */ unicorn_ptr unicorn(context_t& context, const std::string& name) { auto unicorn = context.config().unicorns().get(name); if(!unicorn) { throw error_t(error::component_not_found, "unicorn component \"{}\" not found in the config", name); } return context.repository().get<unicorn_t>(unicorn->type(), context, name, unicorn->args()); }
actor_base<Protocol>::actor_base(context_t& context, io::dispatch_ptr_t prototype) : m_context(context), m_log(context.log("core/asio", {{"service", prototype->name()}})), metrics(new metrics_t{ context.metrics_hub().counter<std::int64_t>(cocaine::format("{}.connections.accepted", prototype->name())), context.metrics_hub().counter<std::int64_t>(cocaine::format("{}.connections.rejected", prototype->name())) }), m_prototype(std::move(prototype)) {}
multicast_t::multicast_t(context_t& context, interface& locator, const std::string& name, const dynamic_t& args): category_type(context, locator, name, args), m_context(context), m_log(context.log(name)), m_locator(locator), m_cfg(args.to<multicast_cfg_t>()), m_socket(locator.asio()), m_timer(locator.asio()) { m_socket.open(m_cfg.endpoint.protocol()); m_socket.set_option(socket_base::reuse_address(true)); if(m_cfg.endpoint.address().is_v4()) { m_socket.bind(udp::endpoint(address_v4::any(), m_cfg.endpoint.port())); } else { m_socket.bind(udp::endpoint(address_v6::any(), m_cfg.endpoint.port())); } if(args.as_object().count("interface")) { auto interface = args.as_object().at("interface"); if(m_cfg.endpoint.address().is_v4()) { m_socket.set_option(multicast::outbound_interface(interface.to<ip::address>().to_v4())); } else { m_socket.set_option(multicast::outbound_interface(interface.as_uint())); } } m_socket.set_option(multicast::enable_loopback(args.as_object().at("loopback", false).as_bool())); m_socket.set_option(multicast::hops(args.as_object().at("hops", 1u).as_uint())); COCAINE_LOG_INFO(m_log, "joining multicast group '%s'", m_cfg.endpoint)( "uuid", m_locator.uuid() ); m_socket.set_option(multicast::join_group(m_cfg.endpoint.address())); const auto announce = std::make_shared<announce_t>(); m_socket.async_receive_from(buffer(announce->buffer.data(), announce->buffer.size()), announce->endpoint, std::bind(&multicast_t::on_receive, this, ph::_1, ph::_2, announce) ); m_signals = std::make_shared<dispatch<context_tag>>(name); m_signals->on<context::prepared>(std::bind(&multicast_t::on_publish, this, std::error_code())); context.listen(m_signals, m_locator.asio()); }
app_dispatch_t(context_t& context, const std::string& name, std::shared_ptr<overseer_t> overseer_) : dispatch<io::app_tag>(name), log(context.log(format("%s/dispatch", name))), overseer(std::move(overseer_)) { on<io::app::enqueue>(std::make_shared<slot_type>( std::bind(&app_dispatch_t::on_enqueue, this, ph::_1, ph::_2, ph::_3) )); on<io::app::info>(std::bind(&app_dispatch_t::on_info, this)); // TODO: Temporary here to test graceful app terminating. on<io::app::test>([&](const std::string& v) { COCAINE_LOG_DEBUG(log, "processing test '%s' event", v); if (v == "0") { overseer.lock()->terminate(); } else { std::vector<std::string> slaves; { auto pool = overseer.lock()->get_pool(); for (const auto& p : *pool) { slaves.push_back(p.first); } } for (auto& s : slaves) { overseer.lock()->despawn(s, overseer_t::despawn_policy_t::graceful); } } }); }
adhoc_t::adhoc_t(context_t& context, const std::string& _local_uuid, const std::string& name, const dynamic_t& args): category_type(context, _local_uuid, name, args), m_log(context.log(name)) { std::random_device rd; m_random_generator.seed(rd()); }
logging_t::logging_t(context_t& context, io::reactor_t& reactor, const std::string& name, const Json::Value& args): category_type(context, reactor, name, args) { auto logger = std::ref(context.logger()); using cocaine::logging::logger_concept_t; on<io::logging::emit>("emit", std::bind(&logger_concept_t::emit, logger, _1, _2, _3)); on<io::logging::verbosity>("verbosity", std::bind(&logger_concept_t::verbosity, logger)); }
logging_t::logging_t(context_t& context, io::reactor_t& reactor, const std::string& name, const Json::Value& args): api::service_t(context, reactor, name, args), implementation<io::logging_tag>(context, name) { auto logger = std::ref(context.logger()); using cocaine::logging::logger_concept_t; on<io::logging::emit>(std::bind(&logger_concept_t::emit, logger, _1, _2, _3)); on<io::logging::verbosity>(std::bind(&logger_concept_t::verbosity, logger)); }
void msg_complete(msg_dir_t dir) { switch (ctx.msg.reg) { case WRITE_ID: // Get and save a new given ID id_update(ctx.msg.data[0]); break; case GET_ID: case GET_MODULE_TYPE: case GET_STATUS: case GET_FIRM_REVISION: // ERROR ctx.status.rx_error = TRUE; break; default: if (dir == RX) ctx.rx_cb(dir, &ctx.msg); else ctx.rxgc_cb(dir, &ctx.msg); break; } }
agent_t::agent_t( context_t ctx ) : m_current_state_ptr( &st_default ) , m_was_defined( false ) , m_state_listener_controller( new impl::state_listener_controller_t ) , m_handler_finder{ // Actual handler finder is dependent on msg_tracing status. impl::internal_env_iface_t{ ctx.env() }.is_msg_tracing_enabled() ? &agent_t::handler_finder_msg_tracing_enabled : &agent_t::handler_finder_msg_tracing_disabled } , m_subscriptions( ctx.options().query_subscription_storage_factory()( self_ptr() ) ) , m_message_limits( message_limit::impl::info_storage_t::create_if_necessary( ctx.options().giveout_message_limits() ) ) , m_env( ctx.env() ) , m_event_queue( nullptr ) , m_direct_mbox( impl::internal_env_iface_t{ ctx.env() }.create_mpsc_mbox( self_ptr(), m_message_limits.get() ) ) // It is necessary to enable agent subscription in the // constructor of derived class. , m_working_thread_id( so_5::query_current_thread_id() ) , m_agent_coop( 0 ) , m_priority( ctx.options().query_priority() ) { }
actor_t::actor_t(context_t& context, std::shared_ptr<io::reactor_t> reactor, std::unique_ptr<api::service_t> service): m_context(context), m_log(context.log(service->prototype().name())), m_reactor(reactor) { const io::basic_dispatch_t* prototype = &service->prototype(); // Aliasing the pointer to the service to point to the dispatch (sub-)object. m_prototype = std::shared_ptr<const io::basic_dispatch_t>( std::shared_ptr<api::service_t>(std::move(service)), prototype ); }
/* create (if necessary) all of the nodes in the current context */ void ContextTree::createNodesInCurrentContext(const context_t &context) { CTNode **ctn = &m_root; for (size_t i = 0; i < context.size(); i++) { ctn = &((*ctn)->m_child[context[i]]); if (*ctn == NULL) { void *p = m_ctnode_pool.malloc(); assert(p != NULL); // TODO: make more robust *ctn = new (p) CTNode(); } } }
auth_t::auth_t(context_t& context): m_context(context), m_log(context.log("crypto")), m_evp_md_context(EVP_MD_CTX_create()) { ERR_load_crypto_strings(); // NOTE: Allowing the exception to propagate here, as this is a fatal error. std::vector<std::string> keys( context.get<api::storage_t>("storage/core")->list("keys") ); for(std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it) { std::string identity(*it); std::string object( context.get<api::storage_t>("storage/core")->get<std::string>("keys", identity) ); if(object.empty()) { COCAINE_LOG_ERROR(m_log, "key for user '%s' is malformed", identity); continue; } // Read the key into the BIO object. BIO * bio = BIO_new_mem_buf(const_cast<char*>(object.data()), object.size()); EVP_PKEY * pkey = NULL; pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); if(pkey != NULL) { m_keys.emplace(identity, pkey); } else { COCAINE_LOG_ERROR( m_log, "key for user '%s' is invalid - %s", identity, ERR_reason_error_string(ERR_get_error()) ); } BIO_free(bio); } COCAINE_LOG_INFO(m_log, "loaded %llu public key(s)", m_keys.size()); }
execution_unit_t::execution_unit_t(context_t& context): m_asio(new io_service()), m_chamber(new io::chamber_t("core:asio", m_asio)), m_cron(*m_asio) { m_log = context.log("core:asio", { attribute::make("engine", boost::lexical_cast<std::string>(m_chamber->thread_id())) }); m_asio->post(std::bind(&gc_action_t::operator(), std::make_shared<gc_action_t>(this, boost::posix_time::seconds(kCollectionInterval)) )); COCAINE_LOG_DEBUG(m_log, "engine started"); }
process_t::process_t(context_t& context, const std::string& name, const dynamic_t& args): category_type(context, name, args), m_context(context), m_log(context.log(name)), m_name(name), m_working_directory(fs::path(args.as_object().at("spool", "/var/spool/cocaine").as_string()) / name) { #ifdef COCAINE_ALLOW_CGROUPS int rv = 0; if((rv = cgroup_init()) != 0) { throw std::system_error(rv, cgroup_category(), "unable to initialize cgroups"); } m_cgroup = cgroup_new_cgroup(m_name.c_str()); // NOTE: Looks like if this is not done, then libcgroup will chown everything as root. cgroup_set_uid_gid(m_cgroup, getuid(), getgid(), getuid(), getgid()); for(auto type = args.as_object().begin(); type != args.as_object().end(); ++type) { if(!type->second.is_object() || type->second.as_object().empty()) { continue; } cgroup_controller* ptr = cgroup_add_controller(m_cgroup, type->first.c_str()); for(auto it = type->second.as_object().begin(); it != type->second.as_object().end(); ++it) { COCAINE_LOG_INFO(m_log, "setting cgroup controller '%s' parameter '%s' to '%s'", type->first, it->first, boost::lexical_cast<std::string>(it->second) ); try { it->second.apply(cgroup_configurator_t(ptr, it->first.c_str())); } catch(const cocaine::error_t& e) { COCAINE_LOG_ERROR(m_log, "unable to set cgroup controller '%s' parameter '%s' - %s", type->first, it->first, e.what() ); } } } if((rv = cgroup_create_cgroup(m_cgroup, false)) != 0) { cgroup_free(&m_cgroup); throw std::system_error(rv, cgroup_category(), "unable to create cgroup"); } #endif }
node_service_t::node_service_t(context_t& context, io::reactor_t& reactor, const std::string& name): api::service_t(context, reactor, name, dynamic_t::empty_object), dispatch<io::raft_node_tag<msgpack::object, msgpack::object>>(name), m_context(context), m_log(context.log(name)) { using namespace std::placeholders; typedef io::raft_node<msgpack::object, msgpack::object> protocol; on<protocol::append>(std::bind(&node_service_t::append, this, _1, _2, _3, _4, _5, _6)); on<protocol::apply>(std::bind(&node_service_t::apply, this, _1, _2, _3, _4, _5, _6)); on<protocol::request_vote>(std::bind(&node_service_t::request_vote, this, _1, _2, _3, _4)); on<protocol::insert>(std::bind(&node_service_t::insert, this, _1, _2)); on<protocol::erase>(std::bind(&node_service_t::erase, this, _1, _2)); }
darkmetrics_t::darkmetrics_t(context_t& context, peers_t& peers, const dynamic_t& args) : unicorn_name_(args.as_object().at("unicorn", dynamic_t::empty_string).as_string()) , unicorn_prefix_(args.as_object().at("unicorn_prefix", dynamic_t::empty_string).as_string()) , unicorn_retry_after_(args.as_object().at("unicorn_retry_after_s", 20U).as_uint()) , enabled_(args.as_object().at("enabled", false).as_bool()) , ttl_(args.as_object().at("ttl_s", 300U).as_uint()) , logger_(context.log("vicodyn/darkmetrics")) , peers_(peers) { if (enabled_) { if (unicorn_name_.empty() || unicorn_prefix_.empty()) { throw error_t("invalid configuration of darkmetrics: `unicorn` and `unicorn_prefix` are required"); } unicorn_ = api::unicorn(context, unicorn_name_); } COCAINE_LOG_INFO(logger_, "balancing by system weights is {}", enabled_ ? "on" : "off"); }
bool ParseContextMap(const string &str, context_t &context) { istringstream iss(str); string element; while (getline(iss, element, ',')) { istringstream ess(element); string tok; getline(ess, tok, ':'); domain_t id = (domain_t) stoi(tok); getline(ess, tok, ':'); float w = stof(tok); context.push_back(cscore_t(id, w)); } return true; }
master_t::master_t(context_t& context, engine_t& engine): m_context(context), m_log(context.log( (boost::format("app/%1%") % engine.manifest().name ).str() )), m_engine(engine), m_heartbeat_timer(m_engine.loop()) { initiate(); // NOTE: Initialization heartbeat can be different. m_heartbeat_timer.set<master_t, &master_t::on_timeout>(this); m_heartbeat_timer.start(m_engine.manifest().policy.startup_timeout); spawn(); }
manifest_t::manifest_t(context_t& context, const std::string& name_): cached<dynamic_t>(context, "manifests", name_), name(name_) { endpoint = cocaine::format("{}/{}.{}", context.config().path().runtime(), name, ::getpid()); try { environment = as_object().at("environment", dynamic_t::empty_object) .to<std::map<std::string, std::string>>(); } catch (const boost::bad_get&) { throw cocaine::error_t("environment should be a map of string -> string"); } if(as_object().find("slave") != as_object().end()) { executable = as_object().at("slave").as_string(); } else { throw cocaine::error_t("runnable object has not been specified"); } }
app_state_t(context_t& context, manifest_t manifest_, profile_t profile_, cocaine::deferred<void> deferred_): log(context.log(format("%s/app", manifest_.name))), context(context), state(new state::stopped_t), deferred(std::move(deferred_)), manifest_(std::move(manifest_)), profile(std::move(profile_)), loop(std::make_shared<asio::io_service>()), work(std::make_unique<asio::io_service::work>(*loop)) { COCAINE_LOG_TRACE(log, "application has initialized its internal state"); thread = boost::thread([=] { loop->run(); }); }
slave_t::slave_t(context_t& context, slave_config_t config): unique_id_t(config.uuid), m_context(context), m_log(context.log( (boost::format("app/%1%") % config.app ).str() )), m_app(config.app), m_bus(m_context.io(), config.uuid), m_bus_timeout(m_bus, defaults::bus_timeout) { int linger = 0; m_bus.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); #ifdef ZMQ_ROUTER_BEHAVIOR int mode = 1; m_bus.setsockopt(ZMQ_ROUTER_BEHAVIOR, &mode, sizeof(mode)); #endif m_bus.connect( (boost::format("ipc://%1%/%2%") % m_context.config.ipc_path % config.app ).str() ); m_watcher.set<slave_t, &slave_t::message>(this); m_watcher.start(m_bus.fd(), ev::READ); m_processor.set<slave_t, &slave_t::process>(this); m_check.set<slave_t, &slave_t::check>(this); m_check.start(); m_heartbeat_timer.set<slave_t, &slave_t::heartbeat>(this); m_heartbeat_timer.start(0.0f, 5.0f); configure(); }
app_t::app_t(context_t& context, const std::string& name, const std::string& profile): m_context(context), m_log(context.log( cocaine::format("app/%1%", name) )), m_manifest(new manifest_t(context, name)), m_profile(new profile_t(context, profile)) { fs::path path(fs::path(m_context.config.spool_path) / name); if(!fs::exists(path)) { deploy(name, path.string()); } m_control.reset(new control_channel_t(context, ZMQ_PAIR)); std::string endpoint = cocaine::format( "inproc://%s", m_manifest->name ); try { m_control->bind(endpoint); } catch(const zmq::error_t& e) { throw configuration_error_t("unable to bind the engine control channel - %s", e.what()); } // NOTE: The event loop is not started here yet. m_engine.reset( new engine_t( m_context, *m_manifest, *m_profile ) ); }
archive_t::archive_t(context_t& context, const std::string& archive): m_log(context.log("packaging")), m_archive(archive_read_new()) { #if ARCHIVE_VERSION_NUMBER < 3000000 archive_read_support_compression_all(m_archive); #else archive_read_support_filter_all(m_archive); #endif archive_read_support_format_all(m_archive); const int rv = archive_read_open_memory( m_archive, const_cast<char*>(archive.data()), archive.size() ); if(rv != ARCHIVE_OK) { throw archive_error_t(m_archive); } COCAINE_LOG_INFO(m_log, "compression: %s, size: %llu bytes", type(), archive.size()); }
running_t(context_t& context, const manifest_t& manifest, const profile_t& profile, const logging::log_t* log, std::shared_ptr<asio::io_service> loop): log(log) { // Create the Overseer - slave spawner/despawner plus the event queue dispatcher. overseer.reset(new overseer_t(context, manifest, profile, loop)); // Create the event balancer. // TODO: Rename method. overseer->balance(std::make_unique<load_balancer_t>(overseer)); // Create a TCP server and publish it. COCAINE_LOG_TRACE(log, "publishing application service with the context"); context.insert(manifest.name, std::make_unique<actor_t>( context, std::make_shared<asio::io_service>(), std::make_unique<app_dispatch_t>(context, manifest.name, overseer) )); // Create an unix actor and bind to {manifest->name}.{pid} unix-socket. COCAINE_LOG_TRACE(log, "publishing worker service with the context"); engine.reset(new unix_actor_t( context, manifest.endpoint, std::bind(&overseer_t::prototype, overseer), [](io::dispatch_ptr_t handshaker, std::shared_ptr<session_t> session) { std::static_pointer_cast<const handshaker_t>(handshaker)->bind(session); }, std::make_shared<asio::io_service>(), std::make_unique<hostess_t>(manifest.name) )); engine->run(); }
node_t::node_t(context_t& context, asio::io_service& asio, const std::string& name, const dynamic_t& args): category_type(context, asio, name, args), dispatch<io::node_tag>(name), context(context), log(context.log(name)) { on<io::node::start_app>(std::bind(&node_t::start_app, this, ph::_1, ph::_2)); on<io::node::pause_app>(std::bind(&node_t::pause_app, this, ph::_1)); on<io::node::list> (std::bind(&node_t::list, this)); on<io::node::info> (std::bind(&node_t::info, this, ph::_1, ph::_2)); // Context signal/slot. signal = std::make_shared<dispatch<io::context_tag>>(name); signal->on<io::context::shutdown>(std::bind(&node_t::on_context_shutdown, this)); const auto runname = args.as_object().at("runlist", "").as_string(); if(runname.empty()) { context.listen(signal, asio); return; } COCAINE_LOG_INFO(log, "reading '%s' runlist", runname); typedef std::map<std::string, std::string> runlist_t; runlist_t runlist; const auto storage = api::storage(context, "core"); try { // TODO: Perform request to a special service, like "storage->runlist(runname)". runlist = storage->get<runlist_t>("runlists", runname); } catch(const std::system_error& err) { COCAINE_LOG_WARNING(log, "unable to read '%s' runlist: %s", runname, err.what()); } if(runlist.empty()) { context.listen(signal, asio); return; } COCAINE_LOG_INFO(log, "starting %d app(s)", runlist.size()); std::vector<std::string> errored; for(auto it = runlist.begin(); it != runlist.end(); ++it) { blackhole::scoped_attributes_t scope(*log, {{ "app", it->first }}); try { start_app(it->first, it->second); } catch(const std::exception& e) { COCAINE_LOG_WARNING(log, "unable to initialize app: %s", e.what()); errored.push_back(it->first); } } if(!errored.empty()) { std::ostringstream stream; std::ostream_iterator<char> builder(stream); boost::spirit::karma::generate(builder, boost::spirit::karma::string % ", ", errored); COCAINE_LOG_WARNING(log, "couldn't start %d app(s): %s", errored.size(), stream.str()); } context.listen(signal, asio); }
engine_t::engine_t(context_t& context, const manifest_t& manifest): m_context(context), m_log(context.log( (boost::format("app/%1%") % manifest.name ).str() )), m_manifest(manifest), m_state(stopped), m_thread(NULL), m_bus(new io::channel_t(context.io(), m_manifest.name)), m_watcher(m_loop), m_processor(m_loop), m_check(m_loop), m_gc_timer(m_loop), m_termination_timer(m_loop), m_notification(m_loop) #ifdef HAVE_CGROUPS , m_cgroup(NULL) #endif { int linger = 0; m_bus->setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); std::string endpoint( (boost::format("ipc://%1%/%2%") % m_context.config.ipc_path % m_manifest.name ).str() ); try { m_bus->bind(endpoint); } catch(const zmq::error_t& e) { throw configuration_error_t(std::string("invalid rpc endpoint - ") + e.what()); } m_watcher.set<engine_t, &engine_t::message>(this); m_watcher.start(m_bus->fd(), ev::READ); m_processor.set<engine_t, &engine_t::process>(this); m_check.set<engine_t, &engine_t::check>(this); m_check.start(); m_gc_timer.set<engine_t, &engine_t::cleanup>(this); m_gc_timer.start(5.0f, 5.0f); m_notification.set<engine_t, &engine_t::notify>(this); m_notification.start(); #ifdef HAVE_CGROUPS Json::Value limits(m_manifest.root["resource-limits"]); if(!(cgroup_init() == 0) || !limits.isObject() || limits.empty()) { return; } m_cgroup = cgroup_new_cgroup(m_manifest.name.c_str()); // XXX: Not sure if it changes anything. cgroup_set_uid_gid(m_cgroup, getuid(), getgid(), getuid(), getgid()); Json::Value::Members controllers(limits.getMemberNames()); for(Json::Value::Members::iterator c = controllers.begin(); c != controllers.end(); ++c) { Json::Value cfg(limits[*c]); if(!cfg.isObject() || cfg.empty()) { continue; } cgroup_controller * ctl = cgroup_add_controller(m_cgroup, c->c_str()); Json::Value::Members parameters(cfg.getMemberNames()); for(Json::Value::Members::iterator p = parameters.begin(); p != parameters.end(); ++p) { switch(cfg[*p].type()) { case Json::stringValue: { cgroup_add_value_string(ctl, p->c_str(), cfg[*p].asCString()); break; } case Json::intValue: { cgroup_add_value_int64(ctl, p->c_str(), cfg[*p].asInt()); break; } case Json::uintValue: { cgroup_add_value_uint64(ctl, p->c_str(), cfg[*p].asUInt()); break; } case Json::booleanValue: { cgroup_add_value_bool(ctl, p->c_str(), cfg[*p].asBool()); break; } default: { m_log->error( "controller '%s' parameter '%s' type is not supported", c->c_str(), p->c_str() ); continue; } } m_log->debug( "setting controller '%s' parameter '%s' to '%s'", c->c_str(), p->c_str(), boost::lexical_cast<std::string>(cfg[*p]).c_str() ); } } int rv = 0; if((rv = cgroup_create_cgroup(m_cgroup, false)) != 0) { m_log->error( "unable to create the control group - %s", cgroup_strerror(rv) ); cgroup_free(&m_cgroup); m_cgroup = NULL; } #endif }
/* * idle function is called when we are ready to receive or send a new message. */ void idle(msg_dir_t dir, volatile unsigned char *data) { static unsigned char *data_to_send; static unsigned char msg_size = 0; static unsigned char RX_count = 0; switch (dir) { case TX: /* * At this point we should have something ready to send. */ if (msg_size) { /* *This case is dedicated to protocol messages */ msg_size--; *data = *data_to_send++; } else { ctx.tx_cb(&ctx.msg); } break; case RX: case RXGC: /* * That should be a new message to receive. */ RX_count++; ctx.msg.reg = *data; switch (ctx.msg.reg) { case GET_ID: // Reply with ID msg_size = 1; data_to_send = &ctx.id; break; case WRITE_ID: // Get and save a new given ID ctx.msg.size = 1; ctx.data_cb = get_data; break; case GET_MODULE_TYPE: // Reply with module_type number msg_size = 1; data_to_send = &ctx.type; break; case GET_STATUS: // Reply with a status register msg_size = 1; data_to_send = (unsigned char*)&ctx.status; // TODO(NR) ca devrais reset le status... break; case GET_FIRM_REVISION: // Reply with the actual firmware revision number // TODO(NR) break; default: ctx.data_cb = get_size; break; } break; case END: if (msg_size > 0) ctx.status.rx_error = TRUE; msg_size = 0; break; } }