Skip to content
Permalink
5d5afefb2e
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
302 lines (256 sloc) 10.2 KB
#include <algorithm>
#include <thread>
#include <stdlib.h>
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Menu, Renderer, Horizontal, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, Element, operator|, window, flex, vbox
using namespace ftxui;
#include <can_wrap.hpp>
using can::operator<<;
#include <status_frames.h>
ftxui::Component Wrap( const std::string& name, Component component )
{
return Renderer(component, [name, component] {
return hbox({
text(name) | size(WIDTH, EQUAL, 10),
separator(),
component->Render() | xflex,
}) |
xflex;
});
}
Component Window(std::string title, Component component) {
return Renderer(component, [component, title] { //
return window(text(title), component->Render()) | flex;
});
}
class CanInterface
{
public:
AxleTorqueFrame frontAxle;
AxleTorqueFrame rearAxle { false };
StatusFrame status;
SteeringFrame steering;
WheelCountsFrame wheelCounts;
WheelSpeedsFrame wheelSpeeds;
std::array< ProcessFrame* const, 6 > frames { &frontAxle, &rearAxle, &status, &steering, &wheelCounts, &wheelSpeeds };
int canSocket;
CanInterface()
{
}
~CanInterface()
{
can::close( canSocket );
}
void connect()
{
canSocket = can::connect( "vcan0" );
}
void process()
{
const can_frame frame = can::read( canSocket );
for( auto& f : frames )
{
if( f->frameId == frame.can_id )
{
f->process( frame );
//std::cout << *f << std::endl;
}
}
}
};
class Layout
{
public:
// == options ======
std::vector<std::string> missionStates { "NOT_SELECTED", "SELECTED", "RUNNING", "FINISHED" };
int missionOpt = 0;
int frontTorque = 0;
int rearTorque = 0;
int steering = 0;
bool ebrake = false;
bool drive = false;
std::array<int,4> wheelTicks { 0, 0, 0, 0 };
ftxui::Component carGrid;
ftxui::Component controls;
ftxui::Component statusInfo;
ftxui::Component info;
ftxui::Component global;
ftxui::Component stateControls;
int count = 0;
Layout( CanInterface &interface )
{
auto cell = [](const char* t) { return text(t) | border; };
statusInfo = Container::Vertical(
{
Window( "Warnings", Renderer( [&]
{
return text( interface.status.warning_message() );
} ) ),
Window( "Faults", Renderer( [&]
{
return text( interface.status.fault_message() );
} ) ),
Window( "Status", Renderer( [&]
{
auto as_state = [&]( StatusFrame::AsState state )
{
switch( state )
{
case StatusFrame::AsState::AS_OFF: return "OFF";
case StatusFrame::AsState::AS_READY: return "READY";
case StatusFrame::AsState::AS_DRIVING: return "DRIVING";
case StatusFrame::AsState::AS_EMERGENCY: return "EMERGENCY";
case StatusFrame::AsState::AS_FINISHED: return "FINISHED";
}
return "ERROR";
};
auto ami_state = [&]( StatusFrame::AmiState state )
{
switch( state )
{
case StatusFrame::AmiState::ACCELERATION: return "ACCELERATION";
case StatusFrame::AmiState::SKIDPAD: return "SKIDPAD";
case StatusFrame::AmiState::AUTOCROSS: return "AUTOCROSS";
case StatusFrame::AmiState::TRACK_DRIVE: return "TRACK_DRIVE";
case StatusFrame::AmiState::STATIC_INSPECTION_A: return "STATIC_INSPECTION_A";
case StatusFrame::AmiState::STATIC_INSPECTION_B: return "STATIC_INSPECTION_B";
case StatusFrame::AmiState::AUTONOMOUS_DEMO: return "AUTONOMOUS_DEMO";
}
return "ERROR";
};
return vbox({hbox({text("AS "),text(as_state(interface.status.as_state()))}),
hbox({text("AMI "),text(ami_state(interface.status.ami_state()))}),
hbox({text("Handshake "),text(interface.status.handshake()?"ON":"OFF")}),});
} ) ),
} );
carGrid = Renderer( [&]()
{
auto wheel = [&]( int count, int rpm )
{
return vbox(
{
hbox({text("count "), text(std::to_string(count))}),
hbox({text("rpm "), text(std::to_string(rpm))}),
} ) | border;
};
auto axle = [&]( float current, float max, float requested )
{
return vbox(
{
hbox({text("crrnt "), text(std::to_string(current))}),
hbox({text("max "), text(std::to_string(max))}),
hbox({text("rqstd "), text(std::to_string(requested))}),
} ) | border;
};
auto chassis = [&]( bool as, bool ts, bool ebrake )
{
return vbox(
{
hbox({text("AS "), text(as?"ON":"OFF")}),
hbox({text("TS "), text(ts?"ON":"OFF")}),
hbox({text("Ebrake "), text(ebrake?"ON":"OFF")}),
} ) | border;
};
return gridbox(
{
{
wheel( interface.wheelCounts.front_left(),
interface.wheelSpeeds.front_left() ),
vcenter( hcenter( text("Front") ) ),
wheel( interface.wheelCounts.front_right(),
interface.wheelSpeeds.front_right() ),
},
{
text(""),
axle( interface.frontAxle.get_current(),
interface.frontAxle.get_max(),
interface.frontAxle.get_requested() ),
text(""),
},
{
text(""),
chassis( interface.status.as_switch(),
interface.status.ts_switch(),
false ),
text(""),
},
{
text(""),
axle( interface.rearAxle.get_current(),
interface.rearAxle.get_max(),
interface.rearAxle.get_requested() ),
text(""),
},
{
wheel( interface.wheelCounts.rear_left(),
interface.wheelSpeeds.rear_left() ),
vcenter( hcenter( text("Rear") ) ),
wheel( interface.wheelCounts.rear_right(),
interface.wheelSpeeds.rear_right() ),
},
} );
} );
controls = Container::Vertical(
{
Slider( "Front:", &frontTorque, 0, 100, 1 ),
Slider( "Rear :", &rearTorque, 0, 100, 1 ),
Slider( "Steering:", &steering, -20, 20, 1 )
} );
stateControls = Window( "Controls", Container::Vertical(
{
Window( "Mission status", Menu( &missionStates, &missionOpt ) ),
Checkbox( "Ebrake", &this->ebrake ),
Checkbox( "Drive", &this->drive ),
} ) );
global = Container::Horizontal(
{
statusInfo,
Container::Vertical(
{
carGrid | xflex_grow | yflex_grow,
controls | size( WIDTH, GREATER_THAN, 30 ) | xflex,
}),
stateControls
} );
}
ftxui::Component& operator()()
{
return this->global;
}
};
int main( int argc, char *argv[] )
{
CanInterface interface;
interface.connect();
Layout layout( interface );
auto screen = ScreenInteractive::Fullscreen();
bool canThreadRunning = true;
std::thread canThread = std::thread( [&]
{
std::this_thread::sleep_for( std::chrono::milliseconds(500) );
while( canThreadRunning )
{
const can_frame frame = can::read( interface.canSocket );
for( auto& f : interface.frames )
{
if( f->frameId == frame.can_id )
{
//std::cout << frame << std::endl;
//f->process( frame );
screen.Post( [frame,&f](){ f->process( frame ); } );
}
}
screen.Post( Event::Custom );
//std::this_thread::sleep_for( std::chrono::milliseconds(5) );
}
//std::cout << "Ending" << std::endl;
} );
screen.Loop( layout() );
//std::this_thread::sleep_for( std::chrono::seconds(500) );
canThreadRunning = false;
canThread.join();
return 0;
}