I am developing nema stepper motor driver interfacing with arduino. I created a class. I named it Axis. I want to create an axis object for each motor with this class. but, I can not call the attachInterrupt function in the arduino.h from the class. It return this error :
In member function 'void Axis::setReverseInt()':
parsstep.cpp:12:77: error: invalid use of non-static member function 'void Axis::revDirection()'
attachInterrupt(digitalPinToInterrupt(reverseDirPin), revDirection, RISING);
Axis::Axis()
{
}
Axis::~Axis()
{
}
void Axis::setReverseInt () {
attachInterrupt(digitalPinToInterrupt(reverseDirPin), revDirection, RISING);
}
void Axis::setStopInt () {
//attachInterrupt(digitalPinToInterrupt(stopPin), stopMotor, RISING);
}
void Axis::revDirection()
{
dirMode = !dirMode;
}
void Axis::stopMotor()
{
moveMotor = !moveMotor;
}
void Axis::startMotor()
{
moveMotor = true;
}
void Axis::moveStep(int pulseRev, byte laps, boolean dir)
{
digitalWrite(dirPin, dir);
int totalPulse = pulseRev * laps;
for (int i = 0; i < totalPulse; i++)
{
speedValue = map((analogRead(speedPin)), 0, 1023, 2000, 10);
digitalWrite(pulsePin, HIGH);
delayMicroseconds(speedValue);
digitalWrite(pulsePin, LOW);
delayMicroseconds(speedValue);
}
}
I faced a similar issue when writing my own libraries for a big project I've been working on. It happened to me while configuring interrupts inside a method. I found a workaround that while it might seem a bit more complex, it does the trick. In my case, I used it for reading a rotary encoder its switch.
What I used is a pointer to an ISR handler and a method to call it. On your setup function you can call the initialization of the ISR service.
First, in your .h file declare the following methods (in addition to your own):
void init();
static void ISRHandler();
void setupISRHandler(uint8_t pin, void (*ISR)(void), int state); // this will configure your ISR
and a pointer:
static Axis *_ISRPointer; // can be declared as private (like in here from the '_' prefix)
Then, in your .cpp file you use it like this:
#include "Axis.h"
Axis *Axis::_ISRPointer = nullptr;
you will initialize the ISR handler during the setup using the init method:
void Axis::init(){
setupISRHandler(reverseDirPin, Axis::ISRHandler, RISING);
}
the setup method looks like:
void Axis::setupISRHandler(uint8_t pin, void (*ISRFunction)(void), int state){
attachInterrupt(digitalPinToInterrupt(pin), ISRFunction, state);
}
the ISRHandler is in charge of calling the ISR routine:
void Axis::ISRHandler(){
_ISRPointer-> revDirection();
}
void Axis::revDirection(void){
// Do not forget to disable interrupts
cli();
// your routine goes here
dirMode= !dirMode;
sei();
}
Therefore, you will do something like this in your main .ino file:
#include "Axis.h"
#include <whateverotherlibraryyouneed.h>
Axis ax = Axis(); // your new object
void setup(){
ax.init();
ax.startMotor();
}
void loop(){
if(day == SUNNY){
ax.moveStep(100, 2 , CLOCKWISE);
} else {
ax.stopMotor();
}
ax.someOtherMethodToControlTheMotor(anyArgumentYouWant);
}
I hope that my convoluted solution helps
Cheers
Dr. Daniel
Related
I'm trying to create a level editor for my futur game, to do that I need to get cocos2dx scene showing in a wxGLCanvas of the wxWidgets library.
How to link the wxGLCanvas with cocos2d::GLView ?
What I've done :
Created a class ccwxGLView that inherits from GLView:
class ccwxGLView : public cocos2d::GLView
{
ccwxGLCanvas* mGLCanvas;
public:
ccwxGLView(ccwxGLCanvas* canvas) {
setGLCanvas(canvas);
}
virtual ~ccwxGLView(void) {}
static ccwxGLView* create(ccwxGLCanvas* canvas) {
auto ret = new (std::nothrow) ccwxGLView(canvas);
if(ret) {
ret->autorelease();
return ret;
}
return nullptr;
}
void setGLCanvas(ccwxGLCanvas* canvas) {
mGLCanvas = canvas;
}
ccwxGLCanvas* getGLCanvas() {
return mGLCanvas;
}
HWND getWin32Window() {
return mGLCanvas->GetParent()->GetHWND();
}
/** Force destroying EGL view, subclass must implement this method. */
virtual void end() {
mGLCanvas->Close();
wxDELETE(mGLCanvas);
mGLCanvas = nullptr;
}
/** Get whether opengl render system is ready, subclass must implement this method. */
virtual bool isOpenGLReady() {
return (mGLCanvas && mGLCanvas->IsShown());
}
/** Exchanges the front and back buffers, subclass must implement this method. */
virtual void swapBuffers() {
mGLCanvas->SwapBuffers();
}
virtual void setIMEKeyboardState(bool open) {}
virtual bool windowShouldClose() {
return (mGLCanvas == nullptr);
}
};
Created a class that inherits from wxGLCanvas :
class ccwxGLCanvas : public wxGLCanvas
{
wxGLContext* m_context;
public:
ccwxGLCanvas(wxFrame* parent, int* args)
: wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
m_context = new wxGLContext(this);
}
virtual ~ccwxGLCanvas() { delete m_context; }
void resized(wxSizeEvent& evt) {
Refresh();
}
void render(wxPaintEvent& evt) {
cocos2d::Director* director = cocos2d::Director::getInstance();
if(director != nullptr && director->getRunningScene() != nullptr)
director->drawScene();
}
};
In the AppDelegate I modified the glView initialization by :
if(!glview) {
glview = ccwxGLView::create(mGLCanvas);
director->setOpenGLView(glview);
}
And on the app init function, I wrote something like this :
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
frame = new wxFrame((wxFrame *)NULL, -1, wxT("Hello GL World"), wxPoint(50,50), wxSize(400,200));
int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
glPane = new ccwxGLCanvas( (wxFrame*) frame, args);
sizer->Add(glPane, 1, wxEXPAND);
frame->SetSizer(sizer);
frame->SetAutoLayout(true);
frame->Show();
ccApp = new AppDelegate();
ccApp->setGLCanvas(glPane);
ccApp->applicationDidFinishLaunching();
When I run, a wxFrame (window) is shown and the app crashes immediately.
Call stack :
libcocos2d.dll!cocos2d::Renderer::setupVBO() Line 352 C++
libcocos2d.dll!cocos2d::Renderer::setupBuffer() Line 285 C++
libcocos2d.dll!cocos2d::Renderer::initGLView() Line 272 C++
libcocos2d.dll!cocos2d::Director::setOpenGLView(cocos2d::GLView * openGLView) Line 394 C++
editor.exe!AppDelegate::applicationDidFinishLaunching() Line 44 C++
editor.exe!EditorApp::OnInit() Line 25 C++
wxbase30ud_vc_custom.dll!wxAppConsoleBase::CallOnInit() Line 93 C++
wxbase30ud_vc_custom.dll!wxEntryReal(int & argc, wchar_t * * argv) Line 479 C++
wxbase30ud_vc_custom.dll!wxEntry(int & argc, wchar_t * * argv) Line 188 C++
Can enyone tell me how to call AdMob Interstitial between scenes in my cocos2d-x game?
I have tried this http://robwirving.com/2014/07/21/calling-c-methods-c-winrt-components/ guide, but i don't know how to run it from cocos classes.
Is there any another ways, or some guides?
I've recently made it. You have to do few things. First of all create helper class, which will help you calling native function (I use this for all 3 platforms, but here's just windows phone):
NativeHelper.h:
#ifndef __NATIVE_HELPER_H_
#define __NATIVE_HELPER_H_
#include <string>
#include <functional>
#include "cocos2d.h"
using namespace std;
USING_NS_CC;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
namespace cocos2d
{
public delegate void CSharpShowInterstitialDelegate();
public ref class WP8NativeEventHelper sealed
{
public:
void WP8NativeEventHelper::SetCSharpShowInterstitialDelegate(CSharpShowInterstitialDelegate^ delegate){
m_CSharpShowInterstitialDelegate = delegate;
}
void CallShowInterstitial();
private:
property static CSharpShowInterstitialDelegate^ m_CSharpShowInterstitialDelegate;
};
}
#endif
class NativeHelper
{
public:
static void showInterstitial(string adSdk);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
WP8NativeEventHelper^ wp8helper;
#endif
//instance required only for setting callback
static NativeHelper* getInstance();
~NativeHelper()
{
instanceFlag = false;
}
private:
static bool instanceFlag;
static NativeHelper* instance;
NativeHelper() {};
};
#endif // __NATIVE_HELPER_H_
So. We have special C++/CX class Wp8NativeEventHelper, which can "talk" with C#. Here we store a delegate.
How it works:
C# is calling SetCSharpShowInterstitialDelegate and passes a delegate to it, which will be remembered in static property.
Then C++\CX can call it using CallShowInterstitial.
Now NativeHelperWP.cpp:
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
#ifndef __NATIVE_HELPER_WP_H_
#define __NATIVE_HELPER_WP_H_
#include "NativeHelper.h"
void WP8NativeEventHelper::CallShowInterstitial(){
if (m_CSharpShowInterstitialDelegate)
{
m_CSharpShowInterstitialDelegate->Invoke();
}
}
bool NativeHelper::instanceFlag = false;
NativeHelper* NativeHelper::instance = NULL;
NativeHelper* NativeHelper::getInstance()
{
if(!instanceFlag){
instance = new NativeHelper();
instanceFlag = true;
instance->wp8helper = ref new WP8NativeEventHelper();
}
return instance;
}
void NativeHelper::showInterstitial(){
NativeHelper::getInstance()->wp8helper->CallShowInterstitial();
}
#endif
#endif
Here is just an implementation of CallShowInterstitial. Also in NativeHelper::showInterstitial we're calling C++/CX, which later calls c#.
Now c# code (MainPage.xaml.cs):
outside namespace:
using GoogleAds;
inside class:
private InterstitialAd interstitialAd;
in constructor:
WP8NativeEventHelper helper = new WP8NativeEventHelper();
helper.SetCSharpShowInterstitialDelegate(showInterstitial);
and also create showInterstitial function:
public void showInterstitial() //we recreate interstitial each time, because otherwise it'll show only once, only new requests won't work
{
interstitialAd = new InterstitialAd("MY_AD_UNIT_ID");
AdRequest adRequest = new AdRequest();
#if DEBUG
// Enable test ads.
adRequest.ForceTesting = true;
#endif
interstitialAd.ReceivedAd += OnAdReceived;
interstitialAd.LoadAd(adRequest);
}
and finally OnAdReceived:
private void OnAdReceived(object sender, AdEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Ad received successfully");
interstitialAd.ShowAd();
}
Follow this guide to setup admob: https://developers.google.com/mobile-ads-sdk/docs/admob/wp/quick-start
Now let's use this.
In HelloWorldScene.h add:
#include "NativeHelper.h"
In HelloWorldScene.cpp:
NativeHelper::showInterstitial();
The same way you can show/hide/change position of admob banner for example (however it's buggy so I'm using ad mediation).
Here is the topic on Difference between CCNode::init() and CCNode::onEnter(). However I followed the advice they gave.
void MyLayer::onEnter() {
CCLayer::onEnter();
//your code goes here
}
I got the Assertion failed! error!
MyLayer code:
class MyLayer : public CCLayerColor
Should I add CCLayerColor::onEnter() in my MyLayer::onEnter() code? And what is the difference between CCLayer::init() and CCLayer::onEnter(). Which part of code should I put into init() and which part should put into onEnter()?
Cocos2d-x has its memory allocation model as a two-step process, like objective-c. Each object has memory allocated (usually using a "create" method) and then has its state initialized (usually using a method called "init"). So in the create/init methods, you allocate the memory and do any object initialization necessary for it to run.
When the object starts to be put onto the display, or when it is added to another container, its "onEnter" method is called. This gets called when a CCScene/CCLayer (either of which may be containing your CCNode derived object) is displayed by the framework itself.
There are at least 2 patterns for memory allocation and object creation, I tend to follow the pattern of having a class contain a static factory method and a private constructor so that it is unambiguous that you must create the objects through the factory and cannot create one yourself.
For example, I am currently working on this "button" class:
class ActionButton;
class ActionButtonTarget
{
public:
virtual void ActionButtonActivated(ActionButton* button) = 0;
};
class ActionButton : public CCNode, public CCTargetedTouchDelegate
{
private:
ActionButton();
CCNode* _node; // Weak Reference
CCRect _testRect;
ActionButtonTarget* _target;
bool init(ActionButtonTarget* target, CCNode* node, CCRect rect);
bool IsTouchInside(CCTouch* touch);
void NotifyTarget();
protected:
virtual CCAction* CreateAction();
public:
virtual ~ActionButton();
// The class registers/unregisters on entry
// or exit of the layer. This
virtual void onEnterTransitionDidFinish();
virtual void onExitTransitionDidStart();
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
static ActionButton* create(ActionButtonTarget* target, CCNode* node, CCRect rect);
};
Note that the "create" method is the only way to create it. In this case, it takes arguments for parameters of the button. Other CCNode derived objects (e.g. CCScene) usually do not.
Internally:
ActionButton::ActionButton()
{
}
ActionButton::~ActionButton()
{
}
// The class registers/unregisters on entry
// or exit of the layer. This
void ActionButton::onEnterTransitionDidFinish()
{
CCNode::onEnterTransitionDidFinish();
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
}
void ActionButton::onExitTransitionDidStart()
{
CCNode::onExitTransitionDidStart();
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}
bool ActionButton::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
if(IsTouchInside(pTouch))
{
return true;
}
return false;
}
void ActionButton::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
// Nothing to do here.
}
void ActionButton::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
NotifyTarget();
}
bool ActionButton::IsTouchInside(CCTouch* touch)
{
CCPoint point = touch->getLocationInView();
point = CCDirector::sharedDirector()->convertToGL(point);
return _testRect.containsPoint(point);
}
void ActionButton::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)
{
_target->ActionButtonActivated(this);
}
ActionButton* ActionButton::create(ActionButtonTarget* target, CCNode* node, CCRect rect)
{
ActionButton *pRet = new ActionButton();
if (pRet && pRet->init(target,node,rect))
{
pRet->autorelease();
return pRet;
}
else
{
CC_SAFE_DELETE(pRet);
return NULL;
}
}
CCAction* ActionButton::CreateAction()
{
return NULL;
}
void ActionButton::NotifyTarget()
{
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(Constants::SOUND_EFFECT_BUTTON_CLICK());
_target->ActionButtonActivated(this);
}
bool ActionButton::init(ActionButtonTarget* target, CCNode* node, CCRect rect)
{
assert(target != NULL);
assert(node != NULL);
assert(dynamic_cast<ActionButtonTarget*>(target) != NULL);
_target = target;
_node = node;
_testRect = rect;
addChild(_node);
return true;
}
Note the OnEnterXXX and onExitXXX methods call the parent class method. YOU MUST DO THIS or it will not work as expected.
This class is a button that will run an action on the node (maybe make it grow/shrink to indicate it got pressed). It takes touches from the user. I cannot add it to the touch manager before it has entered the scene. So I use the onEnterTransitionDidFinish method to add it and also use the onExitTransitionDidStart to remove it so it will not continue to receive touches after the scene has been removed. I don't know if the container will be destroyed or not, so I must remove it when the button exits the display.
Was this helpful?
Ist Part
Check out OnEnter method of base class(CCLayer),if some serious stuff is going on ,then you should have called it.
IInd Part
As in the topic... OnEnter is called when "viewDidAppear" and init during initialisation.
Suppose you create layer by this
MyLayer *newLayer=MyLayer::create(); //...init is called before OnEnter..
After that you add it to some scene
X->addChild(newLayer); // ...*Now onEnter Method is called
*X must be added to some scene or parent and so on.
IIIrd Part
In some case you just create multiple objects stored in array,but didn't add them. You are waiting for right time for adding them.This might be case when object enter/add to screen ,you want it to perform specific task.
Ex. In a game you have to attack someone and have 30 troops.All the troops are created in loading scene but none of them add to layer.
When battle begins, the deployed troop by user appear on the screen.Troop on enter has a task to go to target building and that method can be called through onEnter.
You call onEnter() if you want to do something the moment it appears on the screen.
The init() method will be called even without the layer being on the screen.
Something like this:
void FirstScene::methodInit()
{
customlayer = new CustomLayer();
customlayer -> init();
customlayer-> retain();
// At this point,customlayer (which is a CustomLayer object that is a subclass of CCLayer)
// is still not on the screen, hence, CustomLayer::onEnter() is still not called
}
void FirstScene::methodEnter
{
this -> addChild( customLayer, customIndex, customTag );
customLayer -> release();
// At this point, CustomLayer::onEnter() is called, because customLayer is being rendered
}
Is it possible to have two or more outer function-scoped functions that have mutual call dependencies on each other?
I'm asking because
void main(string args[]) {
int x = 42;
void a() {
// do something with x
b();
}
void b() {
// do something with x
a();
}
}
errors in DMD as
/home/per/Work/justd/t_funs.d(5): Error: undefined identifier b
If not is this an unresolved issue or a feature?
you can declare the delegate b before a and then assign b
void main(string args[]) {
int x = 42;
void delegate() b;
void a() {
// do something with x
b();
}
b = delegate void () {
// do something with x
a();
};
}
it'll require a refactor but not as bad as throwing it all in structs
Let's say you could. Then you could do:
void main(string args[]) {
void a() {
b();
}
a();
int x = 42;
void b() {
// do something with x
a();
}
}
And viola - you use x before declaring it.
There are workarounds to that - like ratchet freak said you could use a delegate, but you could also use a struct:
void main(){
int x=5;
struct S{
void a(){
writefln("in a, x=%d",x);
--x;
if(0<x){
b();
}
}
void b(){
writefln("in b, x=%d",x);
--x;
if(0<x){
a();
}
}
}
S().a();
}
Notice that both solutions prevent using x before it's declaration. If you use a delegate you can't call it before you assign a function to it, which you can only do after you declare the other function, which happens after you declare x. If you use a struct you can't declare x either before of in the struct - but you can only call the functions after the struct is declared - which also means after x is declared.
That's by design: "Unlike module level declarations, declarations within function scope are processed in order." (http://dlang.org/function.html#variadicnested)
Don't know the rationale though.
my goal is to design a CCTableViewCell via CocosBuilder
and load it via CCBReader.
My steps so far:
I added a new non-fullscreen CCNode TestCell.ccb in cocosbuilder,
set the root's custom class to TestCell
and added a CCSprite as the roots child while setting
it's doc-root-var to bg.
My problem: after implementing a loader TestCellLoader
as well as the Cell TestCell the callback-function
TestCell::onAssignCCBMemberVariable is not called at all.
What I tried:
Using a CCLayerLoader instead of a CCNodeLoader worked for me so far,
this is the first time I'm using a CCNodeLoader so maybe I missed
a crucial point.
Thank you,
Ciao!
Ben
Here are the codes:
TestCellLoader.h
#include <cocos2d.h>
#include "cocos-ext.h"
#include "TestCell.h"
using namespace cocos2d;
using namespace cocos2d::extension;
class TestCellLoader : public CCNodeLoader
{
public:
CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(TestCellLoader, create);
protected:
CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(TestCell);
virtual CCNode* loadCCNode(CCNode *, CCBReader * pCCBReader);
};
TestCellLoader.cpp
#include "TestCellLoader.h"
CCNode * TestCellLoader::loadCCNode(CCNode * pParent, CCBReader * pCCBReader)
{
CCLOG("TestCell::loadCCNode");
CCNode * ccNode = this->createCCNode(pParent, pCCBReader);
return ccNode;
}
TestCell.h
class TestCell : public CCTableViewCell, public CCNodeLoaderListener, public CCBMemberVariableAssigner
{
public:
TestCell();
virtual ~TestCell();
static TestCell *create();
virtual bool init();
virtual bool initWithBG(CCSprite* bg);
static TestCell* cellWithBG(CCSprite* bg);
// ccbuilder callbacks
virtual bool onAssignCCBMemberVariable(cocos2d::CCObject * pTarget, const char * pMemberVariableName, cocos2d::CCNode * pNode);
virtual void onNodeLoaded(cocos2d::CCNode * pNode, cocos2d::extension::CCNodeLoader * pNodeLoader);
private:
CC_PROPERTY(CCSprite*, bg, Bg);
};
TestCell.m
#include "TestCell.h"
using namespace cocos2d;
using namespace cocos2d::extension;
TestCell::TestCell(){}
TestCell::~TestCell(){}
#pragma mark creation
TestCell* TestCell::create(){
TestCell *pRet = new TestCell();
pRet->init();
pRet->autorelease();
return pRet;
}
bool TestCell::init(){
return true;
}
bool TestCell::initWithBG(CCSprite* bg){
return true;
}
TestCell* TestCell::cellWithBG(CCSprite* bg){
return new TestCell;
}
#pragma mark - synthesize
void TestCell::setBg(cocos2d::CCSprite *sprite){
this->bg = sprite;
}
CCSprite* TestCell::getBg(){
return this->bg;
}
#pragma mark - ccbuilder callbacks
void TestCell::onNodeLoaded(cocos2d::CCNode * pNode, cocos2d::extension::CCNodeLoader * pNodeLoader)
{
CCLOG("TestCell::onNodeLoaded");
}
bool TestCell::onAssignCCBMemberVariable(CCObject* pTarget, const char* pMemberVariableName, CCNode* pNode)
{
CCLOG("TestCell::onAssignCCBMemberVariable %s", pMemberVariableName);
return false;
}
I guess you used a CCLayer as TestCell.ccb's Root object type. Since when you are creating a new ccb file, CCLayer is as default option.
And this is why you use a CCLayerLoader instead of a CCNodeLoader worked.
So change your TestCell.ccb's Root object type to CCNode, this maybe works.