How to use a wireless controller on the Google Coral Dev Board? - google-coral

With the Jetson Nano I connected a PS4 controller via bluetooth and the device showed up under /dev/input/js0. However when I connect the controller via bluetooth to my Coral board, I am seeing nothing at that location, maybe because of Mendel instead of Ubuntu? What is the recommended way to connect a PS4 controller and access it from C++? Is there a different joystick I should use?

After doing some research I learned about the difference between joydev and evdev on linux. It seems my PS4 controller showed up as a joydev device on the Jetson, whereas on the Coral running Mendel it showed up as an evdev device. I found some example C++ code for evdev devices from Croepha
/ David Butler here: https://handmade.network/forums/t/3673-modern_way_to_read_gamepad_input_with_c_on_linux
I modified this code for the PS4 controller like this:
void runJoystick() {
auto gamepad = open("/dev/input/event4", O_RDONLY | O_NONBLOCK); //todo use /proc/bus/input/devices instead
assert(gamepad != -1);
std::cout << "Running joystick" << std::endl;
while (m_still_running) {
struct input_event events[8]; // 8 events per frame is pretty extreme, more like 1 or 2, sometimes as high as 4
auto r1 = read(gamepad, events, sizeof events);
if (r1 != -1) {
int new_event_count = r1 / sizeof(struct input_event);
for (int evi = 0; evi < new_event_count; evi++) {
auto& ev = events[evi];
switch (ev.type) {
case EV_ABS: {
switch (ev.code) {
case ABS_X: { // left x
// std::cout << "type " << ev.code << "value:" << ev.value << std::endl;
} break;
case ABS_Y: { // left y
// std::cout << "type " << ev.code << "value:" << ev.value << std::endl;
} break;
case ABS_Z: { // right x
// std::cout << "type " << ev.code << "value:" << ev.value << std::endl;
} break;
case ABS_RZ: { // right y
// std::cout << "type " << ev.code << "value:" << ev.value << std::endl;
} break;
}
} break;
case EV_KEY: {
switch (ev.code) {
case BTN_A: { // square
std::cout << "Square ";
} break;
case BTN_B: { // x
std::cout << "X ";
} break;
case BTN_C: { // circle
std::cout << "Circle ";
} break;
case BTN_X: { // triangle
std::cout << "Triangle ";
} break;
}
if (ev.value) {
std::cout << "Pressed " << std::endl;
} else {
std::cout << "Released " << std::endl;
}
} break;
}
}
}
assert(r1 != -1 || errno == EWOULDBLOCK || errno == EAGAIN);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}

Related

iOS - Read/Write XMP metadatas of mp4 videos

I need to read and inject XMP metadatas in an mp4 container.
I know this is possible on android with the "mp4parser" library, but I couldn't find an equivalent for iOS.
For the read part, is it possible to read every footage from the camera roll to inspect their 360 XMP metadatas quickly ?
For the writing, I'm trying to use Adobe's XMP toolkit. I have an mp4 video in a folder, and I want to inject into it some 360 metadatas.
After injecting the metadatas (I suppose it works), I export the video to the camera roll, but it looks like the video is converted to m4v and it lost every metadata I've written. Is it expected, or is my code wrong ?
Here's the code :
MetadataManager.mm
#import "MetadataManager.h"
#define IOS_ENV 1
#include <string>
#define TXMP_STRING_TYPE std::string
#define XMP_INCLUDE_XMPFILES 1
#include "XMP.incl_cpp"
#include "XMP.hpp"
#include <iostream>
#include <fstream>
using namespace std;
#implementation MetadataManager {
}
+ (void)write360Metadatas:(NSString *)filePath {
if (!SXMPMeta::Initialize())
exit(1);
if (!SXMPFiles::Initialize())
exit(1);
SXMPFiles myFile;
XMP_OptionBits opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUseSmartHandler;
std::string status = "";
std::string filePathStd = std::string([filePath UTF8String]);
// First, try to open the file
bool ok = myFile.OpenFile(filePathStd, kXMP_UnknownFile, opts);
if( ! ok ){
status += "No smart handler available for " + filePathStd + "\n";
status += "Trying packet scanning.\n";
// Now try using packet scanning
opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning;
ok = myFile.OpenFile(filePathStd, kXMP_UnknownFile, opts);
}
if(ok){
SXMPMeta meta;
myFile.GetXMP( &meta );
displayPropertyValues(&meta);
injectMetadatas(&meta);
// Check we can put the XMP packet back into the file
if(myFile.CanPutXMP(meta))
{
// If so then update the file with the modified XMP
myFile.PutXMP(meta);
}
// Close the SXMPFile. This *must* be called. The XMP is not
// actually written and the disk file is not closed until this call is made.
myFile.CloseFile();
}
}
SXMPMeta createXMPFromRDF()
{
const char * rdf =
"<rdf:SphericalVideo xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'"
" xmlns:GSpherical='http://ns.google.com/videos/1.0/spherical/'>"
"<GSpherical:Spherical>true</GSpherical:Spherical>"
"<GSpherical:Stitched>true</GSpherical:Stitched>"
"<GSpherical:StitchingSoftware>Spherical Metadata Tool</GSpherical:StitchingSoftware>"
"<GSpherical:ProjectionType>equirectangular</GSpherical:ProjectionType>"
"</rdf:SphericalVideo>";
SXMPMeta meta;
// Loop over the rdf string and create the XMP object
// 10 characters at a time
int i;
for (i = 0; i < (long)strlen(rdf) - 10; i += 10 )
{
meta.ParseFromBuffer ( &rdf[i], 10, kXMP_ParseMoreBuffers );
}
// The last call has no kXMP_ParseMoreBuffers options, signifying
// this is the last input buffer
meta.ParseFromBuffer ( &rdf[i], (XMP_StringLen) strlen(rdf) - i );
return meta;
}
void injectMetadatas(SXMPMeta * meta)
{
// Add an item onto the dc:creator array
// Note the options used, kXMP_PropArrayIsOrdered, if the array does not exist it will be created
meta->AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Author Name", 0);
meta->AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Another Author Name", 0);
// Now update alt-text properties
meta->SetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", "An English title");
meta->SetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", "Un titre Francais");
// Display the properties again to show changes
cout << "After update:" << endl;
displayPropertyValues(meta);
// Create a new XMP object from an RDF string
SXMPMeta rdfMeta = createXMPFromRDF();
// Append the newly created properties onto the original XMP object
// This will:
// a) Add ANY new TOP LEVEL properties in the source (rdfMeta) to the destination (meta)
// b) Replace any top level properties in the source with the matching properties from the destination
SXMPUtils::ApplyTemplate(meta, rdfMeta, kXMPTemplate_AddNewProperties | kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties);
// Display the properties again to show changes
cout << "After Appending Properties:" << endl;
displayPropertyValues(meta);
}
void displayPropertyValues(SXMPMeta * meta)
{
// Read a simple property
string simpleValue; //Stores the value for the property
meta->GetProperty(kXMP_NS_XMP, "CreatorTool", &simpleValue, 0);
cout << "meta:CreatorTool = " << simpleValue << endl;
// Get the first and second element in the dc:creator array
string elementValue;
meta->GetArrayItem(kXMP_NS_DC, "creator", 1, &elementValue, 0);
if(elementValue != "")
{
cout << "dc:creator[1] = " << elementValue << endl;
meta->GetArrayItem(kXMP_NS_DC, "creator", 2, &elementValue, 0);
cout << "dc:creator[2] = " << elementValue << endl;
}
// Get the the entire dc:subject array
string propValue;
int arrSize = meta->CountArrayItems(kXMP_NS_DC, "subject");
for(int i = 1; i <= arrSize;i++)
{
meta->GetArrayItem(kXMP_NS_DC, "subject", i, &propValue, 0);
cout << "dc:subject[" << i << "] = " << propValue << endl;
}
// Get the dc:title for English and French
string itemValue;
string actualLang;
meta->GetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", 0, &itemValue, 0);
cout << "dc:title in English = " << itemValue << endl;
meta->GetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", 0, &itemValue, 0);
cout << "dc:title in French = " << itemValue << endl;
// Get dc:MetadataDate
XMP_DateTime myDate;
if(meta->GetProperty_Date(kXMP_NS_XMP, "MetadataDate", &myDate, 0))
{
// Convert the date struct into a convenient string and display it
string myDateStr;
SXMPUtils::ConvertFromDate(myDate, &myDateStr);
cout << "meta:MetadataDate = " << myDateStr << endl;
}
cout << "----------------------------------------" << endl;
}
#end
Any help would be appreciated, thanks.
I've finally succeeded, using the c++ port of "spatial-media" instead of Adobe's xmp toolkit.
spatial-media (github repository)

OpenCV FileStorage empty after loading

Im trying to load a string into filestorage. I will not have the file to pass filename as a parameter to load it. Instead I recive an xml document as a string. In the doc http://docs.opencv.org/modules/core/doc/xml_yaml_persistence.html#filestorage it is mentioned that source attribute of fs.open can be "text string to read the data from". I run some simple tests with OpenCv CascadeClassifier as a string but I get an empty FileStorage. What am I doing wrong?
CascadeClassifier face_cascade;
std::ifstream t("haarcascade_frontalface_alt.xml");
std::string ClasifierInString((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
cout << ClasifierInString << endl; //I CAN PRINT THE FILE AND SEE IT
cv::FileStorage fs;
if (!fs.open(ClasifierInString, cv::FileStorage::READ | cv::FileStorage::MEMORY | cv::FileStorage::FORMAT_XML))
{
cout << "Couldn't load file into memory" << endl;
return -2;
}
FileNodeIterator it = fs.getFirstTopLevelNode().begin(), it_end = fs.getFirstTopLevelNode().end();
for (; it != it_end; ++it)
{
cout << (string)*it << "\n"; //EMPTY LINE????
}
if (!face_cascade.read(fs.getFirstTopLevelNode()))
{
cout << "Couldn't read file from memory" << endl;
return -1;
}
EDIT:
#sop can't comment yet. Maybe your using older version of OpenCV. I have the file and I am able to load it with:
face_cascade.load("haarcascade_frontalface_alt.xml");
and it works. The problem is I'm unable to read it as a string with face_cascade.read(string)
#berak comment is the correct answer. I used lbpcascade_frontalface.xml as this is new cascade (and is faster! :) Thx for help.
I think your problem is the file name: "haarcascade_frontalface_alt.xml". There is no such a file in the OpenCV flder... Try "haarcascade_frontalface_alt_tree.xml".
Here is my code that works:
cv::CascadeClassifier face_cascade;
std::ifstream t("haarcascade_frontalface_alt_tree.xml");
std::string ClasifierInString((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
std::cout << ClasifierInString << std::endl; //I CAN PRINT THE FILE AND SEE IT
cv::FileStorage fs;
if (!fs.open(ClasifierInString, /*cv::FileStorage::READ | */cv::FileStorage::MEMORY | cv::FileStorage::FORMAT_XML))
{
std::cout << "Couldn't load file into memory" << std::endl;
return -2;
}
cv::FileNodeIterator it = fs.getFirstTopLevelNode().begin(), it_end = fs.getFirstTopLevelNode().end();
for (; it != it_end; ++it)
{
std::cout << (std::string)*it << "\n"; //EMPTY LINE????
}
if (!face_cascade.read(fs.getFirstTopLevelNode()))
{
std::cout << "Couldn't read file from memory" << std::endl;
return -1;
}

how to use mouse event to get out loop in opencv using setmousecallback

I am using openCV's setmousecallback() function to break from the for while loop(of webcam video frames) as soon as user presses mouse right click..
But the program is getting hang instead. Someone can help me please..
Below is the code i am using, please pardon me for any compilation error
//mouse callback funtion
void getMouseLoc(int event, int xCor, int yCor, int flags, void* userInput)
{
Point3_<int> *mouseInputs = (Point3_<int>*)userInput;
mouseInputs->x= xCor;
mouseInputs->y = yCor;
mouseInputs->z = event;
}
// for loop
for( ; ; )
{
camera >> frame;
imshow("averageFrame", aver`enter code here`ageFrame);
setMouseCallback("averageFrame", getMouseLoc, &mouseInputs);
if( mouseInputs.z == EVENT_RBUTTONDOWN)
{
cout << "topmost cordinates of ROI selected by user" << endl;
count << mouseInputs.x << " and " << mouseInputs.y << endl;
break;
}
}
//mouse callback function
void getMouseLoc(int event, int xCor, int yCor, int flags, void* userInput)
{
Point3_<int> *mouseInputs = (Point3_<int>*)userInput;
mouseInputs->x= xCor;
mouseInputs->y = yCor;
mouseInputs->z = event;
}
// this does not have to be inside the loop, once is enough:
Point3_<int> mouseInputs;
setMouseCallback("averageFrame", getMouseLoc, &mouseInputs);
// for loop
for( ; ; )
{
camera >> frame;
imshow("averageFrame", aver`enter code here`ageFrame);
// you're missing a call to waitKey(), else your image won't get updated !!
int k = waitKey(40);
if ( k == 27 ) break; // esc pressed.
if( mouseInputs.z == EVENT_RBUTTONDOWN)
{
cout << "topmost cordinates of ROI selected by user" << endl;
count << mouseInputs.x << " and " << mouseInputs.y << endl;
break;
}
}

Boost Asio SSL Certification on iOS

I am trying to use Boost Asio on iOS, and have figured out everything, but how to check the certificate of the server I am connecting to.
How do you check the connecting server's certificate in iOS with Boost Asio?
In another answer of mine you can see a simple SSL client.
In this code you'll quickly note verify_certificate which you can use to (additionally) verify the server certificate.
Sidenote
Note that I don't know which libraries are underlying the Asio SSL implementation iOS, but keep in mind verifying (or even pinning) theserver certificate could be rather useless. It would only verify the authenticity of the certificate presented. In the light of yesterday's security debacle I don't think this helps much, because unless properly patched the server could have presented a valid certificate, but still use unrelated encryption keys - this still allows a MiTM scenario
Just noting this in case your question is somehow related to this situration
From A: HTTPS POST request with boost asio
#define DEMO_USING_SSL
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
#include <iostream>
#include <iomanip>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
class client
{
public:
client(boost::asio::io_service& io_service,
boost::asio::ssl::context& context,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
: socket_(io_service
#ifdef DEMO_USING_SSL
, context)
{
socket_.set_verify_mode(boost::asio::ssl::verify_peer);
socket_.set_verify_callback(
boost::bind(&client::verify_certificate, this, _1, _2));
#else
)
{
(void) context;
#endif
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
}
bool verify_certificate(bool preverified,
boost::asio::ssl::verify_context& ctx)
{
// The verify callback can be used to check whether the certificate that is
// being presented is valid for the peer. For example, RFC 2818 describes
// the steps involved in doing this for HTTPS. Consult the OpenSSL
// documentation for more details. Note that the callback is called once
// for each certificate in the certificate chain, starting from the root
// certificate authority.
// In this example we will simply print the certificate's subject name.
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying " << subject_name << "\n";
return preverified;
}
void handle_connect(const boost::system::error_code& error)
{
#ifdef DEMO_USING_SSL
if (!error)
{
socket_.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&client::handle_handshake, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Connect failed: " << error.message() << "\n";
}
#else
handle_handshake(error);
#endif
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "Enter message: ";
static char const raw[] = "POST / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n";
static_assert(sizeof(raw)<=sizeof(request_), "too large");
size_t request_length = strlen(raw);
std::copy(raw, raw+request_length, request_);
{
// used this for debugging:
std::ostream hexos(std::cout.rdbuf());
for(auto it = raw; it != raw+request_length; ++it)
hexos << std::hex << std::setw(2) << std::setfill('0') << std::showbase << ((short unsigned) *it) << " ";
std::cout << "\n";
}
boost::asio::async_write(socket_,
boost::asio::buffer(request_, request_length),
boost::bind(&client::handle_write, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Handshake failed: " << error.message() << "\n";
}
}
void handle_write(const boost::system::error_code& error,
size_t /*bytes_transferred*/)
{
if (!error)
{
std::cout << "starting read loop\n";
boost::asio::async_read_until(socket_,
//boost::asio::buffer(reply_, sizeof(reply_)),
reply_, '\n',
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Write failed: " << error.message() << "\n";
}
}
void handle_read(const boost::system::error_code& error, size_t /*bytes_transferred*/)
{
if (!error)
{
std::cout << "Reply: " << &reply_ << "\n";
}
else
{
std::cout << "Read failed: " << error.message() << "\n";
}
}
private:
#ifdef DEMO_USING_SSL
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
#else
boost::asio::ip::tcp::socket socket_;
#endif
char request_[1024];
boost::asio::streambuf reply_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 3)
{
std::cerr << "Usage: client <host> <port>\n";
return 1;
}
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
ctx.set_default_verify_paths();
client c(io_service, ctx, iterator);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}

removing two items from a stack and adding their values

I am writing a program that creates a stack using linked lists. I have all the functionality finished like push(), pop(), top(), etc.
The thing I am trying to figure out is how to remove two values from the stack, add them together, then push that into the stack. This is part of the assignment and we have to continue to do it until all the items are added together and only the sum remains in the stack.
Any help or tips would be appreciated!
EDIT: I solved my problem by just making another function!
Thank you to everyone who tried to help!
Here is my code:
#include <cstdlib>
#include <iostream>
using namespace std;
//Creating a node structure
struct node
{
int data;
struct node *next;
};
//class stack
class stack
{
struct node *top;
int size;
public:
stack()
{
top=NULL;
}
void push(); // insert an element
void pop(); // delete an element
void stackTop(); //retrive top item without removal
void stackSize(); //return the size of the stack
void isEmpty(); // return 1 if empty, 0 if not
void show(); // show the stack
};
//push items into a stack
void stack::push()
{
int value;
struct node *ptr;
cout << "\nEnter a number to insert: ";
cin >> value;
ptr = new node;
ptr->data = value;
ptr->next = NULL;
if(top != NULL)
{
ptr->next = top;
}
top = ptr;
cout<<"\nNew item is inserted to the stack!!!" << endl;
size ++;
}
//remove the top item
void stack::pop()
{
struct node *temp;
if(top == NULL)
{
cout<<"\nThe stack is empty!!!";
return;
}
temp = top;
top = top->next;
cout << "\nPoped value is " << temp->data << endl;
delete temp;
size--;
}
//retrive top value without removing it
void stack::stackTop()
{
struct node *temp;
if(top == NULL)
{
cout<<"\nThe stack is empty!!!";
return;
}
temp = top;
cout << "The top item is: " << temp->data << endl;
delete temp;
}
//show the stack
void stack::show()
{
struct node *ptr1 = top;
cout << "\nThe stack is:" << endl;
while(ptr1 != NULL)
{
cout << ptr1->data << " ->";
ptr1 = ptr1->next;
}
cout << "NULL" << endl;
}
//return if empty or not
void stack::isEmpty()
{
if(top == NULL)
{
cout<<"\nThe stack is empty!!!" << endl;
return;
}
else
{
cout << "\nThe stack is not empty!!!" << endl;
return;
}
}
//return the number of items in the stack
void stack::stackSize()
{
if(top == NULL)
{
cout<<"\nThe stack is empty!!!" << endl;
return;
}
else
{
cout << "\nThe stack has " << size << " items" << endl;
return;
}
}
//main function
int main()
{
stack s;
int choice;
while(1)
{
cout << "\nSTACK USING LINKED LIST" << endl << endl;
cout << "1:PUSH" << endl;
cout << "2:POP" << endl;
cout << "3:DISPLAY STACK" << endl;
cout << "4:RETRIVE TOP ITEM" << endl;
cout << "5:GET THE SIZE" << endl;
cout << "6:IS THE STACK EMPTY?" << endl;
cout << "7:EXIT" << endl;
cout << "Enter your choice(1-7): ";
cin >> choice;
switch(choice)
{
case 1:
s.push();
break;
case 2:
s.pop();
break;
case 3:
s.show();
break;
case 4:
s.stackTop();
break;
case 5:
s.stackSize();
break;
case 6:
s.isEmpty();
break;
case 7:
exit(0);
break;
default:
cout << "\nPlease enter correct choice(1-7)!!!" << endl;
break;
}
}
return 0;
}
Is the interface you have mandatory? Normally you would have your pop() operation return the value you just popped (rather than void), instead of just printing it. If you do that, your problem becomes simple, and you can just repeatedly use your algorithm to add them together.
As a matter of fact, pop(), stackTop(), stackSize(), and isEmpty() should probably all return their values. If the print statements aren't required within the functions, you could then just have your main program print the values it finds.

Resources