Go to Post 2015 never happened - Chris is me [more]
Home
Go Back   Chief Delphi > Technical > Programming > C/C++
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Reply
 
Thread Tools Rate Thread Display Modes
  #1   Spotlight this post!  
Unread 29-01-2009, 21:44
Phazonmutant's Avatar
Phazonmutant Phazonmutant is offline
Winrar
AKA: Greg Mitchell
FRC #2556 (RadioActive Roaches)
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2008
Location: Niceville, FL
Posts: 17
Phazonmutant is on a distinguished road
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; \
	} \
}
This makes no sense to me. Where is the main() function that would presumably instantiate the robot class? Also, what is this START_ROBOT_CLASS doing exactly?

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;
}
I understand that it's some sort of error code, but how exactly does it work? From the FRC C++ guide, the WPI library doesn't use C++'s exception handling system (for the rather odd reason that an uncaught exception might be thrown - which might happen anyway if there's no push to use exception handling). The only thing that has any macro definitions seems to be the WPIStatus.h file. Relevant section:
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
What does that do?? I confess, I'm not very well versed in preprocessor directives, but that doesn't even make a bit of sense to me.

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
Reply With Quote
  #2   Spotlight this post!  
Unread 29-01-2009, 22:17
MattD's Avatar
MattD MattD is offline
Registered User
AKA: Matthew Douglas
FRC #0228 (GUS Robotics)
Team Role: Alumni
 
Join Date: Feb 2006
Rookie Year: 2005
Location: Indianapolis, IN
Posts: 185
MattD is a splendid one to beholdMattD is a splendid one to beholdMattD is a splendid one to beholdMattD is a splendid one to beholdMattD is a splendid one to beholdMattD is a splendid one to beholdMattD is a splendid one to behold
Send a message via AIM to MattD
Re: Understanding the Source code

Quote:
This makes no sense to me. Where is the main() function that would presumably instantiate the robot class? Also, what is this START_ROBOT_CLASS doing exactly?
I can try to explain this, to the best of my knowledge. Here's how it works as far as I can tell:

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:
The next major macro confusion is with the "wpi_assert"s and "wpi_fatal"s that are sprinkled across the code.
The code for these functions is in Utility.cpp. It seems like they handle some output to stdout, breaking, and stack tracing. I'm pretty curious about these too. I haven't really played around with it yet so I'll leave it up to someone more knowledgeable than myself to explain.
__________________
GUS Robotics Team 228

2010 WPI Engineering Inspiration Award
2010 WPI Regional Champions (Thanks 230 & 20!)
2010 CT VEX Champions
2010 CT VEX Innovate Award
2009 QCC VEX Champions
2009 CT Motorola Quality Award
2007 CT J&J Sportsmanship Award
2006 CT Best Website Award
Reply With Quote
  #3   Spotlight this post!  
Unread 29-01-2009, 22:43
gvarndell's Avatar
gvarndell gvarndell is offline
Software Engineer
AKA: Addi's and Georgie's Dad
FRC #1629 (GaCo)
Team Role: Parent
 
Join Date: Jan 2009
Rookie Year: 2008
Location: Grantsville, Maryland
Posts: 350
gvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond reputegvarndell has a reputation beyond repute
Re: Understanding the Source code

Quote:
Originally Posted by Phazonmutant View Post
Relevant section:
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
What does that do??
I'm not sure, but I think this is something called "stringification".

As for your other complaints -- I hear ya brother. Gotta love C++.
Reply With Quote
  #4   Spotlight this post!  
Unread 29-01-2009, 23:39
Phazonmutant's Avatar
Phazonmutant Phazonmutant is offline
Winrar
AKA: Greg Mitchell
FRC #2556 (RadioActive Roaches)
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2008
Location: Niceville, FL
Posts: 17
Phazonmutant is on a distinguished road
Re: Understanding the Source code

Quote:
As for your other complaints -- I hear ya brother. Gotta love C++.
Indeed. What do you guys mostly code in?

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?
Reply With Quote
  #5   Spotlight this post!  
Unread 31-01-2009, 02:03
virtuald's Avatar
virtuald virtuald is offline
RobotPy Guy
AKA: Dustin Spicuzza
FRC #1418 (), FRC #1973, FRC #4796, FRC #6367 ()
Team Role: Mentor
 
Join Date: Dec 2008
Rookie Year: 2003
Location: Boston, MA
Posts: 1,039
virtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant future
Re: Understanding the Source code

Quote:
Originally Posted by Phazonmutant View Post
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?
Yes.

Quote:
OK, so, in lieu of using try-catch blocks, I should use wpi_assert around conditionals that try to trap errors like null pointers?
No. On code that you run on a 'normal' system, when the condition inside the parentheses of assert() is false, the program immediately prints out a message with whatever is inside the parentheses and a line number and the program ends (strictly speaking, it isn't always implemented this way, but thats typically the case). However, when NDEBUG is defined, then assert expands to nothing and does nothing.

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");
}
An alternative way of doing this would be:

Code:
assert((some_val == 1 || some_val == 2) && "this should never be a different value");

switch (some_val)
{
    // cases here... 
}
However, this usage of assert does not seem to be what is implemented in WPILib by default. In particular, it does not appear to care about the value of NDEBUG. Instead it just prints out the error message and continues (as far as I can see, without actually going back up the stack). However, if you call wpi_suspendOnAssertEnabled(true) then I believe you will get this type of behavior.

Look at Utility.cpp in WPILib for the implementation.
__________________
Maintainer of RobotPy - Python for FRC
Creator of pyfrc (Robot Simulator + utilities for Python) and pynetworktables/pynetworktables2js (NetworkTables for Python & Javascript)

2017 Season: Teams #1973, #4796, #6369
Team #1418 (remote mentor): Newton Quarterfinalists, 2016 Chesapeake District Champion, 2x Innovation in Control award, 2x district event winner
Team #1418: 2015 DC Regional Innovation In Control Award, #2 seed; 2014 VA Industrial Design Award; 2014 Finalists in DC & VA
Team #2423: 2012 & 2013 Boston Regional Innovation in Control Award


Resources: FIRSTWiki (relaunched!) | My Software Stuff

Last edited by virtuald : 31-01-2009 at 02:06. Reason: Bad example.
Reply With Quote
  #6   Spotlight this post!  
Unread 03-02-2009, 00:44
Phazonmutant's Avatar
Phazonmutant Phazonmutant is offline
Winrar
AKA: Greg Mitchell
FRC #2556 (RadioActive Roaches)
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2008
Location: Niceville, FL
Posts: 17
Phazonmutant is on a distinguished road
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.
Reply With Quote
  #7   Spotlight this post!  
Unread 03-02-2009, 10:33
Alan Anderson's Avatar
Alan Anderson Alan Anderson is offline
Software Architect
FRC #0045 (TechnoKats)
Team Role: Mentor
 
Join Date: Feb 2004
Rookie Year: 2004
Location: Kokomo, Indiana
Posts: 9,112
Alan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond repute
Re: Understanding the Source code

Quote:
Originally Posted by Phazonmutant View Post
I've been wondering what the keyword extern does.
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.
Reply With Quote
  #8   Spotlight this post!  
Unread 03-02-2009, 10:36
Jared Russell's Avatar
Jared Russell Jared Russell is offline
Taking a year (mostly) off
FRC #0254 (The Cheesy Poofs), FRC #0341 (Miss Daisy)
Team Role: Engineer
 
Join Date: Nov 2002
Rookie Year: 2001
Location: San Francisco, CA
Posts: 3,071
Jared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond repute
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
Reply With Quote
  #9   Spotlight this post!  
Unread 05-02-2009, 21:13
Phazonmutant's Avatar
Phazonmutant Phazonmutant is offline
Winrar
AKA: Greg Mitchell
FRC #2556 (RadioActive Roaches)
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2008
Location: Niceville, FL
Posts: 17
Phazonmutant is on a distinguished road
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)?
Reply With Quote
  #10   Spotlight this post!  
Unread 05-02-2009, 21:24
byteit101's Avatar
byteit101 byteit101 is offline
WPILib maintainer (WPI)
AKA: Patrick Plenefisch
no team (The Cat Attack (Formerly))
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2009
Location: Worcester
Posts: 699
byteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of light
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:
We have chosen to not use the C++ exception handling mechanism, although it is available
to teams for their programs. Our reasoning has been that uncaught exceptions will unwind
the entire call stack and cause the whole robot program to quit. That didn't seem like a
good idea in a finals match in the Championship when some bad value causes the entire
robot to stop.
I can still cause the program to quit!
so no exceptions
look for c complilers operations (google it) for #ifndef and #define, they are compiler constants.
__________________
Bubble Wrap: programmers rewards
Watchdog.Kill();
printf("Watchdog is Dead, Celebrate!");
How to make a self aware robot: while (∞) cout<<(sqrt(-∞)/-0);
Previously FRC 451 (The Cat Attack)
Now part of the class of 2016 at WPI & helping on WPILib
Reply With Quote
  #11   Spotlight this post!  
Unread 05-02-2009, 21:32
Phazonmutant's Avatar
Phazonmutant Phazonmutant is offline
Winrar
AKA: Greg Mitchell
FRC #2556 (RadioActive Roaches)
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2008
Location: Niceville, FL
Posts: 17
Phazonmutant is on a distinguished road
Re: Understanding the Source code

Agreed, C++ is...well, a bit low-level after working with C# for so long.
Quote:
I can still cause the program to quit!
so no exceptions
Yeah, that's what I'm worried about. I haven't thrown any exceptions yet, but it seems stupid, hence my original comment:
Quote:
From the FRC C++ guide, the WPI library doesn't use C++'s exception handling system (for the rather odd reason that an uncaught exception might be thrown - which might happen anyway if there's no push to use exception handling)
How have you been using the preprocessor to handle defines? It's more conventional (from the C++ standpoint) to use the "const" keyword.
Reply With Quote
  #12   Spotlight this post!  
Unread 06-02-2009, 18:01
byteit101's Avatar
byteit101 byteit101 is offline
WPILib maintainer (WPI)
AKA: Patrick Plenefisch
no team (The Cat Attack (Formerly))
Team Role: Programmer
 
Join Date: Jan 2009
Rookie Year: 2009
Location: Worcester
Posts: 699
byteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of lightbyteit101 is a glorious beacon of light
Re: Understanding the Source code

Quote:
How have you been using the preprocessor to handle defines? It's more conventional (from the C++ standpoint) to use the "const" keyword.
i use enum { Var1, Var2}; and const float speed=1; but just at the top or near the top #define VAR_NAME 1(Optional value)
also
Quote:
#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
a file may be included more than once (weird, i know, but that is the way the C++ compiler works) so the compiler sees:
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;
  }
}
Got it? (I like medium level languages that are safer like C# or (ick!)VB!)
__________________
Bubble Wrap: programmers rewards
Watchdog.Kill();
printf("Watchdog is Dead, Celebrate!");
How to make a self aware robot: while (∞) cout<<(sqrt(-∞)/-0);
Previously FRC 451 (The Cat Attack)
Now part of the class of 2016 at WPI & helping on WPILib
Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
need help understanding c code in robotdrive mahmosh C/C++ 14 16-01-2009 08:56
i downloaded the source code, now what do i do? programmr Programming 2 12-12-2008 14:39
Source code for the Easy C Pro library functions? bobpskier Programming 3 05-02-2007 21:39
[FVG]: Source Code SilverStar FIRST-related Organizations 5 24-08-2004 14:28
Patent source code? Kyle Fenton Chit-Chat 3 20-10-2001 17:53


All times are GMT -5. The time now is 02:57.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi