hackens-org-configurations/machines/agb02/agb/agb.cpp

183 lines
5.7 KiB
C++
Raw Normal View History

2024-10-12 00:40:55 +02:00
#include <curlpp/cURLpp.hpp>
2024-10-12 18:44:35 +02:00
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
2024-10-12 00:40:55 +02:00
#include <gpiod.hpp>
#include <iostream>
2024-10-12 18:44:35 +02:00
#include <fstream>
2024-10-12 00:40:55 +02:00
#include <thread>
using namespace std::literals::chrono_literals;
constexpr std::chrono::microseconds debounce = 40ms;
2024-10-12 16:00:59 +02:00
constexpr std::chrono::microseconds poll_period = 5ms;
2024-10-12 18:44:35 +02:00
constexpr std::chrono::microseconds server_ratelimit = 50ms;
constexpr const char* url = "https://agb.hackens.org/api/control-box";
2024-10-12 00:40:55 +02:00
constexpr std::pair<double, double> joystick_movement(1.0, 1.0);
const gpiod::line::offsets drive_down = { 21, 13, 6 };
2024-10-12 16:00:59 +02:00
const gpiod::line::offsets decoder = { 2, 3, 4, 14, 15, 18, 23, 24 }; // lsbf
2024-10-12 00:40:55 +02:00
const gpiod::line::offsets joystick = { 0, 0, 0, 0 }; // x+, y+, x-, y-
const gpiod::line::offset black_button = 0;
const gpiod::line::offset white_button = 0;
const gpiod::line_settings input_settings =
gpiod::line_settings()
.set_direction(gpiod::line::direction::INPUT)
.set_bias(gpiod::line::bias::PULL_UP)
.set_active_low(true)
.set_debounce_period(debounce);
2024-10-12 16:00:59 +02:00
constexpr std::array<uint8_t, 256> decoder_table =
#include "decoder_table.inl"
2024-10-12 00:40:55 +02:00
uint8_t read_decoder_realpos(gpiod::line_request& line_reader){
static gpiod::line::values decoder_read(8);
line_reader.get_values(decoder, decoder_read);
uint8_t graycode = 0;
for(uint8_t i = 0; i < 8; ++i) graycode |= uint8_t(decoder_read[i]) << i;
2024-10-12 16:00:59 +02:00
return decoder_table[graycode];
2024-10-12 00:40:55 +02:00
};
inline void clamp_decoder(uint8_t& decoder, int move){
decoder = uint8_t(std::clamp(decoder + move, 0, 255));
}
int main(const int argc, char const* const* const argv) {
2024-10-12 18:44:35 +02:00
if(argc < 3) {
std::cerr << "usage: agb gpiodevice tokenfile" << std::endl;
2024-10-12 00:40:55 +02:00
return 1;
2024-10-12 18:44:35 +02:00
}
2024-10-12 00:40:55 +02:00
/// init gpio chip ///
gpiod::chip chip(argv[1]);
gpiod::line_request line_reader =
chip.prepare_request()
.set_consumer("AGB")
.add_line_settings(drive_down,
gpiod::line_settings()
.set_direction(gpiod::line::direction::OUTPUT)
.set_drive(gpiod::line::drive::OPEN_DRAIN)
.set_output_value(gpiod::line::value::INACTIVE)
)
.add_line_settings({ black_button, white_button }, input_settings)
.add_line_settings(joystick, input_settings)
2024-10-12 16:00:59 +02:00
.add_line_settings(decoder,
gpiod::line_settings(input_settings)
.set_active_low(false)
.set_debounce_period(0ms))
2024-10-12 00:40:55 +02:00
.do_request();
// let the settings apply
std::this_thread::sleep_for(poll_period);
/// init server communication ///
cURLpp::initialize();
2024-10-12 18:44:35 +02:00
std::string token;
{
std::ifstream tokenFile(argv[2]);
std::getline(tokenFile, token);
}
std::list<std::string> header;
header.push_back("Content-Type: application/json");
header.push_back("Authorization: Bearer " + token);
2024-10-12 00:40:55 +02:00
2024-10-12 18:44:35 +02:00
/// internal state and buffers ///
2024-10-12 00:40:55 +02:00
gpiod::line::values joystick_read(4);
std::pair<double, double> spot_pos(0.0, 0.0); //TODO: init from server
uint8_t decoder_pos = 0; //TODO: init from server
uint8_t decoder_realpos = read_decoder_realpos(line_reader);
bool white_pressed = false;
bool black_pressed = false;
2024-10-12 18:44:35 +02:00
bool has_changed = false;
std::chrono::time_point last_send = std::chrono::system_clock::now();
std::string postData;
2024-10-12 00:40:55 +02:00
for(;;){
std::this_thread::sleep_for(poll_period);
/// joystick ///
line_reader.get_values(joystick, joystick_read);
if(bool(joystick_read[0])) spot_pos.first += joystick_movement.first;
if(bool(joystick_read[1])) spot_pos.second += joystick_movement.second;
if(bool(joystick_read[2])) spot_pos.first -= joystick_movement.first;
if(bool(joystick_read[3])) spot_pos.second -= joystick_movement.second;
if (bool(joystick_read[0]) || bool(joystick_read[1])
|| bool(joystick_read[2]) || bool(joystick_read[3]))
2024-10-12 18:44:35 +02:00
has_changed = true;
2024-10-12 00:40:55 +02:00
/// Buttons ///
bool pressed = bool(line_reader.get_value(black_button));
if(pressed ^ black_pressed)
2024-10-12 18:44:35 +02:00
has_changed = true;
2024-10-12 00:40:55 +02:00
black_pressed = pressed;
pressed = bool(line_reader.get_value(white_button));
if(pressed ^ white_pressed)
2024-10-12 18:44:35 +02:00
has_changed = true;
2024-10-12 00:40:55 +02:00
white_pressed = pressed;
/// decoder ///
uint8_t new_realpos = read_decoder_realpos(line_reader);
uint8_t seen_travel = std::abs(int(new_realpos) - int(decoder_realpos));
2024-10-12 18:44:35 +02:00
// CCW
2024-10-12 00:40:55 +02:00
if(seen_travel < 50 && new_realpos < decoder_realpos)
2024-10-12 16:00:59 +02:00
clamp_decoder(decoder_pos, -seen_travel);
2024-10-12 00:40:55 +02:00
if(seen_travel >= 50 && new_realpos > decoder_realpos)
2024-10-12 16:00:59 +02:00
clamp_decoder(decoder_pos, seen_travel - 128);
2024-10-12 00:40:55 +02:00
2024-10-12 18:44:35 +02:00
// CW
2024-10-12 00:40:55 +02:00
if(seen_travel < 50 && new_realpos > decoder_realpos)
2024-10-12 16:00:59 +02:00
clamp_decoder(decoder_pos, seen_travel);
2024-10-12 00:40:55 +02:00
if(seen_travel >= 50 && new_realpos < decoder_realpos)
2024-10-12 16:00:59 +02:00
clamp_decoder(decoder_pos, 128 - seen_travel);
2024-10-12 00:40:55 +02:00
2024-10-12 16:00:59 +02:00
decoder_realpos = new_realpos;
2024-10-12 00:40:55 +02:00
if(seen_travel)
2024-10-12 18:44:35 +02:00
has_changed = true;
/// server notification
std::chrono::time_point now = std::chrono::system_clock::now();
if(has_changed && (now - last_send > server_ratelimit)){
curlpp::Easy request;
request.setOpt(curlpp::options::Url(url));
request.setOpt(curlpp::options::HttpHeader(header));
postData.clear();
std::format_to(std::back_inserter(postData), "{{"
"\"pan\": {},"
"\"tilt\": {},"
"\"focus\": {},"
"\"whiteButton\": {},"
"\"blackButton\": {}"
"}}",
spot_pos.first,
spot_pos.second,
int(decoder_pos),
white_pressed,
black_pressed
);
request.setOpt(curlpp::options::PostFields(postData));
request.setOpt(curlpp::options::PostFieldSize(postData.size()));
//request.perform();
// std::cout << std::chrono::system_clock::now() - now << std::endl;
std::cout << postData << std::endl;
has_changed = false;
last_send = now;
}
2024-10-12 00:40:55 +02:00
}
}