|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
|
|
Thread Tools | Rate Thread | Display Modes |
|
|
|
#1
|
||||
|
||||
|
Understanding the Source code
I'm a pretty proficient programmer (most of my experience is with C#), but I'm still finding myself stumped by some of the source code. I'm hoping that if I understand the source I can implement new classes as necessary and use proper conventions (especially where error handling is concerned).
First question: Macros. FRC apparently (and inexplicably) has made extensive use of macros. I'm not extremely familiar with them, but they seem to serve many purposes. The first one I came across: "START_ROBOT_CLASS(IterativeDemo);" at the bottom of the demo class. This references RobotBase.h, which has: Code:
#define START_ROBOT_CLASS(_ClassName_) \
RobotBase *FRC_userClassFactory(void) \
{ \
return new _ClassName_(); \
} \
extern "C" { \
int FRC_UserProgram_StartupLibraryInit(void) \
{ \
RobotBase::startRobotTask((FUNCPTR)FRC_userClassFactory); \
return 0; \
} \
}
Second question: Macros. Heh, sorry, I mean Macros that do error handling. The next major macro confusion is with the "wpi_assert"s and "wpi_fatal"s that are sprinkled across the code. One example in RobotDrive.cpp: Code:
void RobotDrive::SetInvertedMotor(MotorType motor, bool isInverted)
{
if (motor < 0 || motor > 3)
{
wpi_fatal(InvalidMotorIndex);
return;
}
m_invertedMotors[motor] = isInverted ? -1 : 1;
}
Code:
#ifdef WPI_STATUS_DEFINE_STRINGS #define S(label, offset, message) const int wpi_v_##label = offset; const char *wpi_s_##label = message ; #else #define S(label, offset, message) const int wpi_v_##label = offset; extern const char *wpi_s_##label; #endif Sorry if this was a lot of questions... Basically, I want to know: -What happened to main() and what is the START_ROBOT_CLASS macro doing -How the wpi_assert and _demands handle errors |
|
#2
|
||||
|
||||
|
Re: Understanding the Source code
Quote:
The program's entry point is FRC_UserProgram_StartupLibraryInit. This is what the LabVIEW Run-Time calls when it loads the user program. The START_ROBOT_CLASS macro sets up a "user class factory", which is a function that returns a pointer new instance of your robot class. Additionally, it creates the entry point function, FRC_UserProgram_StartupLibraryInit. This entry point calls RobotBase::startRobotTask() with a pointer to the "factory" function. From here, a new task is spawned to run the user program. This task creates an instance of your Robot class and calls its StartCompetition() function. I'm not sure I quite understand the reason behind spawning off this new task, but I believe it somehow makes it easier to debug. Quote:
|
|
#3
|
||||
|
||||
|
Re: Understanding the Source code
Quote:
As for your other complaints -- I hear ya brother. Gotta love C++. |
|
#4
|
||||
|
||||
|
Re: Understanding the Source code
Quote:
Thank you, Matt! With those pointers in the right direction (heh), I think I understand the code now. So, just to recap: -START_ROBOT_CLASS, through many convolutions, defines the entry point FRC_UserProgram_StartupLibraryInit, which is called from external code (on the cRIO), which: -Spawns a new task running an instance of the robot class Do I have that right? OK, so, in lieu of using try-catch blocks, I should use wpi_assert around conditionals that try to trap errors like null pointers? From what I can tell, this prints a message to the console (and puts a condition on the stack?). So, if I wanted to flush the error stack, I'd use wpi_assertCleanStatus. What's the difference between wpi_assert and wpi_fatal? |
|
#5
|
||||
|
||||
|
Re: Understanding the Source code
Quote:
Quote:
Additionally, if a debugger is attached, when the assert condition is false then the debugger usually takes over at that point and you can examine the local variables and see what happened that caused the condition to be false. Now why is that useful? When you're making something, its useful to put in little checks basically saying "this condition should never happen, if it does then we need to immediately stop execution". You can also put in more expensive checks in there that only run in the debug build, so that way the code is more optimized in the release build (since, the checks are not done if NDEBUG is defined). Code:
switch (some_val)
{
case 1:
// do something
break;
case 2:
// do something
break;
default:
// some_val should never be this
assert(0 && "this should never have happened");
}
Code:
assert((some_val == 1 || some_val == 2) && "this should never be a different value");
switch (some_val)
{
// cases here...
}
Look at Utility.cpp in WPILib for the implementation. Last edited by virtuald : 01-31-2009 at 02:06 AM. Reason: Bad example. |
|
#6
|
||||
|
||||
|
Re: Understanding the Source code
Sounds good, thanks.
I've been wondering what the keyword extern does. I see "extern "C"" a lot. None of the C++ references really provide a good explanation in the context of this code. |
|
#7
|
|||||
|
|||||
|
Re: Understanding the Source code
It basically tells the compiler "This is the name of something that is defined in a separate file. You don't need to know any more details about it at the present time. Make sure to put the appropriate placeholder information in the object file so that things can be linked together correctly later."
The extern "C" gives a hint to the compiler that the separate file will be using C conventions, so the linker doesn't get confused trying to connect C and C++ object files together without the appropriate conversion. |
|
#8
|
|||||
|
|||||
|
Re: Understanding the Source code
Like the words "static" and "const", "extern" is somewhat context-dependent in C++. For more: http://en.wikipedia.org/wiki/Extern
|
|
#9
|
||||
|
||||
|
Re: Understanding the Source code
Ah, thanks.
Something that my programming teacher asked me and I had no idea: does the cRIO use interrupts to handle input from joysticks (like a Windows environment does)? |
|
#10
|
||||
|
||||
|
Re: Understanding the Source code
I (a fellow C#er) don't personaly like the unsafe nature of C++, but alas!
Anyhow, in the C Programming guide: Quote:
so no exceptions look for c complilers operations (google it) for #ifndef and #define, they are compiler constants. |
|
#11
|
||||
|
||||
|
Re: Understanding the Source code
Agreed, C++ is...well, a bit low-level after working with C# for so long.
Quote:
Quote:
|
|
#12
|
||||
|
||||
|
Re: Understanding the Source code
Quote:
also Quote:
Code:
if i have not defined "WPI_STATUS_DEFINE_STRINGS" then
{
replace the macro "S(label, offset, message)" with
{
const int wpi_v_##label = offset;
const char *wpi_s_##label = message ;
}
}
else (if i have defined "WPI_STATUS_DEFINE_STRINGS")
{
replace the macro "S(label, offset, message)" with
{
const int wpi_v_##label = offset;
extern const char *wpi_s_##label;
}
}
|
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| need help understanding c code in robotdrive | mahmosh | C/C++ | 14 | 01-16-2009 08:56 AM |
| i downloaded the source code, now what do i do? | programmr | Programming | 2 | 12-12-2008 02:39 PM |
| Source code for the Easy C Pro library functions? | bobpskier | Programming | 3 | 02-05-2007 09:39 PM |
| [FVG]: Source Code | SilverStar | FIRST-related Organizations | 5 | 08-24-2004 02:28 PM |
| Patent source code? | Kyle Fenton | Chit-Chat | 3 | 10-20-2001 05:53 PM |