162 lines
4.1 KiB
C++
162 lines
4.1 KiB
C++
#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();
|
|
}
|