How I can pass a variable from a C++ program to another?
the variable that I need to pass is a string.
This is the C++ file in which I have to send the string:
#include <string>
#include <iostream>
#include <ros/ros.h>
#include <json_prolog/prolog.h>
using namespace std;
using namespace json_prolog;
int main(int argc, char *argv[])
{
ros::init(argc, argv, "Info");
Prolog pl;
int c=0;
do
{
int i=0;
std::string M;
cout<<"Declare the name of the class of interest"<< "\t";
cin>>M;
if (M=="knife")
.........
In this program I decide what string M is, but I want that this M comes from the output of another cpp file that obviously has to give a string as output.
this is the c++ that has to send me a string:
#include<aruco_marker_detector/arucoMarkerDetector.h>
namespace MarkerDetector {
void FilterButter(Vector3d &s, Vector3d &sf, Vector3d &bButter, Vector3d &aButter)
{
double r,rf;
r=bButter.transpose()*s;
rf=aButter.transpose()*sf;
sf(0)=r-rf;
s(2)=s(1);
s(1)=s(0);
sf(2)=sf(1);
sf(1)=sf(0);
}
MarkerTracker::MarkerTracker(ros::NodeHandle &n)
{
this->nh = n;//dopo questa istruzione l'indirizzo che contiene l'id del nodo n e' salvato in nh
this->it = new image_transport::ImageTransport(this->nh);//salva in &it l'indirizzo della funzione ImageTransport(this->nh) appartenente al nuovo namespace image_transport
// ros::Duration r(1);
XmlRpc::XmlRpcValue my_list;
nh.getParam("marker_ids", my_list);
for (int32_t i = 0; i < my_list.size(); ++i)
{
this->markerIDs.push_back(-1);
//ROS_ASSERT(my_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
this->markerIDs[i]=static_cast<int>(my_list[i]);
//ROS_ERROR_STREAM("markerIDs["<<i<<"]: "<<this->markerIDs[i]);
}
//r.sleep();
nh.getParam("marker_labels", my_list);
for (int32_t i = 0; i < my_list.size(); ++i)
{
this->markerLables.push_back("NotSet");
//ROS_ASSERT(my_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
this->markerLables[i]=static_cast<std::string>(my_list[i]);
//ROS_ERROR_STREAM("markerLables["<<i<<"]: "<<this->markerLables[i]);
}
//r.sleep();
this->markerTrackerID=-1;
//
//Load Parameters (rosparameters)
nh.getParam("marker_tracker_id",this->markerTrackerID);
//nh.getParam("marker_id",this->markerID);
nh.getParam("camera_info_url",this->cameraParametersFile);
nh.getParam("marker_size",this->markerSize);
nh.getParam("block_size",this->thresParam1);
nh.getParam("sub_constant",this->thresParam2);
nh.getParam("camera_reference_frame",this->cameraReferenceFrame);
nh.getParam("filter_coefficient_B", my_list);
for (int32_t i = 0; i < my_list.size(); ++i)
{
//ROS_ASSERT(my_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
this->B(i)=static_cast<double>(my_list[i]);
}
nh.getParam("filter_coefficient_A", my_list);
for (int32_t i = 0; i < my_list.size(); ++i)
{
//ROS_ASSERT(my_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
this->A(i)=static_cast<double>(my_list[i]);
}
nh.getParam("image_topic_name_raw",this->imageTopicRaw);
nh.getParam("image_topic_name_proc",this->imageTopicProcessed);
nh.getParam("camera_name_tag",this->cameraNameTag);
nh.getParam("broadcast_tf_flag",this->broadcastTF);
nh.getParam("camera_extrinsics",my_list);
VectorXd in(16);
this->TC_torso.Identity();
for (int32_t i = 0; i < my_list.size(); ++i)
{
in(i)=static_cast<double>(my_list[i]);
}
ROS_WARN_STREAM("in: \n"<<in.transpose());
// r.sleep();
// this->TC_torso.matrix()(0,0)=in(0*4+0);
// this->TC_torso.matrix()(0,1)=in(0*4+1);
// this->TC_torso.matrix()(0,2)=in(0*4+2);
// this->TC_torso.matrix()(0,3)=in(0*4+3);
// this->TC_torso.matrix()(1,0)=in(1*4+0);
// this->TC_torso.matrix()(1,1)=in(1*4+1);
// this->TC_torso.matrix()(1,2)=in(1*4+2);
// this->TC_torso.matrix()(1,3)=in(1*4+3);
// this->TC_torso.matrix()(2,0)=in(2*4+0);
// this->TC_torso.matrix()(2,1)=in(2*4+1);
// this->TC_torso.matrix()(2,2)=in(2*4+2);
// this->TC_torso.matrix()(2,3)=in(2*4+3);
// this->TC_torso.matrix()(3,0)=in(3*4+0);
// this->TC_torso.matrix()(3,1)=in(3*4+1);
// this->TC_torso.matrix()(3,2)=in(3*4+2);
// this->TC_torso.matrix()(3,3)=in(3*4+3);
for(unsigned int i=0;i<4;i++)
{
for(unsigned int j=0;j<4;j++)
{
this->TC_torso.matrix()(i,j)=in(i*4+j);
}
}
// this->TC_torso=Tmp;
// Tmp.matrix()<<in;
//
// this->TC_torso=Tmp.matrix().transpose();
ROS_WARN_STREAM("TC_torso: \n"<<TC_torso.matrix());
//r.sleep();
//ROS_INFO_STREAM("B: "<<this->B.transpose());
//ROS_INFO_STREAM("A: "<<this->A.transpose());
//r.sleep();
//ROS_INFO_STREAM("marker_size: "<<this->markerSize);
//r.sleep();
//ROS_INFO_STREAM("block_size: "<<this->thresParam1);
//ROS_INFO_STREAM("sub_constant: "<<this->thresParam2);
//r.sleep();
//ROS_INFO_STREAM("camera_info_url: "<<this->cameraParametersFile);
//ROS_INFO_STREAM("markerTrackerID: "<<this->markerTrackerID);
//r.sleep();
//ROS_INFO_STREAM("markerID: "<<this->markerID);
std::stringstream label;
label<<"SwitchFilter_"<<this->markerTrackerID;
this->switchFilterService=this->nh.advertiseService(label.str(),&MarkerDetector::MarkerTracker::SwitchFilterCallBack,this);
label.str("");
//this->cameraParameters.readFromXMLFile(this->cameraParametersFile);
this->sub = it->subscribe(this->imageTopicRaw, 1, &MarkerDetector::MarkerTracker::imageCallback,this);
//Publisher for the processed image
this->pub = it->advertise(this->imageTopicProcessed, 1);
// label<<"tfTarget_"<<this->cameraNameTag<<"_"<<this->markerTrackerID;
// this->pubTF = nh.advertise<geometry_msgs::TransformStamped>(label.str(),100);
// label.str("");
label<<"visualPoints_"<<this->cameraNameTag<<"_"<<this->markerTrackerID;
this->pubVisData=nh.advertise<aruco_marker_detector::MarkerDataArray>(label.str(),100);
label.str("");
this->Rz180<<-1,0,0,0,-1,0,0,0,1;
this->setOld=true;
this->filtered=true;
this->cameraConfigured=false;
}
MarkerTracker::~MarkerTracker()
{
delete it;
}
//bool function switch on/off the filter
bool MarkerTracker::SwitchFilterCallBack(aruco_marker_detector::switch_filter::Request &req,aruco_marker_detector::switch_filter::Response &res)
{
this->filtered=!this->filtered;//req.filtered;
res.confirm=this->filtered;
if(this->filtered)
ROS_INFO_STREAM("Marker Tracker ("<<this->markerTrackerID<<") Filter Switched ON ("<<this->filtered<<")");
else
ROS_INFO_STREAM("Marker Tracker ("<<this->markerTrackerID<<") Filter Switched OFF ("<<this->filtered<<")");
return true;
}
//This function is called everytime a new image is published
void MarkerTracker::imageCallback(const sensor_msgs::ImageConstPtr& original_image)
{
//Convert from the ROS image message to a CvImage suitable for working with OpenCV for processing
cv_bridge::CvImagePtr cv_ptr;
static tf::TransformBroadcaster br1;
tf::Transform transform;
double markerPosition[3];
double markerOrientationQ[4];
Matrix3d R,Rfixed;
//Affine3d TC_torso;
Quaterniond q_eigen;
tf::Quaternion q_tf;
//
try
{
//Always copy, returning a mutable CvImage
//OpenCV expects color images to use BGR channel order.
cv_ptr = cv_bridge::toCvCopy(original_image, sensor_msgs::image_encodings::BGR8);
}
catch (cv_bridge::Exception& e)
{
//if there is an error during conversion, display it
ROS_ERROR_STREAM(__FILE__<<"::cv_bridge exception("<<__LINE__<<": "<<e.what());
return;
}
//Get intrinsic parameters of the camera and size from image
if(!this->cameraConfigured)
{
this->cameraParameters.readFromXMLFile(this->cameraParametersFile);
this->cameraParameters.resize(cv_ptr->image.size());
this->cameraConfigured=true;
}
this->MDetector.pyrDown(0);
this->MDetector.setThresholdParams(this->thresParam1,this->thresParam2);
this->MDetector.setCornerRefinementMethod(aruco::MarkerDetector::SUBPIX);
//Detect Markers
this->MDetector.detect(cv_ptr->image,this->Markers,this->cameraParameters,this->markerSize);
std::stringstream s;
//Camera Frame
// Rz180<<-1,0,0,0,-1,0,0,0,1;
//This is the transformation from camera to world and it must be obtained from camera calib
//TC_torso.matrix()<<0,0,1,-1.1,-1,0,0,0.1,0,-1,0,0.0;
tf::transformEigenToTF(TC_torso,transform);
if(this->broadcastTF)
{
br1.sendTransform(tf::StampedTransform(transform, ros::Time::now(), cameraReferenceFrame, this->cameraNameTag));
}
tf::StampedTransform sTransform;
geometry_msgs::Transform msgTransform;
aruco_marker_detector::MarkerDataArray msgVisPointsArray;
aruco_marker_detector::MarkerData aux;
aruco::Marker tmp;
bool publishTF=false;
bool idNotDefined=true;
//for each marker, draw info and its boundaries in the image
for (unsigned int i=0;i<this->Markers.size();i++)
{
idNotDefined=true;
this->Markers[i].draw(cv_ptr->image,cv::Scalar(0,0,255),2);
this->Markers[i].OgreGetPoseParameters(markerPosition,markerOrientationQ);
R = Eigen::Quaterniond(markerOrientationQ[0], markerOrientationQ[1], markerOrientationQ[2], markerOrientationQ[3]);
Rfixed=this->Rz180*R;
q_eigen=Rfixed;
tf::quaternionEigenToTF(q_eigen,q_tf);
transform.setOrigin( tf::Vector3(-markerPosition[0], - markerPosition[1],markerPosition[2]) );
transform.setRotation(q_tf);
for(unsigned int j=0;j<this->markerIDs.size();j++)
{
if(Markers[i].id==this->markerIDs[j])
{
s<<this->markerLables[j]<<"_"<<this->cameraNameTag;
idNotDefined=false;
break;
}
}
//This is what he do if recognise a marker
//Marker with id 455 represents the target and we need to filter its pose
//If you need to filter any marker then remove the if statement and set publishTF=true
if(Markers[i].id<=40 && Markers[i].id>=20)
{
int z=Markers[i].id;
switch (z){
case 20:
{
publishTF=true;
s<<"Electronics:Phone";
break;
}
case 30:
{
publishTF=true;
s<<"Electronics:Pc";
break;
}
case 40:
{
publishTF=true;
s<<"Electronics:Printer";
break;
}
default:
{
publishTF=true;
s<<"Electronics:Undefined_Object";
}
}
}
else if(Markers[i].id<=935 && Markers[i].id>=915)
{
int z=Markers[i].id;
switch (z){
case 915:
{
publishTF=true;
s<<"Kitchen_utensil:Fork";
break;
}
case 925:
{
publishTF=true;
s<<"Kitchen_utensil:Spoon";
break;
}
case 935:
{
publishTF=true;
s<<"Kitchen_utensil:Knife";
break;
}
default:
{
publishTF=true;
s<<"Kitchen_utensil:Undefined_Object";
}
}
}
else if(Markers[i].id<=220 && Markers[i].id>=200)
{
int z=Markers[i].id;
switch (z){
case 200:
{
publishTF=true;
s<<"Container:Pot";
break;
}
case 210:
{
publishTF=true;
s<<"Container:Basket";
break;
}
case 220:
{
publishTF=true;
s<<"Container:Box";
break;
}
default:
{
publishTF=true;
s<<"Container:Undefined_Object";
}
}
}
else
{
s<<"Unknown_Object";
}
if(publishTF)
{
//Filter Signal
if(filtered)
{ //If the signal is non filtered,filter it and than save values of position and orientation
tf::Vector3 X=transform.getOrigin();
tf::Quaternion Q=transform.getRotation();
//Orientation
this->qx(0)=Q.getX();
this->qy(0)=Q.getY();
this->qz(0)=Q.getZ();
this->qw(0)=Q.getW();
//Position
this->x(0)=X.getX();
this->y(0)=X.getY();
this->z(0)=X.getZ();
if(setOld)
{
//copy the first transformation to old and vold in both real and filtered
for(unsigned int i=1;i<3;i++)
{
this->qx(i)=qx(0);
this->qy(i)=qy(0);
this->qz(i)=qz(0);
this->qw(i)=qw(0);
this->qxf(i)=qx(0);
this->qyf(i)=qy(0);
this->qzf(i)=qz(0);
this->qwf(i)=qw(0);
this->x(i)=x(0);
this->y(i)=y(0);
this->z(i)=z(0);
this->xf(i)=x(0);
this->yf(i)=y(0);
this->zf(i)=z(0);
}
setOld=false;
}
MarkerDetector::FilterButter(this->qx,this->qxf,this->B,this->A);
MarkerDetector::FilterButter(this->qy,this->qyf,this->B,this->A);
MarkerDetector::FilterButter(this->qz,this->qzf,this->B,this->A);
MarkerDetector::FilterButter(this->qw,this->qwf,this->B,this->A);
MarkerDetector::FilterButter(this->x,this->xf,this->B,this->A);
MarkerDetector::FilterButter(this->y,this->yf,this->B,this->A);
MarkerDetector::FilterButter(this->z,this->zf,this->B,this->A);
transform.setRotation(tf::Quaternion(this->qxf(0),this->qyf(0),this->qzf(0),this->qwf(0)));
transform.setOrigin(tf::Vector3(this->xf(0),this->yf(0),this->zf(0)));
}
sTransform=tf::StampedTransform(transform, ros::Time::now(), this->cameraNameTag, s.str());
if(this->broadcastTF)
{
br1.sendTransform(sTransform);
}
publishTF=false;
}
else
{
sTransform=tf::StampedTransform(transform, ros::Time::now(), this->cameraNameTag, s.str());
if(this->broadcastTF)
{
br1.sendTransform(sTransform);
}
}
//Clear the labels
s.str("");
if (cameraParameters.isValid())
{
// aruco::CvDrawingUtils::draw3dCube(cv_ptr->image,Markers1[i],cameraParameters1);
aruco::CvDrawingUtils::draw3dAxis(cv_ptr->image,Markers[i],cameraParameters);
}
aux.markerID=Markers[i].id;
cv::Point2f cent=Markers[i].getCenter();
for(unsigned int ind=0;ind<4;ind++)
{
aux.points[ind].x=Markers[i][ind].x;
aux.points[ind].y=Markers[i][ind].y;
//Force the visual points to be homogeneous --this is used with the homography transformation --
aux.points[ind].z=1.0;
}
//Plot Marker Center
aux.points[4].x=cent.x;
aux.points[4].y=cent.y;
//Force the visual points to be homogeneous --this is used with the homography transformation --
aux.points[4].z=1.0;
cv::circle(cv_ptr->image,cv::Point2f(aux.points[4].x,aux.points[4].y),1,cv::Scalar(0,255,255),6);
//Copy current transform
tf::transformTFToMsg(transform,msgTransform);
aux.tfMarker=msgTransform;
msgVisPointsArray.header.stamp = ros::Time::now();
msgVisPointsArray.header.frame_id = this->cameraNameTag;
msgVisPointsArray.mTrackerID = this->markerTrackerID;
msgVisPointsArray.markerData.push_back(aux);
//Print the visual position of the marker's center
s<<"("<<msgVisPointsArray.markerData[i].points[4].x<<","<<msgVisPointsArray.markerData[i].points[4].y<<")";
cv::putText(cv_ptr->image,s.str().c_str(),cent,cv::FONT_HERSHEY_COMPLEX,1,cv::Scalar(255,0,0),3);
s.str("");
}
/**
* The publish() function is how you send messages. The parameter
* is the message object. The type of this object must agree with the type
* given as a template parameter to the advertise<>() call, as was done
* in the constructor in main().
*/
//Convert the CvImage to a ROS image message and publish it on the "camera/image_processed" topic.
pub.publish(cv_ptr->toImageMsg());
pubVisData.publish(msgVisPointsArray);
msgVisPointsArray.markerData.clear();
}
This program recognize a marker with a specific Id! i want to use the second program using this specific marker as input
The best way to do this?
The code below will run a separate process specified by the command command and pipe the output of stdout to the string M.
FILE* p = popen("command", "r");
if (!p)
return 1;
char buf[100];
std::string M;
while (!feof(p)) {
if (fgets(buf, 100, p) != NULL)
M += buf;
}
pclose(p);
If you know that command will print whatever you need on its standard output, this should do what you want. Required includes:
#include <string>
#include <iostream>
#include <stdio.h>
EDIT:
After you posted the code of the other process, it is clear to me that you are approaching the problem wrong. You are using ROS which is basically a middleware facilitating interprocess communication in robotic applications. ROS itself provides the tools for performing the exchange of strings between the processes and you should use ROS to perform that exchange. You use topics to exchange data and in your case, one process should subscribe to a topic while another should publish to it. The receiving process will receive a callback whenever string is being published and will have access to the data. Check out http://wiki.ros.org/Topics for more info about topics in ROS.
If you are on a unix/linux system, you can pass output of one program to another with a pipe. For example
ls | wc -l
ls prints the names of all the files in a directory and wc -l takes that output and counts the number of lines.
To accept a pipe, your receiving program needs to read from stdin. For example
std::string s;
while (std::cin >> s) {
// do something with the string
}
Related
I am using the Windows api Gatt Client BLE for C++, my goal is to connect two devices (but in this case I will try just one) and keep reading and writing data constantly without closing the device at any time. All my devices have one specific service that contains a read characteristic and a write one.
HOW TO TEST:
Use Visual studio 2017 (v141) with Windows SDK Version: 10.0.18362.0, create a new console (.exe) solution, change the Platform in Project -> Properties to Win32 and go to Project -> Properties -> C/C++ -> Command Line and add these options:
/std:c++17 /await
Then copy the following code in a file (you can copy all in the same .cpp file):
#pragma once
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <queue>
#include <map>
#include <mutex>
#include <condition_variable>
#include <string>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h"
#include "winrt/Windows.Devices.Enumeration.h"
#include "winrt/Windows.Storage.Streams.h"
#pragma comment(lib, "windowsapp")
using namespace std;
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Web::Syndication;
using namespace Windows::Devices::Bluetooth;
using namespace Windows::Devices::Bluetooth::GenericAttributeProfile;
using namespace Windows::Devices::Enumeration;
using namespace Windows::Storage::Streams;
#pragma region STRUCS AND ENUMS
#define LOG_ERROR(e) cout << e << endl;
union to_guid
{
uint8_t buf[16];
guid guid;
};
const uint8_t BYTE_ORDER[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
guid make_guid(const wchar_t* value)
{
to_guid to_guid;
memset(&to_guid, 0, sizeof(to_guid));
int offset = 0;
for (unsigned int i = 0; i < wcslen(value); i++) {
if (value[i] >= '0' && value[i] <= '9')
{
uint8_t digit = value[i] - '0';
to_guid.buf[BYTE_ORDER[offset / 2]] += offset % 2 == 0 ? digit << 4 : digit;
offset++;
}
else if (value[i] >= 'A' && value[i] <= 'F')
{
uint8_t digit = 10 + value[i] - 'A';
to_guid.buf[BYTE_ORDER[offset / 2]] += offset % 2 == 0 ? digit << 4 : digit;
offset++;
}
else if (value[i] >= 'a' && value[i] <= 'f')
{
uint8_t digit = 10 + value[i] - 'a';
to_guid.buf[BYTE_ORDER[offset / 2]] += offset % 2 == 0 ? digit << 4 : digit;
offset++;
}
else
{
// skip char
}
}
return to_guid.guid;
}
mutex subscribeLock;
condition_variable subscribeSignal;
mutex _mutexWrite;
condition_variable signalWrite;
struct DeviceCacheEntry {
BluetoothLEDevice device = nullptr;
GattDeviceService service = nullptr;
GattCharacteristic characteristic = nullptr;
};
map<wstring, DeviceCacheEntry> cache;
struct Subscription {
GattCharacteristic::ValueChanged_revoker revoker;
};
struct BLEDeviceData {
wstring id;
wstring name;
bool isConnectable = false;
Subscription* subscription = NULL;
};
vector<BLEDeviceData> deviceList{};
mutex deviceListLock;
condition_variable deviceListSignal;
#pragma endregion
#pragma region CACHE FUNCTIONS
//Call this function to get a device from cache or async if it wasn't found
IAsyncOperation<BluetoothLEDevice> getDevice(wchar_t* deviceId) {
if (cache.count(wstring(deviceId)) && cache[wstring(deviceId)].device)
co_return cache[wstring(deviceId)].device;
BluetoothLEDevice result = co_await BluetoothLEDevice::FromIdAsync(deviceId);
if (result == nullptr) {
LOG_ERROR("Failed to connect to device.")
co_return nullptr;
}
else {
DeviceCacheEntry d;
d.device = result;
if (!cache.count(wstring(deviceId))) {
cache.insert({ wstring(deviceId), d });
}
else {
cache[wstring(deviceId)] = d;
}
co_return cache[wstring(deviceId)].device;
}
}
//Call this function to get a service from cache or async if it wasn't found
IAsyncOperation<GattDeviceService> getService(wchar_t* deviceId, wchar_t* serviceId) {
if (cache.count(wstring(deviceId)) && cache[wstring(deviceId)].service)
co_return cache[wstring(deviceId)].service;
auto device = co_await getDevice(deviceId);
if (device == nullptr)
co_return nullptr;
GattDeviceServicesResult result = co_await device.GetGattServicesForUuidAsync(make_guid(serviceId), BluetoothCacheMode::Cached);
if (result.Status() != GattCommunicationStatus::Success) {
LOG_ERROR("Failed getting services. Status: " << (int)result.Status())
co_return nullptr;
}
else if (result.Services().Size() == 0) {
LOG_ERROR("No service found with uuid")
co_return nullptr;
}
else {
if (cache.count(wstring(deviceId))) {
cache[wstring(deviceId)].service = result.Services().GetAt(0);
}
co_return cache[wstring(deviceId)].service;
}
}
//Call this function to get a characteristic from cache or async if it wasn't found
IAsyncOperation<GattCharacteristic> getCharacteristic(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId) {
try {
if (cache.count(wstring(deviceId)) && cache[wstring(deviceId)].characteristic)
co_return cache[wstring(deviceId)].characteristic;
auto service = co_await getService(deviceId, serviceId);
if (service == nullptr)
co_return nullptr;
GattCharacteristicsResult result = co_await service.GetCharacteristicsForUuidAsync(make_guid(characteristicId), BluetoothCacheMode::Cached);
if (result.Status() != GattCommunicationStatus::Success) {
LOG_ERROR("Error scanning characteristics from service. Status: " << (int)result.Status())
co_return nullptr;
}
else if (result.Characteristics().Size() == 0) {
LOG_ERROR("No characteristic found with uuid")
co_return nullptr;
}
else {
if (cache.count(wstring(deviceId))) {
cache[wstring(deviceId)].characteristic = result.Characteristics().GetAt(0);
}
co_return cache[wstring(deviceId)].characteristic;
}
}
catch (...) {
LOG_ERROR("Exception while trying to get characteristic")
}
}
#pragma endregion
#pragma region SCAN DEVICES FUNCTIONS
DeviceWatcher deviceWatcher{ nullptr };
mutex deviceWatcherLock;
DeviceWatcher::Added_revoker deviceWatcherAddedRevoker;
DeviceWatcher::Updated_revoker deviceWatcherUpdatedRevoker;
DeviceWatcher::Removed_revoker deviceWatcherRemovedRevoker;
DeviceWatcher::EnumerationCompleted_revoker deviceWatcherCompletedRevoker;
struct TestBLE {
static void ScanDevices();
static void StopDeviceScan();
};
//This function would be called when a new BLE device is detected
void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo) {
BLEDeviceData deviceData;
deviceData.id = wstring(deviceInfo.Id().c_str());
deviceData.name = wstring(deviceInfo.Name().c_str());
if (deviceInfo.Properties().HasKey(L"System.Devices.Aep.Bluetooth.Le.IsConnectable")) {
deviceData.isConnectable = unbox_value<bool>(deviceInfo.Properties().Lookup(L"System.Devices.Aep.Bluetooth.Le.IsConnectable"));
}
deviceList.push_back(deviceData);
}
//This function would be called when an existing BLE device is updated
void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
wstring deviceData = wstring(deviceInfoUpdate.Id().c_str());
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceData) {
if (deviceInfoUpdate.Properties().HasKey(L"System.Devices.Aep.Bluetooth.Le.IsConnectable")) {
deviceList[i].isConnectable = unbox_value<bool>(deviceInfoUpdate.Properties().Lookup(L"System.Devices.Aep.Bluetooth.Le.IsConnectable"));
}
break;
}
}
}
void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
}
void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, IInspectable const&) {
TestBLE::StopDeviceScan();
TestBLE::ScanDevices();
}
//Call this function to scan async all BLE devices
void TestBLE::ScanDevices() {
try {
lock_guard lock(deviceWatcherLock);
IVector<hstring> requestedProperties = single_threaded_vector<hstring>({ L"System.Devices.Aep.DeviceAddress", L"System.Devices.Aep.IsConnected", L"System.Devices.Aep.Bluetooth.Le.IsConnectable" });
hstring aqsFilter = L"(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")"; // list Bluetooth LE devices
deviceWatcher = DeviceInformation::CreateWatcher(aqsFilter, requestedProperties, DeviceInformationKind::AssociationEndpoint);
deviceWatcherAddedRevoker = deviceWatcher.Added(auto_revoke, &DeviceWatcher_Added);
deviceWatcherUpdatedRevoker = deviceWatcher.Updated(auto_revoke, &DeviceWatcher_Updated);
deviceWatcherRemovedRevoker = deviceWatcher.Removed(auto_revoke, &DeviceWatcher_Removed);
deviceWatcherCompletedRevoker = deviceWatcher.EnumerationCompleted(auto_revoke, &DeviceWatcher_EnumerationCompleted);
deviceWatcher.Start();
}
catch (exception e) {
LOG_ERROR(e.what())
}
}
void TestBLE::StopDeviceScan() {
scoped_lock lock(deviceListLock, deviceWatcherLock);
if (deviceWatcher != nullptr) {
deviceWatcherAddedRevoker.revoke();
deviceWatcherUpdatedRevoker.revoke();
deviceWatcherRemovedRevoker.revoke();
deviceWatcherCompletedRevoker.revoke();
deviceWatcher.Stop();
deviceWatcher = nullptr;
}
deviceListSignal.notify_one();
}
#pragma endregion
#pragma region SUBSCRIBE/READ FUNCTIONS
//On this function you can read all data from the specified characteristic
void Characteristic_ValueChanged(GattCharacteristic const& characteristic, GattValueChangedEventArgs args)
{
LOG_ERROR("Read data from device: " << to_string(characteristic.Service().Device().DeviceId()) << ", data size: " << args.CharacteristicValue().Length())
}
//Function used to subscribe async to the specific device
fire_and_forget SubscribeCharacteristicAsync(wstring deviceId, wstring serviceId, wstring characteristicId, bool* result) {
try {
auto characteristic = co_await getCharacteristic(&deviceId[0], &serviceId[0], &characteristicId[0]);
if (characteristic != nullptr) {
auto status = co_await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify);
if (status != GattCommunicationStatus::Success) {
LOG_ERROR("Error subscribing to characteristic. Status: " << (int)status)
}
else {
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceId) {
deviceList[i].subscription = new Subscription();
deviceList[i].subscription->revoker = characteristic.ValueChanged(auto_revoke, &Characteristic_ValueChanged);
break;
}
}
if (result != 0)
*result = true;
}
}
}
catch (hresult_error& ex)
{
LOG_ERROR("SubscribeCharacteristicAsync error: " << to_string(ex.message().c_str()))
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceId && deviceList[i].subscription) {
delete deviceList[i].subscription;
deviceList[i].subscription = NULL;
break;
}
}
}
subscribeSignal.notify_one();
}
//Call this function to subscribe to the specific device so you can read data from it
bool SubscribeCharacteristic(wstring deviceId, wstring serviceId, wstring characteristicId) {
unique_lock<mutex> lock(subscribeLock);
bool result = false;
SubscribeCharacteristicAsync(deviceId, serviceId, characteristicId, &result);
subscribeSignal.wait(lock);
return result;
}
#pragma endregion
#pragma region WRITE FUNCTIONS
//Function used to send data async to the specific device
fire_and_forget SendDataAsync(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, uint8_t * data, uint16_t size, bool* result) {
try {
auto characteristic = co_await getCharacteristic(deviceId, serviceId, characteristicId);
if (characteristic != nullptr) {
DataWriter writer;
writer.WriteBytes(array_view<uint8_t const>(data, data + size));
IBuffer buffer = writer.DetachBuffer();
auto status = co_await characteristic.WriteValueAsync(buffer, GattWriteOption::WriteWithoutResponse);
if (status != GattCommunicationStatus::Success) {
LOG_ERROR("Error writing value to characteristic. Status: " << (int)status)
}
else if (result != 0) {
LOG_ERROR("Data written succesfully")
*result = true;
}
}
}
catch (hresult_error& ex)
{
LOG_ERROR("SendDataAsync error: " << to_string(ex.message().c_str()))
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceId && deviceList[i].subscription) {
delete deviceList[i].subscription;
deviceList[i].subscription = NULL;
break;
}
}
}
signalWrite.notify_one();
}
//Call this function to write data on the device
bool SendData(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, uint8_t * data, uint16_t size) {
bool result = false;
unique_lock<mutex> lock(_mutexWrite);
// copy data to stack so that caller can free its memory in non-blocking mode
SendDataAsync(deviceId, serviceId, characteristicId, data, size, &result);
signalWrite.wait(lock);
return result;
}
#pragma endregion
Finally copy this main function (it can be copied at the end of the same file):
int main() {
//The mac of the device that will be tested
wstring deviceMac = L"00:11:22:33:44:55";
//These are the serviceUUID, readCharacteristicUUID and writeCharacteristicUUID as I said previously
wstring serviceUUID = L"{47918888-5555-2222-1111-000000000000}";
wstring readUUID = L"{31a28888-5555-2222-1111-00000000cede}";
wstring writeUUID = L"{f55a8888-5555-222-1111-00000000957a}";
//I think it is the mac of the BLE USB Dongle because it is in all device id when they are enumerated
wstring otherMac = L"24:4b:fe:3a:1a:ba";
//The device Id that we are looking for
wstring deviceId = L"BluetoothLE#BluetoothLE" + otherMac;
deviceId += L"-";
deviceId += deviceMac;
//To start scanning just call this function
TestBLE::ScanDevices();
//Data to be written all the time
const uint16_t dataSize = 3;
uint8_t data [dataSize]= { 0x0, 0xff, 0xff };
//Wait time in miliseconds between each write
chrono::milliseconds waitTime = 100ms;
//It will be executed always
while (true) {
//Then every device and their info updated would be in this vector
for (int i = 0; i < deviceList.size(); i++) {
//If the device is connectable we will try to connect if we aren't subscribed yet or send information
if (deviceList[i].isConnectable) {
//We can do here the following code to know the structure of the device id (if otherMac variable is the BLE USB dongle mac or not)
//cout << to_string(deviceList[i].id) << endl;
if (!deviceList[i].subscription && deviceList[i].id == deviceId) {
SubscribeCharacteristic(deviceList[i].id, serviceUUID, readUUID);
}
else if (deviceList[i].subscription) {
SendData(&deviceId[0], &serviceUUID[0], &writeUUID[0], data, dataSize);
}
}
}
this_thread::sleep_for(waitTime);
}
}
You will need a BLE device with a service that contains a reading and a writing characteristic, set the corresponding values in the deviceMac, serviceUUID, readUUID and writeUUID variables, you can also modify the bytes that are going to be written in data and dataSize, and the time between writes in waitTime. The otherMac variable should be the mac of the BLE USB dongle device but I recommend that you check it by getting the id of the devices from deviceList inside the for loop.
When you run this code on some rare times you will get the error "Failed getting services. Status:" with result 1 (unreachable) or 3 (access denied) and in the rest of the cases it will be reading the device data correctly and after a while it will give the error "SendDataAsync error: Object has been disposed" and from there it will continue giving "SubscribeCharacteristicAsync error: Object has been disposed", so at some point it will stop being able to read data of the device. What could be the reason?
EDIT 1:
It is quite strange because with this code the data is never written correctly (the "Data written succesfully" message is not displayed) but in my completed code I have always been able to write the data, maybe the problem is still the same and it is related to the characteristic stored in the "map <wstring, DeviceCacheEntry> cache" since perhaps it is stored as a copy and when trying to access it at some point it is disposed by Windows (since it is a copy of the original that is stored in the cache) and gives the error as described in the answer to this post in the point named "UPDATE 2 - SOME WEIRDNESS"
How do I take images with Sapera SDK and transfer the image data from the SapBuffer object to vector?
To handle images taken by camera using Sapera, you should make specialization of SapProcessing class, which is used to process buffers. Otherwise the buffer is cleared automatically after each frame, and you lose the data.
The imaging process goes as follows:
You call Grab() on the camera object to start imaging
After each frame has been taken, transfer callback is called. Here you request your SapProcessing object to process the next frame.
Run() function of your SapProcessing object is called. Here you can read data from the buffer.
After Run() function, processing callback is called.
When you have received enough frames, call Freeze() to stop imaging.
This example code takes images using default settings on the camera (monochrome 8-bit pixel format).
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include <atomic>
#include "SapClassBasic.h"
// Helper function to find the camera by its serial number
SapAcqDevice getDeviceBySN(const std::string& sn)
{
char serverName[CORSERVER_MAX_STRLEN];
char serialNumberName[2048];
const int serverCount = SapManager::GetServerCount();
for (int i = 0; i < serverCount; i++) {
if (SapManager::GetResourceCount(i, SapManager::ResourceAcqDevice) != 0)
{
SapManager::GetServerName(i, serverName, sizeof(serverName));
SapAcqDevice camera(serverName);
if (!camera.Create()) {
throw std::runtime_error("Failed to create camera object.");
}
int featureCount;
if (camera.GetFeatureCount(&featureCount) && featureCount > 0)
{
if (camera.GetFeatureValue("DeviceID", serialNumberName, sizeof(serialNumberName))
&& serialNumberName == sn)
{
return camera;
}
}
camera.Destroy();
}
}
const auto errorStr = "Camera \"" + sn + "\" was not found.";
throw std::runtime_error(errorStr.c_str());
}
class SapMyProcessing : public SapProcessing
{
public:
SapMyProcessing(SapBuffer* pBuffers, SapProCallback pCallback, void* pContext);
virtual ~SapMyProcessing();
protected:
virtual BOOL Run();
};
SapMyProcessing::SapMyProcessing(SapBuffer* pBuffers, SapProCallback pCallback, void* pContext)
: SapProcessing(pBuffers, pCallback, pContext)
{}
SapMyProcessing::~SapMyProcessing()
{
if (m_bInitOK) Destroy();
}
BOOL SapMyProcessing::Run()
{
// Get the current buffer index
const int proIndex = GetIndex();
// If this is not true, buffer has overflown
SapBuffer::State state;
bool goodContent = m_pBuffers->GetState(proIndex, &state)
&& state == SapBuffer::StateFull;
if (goodContent) {
void *inAddress = nullptr;
m_pBuffers->GetAddress(proIndex, &inAddress);
int inSize = 0;
m_pBuffers->GetSpaceUsed(proIndex, &inSize);
// Width, height and pixel format are received from the camera
const int width = m_pBuffers->GetWidth();
const int height = m_pBuffers->GetHeight();
const auto format = m_pBuffers->GetFormat();
const int outSize = width * height;
// Skip unexpected pixel format or incomplete frame
goodContent = format == SapFormatMono8
&& inSize == outSize;
if (goodContent) {
// Copy data to vector
std::vector<uint8_t> outBuffer(outSize);
std::copy((uint8_t*)inAddress, (uint8_t*)(inAddress) + outSize, outBuffer.begin());
// Print the first line
for (int i = 0; i < width; i++) {
std::cout << std::hex << int(outBuffer[i]);
}
std::cout << std::endl << std::endl;
}
}
return TRUE;
}
// Information to pass to callbacks
struct TransferContext {
std::atomic_int frameGrabCount = 0, frameProcessingCount = 0;
std::shared_ptr<SapMyProcessing> processing;
};
void transferCallback(SapXferCallbackInfo *info)
{
auto context = (TransferContext*)info->GetContext();
context->frameGrabCount++;
if (!info->IsTrash()) {
// Execute Run() for this frame
context->processing->ExecuteNext();
}
}
// Processing callback is called after Run()
void processingCallback(SapProCallbackInfo* info)
{
auto context = (TransferContext*)info->GetContext();
// Processing has finished
context->frameProcessingCount++;
}
// The main imaging function
void grab(const std::string& serialNumber)
{
// Number of frames to receive from the camera
const int maxFrameCount = 10;
TransferContext context;
auto camera = getDeviceBySN(serialNumber);
std::unique_ptr<SapBuffer> buffer
= std::make_unique<SapBufferWithTrash>(maxFrameCount, &camera);
std::unique_ptr<SapTransfer> transfer
= std::make_unique<SapAcqDeviceToBuf>(&camera, buffer.get(), transferCallback, &context);
context.processing = std::make_shared<SapMyProcessing>(buffer.get(), processingCallback, &context);
auto cleanup = [&]() {
if (context.processing) context.processing->Destroy();
if (transfer) transfer->Destroy();
if (buffer) buffer->Destroy();
camera.Destroy();
};
try {
if (!buffer->Create()) {
throw std::runtime_error("Failed to create buffer object.");
}
if (!transfer->Create()) {
throw std::runtime_error("Failed to create transfer object.");
}
if (!context.processing->Create()) {
throw std::runtime_error("Failed to create processing object.");
}
transfer->SetAutoEmpty(false);
context.processing->SetAutoEmpty(true);
context.processing->Init();
transfer->Grab();
// Wait for the camera to grab all frames
while (context.frameGrabCount < maxFrameCount);
transfer->Freeze();
if (!transfer->Wait(5000)) {
throw std::runtime_error("Failed to stop grab.");
}
// Wait for processing to complete
while (context.frameProcessingCount < maxFrameCount);
cleanup();
}
catch (...) {
cleanup();
throw;
}
}
I need to make small video player with OpenCV, which have to support the following functionality. Key 'p' on keyboard - pause/unpause, 'q' - exit, left and right arrow keys - play video frame by frame straight and reverse when it is paused. So the problem is when I try to show video with high quality and I hold arrow key for several seconds it does not run, but freeze and then jump to current frame after I release key. I tried to fix this with adding this_thread::sleep after cv::imshow() to give time to draw, but it did not help at all. So here is the code. Also, I have some reasons to use boost instead of C++11, so it is ok.
main.cpp
#include "VideoPlayer.hpp"
#include <iostream>
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cerr << "Video file full name required as argument." << std::endl;
}
VideoPlayer vp(argv[1]);
if (!vp.play())
return 1;
return 0;
}
VideoPlayer.hpp
#pragma once
#include <opencv/cxcore.hpp>
#include <opencv/highgui.h>
#include <string>
class VideoPlayer
{
public:
VideoPlayer(const std::string &video, const std::string &windowName = "Output window",
unsigned int delay = 30);
bool play();
private:
cv::VideoCapture videoCapture_;
std::string windowName_;
unsigned int delay_;
private:
bool processKey(int key);
void setFrame(int frameNum);
};
VideoPlayer.cpp
#include "VideoPlayer.hpp"
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
VideoPlayer::VideoPlayer(const std::string &video, const std::string &windowName,
unsigned int delay)
: videoCapture_(video)
, windowName_(windowName)
, delay_(delay)
{}
bool VideoPlayer::play()
{
if (!videoCapture_.isOpened()) {
std::cerr << "Unable to open video." << std::endl;
return false;
}
cv::namedWindow(windowName_);
for (;;) {
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
int key = cv::waitKey(delay_);
if (processKey(key))
break;
}
return true;
}
bool VideoPlayer::processKey(int key)
{
if (key == 'p') {
for (;;) {
int pausedKey = cv::waitKey(0);
if (pausedKey == 'p') {
break;
} else if (pausedKey == 'q') {
return true;
} else if (pausedKey == 65363) {
int frameNum = videoCapture_.get(CV_CAP_PROP_POS_FRAMES);
setFrame(frameNum);
} else if (pausedKey == 65361) {
int frameNum = videoCapture_.get(CV_CAP_PROP_POS_FRAMES);
setFrame(frameNum - 2);
}
}
} else if (key == 'q') {
return true;
}
return false;
}
void VideoPlayer::setFrame(int frameNum)
{
if (frameNum > 0 && frameNum < videoCapture_.get(CV_CAP_PROP_FRAME_COUNT)) {
std::cerr << frameNum << std::endl;
videoCapture_.set(CV_CAP_PROP_POS_FRAMES, frameNum);
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
}
I also created a multithreading implementation with buffer based on std::queue with lock, but it didn't solve the problem. And I tried to use boost::lockfree::queue, but I could not manage to finish it because of some strange behavior. I will share this code later, if it is necessary.
So, if somebody knows some good practice, how to avoid this problem, help me please.
EDIT:
Replacing boost::this_thread::sleep(boost::posix_time::milliseconds(10)); with cv::waitKey(0) is bad, because is makes me to do two short presses on arrow key to change one frame, and it does not help, because holding key skips it very fast. So the following code helped, but it is too strange and it is necessary to select times each for each video.
void VideoPlayer::setFrame(int frameNum)
{
if (frameNum > 0 && frameNum < videoCapture_.get(CV_CAP_PROP_FRAME_COUNT)) {
std::cerr << frameNum << std::endl;
videoCapture_.set(CV_CAP_PROP_POS_FRAMES, frameNum);
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
int times = 7;
for (int i = 0; i < times; i++)
cv::waitKey(10);
}
}
Also, I'm unable to use Qt or something else, only C++03 with boost and OpenCV.
I think I need some trick to make cv::waitKey(time) wait fortime whether any key pressed or not.
I know this question has answers in stackoverflow, but still i can't resolv my problem, I don't see the error. I'm using vector and I think I'm using it correctly, I'm not doing any free or malloc/calloc or something. However, I'm sure the problem comes with vector, doing something wrong.
The most strange part is debbuging the program, it ocurrs in two or three differents sites.
I compile the code with SDL2 and the default gcc on linux. I'm using Netbeans, using the command
g++ -std=c++11 -g -Wall -c -g -MMD -MP -MF "path/src/game/Game.o.d" -o path/src/game/Game.o src/game/Game.cpp
and linking with -lSDL2 -lSDL2_image
The error, one of this
malloc(): memory corruption (fast): 0x0000000000d86d50 ***
corrupted double-linked list: 0x00000000013fb5d0 ***
or less usual: [link][1]
Valgrind show something like this but I don't know how to use it: [link][2]
I put here the most important code, but I leave you the complete project to see if you want. Hope you can help me. I'm not sure if I'm doing something wrong or the problem come on other way.
[Link to project][3]
Main.cpp
#include ... //some includes
using namespace std;
Shape* shape;
TableBoard board;
Square* square;
Command* command;
void keyDown(SDL_Event &evento) {
if (evento.type == SDL_KEYDOWN) {
SDL_Keycode key = evento.key.keysym.sym;
command = nullptr;
switch (key) {
case SDLK_LEFT:
command = new LeftRight(board, *shape, Direction::LEFT);
shape->addCommand(command);
break;
case SDLK_RIGHT:
command = new LeftRight(board, *shape, Direction::RIGHT);
shape->addCommand(command);
break;
case SDLK_DOWN:
command = new FallToGround(board, *shape);
shape->addCommand(command);
break;
case SDLK_ESCAPE:
exit(0);
}
}
}
void newShape() {
if (shape == nullptr || !shape->isCanFall()) {
shape = new LShape(*square);
board.addShape(shape);
shape->setCanFall(true);
Command* command = new Fall(board, *shape);
shape->addCommand(command);
}
}
int main(int argc, char** argv) {
Window pantalla;
SDL_Event evento;
board = TableBoard(pantalla.getWindow(), 20, 10);
Board meassureBoard = board.getMeassureBoard();
SDL_Texture* image = IMG_LoadTexture(pantalla.getPantalla(),
"resources/images/blue_bold.png");
//creo una celda, le paso datos de table y que él se pinte
square = new Square();
square = new Square();
square->setGraphics(meassureBoard, image);
square->setX(3);
square->setY(1);
bool letsQuit = false;
Timer timer{};
timer.start();
newShape();
while (!letsQuit) {
pantalla.clear();
shape->executeCommands();
shape->clearCommandsFinished();
board.paint(pantalla.getPantalla());
board.drawLines(pantalla.getPantalla());
pantalla.actualizar();
while (SDL_PollEvent(&evento)) {
if (evento.type == SDL_QUIT) { // Si es de salida
letsQuit = true;
} else {
keyDown(evento);
}
}
newShape();
if (timer.delta() < 16) {
SDL_Delay(16 - timer.delta());
}
timer.restart();
}
return 0;
}
Part of Shape (parent class of LShape)
void Shape::executeCommands() {
for(vector<Command*>::iterator it = commands.begin(); it != commands.end(); ++it) {
(*it)->execute();
}
}
void Shape::clearCommandsFinished() {
vector<int> remove;
int index=0;
for(vector<Command*>::iterator it = commands.begin(); it != commands.end(); ++it) {
if ((*it)->isAlive() != true) {
remove.push_back(index);
}
index++;
}
for(vector<int>::iterator it = remove.begin(); it != remove.end(); ++it) {
commands.erase(commands.begin()+(*it));
}
}
Part of command Fall, left and right is similar. Here gives the error
void Fall::execute() {
if (isAlive() && timer.delta() >= milisecondsFalling) {
timer.restart();
bool canMove = true;
vector<Square> squares = shape->nextMove(0, 1);
if (shape->isCanFall()) {
int number=shape->getNUMBER_OF_SQUARES();
for (int i = 0; i < number && canMove; i++) {
//check the range
if (squares[i].getX() < 0
|| squares[i].getX() > board.getNumberColumns() - 1
|| squares[i].getY() < 0
|| squares[i].getY() > board.getNumberRows() - 1) {
canMove = false;
} else {
if (board.isFilled(shape, squares[i])) {
canMove = false;
}
}
}
//if we can move, move it definitively
if (canMove) {
shape->move(0, 1);
board.updateBoard();
}else{
shape->setCanFall(false);
}
} else {
alive = false;
} //-> AT THIS EXACTLY MOMENT GIVE THE ERROR!! NOT AFTER, NOT BEFORE
}
}
Not important, but gives error here too. Parts of the window class
void Window::actualizar() {
// Mostramos la pantalla
SDL_RenderPresent(renderer); //EXACTLY POINT WHERE THROW THE ERROR, less frecuent
}
void Window::inicializacion() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
cout << "No se pudo iniciar SDL: " << SDL_GetError() << endl;
exit(1);
}
atexit(SDL_Quit);
pantalla = SDL_CreateWindow("Tetris", //CREATED AS PRIVATE IN HEADER INSIDE CLASS: SDL_Window *pantalla;
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
window.w, window.h,
0);
renderer = SDL_CreateRenderer(pantalla, -1, SDL_RENDERER_ACCELERATED);
this->clear();
if (pantalla == NULL) {
cout << "Error iniciando el entorno gráfico: " << SDL_GetError() << endl;
exit(1);
}
this->pantalla=pantalla;
}
Window::Window() {
window.w=1024;
window.h= 768;
inicializacion();
}
Edit: links deleted. Problem solved
I'm not going to debug this entire thing (which would be utterly non productive for either of us). I took a brief look at your source base, and spotted this:
vector<Square> Shape::nextMove(int x, int y)
{
//make a copy to not really moving the squares
vector<Square> clone(numberSquares);
for (int i = 0; i <= numberSquares; i++) { // <<=== HERE
clone[i] = *(new Square(squares[i]));
}
//get the next move
moveShape(clone, x, y);
//return the modified squares
return clone;
}
That <= is indexing one-past the size of your source and destination vectors, which is BAD. Making matters worse, the code within the for-loop is a blatant memory leak. The entire function should be reduced to this:
vector<Square> Shape::nextMove(int x, int y)
{
vector<Square> clone = squares;
moveShape(clone, x, y);
return clone;
}
Best of luck
I'm new to ncurses and we have a project to create a game of our choice.
The idea of my game is to have a spaceship and have enemies attack from the top.
I only started the code and I already ran into a problem, when i use the space bar to shoot a bullet, the bullet will travel, however i am unable to move my ship at the same time the bullet is moving.
#include<ncurses.h>
typedef struct
{/*define a structure for player information*/
int row;
int col;
}playerinfo;
int changeRow(int x,int m, int c)
{
if(x+m==22 || x+m==0 )
{
beep();
return x;
}
return x+m;
}
int changeColumn(int y,int n, int r)
{
if(y+n==72 || y+n==0 )
{
beep();
return y;
}
return y+n;
}
int main(){
initscr();
start_color();
assume_default_colors(COLOR_GREEN, COLOR_BLACK);
noecho();
cbreak();
curs_set(0); /* turn cursor display off */
timeout(0);
keypad(stdscr,TRUE); /* allow keypad keys to be used */
playerinfo playership;
playership.row= 10;
playership.col= 15;
char player[] =" X ";
char player2[]=" |o| ";
char player3[]=" xX| |Xx ";
char player4[]=" X | | X ";
char player5[]=" X__-|-__X ";
char bullet = '.';
int key = 0;
int i=0;
bool moving= false;
mvprintw(playership.row,playership.col,player);
mvprintw(playership.row+1,playership.col,player2);
mvprintw(playership.row+2,playership.col,player3);
mvprintw(playership.row+3,playership.col,player4);
mvprintw(playership.row+4,playership.col,player5);
timeout(0);
while(key!='q'){
usleep(17000);
mvprintw(playership.row,playership.col," ");
mvprintw(playership.row+5,playership.col," ");
key = getch ();
switch(key){
case KEY_UP: playership.row=changeRow(playership.row,-1,playership.col); /* move up */
break;
case KEY_DOWN: playership.row=changeRow(playership.row,+1,playership.col); /* move down */
break;
case KEY_LEFT:playership.col=changeColumn(playership.col,-1,playership.row); /* move left */
break;
case KEY_RIGHT:playership.col=changeColumn(playership.col,+1,playership.row); /* move right */
break;
case ' ': moving=true; break;
default: break; /* do nothing if other keys */
}
mvprintw(playership.row,playership.col,player);
mvprintw(playership.row+1,playership.col,player2);
mvprintw(playership.row+2,playership.col,player3);
mvprintw(playership.row+3,playership.col,player4);
mvprintw(playership.row+4,playership.col,player5);
if (moving==true){
for( i=0; i <24; i++){
refresh; mvprintw(playership.row-i-2,playership.col+5,"%c", bullet); mvprintw(playership.row,playership.col,player);
refresh();usleep(12000); mvprintw(playership.row-i-1,playership.col+5," ");} moving=false; }
refresh();
}
echo(); /* turn echo back on */
endwin(); /* End curses mode */
return 0;
}
That is because you nested the "firing" code inside your game loop, so all input stops while you do that animation. You need to change your logic to a kind of state machine:
switch(key)
{
// ...
case ' ':
if( !bullet_active )
{
bullet_active = true;
bullet_pos = 0;
}
break;
}
if( bullet_active ) {
// TODO: Draw bullet at bullet_pos
if( ++bullet_pos == 24 ) bullet_active = false;
}