I am trying to access a function of a pointer and it does not work and it gives me an LoadStoreAlignmentCause Exception. Furthermore I want to check if the pointer does exist, but it always returns true for that.
LedFunction.h
#include "Led/LedStates.h"
class LedStates;
class LedFunction {
public:
LedStates *state;
virtual bool init();
bool loadValues();
virtual void render() = 0;
};
LedFunction.cpp
#include "Led/LedFunction.h"
bool LedFunction::init() {
return false;
}
RainbowFunction.h
class RainbowFunction: public LedFunction {
public:
RainbowFunction() {
Serial.println("Rainbow Constructor.");
}
void render() {
Serial.println("From Rainbow...");
}
}
};
LedStates.h
#include "Handlers/LedHandler.h"
#include "Led/LedFunction.h"
class LedHandler;
class LedFunction;
class LedStates {
public:
uint8_t (*values)[3];
int count = 0;
bool dirty = false;
LedHandler* ledHandler;
LedFunction* function = 0;
LedStates(LedHandler* handler);
void setFunction(LedFunction *newFunction);
void setRgb(int i, uint8_t r, uint8_t g, uint8_t b);
void render(); //TODO check virtual key
void setValues(LedStates &to);
void commit();
void fade(LedStates &to, long f0, long f1);
};
LedStates.cpp
#include "Led/LedStates.h"
#include "Led/Animations/RainbowFunction.h"
LedStates::LedStates(LedHandler* handler) {
this->ledHandler = handler;
count = ledHandler->getLength();
values = new uint8_t[count][3];
this->setFunction(new RainbowFunction());
}
void LedStates::setFunction(LedFunction* newFunction) {
Serial.println("SETTING FUNCTION");
if(function)
delete function; //TODO check virtual destructor
function = newFunction;
if(!function)
return;
function->state = this;
Serial.println("-----Setting Done-----");
}
void LedStates::render() {
Serial.println(2);
Serial.println("B:" + (String) (function != 0));
Serial.println("B:" + (String) (function != false));
if(function == nullptr) { //This is the check that is not working properly
Serial.println(22222);
//delay(1000);
//function->render();
} else {
Serial.println(33333);
function->render();
}
Serial.println(3);
}
LedHandler.h
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
//#include "Led/LedFunction.h"
#include "Led/LedStates.h"
#include "Led/Fading.h"
class LedStates;
class LedHandler {
public:
LedHandler(int length, uint16_t pin);
void clear();
void show();
void setColor(int s, int r, int g, int b);
void loop();
Adafruit_NeoPixel getStrip();
int getLength();
private:
LedStates* currentState;
LedStates* targetState;
Fader<LedStates> *ledFader;
int length;
Adafruit_NeoPixel strip;
CRGB* leds;
};
LedHandler.cpp
#include "Handlers/LedHandler.h"
LedHandler::LedHandler(int length, uint16_t pin) {
Serial.begin(115200);
this->length = length;
this->strip = Adafruit_NeoPixel(length, pin);
this->strip.begin();
CRGB* arr = new CRGB[length];
this->leds = arr;
FastLED.addLeds<WS2812B, 6, RGB>(leds, 60).setCorrection(TypicalLEDStrip);
//Serial.println("-----Creating States-----");
LedStates currentLedStates = LedStates(this);
LedStates targetLedStates = LedStates(this);
Fader<LedStates> ledFader = Fader<LedStates>(currentLedStates, targetLedStates);
//Serial.println("-----Created States-----");
this->currentState = ¤tLedStates;
this->targetState = &targetLedStates;
this->ledFader = &ledFader;
}
void LedHandler::loop() {
Serial.println("--::--::--::--::--::--::--");
currentState->render();
Serial.println(99);
Serial.println(6);
currentState->commit();
Serial.println("-------------------------");
delay(10000);
}
The Serialmonitor output:
SETTING FUNCTION
-----Setting Done-----
Rainbow Constructor.
SETTING FUNCTION
-----Setting Done-----
--::--::--::--::--::--::--
2
B:1
B:1
33333
Exception (9):
epc1=0x40202a92 epc2=0x00000000 epc3=0x00000000 excvaddr=0x4020d32d depc=0x00000000
These lines define local variables inside the function LedHandler::LedHandler(int length, uint16_t pin):
LedStates currentLedStates = LedStates(this);
LedStates targetLedStates = LedStates(this);
These lines remember the address of the local variables:
this->currentState = ¤tLedStates;
this->targetState = &targetLedStates;
This line deletes the local variables so the memory can be used for something else:
}
and this line calls the something else (nobody knows what it will be):
currentState->render();
Related
I'm recently learning to make a 2d game in SFML using a tutorial series on youtube by Suraj Sharma(Video 57):
https://www.youtube.com/watch?v=kwd_AVCkvXE&list=PL6xSOsbVA1ebkU66okpi-KViAO8_9DJKg&index=57
His Source Code:
https://github.com/Headturna/SFML_RPG
Right now he's teaching me to symplify the game's menu system by making a mini class 'StateData' in the parent class 'State' so any inherited class can access 'State' parameters via 'StateData'(Ex:MainMenu(StData* Stdata){}).
After debugging the game seems to runs fine.But everytime i click on something on the menu(start,settings,etc...) a 'Read access violation:Stdata was nullptr' occurs in the 'State' class constructor.
Here's the code:
State.h:
#pragma once
#ifndef STATE_H
#define STATE_H
#include "Player.h"
#include "GrphSettings.h"
class Player;
class GrphSettings;
class State;
class StData {
public:
StData(){}
//Vars
float GridSize;
sf::RenderWindow* Window;
GrphSettings* GSettings;
std::map<std::string, int>* SupportedKeys;
std::stack<State*>* states;
};
class State
{
private:
protected:
StData* Stdata;
std::stack<State*>* states;
sf::RenderWindow* window;
std::map<std::string, int>* SupportedKeys ;
std::map<std::string, int> Keybinds;
bool quit;
bool pause;
float keyTime;
float keyTimeMax;
float GridSize;
sf::Vector2i MousePosScr;
sf::Vector2i MousePosWind;
sf::Vector2f MousePosView;
//Resources
std::map<std::string,sf::Texture> texture;
//Funcs
virtual void InitKeybinds() = 0;
public:
State(StData* Stdata);
virtual~State();
//Access
const bool getKeytime();
const bool& getquit()const;
//Funcs
void Endstate();
void PauseSt();
void UnPauseSt();
virtual void UpdateInput(const float& dt) = 0;
virtual void UpdateMousePos();
virtual void UpdateKeyTime(const float& dt);
virtual void Update(const float& dt) = 0;
virtual void Render(sf::RenderTarget* target = nullptr) = 0;
};
#endif // !1
State.cpp:
#include "pch.h"
#include "State.h"
State::State(StData* Stdata)
{
this->Stdata = Stdata;
this->window = Stdata->Window;
this->SupportedKeys = Stdata->SupportedKeys;
this->states = Stdata->states;
this->quit = false;
this->pause = false;
this->keyTime = 0.f;
this->keyTimeMax = 10.f;
this->GridSize = Stdata->GridSize;
}
State::~State()
{
}
//Access
const bool State::getKeytime()
{
if (this->keyTime >= this->keyTimeMax) {
this->keyTime = 0.f;
return true;
}
return false;
}
const bool& State::getquit() const
{
// TODO: insert return statement here
return this->quit;
}
//Funcs
void State::Endstate()
{
this->quit = true;
}
void State::PauseSt()
{
this->pause = true;
}
void State::UnPauseSt()
{
this->pause = false;
}
void State::UpdateMousePos()
{
this->MousePosScr = sf::Mouse::getPosition();
this->MousePosWind = sf::Mouse::getPosition(*this->window);
this->MousePosView = this->window->mapPixelToCoords(sf::Mouse::getPosition(*this->window));
}
void State::UpdateKeyTime(const float& dt)
{
if (this->keyTime < this->keyTimeMax)
this->keyTime += 100.f * dt;
}
Every button one the menu(start,exit...)is an inherited state from 'State' class.This is,for example,the 'Edit' state.
Edit.h:
#pragma once
#ifndef EDIT_H
#define EDIT_H
#include "State.h"
#include "Gui.h"
#include "PauseMenu.h"
#include "TileMap.h"
class State;
class Gui;
class PauseMenu;
class TileMap;
class Edit:public State
{
private:
//Vars
sf::Font Fnt;
PauseMenu* PMenu;
std::map<std::string, gui::Button*> buttons;
TileMap Map;
//Functions
void InitVars();
void InitBackGrnd();
void InitFonts();
void InitKeybinds();
void InitPauseMenu();
void InitBtn();
public:
Edit(StData* Stdata);
virtual~Edit();
//Functions
void UpdateInput(const float& dt);
void Update(const float& dt);
void UpdatePButtons();
void UpdateBtn();
void Endstate();
void RenderBtn(sf::RenderTarget& target);
void Render(sf::RenderTarget* target = nullptr);
};
#endif // ! EDIT_H
Edit.cpp:
#include "pch.h"
#include "Edit.h"
void Edit::InitVars()
{
}
void Edit::InitBackGrnd()
{
}
void Edit::InitFonts()
{
if (!this->Fnt.loadFromFile("Fonts/SPACEMAN.ttf")) {
throw("Error::Edit::Couldn't load font");
}
}
void Edit::InitKeybinds()
{
std::ifstream ifs("Config/EditKeys.ini");
if (ifs.is_open()) {
std::string key = "";
std::string key2 = "";
int keyval = 0;
while (ifs >> key >> key2)
{
this->Keybinds[key] = this->SupportedKeys->at(key2);
}
}
ifs.close();
this->Keybinds["Close"] = this->SupportedKeys->at("ESC");
this->Keybinds["Left"] = this->SupportedKeys->at("A");
this->Keybinds["Right"] = this->SupportedKeys->at("D");
this->Keybinds["Up"] = this->SupportedKeys->at("W");
this->Keybinds["Down"] = this->SupportedKeys->at("S");
}
void Edit::InitPauseMenu()
{
this->PMenu = new PauseMenu(*this->window, this->Fnt);
this->PMenu->addButtons("Quit", 800.f, "Quit");
}
void Edit::InitBtn()
{
}
Edit::Edit(StData* Stdata)
:State(Stdata)
{
this->InitVars();
this->InitBackGrnd();
this->InitFonts();
this->InitKeybinds();
this->InitPauseMenu();
this->InitBtn();
}
Edit::~Edit()
{
auto it = this->buttons.begin();
for (it = this->buttons.begin(); it != this->buttons.end(); ++it) {
delete it->second;
}
delete this->PMenu;
}
//Funcs
void Edit::UpdateInput(const float& dt)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key(this->Keybinds.at("Close")))
&& this->getKeytime()) {
if (!this->pause)
this->PauseSt();
else this->UnPauseSt();
}
}
void Edit::Update(const float& dt)
{
this->UpdateMousePos();
this->UpdateKeyTime(dt);
this->UpdateInput(dt);
if (!this->pause) {//Unpaused
this->UpdateBtn();
}
else {//Paused
this->PMenu->Update(this->MousePosView);
this->UpdatePButtons();
}
this->UpdateBtn();
std::cout << this->MousePosView.x << " " << this->MousePosView.y << "\r";
}
void Edit::UpdatePButtons()
{
if (this->PMenu->isPressed("Quit"))
this->Endstate();
}
void Edit::UpdateBtn()
{ //Update buttons and handle their functions
for (auto& it : this->buttons) {
it.second->Update(MousePosView);
}
}
void Edit::Endstate()
{
std::cout << "Ending State" << "\n";
}
void Edit::RenderBtn(sf::RenderTarget& target)
{
for (auto& it : this->buttons) {
it.second->Render(target);
}
}
void Edit::Render(sf::RenderTarget* target)
{
if (!target)
target = this->window;
this->RenderBtn(*target);
this->Map.Render(*target);
if (this->pause) {//Pause Menu
this->PMenu->Render(*target);
}
sf::Text MText;
MText.setPosition(this->MousePosView);
MText.setFont(this->Fnt);
MText.setCharacterSize(12);
std::stringstream ss;
ss << this->MousePosView.x << ' ' << this->MousePosView.y;
MText.setString(ss.str());
target->draw(MText);
}
Can anyone help me ?
In a pawn class that inherits from the cocos2d Sprite class, I used this->getBoundingBox() in it's update function. This caused an "Access violation at reading location" error. Then, I swapped "this" with "GAME::PLAYER", a variable in a namespace that references the player and it worked. Why does this->getBoundingBox() cause an error when GAME::PLAYER->getBoundingBox() works perfectly fine? Aren't they supposed to be the same thing? Just to note, "this->" works with any other function but getBoundingBox. Is it something I'm doing wrong? I'm not THAT good with C++
Here's pawn.h
#include <cocos2d.h>
#ifndef PLAYER_CONTROLLER
#define PLAYER_CONTROLLER GAME::PLAYER
class pawn : public cocos2d::Sprite {
public:
pawn();
~pawn();
static pawn* create();
static pawn* create(bool default_moving);
bool moving;
bool right;
int speed;
cocos2d::Rect getBounds();
void step();
void initOptions();
void update(float dt) override;
void move(cocos2d::Vec2 vec);
void moveX(int x);
void moveY(int y);
virtual bool touchBegan(cocos2d::Touch*, cocos2d::Event*);
virtual void touchEnded(cocos2d::Touch*, cocos2d::Event*);
};
namespace GAME {
static pawn* PLAYER;
};
#endif
Here's pawn.cpp
#include "player.h"
#include <cocos2d.h>
pawn::pawn() {
}
pawn::~pawn() {
}
bool pawn::touchBegan(cocos2d::Touch* touch, cocos2d::Event* event) {
this->move(cocos2d::Vec2(5, 0));
this->moving = false;
return true;
}
void pawn::touchEnded(cocos2d::Touch* touch, cocos2d::Event* event) {
this->moving = true;
}
void pawn::step() {
if (this->moving) {
if (this->right) {
this->move(cocos2d::Vec2(this->speed, 0));
}
else {
this->move(cocos2d::Vec2(-this->speed, 0));
}
if (this->getPositionX() < 0) {
this->right = true;
CCLOG("Going right V4");
}
else {
if (this->getPositionX() + this->getContentSize().width > cocos2d::Director::getInstance()->getWinSizeInPixels().width + cocos2d::Director::getInstance()->getVisibleOrigin().x){
this->right = false;
CCLOG("Going left V4");
}
}
}
}
void pawn::move(cocos2d::Vec2 vec) {
PLAYER_CONTROLLER->setPosition(cocos2d::Vec2(PLAYER_CONTROLLER->getPositionX() + vec.x, PLAYER_CONTROLLER->getPositionY() + vec.y));
}
void pawn::moveX(int x) {
}
void pawn::moveY(int y) {
}
void pawn::update(float dt) {
//cocos2d::Rect act = this->getBoundingBox();
this->getPosition();
this->step();
}
cocos2d::Rect pawn::getBounds() {
if (!PLAYER_CONTROLLER) {
CCLOG("Is this the problem?");
}
return PLAYER_CONTROLLER->getBoundingBox();
}
pawn* pawn::create() {
auto character = new pawn();
character->moving = true;
character->right = false;
character->speed = 5;
character->setPositionY(50);
if (PLAYER_CONTROLLER == NULL) {
CCLOG("There is no player, yet.");
CCLOG("Adding player");
PLAYER_CONTROLLER = character;
}
else {
CCLOG("There's already a player");
return NULL;
}
//character->setPositionX(40);
if (character->initWithFile("Base.jpg")){
return character;
}
CC_SAFE_DELETE(character);
return NULL;
}
pawn* pawn::create(bool default_moving) {
pawn* character = new pawn();
character->moving = default_moving;
character->setPositionX(40);
if (character->initWithFile("Base.jpg")){
return character;
}
CC_SAFE_DELETE(character);
return NULL;
}
Is it maybe because I call a pawn method from another class? I use a Collider class to call functions in pawn
Collider.cpp
#include "Collider.h"
#include "player.h"
Collider::Collider() : CollideMode(OVERLAP) {
}
Collider::~Collider() {
}
Collider* Collider::create() {
Collider* col = new Collider;
if (col->initWithFile("Base.jpg")){
col->setAnchorPoint(cocos2d::Vec2(0, 0));
col->setContentSize(cocos2d::Size(100, 100));
return col;
}
CC_SAFE_DELETE(col);
return NULL;
}
void Collider::collision(cocos2d::Vec2 intersect) {
CCLOG("IT IS COLLIDING");
if (intersect.x < intersect.y) {
PLAYER_CONTROLLER->move(cocos2d::Vec2(-intersect.x, 0));
CCLOG("X");
}
else if (intersect.x > intersect.y) {
PLAYER_CONTROLLER->move(cocos2d::Vec2(0, -intersect.y));
CCLOG("Y");
}
}
void Collider::update(float dt) {
//cocos2d::Rect col = this->getBoundingBox();
auto act = PLAYER_CONTROLLER->getBounds();
if (PLAYER_CONTROLLER) {
if (!PLAYER_CONTROLLER) {
CCLOG("There is no player?");
}
}
else {
CCLOG("Not colliding");
}
}
I don't seems any problem with this->getBoundingBox() inside update(float dt) function.
I've created small test :
declaration inside .h file
class MySprite: public Sprite {
public:
bool init() override;
void update(float) override;
CREATE_FUNC(MySprite);
};
Now method definition inside .cpp file
bool MySprite::init(){
if(!Sprite::init())
return false;
scheduleUpdate();
return true;
}
void MySprite::update(float dt){
auto rect=this->getBoundingBox();
CCLOG("Inside Update method of MySprite Bounding rect Width %f & Height %f",rect.size.width,rect.size.height);
}
Then I created an autoreleased object of MySprite and add to parent.
auto mysprite=MySprite::create();
mysprite->setContentSize(Size(10,10));
addChild(mysprite);
Run, Expected result on output console.
I see my mistake. It was the fact that I redefined the namespace "GAME" and it's variable, "GAME::PLAYER" every time I included pawn.h, the other source files that I called the pawn functions from didn't know what GAME::PLAYER or PLAYER_CONTROLLER ( just a macro for GAME::PLAYER ) was, as I had only defined PLAYER_CONTROLLER in pawn.cpp. That's why when you called PLAYER_CONTROLLER->method() in another file, it passed in NULL as "this", and also why PLAYER_CONTROLLER was referring to a different PLAYER_CONTROLLER than the one passed in as "this".
I solved it by using the extern keyword that makes the variables global between all files, which was my original intention.
pawn.h
#include <cocos2d.h>
#ifndef PLAYER_CONTROLLER
#define PLAYER_CONTROLLER GAME::PLAYER
#define INITIALIZE_PLAYER pawn* GAME::PLAYER = NULL
class pawn : public cocos2d::Sprite {
public:
pawn();
~pawn();
static pawn* create();
static pawn* getController();
static pawn* create(bool default_moving);
bool moving;
bool right;
int speed;
cocos2d::Rect getBounds();
void step();
void initOptions();
void update(float dt) override;
void move(cocos2d::Vec2 vec);
void moveX(int x);
void moveY(int y);
virtual bool touchBegan(cocos2d::Touch*, cocos2d::Event*);
virtual void touchEnded(cocos2d::Touch*, cocos2d::Event*);
};
namespace GAME {
extern pawn* PLAYER;
};
#endif
This is why I said I wasn't that good at C++.
I am trying to make a library for redirection of data printed to Print class. I am unfortunately stuck on error that reads
error: cannot declare variable 'diagData' to be of abstract type 'PrintToString'
note: because the following virtual functions are pure within 'PrintToString'
note: virtual size_t PrintToString::write(uint8_t)
I tried several variations of how to implement this but with no luck. (Sourced from the internet)
Links
Print class: github.com/ Print.h and Print.cpp
My code
PrintToString.h
#ifndef PRINT_TO_STRING_H
#define PRINT_TO_STRING_H
#include <Arduino.h>
class PrintToString : public Print
{
private:
String* data;
public:
PrintToString();
~PrintToString();
String* results();
void clear();
size_t write(uint8_t) = 0;
size_t write(const uint8_t* buffer, size_t size);
};
#endif
PrintToString.cpp
#include "PrintToString.h"
PrintToString::PrintToString()
{
data = new String();
}
PrintToString::~PrintToString()
{
delete data;
data = NULL;
}
String* PrintToString::results()
{
return data;
}
void PrintToString::clear()
{
delete data;
data = new String();
}
size_t PrintToString::write(const uint8_t* buffer, size_t size)
{
size_t n = 0;
while (size--)
{
if (data->concat(*buffer++))
n++;
else
break;
}
return n;
}
TestSketch.ino (I have left out content of all the constants)
#include <ESP8266WiFi.h>
#include <PrintToString.h>
const char* WIFI_SSID
const char* WIFI_PASS
const char* API_HOST
const uint16_t API_PORT
const uint16_t LOCAL_UDP_PORT
WiFiUDP UDPClint;
PrintToString diagData;
uint64_t packetNumber = 0;
void setup()
{
WiFi.begin(WIFI_SSID, WIFI_PASS);
UDPClint.begin(LOCAL_UDP_PORT);
while (WiFi.status() != WL_CONNECTED)
delay(500);
WiFi.printDiag(diagData);
sendStringPacket(diagData.result());
diagData.clear();
}
void loop()
{
delay(1000);
}
void sendStringPacket(String payload)
{
UDPClint.beginPacket(API_HOST, API_PORT);
uint64_t thisPNumber = packetNumber++;
String thisPNumberStr;
while (thisPNumber > 0)
{
uint8_t digit = thisPNumber % 10;
thisPNumberStr.concat(digit);
thisPNumber /= 10;
}
UDPClint.write(';');
for (uint64_t i = 0; i < payload.length(); i++)
UDPClint.write(payload.charAt(i));
UDPClint.endPacket();
}
This is because this class has a pure virtual function here:
size_t write(uint8_t) = 0;
A class with a pure virtual function cannot be instantiated. So method write(uint8_t) must be somehow implemented in your code.
EDIT: Consider making use of the code you used in sendStringPacket() for write(uint8_t). You may be able to redirect output without using sendStringPacket(diagData.result()); statement.
I'm getting this error when I try to compile an Arduino sketch. I don't see where it thinks I'm trying to call Counter::Counter without arguments. What's going on here?
sketch/periodic_effect.cpp: In constructor 'PeriodicEffect::PeriodicEffect(uint32_t, uint32_t, Counter::Mode)':
periodic_effect.cpp:4: error: no matching function for call to 'Counter::Counter()'
PeriodicEffect::PeriodicEffect( uint32_t durationMs, uint32_t periods, Counter::Mode mode) : Runnable(), periods(periods) {
periodic_effect.cpp
#include <Arduino.h>
#include "periodic_effect.h"
PeriodicEffect::PeriodicEffect( uint32_t durationMs, uint32_t periods, Counter::Mode mode) : Runnable(), periods(periods) {
intervalMs = durationMs / periods;
index = Counter(intervalMs, mode);
}
void PeriodicEffect::run() {
uint32_t currTimeMs = millis();
if( (currTimeMs - prevTimeMs) > intervalMs ) {
applyChange();
prevTimeMs = currTimeMs;
index.increment();
}
}
periodic_effect.h
#ifndef PERIODIC_EFFECT_H
#define PERIODIC_EFFECT_H
#include "counter.h"
#include "runnable.h"
class PeriodicEffect : public Runnable {
public:
PeriodicEffect( uint32_t durationMs, uint32_t periods, Counter::Mode mode = Counter::Mode::RESETTING );
Counter index;
private:
uint32_t intervalMs, periods, prevTimeMs;
virtual void applyChange() = 0;
void run();
virtual void setup() = 0;
};
#endif
counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <stdint.h>
class Counter {
public:
enum Mode { RESETTING, RETURNING };
Counter(uint32_t limit, Counter::Mode mode = RESETTING, uint32_t index = 0);
uint32_t getIndex();
void increment();
float percent();
private:
bool goingForward;
uint32_t index;
const uint32_t limit;
Counter::Mode mode;
void incrementReturning();
void incrementResetting();
};
#endif
counter.cpp
#include "counter.h"
Counter::Counter(uint32_t limit, Counter::Mode mode, uint32_t index) : index(index), limit(limit), mode(mode) {
goingForward = true;
}
uint32_t Counter::getIndex() {
return index;
}
void Counter::increment() {
switch( mode ) {
case RESETTING : incrementResetting();
case RETURNING : incrementReturning();
}
}
void Counter::incrementResetting() {
index = (index + 1) % limit;
}
void Counter::incrementReturning() {
if( goingForward ) {
index++;
if( index >= limit ) {
index = limit - 1;
goingForward = false;
}
} else {
index--;
if( index <= 0 ) {
index = 1;
goingForward = true;
}
}
}
float Counter::percent() {
return (float) index / (float) limit;
}
Your class PeriodicEffect has a Counter member variable, and no constructor. This means the member variable will need to be default constructed, i.e. constructed by a constructor with no parameters. You haven't supplied one.
You can either give Counter a default constructor, or let the existing constructor have defaults for all of the parameters. Or you can make a PeriodicEffect constructor with an initializer list to provide the proper parameters to index.
PeriodicEffect::PeriodicEffect(
uint32_t durationMs, uint32_t periods, Counter::Mode mode) :
Runnable(), periods(periods) { /* ... */
PeriodicEffect has a member Counter index;. Since index is not in the member initializer list of this constructor, it gets default constructed.
The statement
index = Counter(intervalMs, mode);
inside the constructor is an assignment, not an initialization. Too late.
I have a class called PID. I #include the header for the class. I have been using this class in various files including the file the error points to. The compiler complains about defining the function declaration itself void dispPid(char *name, PID &pid){}. All the contents of the function are commented out. The error reads AutoTrucker:-1: error: 'PID' has not been declared with no other errors. Commenting out the function in its entirety removes the error completely, compiles and works fine.
What really gets me confused is that:
The error points to line -1
The file exists, and is included
I use this PID class in right above as a pointer:
PID *pid;
if (chk(arg2,"roll")){pid = &aircraft.ap.pid.wingLeveler;}
else if (chk(arg2,"heading") || chk(arg2,"hdg")){pid = &aircraft.ap.pid.headingHold;}
else if (chk(arg2,"pitch")){pid = &aircraft.ap.pid.pitchHold;}
...
This code specified directly above compiles and works properly. So what gives?
EDIT 2:
This is such a jimmy rig it makes me sick. But is does solve the problem for the time being. So what gives? The compiler does not like the PID class as a function argument, but it finds it acceptable inside the function? I would really like to find a proper solution to this instead of passing in a void pointer and converting it!
void dispPid(const char *name, void *tpid)
{
PID &pid = *((PID*)tpid);
...
}
EDIT: (adding in some more source code as requested)
void cmdsPid(char *buffer)
{
if (chk(buffer,"pid"))
{
char *arg1 = next(buffer);
if (chk(arg1,"ls"))
{
char *arg2 = next(arg1);
if (chk(arg2,"") || chk(arg2,"all"))
{
/*
Serial.println("Listing all PIDs:");
dispPid("Roll",aircraft.ap.pid.wingLeveler);
Serial.print("\t");
dispPid("Heading",aircraft.ap.pid,headingHold);
dispPid("Pitch",aircraft.ap.pid,pitchHold);
Serial.print("\t");
dispPid("V-Rate",aircraft.ap.pid.climbHold);
Serial.print("\t\t");
dispPid("Altitude",aircraft.ap.pid.altHold);
dispPid("Throttle",aircraft.ap.pid.throttleHold);
dispPid("Slip",aircraft.ap.pid.slipHold);
*/
}
else
{
Serial.print("Unknown argument");
}
}
else if (chk(arg1,"w"))
{
char *arg2 = next(arg1);//name
char *arg3 = next(arg2);//attr
char *arg4 = next(arg3);//val
double val = 0.0;
bool onoff = false;
if (chk(arg3,"inv"))
{
onoff = (chk(arg4,"off") || chk(arg4,"-"));
}
else if (chk(arg3,"max") || chk(arg3,"min"))
{
if (chk(arg4,"off") || chk(arg4,"-"))
{
onoff = false;
}
else
{
onoff = true;
val = parseDoubleArg(arg4);
}
}
else
{
val = parseDoubleArg(arg4);
}
PID *pid;
if (chk(arg2,"roll")){pid = &aircraft.ap.pid.wingLeveler;}
else if (chk(arg2,"heading") || chk(arg2,"hdg")){pid = &aircraft.ap.pid.headingHold;}
else if (chk(arg2,"pitch")){pid = &aircraft.ap.pid.pitchHold;}
else if (chk(arg2,"vrate")){pid = &aircraft.ap.pid.climbHold;}
else if (chk(arg2,"alt")){pid = &aircraft.ap.pid.altHold;}
else if (chk(arg2,"th")||chk(arg2,"thr")||chk(arg2,"thro")||chk(arg2,"throttle")){pid = &aircraft.ap.pid.throttleHold;}
else if (chk(arg2,"slip")){pid = &aircraft.ap.pid.slipHold;}
if (chk(arg3,"p")){pid->setPGain(val);}
else if (chk(arg3,"i")){pid->setIGain(val);}
else if (chk(arg4,"d")){pid->setDGain(val);}
else if (chk(arg4,"max"))
{
if (onoff){pid->setLimitMax(val);}
else{pid->disableMaxLimit();}
}
else if (chk(arg4,"min"))
{
if (onoff){pid->setLimitMin(val);}
else{pid->disableMinLimit();}
}
}
else
{
Serial.println("Unknown argument");
}
}
}
void dispPid(char *name, PID &pid){}
The PID class (header):
#pragma once
#define PID_VERSION "1.1"
#include <inttypes.h>
#define allowLimitMax 1
#define allowLimitMin 2
#define invert 4
#define enabled 8
class PID
{
private:
double pGain,iGain,dGain;
double integrator;
double *input,*output,*setpoint;
double lastInput;
double limitMax,limitMin;
char settings;
public:
struct Spid {
double p,i,d,limitMax,limitMin;
char settings;
};
PID();//constructor
//getters
double getPGain();
double getIGain();
double getDGain();
double getLimitMax();
double getLimitMin();
bool isLimitMaxSet();
bool isLimitMinSet();
bool isInverted();
//setters
void setPGain(double newPGain);
void setIGain(double newIGain);
void setDGain(double newDGain);
void setPIDGain(double newPGain, double newIGain, double newDGain);
void setInput(double *newInput);
void setOutput(double *newOutput);
void setSetpoint(double *newSetpoint);
void setIOS(double *newInput, double *newOutput, double *newSetpoint);
void setLimitMax(double newLimitMax);
void setLimitMin(double newLimitMin);
void setLimits(double newLimitMin, double newLimitMax);
void disableMaxLimit();
void disableMinLimit();
void disableLimits();
void zeroOutIntegrator();
void nullOut();
void setInverted(bool newInvert);
//actions
void run();
void run(double dt);
void setFrom(Spid copy);
void copy(Spid ©);
};