I'm trying to write an arduino library. I've written a few classes before but nothing for arduino. I'm running into one error pretty consistently. First let me show you the code:
Code
Main.ino (The arduino project)
#include <Wire.h>
#include "Mobility.h"
Mobility mol = new Mobility();
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Serial.println("loop");
mol.move(true, 125, false, 125, 10);
delay(2000);
}
Mobility.h
#ifndef MOBILITY_H
#define MOBILITY_H
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
const int DEFAULT_MOBILITY_ADD = 4;
class Mobility
{
public:
void begin();
void begin(int address);
int i2cAdd;
int move(bool lPos, unsigned char leftPower, bool rPos, unsigned char rightPower, unsigned char msec);
private:
};
/**/
#endif
Mobility.cpp
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Mobility.h"
#include "Wire.h"
void Mobility::begin(){
Wire.begin();
this.i2cAdd = DEFAULT_MOBILITY_ADD;
}
void Mobility::begin(int address){
Wire.begin();
this.i2cAdd = address;
}
int Mobility::move(bool lPos, unsigned char leftPower,bool rPos, unsigned char rightPower, unsigned char msec){
if (leftPower < -255 || leftPower > 255){
return -1;
}
if (rightPower < -255 || rightPower > 255){
return -2;
}
if(msec <= 0){
return -3;
}
Wire.beginTransmission(this.i2cAdd);
Wire.write(lPos);
Wire.write(leftPower);
Wire.write(rPos);
Wire.write(rightPower);
Wire.write(msec);
Wire.endTransmission();
return 0;
}
ERRORS
I've been getting two big errors while I've been trying to fix the code. The first is:
error: conversion from 'Mobility*' to non-scalar type 'Mobility' requested
Mobility mol = new Mobility();
The problem is caused by this line:
Mobility mol = new Mobility();
the first part is static memory allocation:Mobility mol - statically allocates memory for the object mol.
the second part uses dynamic memory allocation: new - dynamically allocates memory.
So you can do :
Mobility mol;// static allocation
or
Mobility *mol = new Mobility(); //dynamic allcocation
But not a mix of the two. Either way the constructor will be called when creating the object.
Related
I am working with GNU AVR GCC version 5.4.0 and Atmelstudio 7.0.2397 and I have the following problem.
Problem Description
In the following Image, ye can see that up to line 13, the program has stored the address of function usart_send into the transmitter variable which is member of SimpleClass object sc.
The prototype of the transmitter function is void (*transmitter)(uint8_t * txbuff, uint8_t len); and usart_send function prototype definition is void usart_send(uint8_t *, uint8_t);.
Now when I step into the foo function, notice that when inside the member function of the class's object, the address of transmitter is now 0.
Similarly inside the function flush, its value is still 0. So I cannot call the desired function. And this is what disassembly is showing and so is my MCU.
Cause of this problem
So I have the following code for SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
Notice that have the length of txBuffer and rxBuffer defined using define. And in incfile1.h I have the following code.
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
In here I have redefined rxBufferLen and txBufferLen. This definition of define causes the above problem. If I remove these two lines, this code is working fine.
Question
So you can see that by defining the buffer length for a buffer which is inside a class, causes its member function to loose the value the class's function pointer (which is a member variable). And I want to know why?
Code
Here are many un used functions and this is because I was isolating bug(if it is a bug!) from my project.
main.cpp
#include "IncFile1.h"
SimpleClass sc;
int main(void)
{
usart_init();
timer0_init();
sc.transmitter = &usart_send;
sc.foo();
while (1)
{
}
}
IncFile.h
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
SimpleClass.cpp
#include "simpleClass.h"
void SimpleClass::flush(){
transmitter(txBuffer, txbuff_index);
}
void SimpleClass::pushtx(uint8_t byte){
txBuffer[txbuff_index++] = byte;
}
void SimpleClass::pushrx(uint8_t byte){
rxbuffer[rxbuff_index++] = byte;
}
void SimpleClass::foo(){
uint8_t dv = 0;
dv ++ ;
pushtx(0x01);
pushtx(0x02);
pushtx(0x03);
pushtx(0x04);
pushtx(0x05);
flush();
}
CPPFile1.cpp
#include "IncFile1.h"
void usart_init(){
unsigned int ubrr = 51;
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, stop bit */
UCSR0C = (3<<UCSZ00);
}
void timer0_init(){
TCCR0B = TIMER0_CLOCK_PRESCALAR;
TIMSK0 = 1; // enable timer overflow interrupt
TCNT0 = TIMER0_CLOCK_COUNT;
}
void serial_send(const char * c){
for(uint8_t i=0 ; c[i] != '\0';i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = c[i];
}
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0a;
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0d;
}
void usart_send(uint8_t *buff, uint8_t len){
for(uint8_t i = 0; i < len; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = buff[i];
}
}
void usart_send_ln(uint32_t num){
for(uint8_t i =0;i < 4; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = num >> (8*(3-i));
}
}
Edits
You are violating the One Definition Rule - linking C++ program where the same class is defined twice and these definitions are not identical is undefined behaviour. The compiler/linker is not required to check or report these errors.
You are doing just that:
CPPFile1.cpp includes IncFile1.h which creates SimpleClass definition with buffers[50],
SimpleClass.cpp includes SimpleClass.h with buffers[30].
I am trying to control four different objects in a micro-controller (a sensor, a motor, a rotary encoder and a class in charge of the logic) with two functions that are mainly switch state statements, one that reads from the serial port and switches a variable accordingly, and one that reads from that variable and calls functions. I can call the functions from the individual objects directly in my loop, but when I call them with the function serialTask(); the compiler fails. This are my headers:
This is motor.h. I used all those arguments in the constructor because I am using two libraries that use those elements to construct their own objects, TMC2130Stepper, Stepper and StepControl
#pragma once
#include <TeensyStep.h>
#include <TMCStepper.h>
#include <SPI.h>
#include <TimerOne.h>
#include <pinout.h>
#define STALL_VALUE 15
#define R_SENSE 0.11 // Match to your driver
// SilentStepStick series use 0.11
// UltiMachine Einsy and Archim2 boards use 0.2
// Panucatt BSD2660 uses 0.1
// Watterott TMC5160 uses 0.075
//BOB = 0.3
struct Motor {
public:
Motor(const int dirPinArg, const int stepPinArg, const int enabPinArg, const int chipSelectArg, const int mosiSdiArg, const int misoSdoArg, const int clkArg, float rSenseArg);
int microsteps = 8;
const uint32_t steps_per_mm = 80;
int frameRatio = (200 * microsteps) / 2.55;
int motorSpeed;
bool motorState = false;
bool isMoving = false;
bool accelerated = false;
void initializeDriver();
void setupMotor();
void accelerate();
void moveMotor();
void oneFrame();
void oneFrameSlow();
void moveMotorSlow();
bool isAccelerated();
void stepperTimer();
void setSpeed();
int spr = 16*200; // 3200 steps per revolution
TMC2130Stepper driver;
Stepper motor;
StepControl controller;
private:
};
This is my encoder, rotary.h:
/*
* Rotary encoder library for Arduino.
*/
#pragma once
#ifndef rotary_h
#define rotary_h
#include "Arduino.h"
// Enable this to emit codes twice per step.
//#define HALF_STEP
// Enable weak pullups
#define ENABLE_PULLUPS
// Values returned by 'process'
// No complete step yet.
#define DIR_NONE 0x0
// Clockwise step.
#define DIR_CW 0x10
// Anti-clockwise step.
#define DIR_CCW 0x20
class Rotary
{
public:
Rotary(char, char);
//Extra
int encoderTest();
// Process pin(s)
unsigned char process();
volatile int aState;
volatile int aLastState;
int counterNew;
int counterOld;
private:
unsigned char state;
unsigned char pin1;
unsigned char pin2;
};
#endif
This is my sensor.h:
#pragma once
#include <pinout.h>
#include <Arduino.h>
#include <open-celluloid.h>
#include <Rotary.h>
struct Sensor {
public:
Sensor(int sensorPinArg);
int readSensor();
void calibrateSensor(OpenCelluloid openCelluloidArg, Rotary rotaryArg);
void printSensorValues();
int sensorHigh{};
int sensorLow{};
};
And this is the other class, open-celluloid.h:
#pragma once
#include <Arduino.h>
#include <TimerOne.h>
#include <HardwareSerial.h>
#include <Stream.h>
#include <Rotary.h>
#include <pinout.h>
class OpenCelluloid {
public:
OpenCelluloid();
void stepperTimer();
void homing();
void checkTrigger();
void calibrateShutter(Rotary rotaryArg);
//HardwareSerial *serial;
//HardwareSerial &serial1 = Serial;
//TimerOne *timer1;
const int sensorThreshold = 300;
int lastSensorState = 0;
uint8_t sensorState = 0; //
uint8_t stepState = 0; //
//trigger
volatile bool gateOpen{};
volatile bool trigger{};
volatile uint8_t triggerCounter{};
volatile bool sameState = true;
volatile byte threshold[8];
volatile uint8_t sum_threshold{};
volatile uint8_t gate{};
volatile uint8_t gatePrevious{};
volatile uint8_t shutterCounter{};
volatile bool boolGate{};
//volatile bool boolState = !digitalRead(sensor);
volatile bool boolState{};
volatile bool home_position{};
volatile bool startCapture;
uint8_t doFullRotation{};
int stepCount = 10000;
volatile char state;
//Rotary rotary = Rotary(5, 6);
private:
Stream *_streamRef;
TimerOne *_timerRef;
//Stepper *_motorRef;
//StepControl *_controllerRef;
};
Apart from that, I have another .h file in which I have functions:
#pragma once
#include <Arduino.h>
#include <TMCStepper.h>
#include <SPI.h>
#include <TimerOne.h>
#include <HardwareSerial.h>
#include <Stream.h>
#include "TeensyStep.h"
#include <Rotary.h>
#include <open-celluloid.h>
#include <pinout.h>
#include <motor.h>
#include <sensor.h>
#define auto_reset 20
#define start_moving_forward 21
#define start_moving_backward 22
#define keep_moving 23
#define stoping 24
#define auto_end 25
#define one_frame 26
#define hundred_frames 27
#define loading 28
#define keep_moving_slow 29
#define test 30
#define test_digital 31
#define test_analog 32
#define encoder_test 33
#define calibrate_shutter 34
#define calibrate_sensor 35
#define read_sensor 36
#define print_values 37
#define test_acceleration 38
void readSensor();
void oneFrame();
void oneFrameSlow();
void serialTask(Sensor sensorArg, Rotary rotaryArg, OpenCelluloid openCelluloidArg, Motor motorArg);
void stateSwitch(OpenCelluloid openCelluloidArg);
void encoder();
void calibrateShutter();
void testDigital(int button);
void testAnalog(int pin);
The problem is the function serialTask(); which looks like this in the file functions.cpp:
void serialTask(OpenCelluloid openCelluloidArg, Motor motorArg, Sensor sensorArg, Rotary rotaryArg) {
switch (openCelluloidArg.state) {
case auto_reset:
openCelluloidArg.state = auto_end;
break;
case start_moving_forward:
if (!motorArg.isMoving) {
//homing();
//accelerate();
motorArg.isMoving = true;
} else {
openCelluloidArg.state = keep_moving;
motorArg.isMoving = true;
}
digitalWrite(dir_Pin, LOW);
//delayMicroseconds(10000);
openCelluloidArg.startCapture = true;
break;
case start_moving_backward:
if ( !motorArg.isMoving) {
//homing();
motorArg.isMoving = true;
} else {
openCelluloidArg.state = keep_moving;
motorArg.isMoving = true;
}
digitalWrite(dir_Pin, HIGH);
//delayMicroseconds(10000);
openCelluloidArg.startCapture = true;
break;
case keep_moving:
openCelluloidArg.home_position = false;
motorArg.moveMotor();
//moveMotorPwm();
//serialFrames();
openCelluloidArg.state = keep_moving;
break;
case keep_moving_slow:
openCelluloidArg.home_position = false;
//moveMotorSlow();
openCelluloidArg.state = keep_moving_slow;
break;
case stoping:
digitalWrite(step_Pin, LOW);
digitalWrite(enabPin, HIGH);
openCelluloidArg.state = auto_end;
motorArg.isMoving = false;
digitalWrite(enabPin, LOW);
openCelluloidArg.startCapture = false;
break;
case auto_end:
openCelluloidArg.home_position = false;
break;
case one_frame:
//oneFrame();
motorArg.oneFrameSlow();
openCelluloidArg.state = auto_end;
break;
case loading:
if ( !motorArg.isMoving) {
motorArg.isMoving = true;
} else {
openCelluloidArg.state = keep_moving_slow;
motorArg.isMoving = true;
}
digitalWrite(dir_Pin, LOW);
break;
case test:
sensorArg.readSensor();
break;
case test_digital:
testDigital(encoButton);
break;
case test_analog:
testAnalog(encoButton);
break;
case encoder_test:
rotaryArg.encoderTest();
break;
case calibrate_shutter:
openCelluloidArg.calibrateShutter(rotaryArg);
break;
case calibrate_sensor:
sensorArg.calibrateSensor(openCelluloidArg, rotaryArg);
break;
case read_sensor:
sensorArg.readSensor();
break;
case print_values:
sensorArg.printSensorValues();
break;
case test_acceleration:
motorArg.accelerate();
}
};
Whenever I call this function in the main loop(), the compiler tells me use of deleted function 'Motor::Motor(const Motor&)'. This is how my main.cpp file looks like:
#include <Arduino.h>
#include <open-celluloid.h>
#include <HardwareSerial.h>
#include <TeensyStep.h>
#include <TMCStepper.h>
#include <functions.h>
#include <motor.h>
#include <Rotary.h>
Motor motorObj(dir_Pin, step_Pin, enabPin, chipSelect, mosiSdi, misoSdo, clk, 0.11f);
Rotary rotaryObj(channelA, channelB);
Sensor sensorObj(sensor);
OpenCelluloid openCelluloidObj{};
void setup() {
pinMode(enabPin, OUTPUT);
pinMode(step_Pin, OUTPUT);
pinMode(chipSelect, OUTPUT);
pinMode(dir_Pin, OUTPUT);
pinMode(sensor, INPUT);
pinMode(led, OUTPUT);
pinMode(channelA, INPUT);
pinMode(channelB, INPUT);
pinMode(startStop, OUTPUT);
pinMode(dirSwitch, OUTPUT);
pinMode(encoButton, INPUT);
pinMode(misoSdo, INPUT_PULLUP);
pinMode(mosiSdi, OUTPUT);
pinMode(clk, OUTPUT);
digitalWrite(enabPin, LOW);
digitalWrite(dir_Pin, LOW);
digitalWrite(step_Pin, LOW);
digitalWrite(chipSelect, LOW);
digitalWrite(mosiSdi, LOW);
digitalWrite(clk, LOW);
Serial.begin(115200);
motorObj.setupMotor();
openCelluloidObj.startCapture = false;
digitalWrite(step_Pin, motorObj.motorState);
rotaryObj.aLastState = digitalRead(channelA);
openCelluloidObj.state = auto_end;
};
void loop() {
stateSwitch(openCelluloidObj);
serialTask(sensorObj, rotaryObj, openCelluloidObj, motorObj);
};
Also I have another .h file called pinout.h in which all my pins are defined as constants and gets called from the other files, but that doesn't seem to be important. The compiler also sends me to errors deep within the libraries that I am using for the motor, but that only happens when I call serialTask(). Maybe there is a problem of redefinition, I am really lost here, any help is greatly appreciated. This are the other error messages that I get:
StepControlBase<a, t>::StepControlBase(const StepControlBase<a, t>&) [with Accelerator = LinStepAccelerator; TimerField = TimerField]' is protected
use of deleted function 'StepControlBase<a, t>::StepControlBase(const StepControlBase<a, t>&) [with Accelerator = LinStepAccelerator; TimerField = TimerField]'
The issue is that your argument is taking Motor by value, so it needs to do a copy.
The copy constructor is deleted when you create your own constructor.
Try passing by reference (const Motor& or Motor&).
No matter how many times I reformat this, I keep getting all kinds of errors. The end result will be a program that can save functions targeting motors in a telescope and set coordinates. Any help in explaining what I am doing wrong with this setup would be greatly appreciated. here is the code:
//IDENTIFY RECEIVER OF MESSAGE / TYPE OF MESSAGE / VIEW ALL TO 1 DEVICE / VIEW SPECIFIC MESSAGE
#include "messaging.h"
#include <string.h>
#include <stdio.h>
using namespace std;
typedef struct MGR{
mess_types messagetype;
int DeviceID;
union E{
//why arte these underlined?
char INST[STRSIZE];
int codes[NBRCODES];
float coords[NBRCOORDS];
} message;
};// info;
void messager(){
MGR my_data;
my_data.messagetype = INST;
my_data.DeviceID = TECH1;
strcpy(my_data.message.INST, "GO HOME");
my_data.messagetype = CODES;
my_data.DeviceID = MOTOR1;
for (int nbr = 0; nbr < NBRCODES; nbr++){
my_data.message.codes[nbr] = nbr;
print_message(my_data);
}
}
int print_message(MGR mydata){
MGR noot;
scanf("%s", &mydata);
switch (mydata.messagetype){
case INST:
printf("Message to Device %d", noot.DeviceID);
break;
case CODES:
printf("The setup codes for device %d are: \n", noot.DeviceID);
for (int code = 0; code < NBRCODES + OFFSET; code++){
printf("%4d\t", noot.message);
}
break;
case COORDS:
printf("The setup codes for device %d are: \n", noot.DeviceID);
for (int code = 0; code < NBRCODES + OFFSET; code++){
printf("%4d\t", noot.message);
}
break;
}
printf("%c", mydata.messagetype);
return(0)
}
void Sendmessage(){
printf("This program does not work... it is under construction...");
}
Just in case: here is the header file
#include "sprint1.h"
#include <string.h>
#include <stdio.h>
#define STRSIZE 50
#define NBRCODES 200
#define NBRCOORDS 200
#define OFFSET 100
#define FACTOR 50
#define TECH1 123
#define MOTOR1 4556
void messager();
int print_message(MGR mydata);
void Sendmessage();
enum mess_types {INST, CODES, COORDS};
Error list: https://drive.google.com/file/d/0B0CXbbHDOrweQVVvOVU1M0VRaEE/view?usp=sharing
I assume the header listed is "messaging.h"
MGR is referenced in the header before it's definition in the code.
Maybe move the definition to the header before the first reference.
I am trying to split up my arduino code base from a single 'ino' file into a proper-ish c++ program by creating classes which have both .h & .cpp files. I am running into a few errors that I just haven't been able to solve. I hope I am missing something simple.
When compiling in visual studio running the "Arduino IDE for Visual Studio" plugin, I get the following errors:
7:8: error: 'class MPU6050' has no member named 'timer
30:5: error: prototype for 'int MPU6050::MPU6050_read(int, uint8_t*, int)' does not match any in class 'MPU6050
What am I missing here?
.h
#ifndef MPU6050_H
#define MPU6050_H
class MPU6050
{
private: // Vars
uint32_t timer; // Hold the value of the timer used for the complementary filter
int error;
public: // Methods
MPU6050();
~MPU6050();
void read_acc_gyr();
float const * const getXa();
float const * const getYa();
float const * const getXvel();
float const * const getYvel();
float const * const getZvel();
float const * const getZang();
double const * const getDt();
private:
void test_gyr_acc();
void MPU6050_init();
void printGyroValues();
void calibrateGyro();
int MPU6050_write(int start, const uint8_t *pData, int size);
int MPU6050_read(int start, uint8_t *buffer, int size);
int MPU6050_write_reg(int reg, uint8_t data);
};
#endif
.cpp
#include "MPU6050.h"
#include "Arduino.h"
#include "MPU6050Definitions.h"
MPU6050::MPU6050()
{
timer = 0; // Always start the timer at 0
error = 1;
Serial.println("Testing Gyro");
test_gyr_acc();
}
MPU6050::~MPU6050()
{
}
int MPU6050::MPU6050_read(int start, uint8_t *buffer, int size)
{
int i, n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS);
n = Wire.write(start);
if (n != 1)
return (-10);
n = Wire.endTransmission(false); // hold the I2C-bus
if (n != 0)
return (n);
// Third parameter is true: relase I2C-bus after data is read.
Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
i = 0;
while (Wire.available() && i<size)
{
buffer[i++] = Wire.read();
}
if (i != size)
return (-11);
return (0); // return : no error
}
void MPU6050::test_gyr_acc()
{
uint8_t c = 0;
error = MPU6050_read(MPU6050_WHO_AM_I, &c, 1);
if (error != 0) {
while (true) {
digitalWrite(13, HIGH);
delay(300);
digitalWrite(13, LOW);
delay(300);
}
}
}
MPUT6050Definitions.h includes all of my constants and looks like the following: (many more #defines which I don't think are relevant to include)
#pragma once
//All the values to setup the MPU6050 gyro/accelermeter
#define MPU6050_AUX_VDDIO 0x01 // R/W
#define MPU6050_SMPLRT_DIV 0x19 // R/W
#define MPU6050_CONFIG 0x1A // R/W
#define MPU6050_GYRO_CONFIG 0x1B // R/W
It looks like I made a simple mistake.
A few more errors down the list was an unknown declaration of type uint_32 which propagated itself causing the errors I was seeing before. I included the Arduino.h header which resolved the uint_32 problem causing the rest of the code to compile as expected.
Moral of the story is don't try to fix your errors from the top down.
I get this error when trying to compile my program:
Field '__jmpbuf' could not be resolved
I looked for a solution for hours and can't seem to find out where is the culprit.
The Thread.h file contains the header of the class. It has the private member:
sigjmp_buf _env;
And the implementation is inside Thread.cpp:
#include "Thread.h"
#include <setjmp.h>
#include "translateAdd.h"
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#define COUNTER_INIT -1
int Thread::_idCounter = COUNTER_INIT;
Thread::Thread(void (*threadsFunc)(void))
: threadsFunction(threadsFunc), _stack(new char[STACK_SIZE]), _quantums(1)
{
address_t sp, pc;
sp = (address_t)_stack + STACK_SIZE - sizeof(address_t);
pc = (address_t)threadsFunc;
// set environment for later return
sigsetjmp(_env, 1);
(_env->__jmpbuf)[JB_SP] = translate_address(sp);
(_env->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&_env->__saved_mask);
_id = ++_idCounter;
_state = READY;
}
EDIT: Using eclipse as the IDE under ubuntu 32bit
EDIT: Another complete example that doesn't compile on my machine:
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#define SECOND 1000000
#define STACK_SIZE 4096
char stack1[STACK_SIZE];
char stack2[STACK_SIZE];
sigjmp_buf env[2];
#ifdef __x86_64__
/* code for 64 bit Intel arch */
typedef unsigned long address_t;
#define JB_SP 6
#define JB_PC 7
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#else
/* code for 32 bit Intel arch */
typedef unsigned int address_t;
#define JB_SP 4
#define JB_PC 5
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%gs:0x18,%0\n"
"rol $0x9,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#endif
void switchThreads(void)
{
static int currentThread = 0;
int ret_val = sigsetjmp(env[currentThread],1);
printf("SWITCH: ret_val=%d\n", ret_val);
if (ret_val == 1) {
return;
}
currentThread = 1 - currentThread;
siglongjmp(env[currentThread],1);
}
void f(void)
{
int i = 0;
while(1){
++i;
printf("in f (%d)\n",i);
if (i % 3 == 0) {
printf("f: switching\n");
switchThreads();
}
usleep(SECOND);
}
}
void g(void)
{
int i = 0;
while(1){
++i;
printf("in g (%d)\n",i);
if (i % 5 == 0) {
printf("g: switching\n");
switchThreads();
}
usleep(SECOND);
}
}
void setup(void)
{
address_t sp, pc;
sp = (address_t)stack1 + STACK_SIZE - sizeof(address_t);
pc = (address_t)f;
sigsetjmp(env[0], 1);
(env[0]->__jmpbuf)[JB_SP] = translate_address(sp);
(env[0]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env[0]->__saved_mask);
sp = (address_t)stack2 + STACK_SIZE - sizeof(address_t);
pc = (address_t)g;
sigsetjmp(env[1], 1);
(env[1]->__jmpbuf)[JB_SP] = translate_address(sp);
(env[1]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env[1]->__saved_mask);
}
int main(void)
{
setup();
siglongjmp(env[0], 1);
return 0;
}
If you really need to use the internal fields (which will only be valid for your compiler on your system) you need to check the types:
typedef struct __jmp_buf_tag sigjmp_buf[1];
That means that sigjmp_buf is not a pointer, but an array with a single structure in it. So you use it like a normal array of structures:
sigjmp_buf _env;
_env[0].__jmpbuf[x] = y;
I really recommend against the use the internal field of this structure. Linux have other functions to simplify cooperative threading (which is what you seem to be implementing).