I'm trying to get familiar with Graphics2D for NaCl, but I'm getting the error "NativeClient: NaCl module crashed" when I try to paint and flush my Graphics2D instance.
Here is the output of my calls to console.log:
View did change
Making graphics context
Drawing
Making blank image data
PaintAndFlush
Flush
I am on main thread
NativeClient: NaCl module crashed
Here is my index.html : https://jsfiddle.net/3c1y4wp9/
And here is my c++ code:
#include <deque>
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array.h"
#include "ppapi/utility/completion_callback_factory.h"
namespace {
const uint32_t kBlue = 0xff4040ffu;
const uint32_t kBlack = 0xff000000u;
}
class GravitySimInstance : public pp::Instance {
public:
explicit GravitySimInstance(PP_Instance instance) : pp::Instance(instance)
{}
virtual ~GravitySimInstance() {}
private:
virtual void HandleMessage(const pp::Var& var_message) {
}
void PaintAndFlush(pp::ImageData* image_data) {
PostMessage("PaintAndFlush");
assert(!flushing_);
graphics_2d_context_.ReplaceContents(image_data);
PostMessage("Flush");
if (pp::Module::Get()->core()->IsMainThread()) {
PostMessage("I am on main thread");
} else {
PostMessage("I am NOT on main thread");
}
graphics_2d_context_.Flush(
callback_factory_.NewCallback(&GravitySimInstance::DidFlush));
flushing_ = true;
}
void DidFlush(int32_t error_code) {
PostMessage("DidFlush");
flushing_ = false;
}
virtual void DidChangeView(const pp::View& view) {
PostMessage("View did change");
if (size_ != view.GetRect().size()) {
size_ = view.GetRect().size();
const bool is_always_opaque = true;
PostMessage("Making graphics context");
graphics_2d_context_ = pp::Graphics2D(this, view.GetRect().size(),
is_always_opaque);
BindGraphics(graphics_2d_context_);
Draw();
}
}
void Draw() {
PostMessage("Drawing");
pp::ImageData image_data = MakeBlankImageData(size_);
PaintAndFlush(&image_data);
}
pp::ImageData MakeBlankImageData(const pp::Size& size) {
PostMessage("Making blank image data");
const bool init_to_zero = false;
pp::ImageData image_data = pp::ImageData(this,
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
size,
init_to_zero);
uint32_t* image_buffer = static_cast<uint32_t*>(image_data.data());
for (int i = 0; i < size.GetArea(); ++i)
image_buffer[i] = kBlack;
return image_data;
}
pp::Graphics2D graphics_2d_context_;
pp::CompletionCallbackFactory<GravitySimInstance> callback_factory_;
/// The size of our rectangle in the DOM, as of the last time DidChangeView
/// was called.
pp::Size size_;
/// true iff we are flushing.
bool flushing_;
/// Stores the most recent histogram so that we can re-draw it if we get
/// resized.
double histogram_[10];
};
class GravitySimModule : public pp::Module {
public:
GravitySimModule() : pp::Module() {}
virtual ~GravitySimModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new GravitySimInstance(instance);
}
};
namespace pp {
Module* CreateModule() {
return new GravitySimModule();
}
} // namespace pp
Nothing looks obviously wrong, except where you initialize the image buffer. You need to take the stride into consideration when working with the image data. However, it doesn't look like you're writing out of bounds. Have you tried making init_to_zero true and using the ImageData as is to see if it still crashes?
Try calling of Flush function only in main thread. If you want to call such functions (which should be called in main thread) from working thread call them throuth pp::Core::CallOnMainThread function.
Related
I need to create a custom blueprint node. I am using the blueprint function library.
The node will look like this:
Input:
int timedelayforeachloop
int numberofloops
output:
exc loop
exc completed
loop1.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "loop1.generated.h"
/**
*
*/
UENUM(BlueprintType)
enum class EMultiBranchEnum1 : uint8
{
BranchA,
BranchB
};
UCLASS()
class MYPROJECT2_API Uloop1 : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable, meta = (DisplayName = "loop", CompactNodeTitle = "2as2", ExpandEnumAsExecs = "Branches"), Category = "1")
//UFUNCTION(BlueprintCallable, Meta = (DisplayName = "Multi Branch1", ExpandEnumAsExecs = "Branches"), Category = 1)
static void multiBranch(EMultiBranchEnum1& Branches, int loopqty);
//EMultiBranchEnum1::BranchB;
};
loop1.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "loop1.h"
void Uloop1::multiBranch(EMultiBranchEnum1& Branches, int loopqty)
{
int currloop1 = 0;
int temp = 2;
int i;
for (i = 0; i < 10; i++){
currloop1 = currloop1 + 1;
Branches = EMultiBranchEnum1::BranchA;
}
if (temp > currloop1) {
Branches = EMultiBranchEnum1::BranchB;
}
if(temp == 0) {
Branches = EMultiBranchEnum1::BranchB;
}
}
-- THE PROBLEM --
The for loop only runs the once (evident by the print node i have on branchA(It only prints a single time))
-- What should happen with the code below --
the loop should run the 10 times (my print node should print 10 times)
Instead of using UBlueprintFunctionLibrary, you should use UBlueprintAsyncActionBase. It will allow you to store state in the node and call things connected to the execution pins asynchronously.
DelayLoop.h file:
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "DelayLoop.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDelayOutputPin);
/**
*
*/
UCLASS()
class TEST_API UDelayLoop : public UBlueprintAsyncActionBase
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(BlueprintAssignable)
FDelayOutputPin Loop;
UPROPERTY(BlueprintAssignable)
FDelayOutputPin Complete;
UFUNCTION(BlueprintCallable,
meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"),
Category = "Flow Control")
static UDelayLoop* DelayLoop(const UObject* WorldContextObject,
const float DelayInSeconds, const int Iterations);
virtual void Activate() override;
private:
const UObject* WorldContextObject;
float MyDelay;
int MyIterations;
bool Active;
UFUNCTION()
void ExecuteLoop();
UFUNCTION()
void ExecuteComplete();
};
DelayLoop.cpp file:
#include "DelayLoop.h"
#include "Engine/World.h"
#include "TimerManager.h"
UDelayLoop::UDelayLoop(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer), WorldContextObject(nullptr), MyDelay(0.0f),
MyIterations(0), Active(false)
{
}
UDelayLoop* UDelayLoop::DelayLoop(const UObject* WorldContextObject,
const float DelayInSeconds, const int Iterations)
{
UDelayLoop* Node = NewObject<UDelayLoop>();
Node->WorldContextObject = WorldContextObject;
Node->MyDelay = DelayInSeconds;
Node->MyIterations = Iterations;
return Node;
}
void UDelayLoop::Activate()
{
if (nullptr == WorldContextObject)
{
FFrame::KismetExecutionMessage(TEXT("Invalid WorldContextObject."),
ELogVerbosity::Error);
return;
}
if (Active)
{
FFrame::KismetExecutionMessage(TEXT("DelayLoop is already running."),
ELogVerbosity::Warning);
}
if (MyDelay <= 0.0f)
{
FFrame::KismetExecutionMessage(
TEXT("DelayLoop delay can't be less or equal to 0."),
ELogVerbosity::Warning);
}
if (MyIterations <= 0)
{
FFrame::KismetExecutionMessage(
TEXT("DelayLoop iterations can't be less or equal to 0."),
ELogVerbosity::Warning);
}
Active = true;
for (int i = 0; i <= MyIterations; i++)
{
FTimerHandle IterationTimer;
WorldContextObject->GetWorld()->GetTimerManager().SetTimer(
IterationTimer, this, &UDelayLoop::ExecuteLoop, MyDelay * i);
}
FTimerHandle CompleteTimer;
WorldContextObject->GetWorld()->GetTimerManager().SetTimer(
CompleteTimer, this, &UDelayLoop::ExecuteComplete,
MyDelay * (MyIterations+1));
// If the Complete pin should happen at the same time as the last iteration
// use `MyDelay * MyIterations` here instead
}
void UDelayLoop::ExecuteLoop()
{
Loop.Broadcast();
}
void UDelayLoop::ExecuteComplete()
{
Complete.Broadcast();
Active = false;
}
This will get you a blueprint that looks like this:
Note: This code is heavily based on This Creating Asynchronous Blueprint Nodes guide by Daniel ~b617 Janowski, now hosted in the legacy wiki here
In order to separate my GUI from the logic (which fetches data from a REST service), I refactored some logic into a controller.
Now, only part of the logic seems to work.
The GUI component looks like this after refactoring (I am using the JUCE framework)
#pragma once
#include "../../JuceLibraryCode/JuceHeader.h"
#include "../../GUI.Controller/includes/ProjectEntryListController.h"
#include "ProjectEntryListComponent.h"
#include "LocalProjectEntryComponent.h"
class ProjectBrowserTabComponent : public TabbedComponent
{
public:
ProjectBrowserTabComponent();
~ProjectBrowserTabComponent();
private:
ProjectEntryListComponent m_remote_proj;
ProjectEntryListComponent m_local_proj;
ProjectEntryListController *pelccont = new ProjectEntryListController(&m_remote_proj);
ProjectEntryListController *pelccont2 = new ProjectEntryListController(&m_local_proj);
};
The GUI controller looks like this:
#define BOOST_THREAD_PROVIDES_FUTURE
#include "../includes/ProjectEntryListController.h"
template<typename R>
bool isReady(std::future<R> const& f)
{
Logger::writeToLog("check future");
return f.wait_for(std::chrono::seconds(-1)) == std::future_status::ready;
}
ProjectEntryListController::ProjectEntryListController(ProjectEntryListComponent *comp) {
m_comp = comp;
requestProjects();
}
void ProjectEntryListController::requestProjects()
{
Logger::writeToLog("requesting projects");
projectsFuture = std::async(std::launch::async, &ProjectsController::getProjects, &pc);
Logger::writeToLog("requested projects");
}
void ProjectEntryListController::backgroundCheckFuture()
{
timer = new boost::asio::deadline_timer(io_service, boost::posix_time::seconds(interval_secs));
timer->async_wait(boost::bind(&ProjectEntryListController::fetchData, this, boost::asio::placeholders::error, timer));
ioSvcFuture = std::async(std::launch::async, static_cast<size_t(boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io_service);
}
void ProjectEntryListController::initData() {
requestProjects();
backgroundCheckFuture();
}
void ProjectEntryListController::fetchData(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* tmr) {
if (isReady(projectsFuture)) {
projects = projectsFuture.get();
for (auto project : projects)
{
ProjectEntryComponent *pec = new ProjectEntryComponent(std::to_string(project.getId()), "222");
m_comp->addListEntry(pec);
m_comp->repaint();
}
Logger::writeToLog("got projs");
}
else {
tmr->expires_at(tmr->expires_at() + boost::posix_time::seconds(interval_secs));
tmr->async_wait(boost::bind(&ProjectEntryListController::fetchData, this, boost::asio::placeholders::error, tmr));
}
}
The requestProjects method's log messages are appearing in my console, but not the log message of the getProjects method I am calling asynchronously:
std::vector<Project> ProjectsController::getProjects() {
std::vector<Project> result;
if(serviceClient != nullptr) {
try
{
std::this_thread::sleep_for(std::chrono::seconds());
std::cout << "controller requested projs\n";
result = serviceClient->getAvailableProjects();
}
catch (const std::exception&)
{
}
}
return result;
}
However, when I debug into the code, the debugger (using VS 2015) also is able to step to the log message.
What am I doing wrong?
Actually I solved this now.
1.) I was calling the wrong method requestProjects instead of initData
2.) I couldn't see the result because the implementation of ProjectEntryComponent::ProjectEntryComponent(std::string name, std::string version) was missing
I'm implementing a "wait for WebSocket response before continuation" mechanism on PNaCl plugin through pp::WebSocketAPI in PPAPI. The following is a simplified version which stores the replied data into a global std::string, while the function myecho() sends a string through WebSocket and polling until the global string changes. The driver web page is the same as in the WebSocket example in NaCl SDK.
#include <string>
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array_buffer.h"
#include "ppapi/utility/websocket/websocket_api.h"
class MyWebSocketReceiveListener
{
public:
virtual void onWebSocketDataReceived(const std::string& data) = 0;
};
class MyWebSocketAPI : protected pp::WebSocketAPI
{
public:
MyWebSocketAPI(pp::Instance* ppinstance, MyWebSocketReceiveListener* recvlistener)
: pp::WebSocketAPI(ppinstance), m_onReceiveListener(recvlistener), m_ppinstance(ppinstance) {}
virtual ~MyWebSocketAPI() {}
bool isConnected() { return pp::WebSocketAPI::GetReadyState() == PP_WEBSOCKETREADYSTATE_OPEN; }
void open(const std::string& url) { pp::WebSocketAPI::Connect(url, NULL, 0); }
void close() { pp::WebSocketAPI::Close(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, "bye"); }
void sendData(const std::string& data) { pp::WebSocketAPI::Send(data); }
protected:
virtual void WebSocketDidOpen() { m_ppinstance->PostMessage("Connected"); }
virtual void WebSocketDidClose(bool wasClean, uint16_t code, const pp::Var& reason) {}
virtual void HandleWebSocketMessage(const pp::Var& message)
{
if (message.is_array_buffer()) {
pp::VarArrayBuffer vararybuf(message);
char *data = static_cast<char*>(vararybuf.Map());
std::string datastr(data, data + vararybuf.ByteLength());
vararybuf.Unmap();
m_onReceiveListener->onWebSocketDataReceived(datastr);
} else { // is string
m_onReceiveListener->onWebSocketDataReceived(message.AsString());
}
}
virtual void HandleWebSocketError() {}
private:
MyWebSocketAPI(const MyWebSocketAPI&);
MyWebSocketAPI& operator=(const MyWebSocketAPI&);
MyWebSocketReceiveListener* const m_onReceiveListener;
pp::Instance * const m_ppinstance;
};
static std::string g_returnval;
class MyPPPluginInstance : public pp::Instance, public MyWebSocketReceiveListener {
public:
explicit MyPPPluginInstance(PP_Instance instance)
: pp::Instance(instance), rpcwebsocket_(this, this) {}
virtual ~MyPPPluginInstance() {}
virtual void HandleMessage(const pp::Var& var_message);
virtual void onWebSocketDataReceived(const std::string& data)
{
g_returnval = data;
}
private:
bool IsConnected() { return rpcwebsocket_.isConnected(); }
void Open(const std::string& url)
{
rpcwebsocket_.open(url);
PostMessage(pp::Var("connecting..."));
}
void Close()
{
if (!IsConnected())
return;
rpcwebsocket_.close();
}
MyWebSocketAPI rpcwebsocket_;
};
std::string myecho(pp::Instance* inst, MyWebSocketAPI& ws, const std::string& in)
{
ws.sendData(in);
while (g_returnval.empty()) {
usleep(1000 * 1000); // 1 sec
inst->PostMessage("Waiting for response...");
}
return g_returnval;
}
void MyPPPluginInstance::HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string())
return;
std::string message = var_message.AsString();
// This message must contain a command character followed by ';' and
// arguments like "X;arguments".
if (message.length() < 2 || message[1] != ';')
return;
switch (message[0]) {
case 'o':
// The command 'o' requests to open the specified URL.
// URL is passed as an argument like "o;URL".
Open(message.substr(2));
break;
case 'c':
// The command 'c' requests to close without any argument like "c;"
Close();
break;
case 'b':
case 't':
PostMessage(std::string("Calling remote echo for ") + message.substr(2));
std::string ret(myecho(this, rpcwebsocket_, message.substr(2)));
PostMessage(ret);
break;
}
}
// Creates MyPPPluginInstance objects when invoked.
class MyPPPluginModule : public pp::Module {
public:
MyPPPluginModule() : pp::Module() {}
virtual ~MyPPPluginModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new MyPPPluginInstance(instance);
}
};
// Implement the required pp::CreateModule function that creates our specific
// kind of Module.
namespace pp {
Module* CreateModule() { return new MyPPPluginModule(); }
} // namespace pp
However, this approach didn't work. After connecting to the echo test server ws://echo.websocket.org and send "hello", I just get
connecting...
Connected
Calling remote echo for hello
Waiting for response...
Waiting for response...
Waiting for response...
Waiting for response...
Waiting for response...
(never replies)
I used another hand-crafted WebSocket server to test, and the message was sent to server successfully. And in addition to the usleep() polling as in my attached snippet, I've also tried to use pthread_cond_wait() and pthread_cond_signal() to wait for and notify about received message.
What should I do to "wait pp::WebSocketAPI receive data" correctly?
The function myecho() blocks MyPPPluginInstance::HandleMessage() and somehow in turn blocks receiving from WebSocket.
I added a pp::SimpleThread as a new data member of class MyPPPluginInstance and dispatch myecho() to another thread through pp::SimpleThread::message_loop().PostWork(). It works smoothly.
I'm trying to pass a single instance of my "Status" class to all my other classes so that they can all set and get the status.
I've been trying to do this by passing the "Status" class by reference into my "BaseStation" class. The code compiles fine but when I set the status from main and then get the status in "BaseStation" it has not changed.
I think this should be possible so I must be missing something.
Here is my main class
#include "mbed.h"
#include "Global.h"
#include "MODSERIAL.h"
#include "Status.h"
#include "Sensors.h"
#include "BaseStation.h"
#include "Rc.h"
#include "FlightController.h"
#include "NavigationController.h"
MODSERIAL _debug(USBTX, USBRX);
//Unused analog pins
DigitalOut _spare1(p16);
DigitalOut _spare2(p17);
DigitalOut _spare3(p18);
DigitalOut _spare4(p19);
//Classes
Status _status;
Sensors _sensors;
BaseStation _baseStation;
Rc _rc;
FlightController _flightController;
NavigationController _navigationController;
int main()
{
_debug.baud(115200);
DEBUG("\r\n");
DEBUG("********************************************************************************\r\n");
DEBUG("Starting Setup\r\n");
DEBUG("********************************************************************************\r\n");
//Set Status
_status.initialise();
//Initialise RC
//_rc.initialise(_status, p8);
//Initialise Sensors
//_sensors.initialise(p13, p14, p28, p27);
//Initialise Navigation
//_navigationController.initialise(_status, _sensors, _rc);
//Initialise Flight Controller
//_flightController.initialise(_status, _sensors, _navigationController, p21, p22, p23, p24);
//Initalise Base Station
_baseStation.initialise(_status, _rc, _sensors, _navigationController, _flightController, p9, p10);
DEBUG("********************************************************************************\r\n");
DEBUG("Finished Setup\r\n");
DEBUG("********************************************************************************\r\n");
_status.setState(Status::STANDBY);
int state = _status.getState();
printf("Main State %d\r\n", state);
}
Here is my Status.cpp
#include "Status.h"
Status::Status(){}
Status::~Status(){}
bool Status::initialise()
{
setState(PREFLIGHT);
DEBUG("Status initialised\r\n");
return true;
}
bool Status::setState(State state)
{
switch(state)
{
case PREFLIGHT:
setFlightMode(NOT_SET);
setBaseStationMode(STATUS);
setBatteryLevel(0);
setArmed(false);
setInitialised(false);
_state = PREFLIGHT;
DEBUG("State set to PREFLIGHT\r\n");
return true;
case STANDBY:
_state = STANDBY;
DEBUG("State set to STANDBY\r\n");
return true;
case GROUND_READY:
return true;
case MANUAL:
return true;
case STABILISED:
return true;
case AUTO:
return true;
case ABORT:
return true;
case EMG_LAND:
return true;
case EMG_OFF:
return true;
case GROUND_ERROR:
return true;
default:
return false;
}
}
Status::State Status::getState()
{
return _state;
}
bool Status::setFlightMode(FlightMode flightMode)
{
_flightMode = flightMode;
return true;
}
Status::FlightMode Status::getFlightMode()
{
return _flightMode;
}
bool Status::setBaseStationMode(BaseStationMode baseStationMode)
{
_baseStationMode = baseStationMode;
DEBUG("Base station mode set\r\n");
return true;
}
Status::BaseStationMode Status::getBaseStationMode()
{
return _baseStationMode;
}
bool Status::setBatteryLevel(float batteryLevel)
{
_batteryLevel = batteryLevel;
return true;
}
float Status::getBatteryLevel()
{
return _batteryLevel;
}
bool Status::setArmed(bool armed)
{
_armed = armed;
return true;
}
bool Status::getArmed()
{
return _armed;
}
bool Status::setInitialised(bool initialised)
{
_initialised = initialised;
return true;
}
bool Status::getInitialised()
{
return _initialised;
}
bool Status::setRcConnected(bool rcConnected)
{
_rcConnected = rcConnected;
return true;
}
bool Status::getRcConnected()
{
return _rcConnected;
}
Here is my status.h
#include "mbed.h"
#include "Global.h"
#ifndef Status_H
#define Status_H
class Status // begin declaration of the class
{
public: // begin public section
Status(); // constructor
~Status(); // destructor
enum State
{
PREFLIGHT,
STANDBY,
GROUND_READY,
MANUAL,
STABILISED,
AUTO,
ABORT,
EMG_LAND,
EMG_OFF,
GROUND_ERROR
};
enum FlightMode
{
RATE,
STAB,
NOT_SET
};
enum BaseStationMode
{
MOTOR_POWER,
PID_OUTPUTS,
IMU_OUTPUTS,
STATUS,
RC,
PID_TUNING,
GPS,
ZERO,
RATE_TUNING,
STAB_TUNING,
ALTITUDE,
VELOCITY
};
bool initialise();
bool setState(State state);
State getState();
bool setFlightMode(FlightMode flightMode);
FlightMode getFlightMode();
bool setBaseStationMode(BaseStationMode baseStationMode);
BaseStationMode getBaseStationMode();
bool setBatteryLevel(float batteryLevel);
float getBatteryLevel();
bool setArmed(bool armed);
bool getArmed();
bool setInitialised(bool initialised);
bool getInitialised();
bool setRcConnected(bool rcConnected);
bool getRcConnected();
private:
State _state;
FlightMode _flightMode;
BaseStationMode _baseStationMode;
float _batteryLevel;
bool _armed;
bool _initialised;
bool _rcConnected;
};
#endif
Here is my BaseStation.cpp
#include "BaseStation.h"
BaseStation::BaseStation() : _status(status){}
BaseStation::~BaseStation(){}
bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{
_status = status;
_rc = rc;
_sensors = sensors;
_navigationController = navigationController;
_flightController = flightController;
_wireless = new MODSERIAL(wirelessPinTx, wirelessPinRx);
_wireless->baud(57600);
_wirelessSerialRxPos = 0;
_thread = new Thread(&BaseStation::threadStarter, this, osPriorityHigh);
DEBUG("Base Station initialised\r\n");
return true;
}
void BaseStation::threadStarter(void const *p)
{
BaseStation *instance = (BaseStation*)p;
instance->threadWorker();
}
void BaseStation::threadWorker()
{
while(_status.getState() == Status::PREFLIGHT)
{
int state = _status.getState();
printf("State %d\r\n", state);
Thread::wait(100);
}
_status.setBaseStationMode(Status::RC);
}
Here is my BaseStation.h
#include "mbed.h"
#include "Global.h"
#include "rtos.h"
#include "MODSERIAL.h"
#include "Rc.h"
#include "Sensors.h"
#include "Status.h"
#include "NavigationController.h"
#include "FlightController.h"
#ifndef BaseStation_H
#define BaseStation_H
class BaseStation
{
public:
BaseStation();
~BaseStation();
struct Velocity
{
float accelX;
float accelY;
float accelZ;
float gps;
float gpsZ;
float barometerZ;
float lidarLiteZ;
float computedX;
float computedY;
float computedZ;
};
bool initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx);
private:
static void threadStarter(void const *p);
void threadWorker();
void checkCommand();
Thread* _thread;
MODSERIAL* _wireless;
Status& _status;
Status status;
Rc _rc;
Sensors _sensors;
NavigationController _navigationController;
FlightController _flightController;
char _wirelessSerialBuffer[255];
int _wirelessSerialRxPos;
};
#endif
The output when I run this is
********************************************************************************
Starting Setup
********************************************************************************
Base station mode set
State set to PREFLIGHT
Status initialised
Rc initialised
HMC5883L failed id check.IMU initialised
Sensors initialised
State 0
Base Station initialised
********************************************************************************
Finished Setup
********************************************************************************
State set to STANDBY
Main State 1
State 0
State 0
I think this is because I'm not in fact passing a single instance of "Status" but copying it.
How can I pass by reference properly?
Thanks
Joe
int x = 42;
int y = 9001;
int& r = x;
r = y;
Now x is 9001. You have not changed anything about r.
Similarly, in your code, although you accept a Status by reference, you then assign its value to a different object.
You may only initialise references. In your case you want to chain them.
Here's how you do what you want to do:
struct Status {};
struct T
{
T(Status& _ref) // 1. Accept parameter by reference;
: ref(_ref) // 2. Initialise member reference;
{} // now this->ref is a reference to whatever _ref was a reference to
Status& ref;
};
int main()
{
Status s;
T obj(s); // now obj holds a reference to s
}
You completely misunderstand how reference works in C++. You can set reference only in constructor and only in member initialization list, any other place you do assignment to object where that reference points to. So
BaseStation::BaseStation() : _status(status){}
Now your reference points to member status
bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{
_status = status;
Now you do assignment to object, where _status points to. So this code is actually equivalent to:
bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{
this->status = status;
It is not a good idea to replace constructor by initialize method in general, but in case you have reference, it is even worse. You need to either change it to a pointer, or initialize your objects properly - in constructor.
I wanted to be able to access my underlaying data structure when I pick a vtkActor. A class derived from vtkActor holding a ptr to my data structure seemed the easiest approach.
I get the subclass to compile just fine but the actor does not seem to be added to the renderer.
So, here's my class:
//.h
#include <vtkActor.h>
#include <vtkObjectFactory.h>
class Node;
struct Actor : public vtkActor {
static Actor* New();
vtkTypeMacro(Actor, vtkActor)
Node* holding_node;
};
//.cpp
#include "actor.h"
vtkStandardNewMacro(Actor)
In my rendering step: if I instantiate the actor with a vtkActor everything shows up as expected, picking works, etc...
vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
But no actor is added if I use my Actor class
vtkSmartPointer<Actor> sphereActor = vtkSmartPointer<Actor>::New();
Nothing else changes in the code. Any ideas of what's wrong?
So, it turns out that there are a bunch of functions that need to be overloaded and a couple touches of macro magic to get this to work.
I pasted below the example that's working for me now. It is mostly from the vtkFollower code (a derived class from vtkActor). Hope this helps!
#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderingCoreModule.h>
#include <vtkProperty.h>
class Node;
class VTKRENDERINGCORE_EXPORT NodeActor : public vtkActor {
public:
vtkTypeMacro(NodeActor, vtkActor);
static NodeActor *New();
virtual void ReleaseGraphicsResources(vtkWindow *window) {
this->Device->ReleaseGraphicsResources(window);
this->Superclass::ReleaseGraphicsResources(window);
}
virtual int RenderOpaqueGeometry(vtkViewport *viewport){
if ( ! this->Mapper ) {
return 0;
}
if (!this->Property) {
this->GetProperty();
}
if (this->GetIsOpaque()) {
vtkRenderer *ren = static_cast<vtkRenderer *>(viewport);
this->Render(ren);
return 1;
}
return 0;
}
virtual int RenderTranslucentPolygonalGeometry(vtkViewport *viewport){
if ( ! this->Mapper ) {
return 0;
}
if (!this->Property) {
this->GetProperty();
}
if (!this->GetIsOpaque()) {
vtkRenderer *ren = static_cast<vtkRenderer *>(viewport);
this->Render(ren);
return 1;
}
return 0;
}
virtual void Render(vtkRenderer *ren){
this->Property->Render(this, ren);
this->Device->SetProperty (this->Property);
this->Property->Render(this, ren);
if (this->BackfaceProperty) {
this->BackfaceProperty->BackfaceRender(this, ren);
this->Device->SetBackfaceProperty(this->BackfaceProperty);
}
if (this->Texture) {
this->Texture->Render(ren);
}
this->ComputeMatrix();
this->Device->SetUserMatrix(this->Matrix);
this->Device->Render(ren,this->Mapper);
}
void ShallowCopy(vtkProp *prop) {
NodeActor *f = NodeActor::SafeDownCast(prop);
this->vtkActor::ShallowCopy(prop);
}
//****************************************//
// my member
//****************************************//
Node* node_i_represent{nullptr};
protected:
vtkActor* Device;
NodeActor() {
this -> Device = vtkActor::New();
}
~NodeActor() {
this -> Device -> Delete();
}
private:
};
vtkStandardNewMacro(NodeActor)