#include <iostream> #include <chrono> #include <cmath> #include <random> #include <semaphore> #include <google/protobuf/arena.h> #include <thread> #include <map> #include "rpc_service.hpp" struct StatusRequest { }; struct SensorStatus { uint64_t online_since; uint32_t battery_charge; uint32_t battery_capacity; uint32_t max_sampling_rate; uint32_t cur_sampling_rate; uint32_t max_chunk_size; uint32_t cur_chunk_size; uint32_t n_chunk_capacity; uint32_t n_full_data_chunks; uint32_t n_empty_data_chunks; }; struct SetSamplingPeriodRequest { uint32_t new_sampling_period; }; enum SetSamplingPeriodResult { SAMPLING_PERIOD_OK, SAMPLING_PERIOD_OUT_OF_RANGE }; struct PopDataChunkRequest { }; struct DataChunk { uint64_t begin; uint32_t sampling_period; float temperature_data[]; }; template < size_t T_Capacity > struct RandomSensor { private: std::chrono::time_point<std::chrono::high_resolution_clock> online_since; std::chrono::duration<uint64_t, std::milli> period_duration; uint32_t chunk_size; uint32_t next_free; uint32_t next_full; float bat_charge; std::counting_semaphore<> sem_full; std::counting_semaphore<> sem_free; float data[ T_Capacity ]; std::thread sensor_thread; void generate_value() { sem_free.acquire(); data[ next_free ] = (float) next_free / 100.0; next_free = (next_free + 1) % T_Capacity; sem_full.release(); } public: RandomSensor() : online_since(std::chrono::high_resolution_clock::now()) , period_duration( 10 ) , chunk_size( 8192 ) , next_free( 0 ) , next_full( 0 ) , bat_charge( 8200.0 ) , sem_full( 0 ) , sem_free( T_Capacity ) , sensor_thread([&] { while(bat_charge > 0) { generate_value(); bat_charge -= 0.01; std::this_thread::sleep_for( period_duration ); } }) {} ~RandomSensor() { sensor_thread.join(); } uint32_t n_chunks_capacity() const { return T_Capacity / chunk_size; } uint32_t n_full_chunks() const { return (( next_free - next_full ) % T_Capacity) / chunk_size; } uint32_t n_empty_chunks() const { return n_chunks_capacity() - n_full_chunks(); } void get_status( StatusRequest const & request, SensorStatus & status ) { status.online_since = std::chrono::duration_cast<std::chrono::milliseconds>(online_since.time_since_epoch()).count(); status.battery_capacity = 8200; status.battery_charge = bat_charge; status.max_sampling_rate = 10; status.cur_sampling_rate = std::chrono::duration_cast<std::chrono::milliseconds>(period_duration).count(); status.cur_chunk_size = chunk_size; status.n_chunk_capacity = n_chunks_capacity(); status.n_full_data_chunks = n_full_chunks(); status.n_empty_data_chunks = n_empty_chunks(); } void set_sampling_period( SetSamplingPeriodRequest const & request, SetSamplingPeriodResult & result ) { result = SAMPLING_PERIOD_OK; } void pop_data_chunk( PopDataChunkRequest const & request, DataChunk & data_chunk ) { } }; enum SensorRpcTag { GET_STATUS = 0, SET_SAMPLING_PERIOD, POP_DATA_CHUNK }; int main( int argc, char* argv[] ) { RandomSensor< 1048576 > sensor; RpcService<SensorRpcTag> service(8070); service.register_handler( GET_STATUS, std::function([&sensor]( StatusRequest const & request, SensorStatus & status ) { sensor.get_status(request, status); })); service.register_handler( SET_SAMPLING_PERIOD, std::function([&sensor]( SetSamplingPeriodRequest const & request, SetSamplingPeriodResult & result ) { sensor.set_sampling_period(request, result); })); service.register_handler( POP_DATA_CHUNK, std::function([&sensor]( PopDataChunkRequest const & request, DataChunk & result ) { sensor.pop_data_chunk(request, result); })); return service.run(); }