Go Down

Topic: Is it possible to port arduino codes to dev C++ for testing algorithm? (Read 4666 times) previous topic - next topic

liuzengqiang

I have this thought: I want to test some algorithm for arduino but I don't have an avr dragon and don't know how to use avr studio to debug but that's not the point. Since the code only concerns algorithm, I should be able to take the code and test it on a PC based compiler and run it as a console program with a debugger, feed it with Stream inputs and see what it does. The difficulties are the defs and includes that arduino uses. If I didn't use any defs or includes, I'm alright but if I use say bitRead(), which is a def, or byte, which is a typedef, I need to include Arduino.h, which includes a whole bunch of other libraries and crazy stuff. I suppose the standard libraries may be interchangeable among different compilers so I can just take Arduino.h and some other includes it is tied to, and put them in my Dev C++ library folder. Is this just simple stupidity?  :smiley-mr-green:

nickgammon

In principle, certainly. And with an #ifdef or two you can simulate things that don't exist on the non-Arduino platform.

As an example, I am working on an adventure game which compiles on the Microsoft Visual Studio Lite (or whatever they call it) and also under Arduino IDE. You can make something like Output which in one case become Serial (with the streaming library) and in the other case "cout".

It isn't too hard to do.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jimLee

Maybe.. Write your own "arduino.h", that you use on your PC to test with. Have it redefine the arduino calls you need into appropriate PC calls. Then you can cross platform test to your hearts content.

-jim lee
PNW Ardiuno & Maker club
1012 9Th Street, Anacortes, WA 98221 (Around the back of building)
GITHUB -> https://github.com/leftCoast

liuzengqiang

Thanks guys! I'm a bit too ambitious. I added the following paths to my Dev C++ include:

\arduino-1.0\hardware\tools\avr\avr\include
\arduino-1.0\hardware\arduino\cores\arduino
\arduino-1.0\hardware\arduino\variants\mega

Most whining of the compiler is ok but there is an error:

\arduino-1.0\hardware\arduino\cores\arduino\WCharacter.h `isblank' undeclared (first use this function)

This 'isblank' is defined in ctype.h, which is included in WCharacter.h among a bunch other classification stuff:

In WCharacter.h
Code: [Select]

inline boolean isAscii(int c)
{
  return ( isascii (c) == 0 ? false : true);
}

inline boolean isWhitespace(int c)
{
  return ( isblank (c) == 0 ? false : true);
}


In ctype.h
Code: [Select]

extern int isascii(int __c) __ATTR_CONST__;

extern int isblank(int __c) __ATTR_CONST__;


If "isascii" is OK, then why would "isbland" be not OK?

All these started because I used a stupid bitRead().  =(

nickgammon

Don't over-egg the pudding. If you need a dummy bitRead under Windows, just make one with a conditional compile. I wouldn't be including all that stuff. Who knows what the side-effects will be?
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

liuzengqiang


Don't over-egg the pudding. If you need a dummy bitRead under Windows, just make one with a conditional compile. I wouldn't be including all that stuff. Who knows what the side-effects will be?


I'll make a fakearduino.h to include some defs and such. This is no problem.

BTW, there must some defs made by the arduino IDE when calling the gcc, so there are defs such as '__AVR_ATmega1280__' and more. I'm guessing the -mmcu=ATmega1280 option in the avr_g++ does that, plus -DF_CPU=16000000L and -DARDUINO=100. Still I don't know why the isblank stops the compile :( Tried hard not to learn what the arduino IDE spits out at compile time til today and now I went through it and learned something, even if it doesn't solve the egg problem.

liuzengqiang

OK finally mastered the amount of egg to add to pudding:

Here is what I did, in case anyone else is interested:
Goal: to compile code I write for arduino on a PC C++ compiler/Dev-C++ IDE, to test algorithm and input/output of my code that doesn't NOT rely on MCU or Arduino Dev board hardware so I don't have to load the code to arduino to debug.
Steps:
1) Copy the following .h files to an Arduino folder in dev C++ include folder: Arduino.h, binary.h
2) Edit Arduino.h
Beginning of the file:

Code: [Select]
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
/*
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/interrupt.h>
*/


In the middle, comment out these that depends on avr/pgmspace.h:
Code: [Select]
/*
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.

#define analogInPinToBit(P) (P)

// On the ATmega1280, the addresses of some of the port registers are
// greater than 255, so we can't store them in uint8_t's.
extern const uint16_t PROGMEM port_to_mode_PGM[];
extern const uint16_t PROGMEM port_to_input_PGM[];
extern const uint16_t PROGMEM port_to_output_PGM[];

extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];

// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
*/


Towards the end:
Code: [Select]
//-#include "WCharacter.h"
//-#include "WString.h"
//-#include "HardwareSerial.h"


and

Code: [Select]
//-#include "pins_arduino.h"


Now make sure your arduino codes and main.cpp have #include <Arduino.h>

Next for compiler options, add the path where you store this modified Arduino.h to C++ includes, Menu->tools->compiler options->directories->C++ includes.
Then with compiler options, add these if you need : Menu->tools->compiler options->Compiler->Add the following commands when calling the compiler -DF_CPU=16000000L -DARDUINO=100 -D__AVR_ATmega1280__

Results: you can compile and debug your arduino hardware-independent code on a PC and debug all you want before putting the working code back to arduino.

liuzengqiang

This seems to be pretty effective. For over a decade I have not used a debugger and 3 years ago I picked up arduino and have enjoyed programming it since. My biggest problem with arduino is no way to trace problems with a debugger. This method works pretty well, since lots of the problems are not hardware related but rather software related. Especially when generating dynamic menus for a project I'm working on, it's ideal. All classes are software and they only interact with hardware in a much later stage. With simple printf I can see how the menus look like with my phi_prompt.

After some tweaking, I was able to simulate the PROGMEM strings and functions in Dev C++, meaning I can push strings to PROGMEM, which means regular memory on PC and FLASH on ATMEGAs. I'm still testing this.

Maverik2210

Hi
sorry for necrotopic. 
have tried this way and it's generally ok, but i'd like to use e.g. String type from arduino ide, but no chance to use it, most likely due to WString.h disabled.
If i de-comment WString.h line in Arduino.h file i got that mentioned mistake of
`isblank' undeclared (first use this function)

bperrybap

For over a decade I have not used a debugger
Ouch.... That is painful.....

Seems like it is probably time to start using more of the full toolset.
gdb has been available for more than 25 years.....
The beauty of the gcc toolset is that just like unix and now linux the commands are very consistent and stable and have been so for decades.
(Although things can be tough if trying to use Windows for s/w development since it wasn't designed for that)

It amazes how many folks stop short of getting their s/w development tools in working order.
In my view part of that is getting s/w tools in order is to get the gdb source level debugger up and working.

For anything complex having the source level debugger up and running will more than pay for the time needed to get the tool working.

As far as using another environment for simulation. I've done this many times over the past 3 decades.
In fact at a company i started, we simulated an entire ASIC  in s/w which allowed writing and debugging the unix drivers and full communications protocol stacks with actual end to end communications between multiple machines before the hardware existed.

I also created a simulated environment when I was bringing up the GLCDv3 library.
I was source level debugging the routines and drawing "pixels" on the screen of my linux machine long before I put the code into a library for the Arduino.

The key thing to keep in mind when doing simulations like this is to write very portable code and to properly layer the code to ensure that functionality is very isolated and interfaces are clean.
i.e. don't have code that does i/o and algorithms or multiple things in the same function.
Also, use wrapping macros whenever possible so that no native/proprietary functions/macros are ever called/used by the mainline code.

liberally use multiple source module files so you can keep the code clean so that that the truly portable code is not jumbled in the same source module file with code that starts to get closer to the i/o which will need simulation macros.

liberally use macros to map/wrap the missing functions/macros into something that simulates needed functionality or create stubs just to get things to link up if the functionality is not needed.

For the lower level code that starts to use proprietary macros/calls, start to create a simulation header that replicates those macros or maps them to something else rather than try to include the actual headers as using the original headers will often cascade and create additional issues.


--- bill

Go Up