smart-sensor-example/random-sensor-ldmc/random-sensor.cpp

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();
}