HTML Documentation with Equation Numbers (Referencing an External PDF Document with Doxygen’s HTML Documentation)
Posted by cheshirekow in C++ Discoveries and Notes, Java Discoveries and Notes, Programming on April 17, 2010
So, anyone who uses Doxygen to document their code knows that it’s pretty much the most amazing thing ever. Seriously, it’s awesome. One cool thing about it is the ability to reference external documentation. For instance, if you use a library in your code and you want to include the library’s documentation with your own. However, let’s say that (hypothetically of course) you’re an academic… and the code you write implements some theoretical design or model. In that case, you may actually want your documentation to reference a paper, or a report that you’ve written. Perhaps, even many such papers or reports.
The Problem
In particular, let’s say that you’re a grad student, in the process of writing a paper (and of course, you used LaTex… because, well, why wouldn’t you?) and you go and write some code to simulate or demonstrate some elements of that paper. In that case, some of your functions may implement certain equations. Some of your classes (if it’s object oriented) may implement certain models. For an example, lets say this is your paper:
Let’s also assume that you’ve been good, and have been documenting your code with Doxygen. Let’s say you had some c++ class that implemented your model and it’s definition looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /** * file CTheoreticalModel.h * author Joe Author (jauthor@institute.edu) * date Apr 17, 2010 * brief Definition file for CTheoreticalModel class */ #ifndef CTHEORETICALMODEL_H_ #define CTHEORETICALMODEL_H_ /** * brief Theoretical Model derived in section 2, on page 1 * * This is a detailed description of the model */ class CTheoreticalModel { private: double m_alpha; ///< [parameter] defined in equation 2.1 double m_beta; ///< [parameter] defined in equation 2.2 public: /** * brief Construct a new model using the given parameters * param[in] alpha [parameter] defined in equation 2.1 * param[in] beta [parameter] defined in equation 2.2 */ CTheoreticalModel( double alpha, double beta ); /** * brief calculates [some property] by implementing algorithm 2.1 * on page 1 * return [some property] */ double algorithmA(); /** * brief updates the model by [some parameter] according to the * dynamics of equation 2.4 * param[in] gamma [parameter] defined in equation 2.3 */ void equationB( double gamma ); /** * brief tests [some parameter] against the model; implements * equation 2.6 * param[in] theta [some parameter] defined by equation 2.5 */ bool testC( double theta ); }; #endif /* CTHEORETICALMODEL_H_ */ |
Then the html documentation that doxygen will generate will look like this:
Now let’s say that you talk to your advisor and he suggests that maybe section 2 should come after section 3. Moreover, you add a bunch of content to section 1 so now all of the code for this model is on page five. So then you end up with this:
So now you have to go back and change all of the equation numbers and page references in your code. But wait, when we wrote our document we “label{}
“ed all of our equations, algorithms, and sections. Wouldn’t it be cool if we could just reference those in the comments? Doxygen exposes latex’s math mode for us to document inline equations. It uses latex to render the equations, and then uses dvipng to turn those into png images. Moreover, latex has the xr
package, which allows us to reference labels from other documents. Lastly, the “ref{}
” command is valid inside math-mode. So we have all the tools we need, but there is one slight problem. In order to use the xr
latex package, we need to include the “externaldocument
” command in the header of the document.
The solution
Now here’s the fun part. When Doxygen renders all of the equations, it does so by generating a single latex source file called “_formulas.tex
“. We don’t have explicit access to modify the preamble of that source file, but we are allowed to add optional packages to the list of what is included. We do that by modifying the “EXTRA_PACKAGES
” line of the doxyfile. For instance, if we edit the doxyfile like this:
1 2 3 4 5 6 | ... # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = amsmath xr amsfonts ... |
then when doxygen generates _formulas.tex
it will include in the preamble a list of includes like this
1 2 3 | usepackage{amsmath} usepackage{xr} usepackage{amsfonts} |
Note that Doxygen tokenizes the list of packages (parses it) at whitespace, and then takes each token and wraps it with “usepackage{EXTRA_PACKAGES
variable like this
1 2 3 | ... EXTRA_PACKAGES = amsmath xr}externaldocument[paper-]{dummy}% amsfonts ... |
Then the preamble of _formulas.tex
will look like this
1 2 3 4 | usepackage{amsmath} usepackage{amsfonts} usepackage{xr}externaldocument[paper-]{dummy}%} usepackage{hyperref} |
Note how we use a comment character (percent) to comment out the closing bracket that doxygen put’s around our ‘package’. Now we have an extra command in our preamble. If you haven’t looked up the xr
documentation yet, this command means to look for a file called “dummy.aux
” generated by latex. The package extracts all the labels from that file and appends “paper-
” to the front of the label names. Now we can change our code documentation to look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /** * file CTheoreticalModel.h * author Joe Author (jauthor@institute.edu) * date Apr 17, 2010 * brief Definition file for CTheoreticalModel class */ #ifndef CTHEORETICALMODEL_H_ #define CTHEORETICALMODEL_H_ /** * brief Theoretical Model derived in section f$ref{paper-sec:Model}f$, * page f$pageref{paper-sec:Model}f$ * * This is a detailed description of the model */ class CTheoreticalModel { private: double m_alpha; ///< [parameter] defined in equation f$ref{paper-eqn:alphaDef}f$ double m_beta; ///< [parameter] defined in equation f$ref{paper-eqn:betaDef}f$ public: /** * brief Construct a new model using the given parameters * param[in] alpha [parameter] defined in equation * f$ref{paper-eqn:alphaDef}f$ * param[in] beta [parameter] defined in equation * f$ref{paper-eqn:betaDef}f$ */ CTheoreticalModel( double alpha, double beta ); /** * brief calculates [some property] by implementing algorithm * f$ref{paper-alg:SomeAlgorithm}f$ on page * f$pageref{paper-alg:SomeAlgorithm}f$ * return [some property] */ double algorithmA(); /** * brief updates the model by [some parameter] according to the * dynamics of equation f$ref{paper-eqn:SomeEquation}f$ * on page f$pageref{paper-eqn:SomeEquation}f$ * param[in] gamma [parameter] defined in equation * f$ref{paper-eqn:gammaDef}f$ */ void equationB( double gamma ); /** * brief tests [some parameter] against the model; implements * condition f$ref{paper-eqn:SomeCondition}f$ * param[in] theta [some parameter] defined by equation * f$ref{paper-eqn:thetaDef}f$ */ bool testC( double theta ); }; #endif /* CTHEORETICALMODEL_H_ */ |
Now all we have to do is dump dummy.aux
(generated when we build the paper using latex) into the html
directory where doxygen is going to build _formulas.tex
and then when we make the documentation it looks like this:
Sure, all the references are images… which isn’t particularly great, but it’s a lot better than having to go in and change the labels every time we make a change to the referenced document. Whenever writing a code and a referenced document are done in parallel, this could be quite a handy trick. If you want the html document to look a little more professional, add a package that will set the font to the same as the font set by your doxygen CSS
stylesheet.
If you want to play around with the files used in this post, pick them up here: dummy.7z. Create the latex document with the following command.
1 | latex dummy.tex |
Then copy dummy.aux
into the html
directory.
1 | cp dummy.aux html/ |
Then run doxygen
1 | doxygen doxyfile |
TxDuino: Configuration Builder in WxWidgets
Posted by cheshirekow in TxDuino on October 31, 2009
In relation to the TxDuino (somewhat documented here), I wrote a C++ class to ease the interfacing with the device. That code was posted here. In this post, I am sharing a program that can be used to easily discover and save the configuration of the saturation points of the different actuators on a vehicle. The program is written using the wxWidgets toolkit so *should* be compatible with any wx-supported operating system. Of course, at this point in time I still haven’t updated the TxDuino class with linux implementations yet, but hopefully that will happen soon.
The saturation points are the raw commands that correspond to the extreme edges of the actuators range. For instance, if the actuator is a servo, then the minimum saturation point is the minimum command that the servo can actually achieve. If a command lower than that is sent, then the servo will constantly jitter as it cannot actually achieve that rotation. By setting the saturation points, normalized commands (percentages) can be sent to the device using the TxDuino::setPercent()
function.
A screenshot of the program in action is below:
You can connect to the device by entering the device name in the text field at the top and clicking “Connect” (or pressing enter). Once the device is connected (success or failure will be reported in the console at the bottom), then commands can start being sent. You can start sending commands by clicking “Continue” or stop at any time by clicking “Pause”. Note that “pausing” won’t stop your vehicle from doing something retarded, the vehicle’s actuators will just be stuck in the last commanded state. If the program is not paused, then every time you change one of the values in the spin controls, then that new value is sent as the current command.
To discover the value of the minimum saturation point of one of the actuators, start by clicking on the spin control for that channel, setting it to zero, and hitting enter (this makes the control think it has changed whether it has or not so the value is sent to that channel). If the actuator is saturated (on a servo, if it’s making noise and/or jittering but not correcting itself) then raise the value by one unit. Keep raising the value until the actuator is no longer saturated. Repeat for the max saturation point and the neutral point. The neutral point is the point corresponding to 0%. For a servo this is most likely near the center of it’s range. For a speed controller, it should be the same as the minimum saturation.
A windows binary of this program can be downloaded here: Tester .
The source can be downloaded here: TxDuino Actuator Configuration Tester.
TxDuino: C++ classes (windows)
Posted by cheshirekow in TxDuino on October 31, 2009
In order to make interfacing with the TxDuino as easy as possible, I wrote a little c++ class to take care of all the heavy lifting. You connect to a TxDuino device by creating a TxDuino
object. The constructor accepts a device name. In windows that looks like “\.COM8
” (my arduino is installed on COM port 8). In linux it’ll look something like “/dev/ttyS2
” except that I haven’t gotten around to implementing the linux part of this class yet.
The class, along with the supporting classes and test program are included here: TxDuino Class Source.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | /** * file TxDuino.h * date: Oct 27, 2009 * brief: * * detail: */ #ifndef CTXDUINO_H_ #define CTXDUINO_H_ #include <vector> #include <string> #include "types.h" namespace txduino { /** * brief operating system dependendant implementation structure */ struct STxDuinoImpl; /** * brief Class encapsulating the interface / API for communicating with one * TxDuino device. The TxDuino sends a standard RC PPM signal encoding * commands for up to 8 PWM channels (servos, engine controllers). * * The magnitude of each channel is divided into 250 discrete segments. * Exactly how those segments are interpreted by the actuators is determined * by the configuration of this object. * * note: channels are zero indexed * * todo add a constructor that accepts a csv file with the saturations and * neutral points that can be generated from the test program */ class CTxDuino { private: STxDuinoImpl* m_osInfo; /// pointer to os-dependant implementation std::string m_devName; /// system device name, /// i.e. "\.COM2", "/dev/tty2" u8 m_chan [9]; /// value for each channel [0,250] u8 m_neutral [8]; /// the "center" for each actuator u8 m_minsat [8]; /// the minimum value for each channel u8 m_maxsat [8]; /// the maximum value for each channel public: /** * brief Constructs a new TxDuino object serving as an interface * into on particular TxDuino device. * param strDevice device string, i.e. "\.COM2", "/dev/tty2" */ CTxDuino( std::string strDevice ); /** * brief cleans up OS resources reserved for this serial connection */ virtual ~CTxDuino(); /** * brief sends the current channel definitions to the device */ void send(); /** * brief sets the value of an actuator as a percent of it's viable * range. * param chan the channel to set * param percent -100% < percent < 100%; value to set channel to */ void setPercent( s32 chan, f64 percent ); /** * brief returns the percent value the indicated actuator is set to, * note: if the neutral point is equal to one of the saturation * points this value may be unreliable * param chan the channel to get * return percent value of actuator on indicated channel */ f64 getPercent( s32 chan ); /** * brief sets the raw value of the actuator pulse width * param chan the channel to set * param value 0 < value < 250; value to set channel to */ void setRaw( s32 chan, u8 value ); /** * brief returns the raw value the indicated actuator is set to * param chan the channel to get * return a value between 0 and 250 indicated the pulse length for * that actuator (multiply by 4us and add 700us to get the * actual pulse length) */ u8 getRaw( s32 chan ); /** * brief sets the raw value of the actuator pulse width corresponding * to a neutral state of that actuator * param chan the channel to set * param value 0 < value < 250; value to set channel to */ void setNeutral( s32 chan, u8 value ); /** * brief returns the raw value corresponding to a neutral state of * the indicated actuator * param chan the channel to get * return a value between 0 and 250 indicated the pulse length for * that actuator (multiply by 4us and add 700us to get the * actual pulse length) */ u8 getNeutral( s32 chan ); /** * brief sets the raw value of the actuator pulse width corresponding * to the minimum state of the indicated actuator * param chan the channel to set * param value 0 < value < 250; value to set channel to */ void setMinSat( s32 chan, u8 value ); /** * brief returns the raw value corresponding to a minimum state of * the indicated actuator * param chan the channel to get * return a value between 0 and 250 indicated the pulse length for * that actuator (multiply by 4us and add 700us to get the * actual pulse length) */ u8 getMinSat( s32 chan ); /** * brief sets the raw value of the actuator pulse width corresponding * to the maximum state of the indicated actuator * param chan the channel to set * param value 0 < value < 250; value to set channel to */ void setMaxSat( s32 chan, u8 value ); /** * brief returns the raw value corresponding to a maximum state of * the indicated actuator * param chan the channel to get * return a value between 0 and 250 indicated the pulse length for * that actuator (multiply by 4us and add 700us to get the * actual pulse length) */ u8 getMaxSat( s32 chan ); /** * brief return the device name that was used to connect to this * txduino */ std::string getName(); }; } #endif /* CTXDUINO_H_ */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | /** * file CTxDuino.cpp * date: Oct 27, 2009 * brief: * * detail: */ #include "CTxDuino.h" #include "compile.h" #include <iostream> #include <iomanip> #include <sstream> #include <cmath> #include "IllegalArgumentException.h" #include "IOException.h" #ifdef TXD_MINGW #include <windows.h> #endif namespace txduino { #ifdef TXD_MINGW struct STxDuinoImpl { HANDLE hComPort; /// handle to the opened COM device }; #endif #ifdef TXD_LINUX struct STxDuinoImpl { FILE hSerialFile; }; #endif /** * The initial state of the individual actuators is initialized as follows * * verbatim * minimum saturation: 0 * neutral: 125 * maximum saturation: 250 * value: 125 * endverbatim * * Note that this is probably not appropriate for your system. Many of the * servos that we've used have minimum saturations around 10 and maximum * saturations around 240. Use the actuator test program to determine what * these values should be. */ CTxDuino::CTxDuino( std::string strDevice ) { using std::cout; using std::endl; using std::stringstream; // intiialize all the arrays for( int i=0; i < 8; i++ ) { m_chan [i] = 125; m_minsat [i] = 0; m_maxsat [i] = 250; m_neutral [i] = 125; } // stop byte m_chan[8] = 0xFF; // initialize the OS dependant information m_osInfo = new STxDuinoImpl(); /* ---------------------------------------------------------------------------- * Windows Specific Implementation: * ---------------------------------------------------------------------------*/ #ifdef TXD_MINGW // open the file using the windows API m_osInfo->hComPort = CreateFile( strDevice.c_str(), // file name GENERIC_READ | GENERIC_WRITE, // access mode: read and write FILE_SHARE_READ|FILE_SHARE_WRITE, // (sharing) NULL, // (security) 0: none OPEN_EXISTING, // (creation) i.e. don't make it 0, // (overlapped operation) NULL); // no template file // check to make sure the file open succeeded if( m_osInfo->hComPort == INVALID_HANDLE_VALUE ) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid Device Name: " << strDevice; throw IllegalArgumentException(message.str()); } // get the current settings on the com port DCB dcb; GetCommState( m_osInfo->hComPort, &dcb ); // change the settings, the TxDuino uses a BAUD rate of 9600 dcb.fBinary = 1; dcb.BaudRate = CBR_9600; dcb.Parity = NOPARITY; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; // set the new settings for the port SetCommState( m_osInfo->hComPort, &dcb ); #endif } CTxDuino::~CTxDuino() { /* ---------------------------------------------------------------------------- * Windows Specific Implementation: * ---------------------------------------------------------------------------*/ #ifdef TXD_MINGW // close the device if it's open if( m_osInfo->hComPort != INVALID_HANDLE_VALUE ) CloseHandle( m_osInfo->hComPort ); #endif delete m_osInfo; } void CTxDuino::send() { using std::stringstream; // ensure that the last byte of the packet is the stop byte m_chan[8] = 0xFF; /* ---------------------------------------------------------------------------- * Windows Specific Implementation: * ---------------------------------------------------------------------------*/ #ifdef TXD_MINGW DWORD bytesWritten; BOOL retVal = WriteFile( m_osInfo->hComPort, // output handle m_chan, // buffer of bytes to send 9, // number of bytes to send from buffer &bytesWritten, // pointer to a word that receives number of // bytes written NULL); // pointer to an OVERLAPPED struct if( bytesWritten != 9 ) { stringstream message( stringstream::in | stringstream::out ); message << "Bytes written to device less than expected: " << bytesWritten << ", expecting 9"; throw IOException(message.str()); } if( retVal == 0 ) { stringstream message( stringstream::in | stringstream::out ); message << "Writing to device failed; error code: " << GetLastError(); throw IOException(message.str()); } #endif } /** * If the percent is positive, the raw value is calculated as follows * * verbatim * raw = neutral + (max - neutral) * percent * endverbatim * * if the percent is negative, the raw value is calculated as follows * * verbatim * raw = neutral - (neutral - min) * percent * endverbatim */ void CTxDuino::setPercent( s32 chan, f64 percent ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } if(percent > 0) { m_chan[chan] = (u8) (m_neutral[chan] + ( m_maxsat[chan] - m_neutral[chan]) * percent ); } else { m_chan[chan] = (u8) (m_neutral[chan] - ( m_minsat[chan] - m_neutral[chan]) * percent ); } } /** * If the value is strictly less than the neutral value then the percent value * is calculated by * * verbatim * percent = -( neutral - value ) / (neutral - min); * endverbatim * * If the value is strictly greater than the neutral value then the percent * value is calculated by * * verbatim * percent = ( value - neutral ) / (max - neutral); * endverbatim * * If the value is equal to the neutral value then the percent value is zero. */ f64 CTxDuino::getPercent( s32 chan ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } if( m_chan[chan] < m_neutral[chan] ) { return (double)(-(m_neutral[chan] - m_chan[chan])) / (m_neutral[chan] - m_minsat[chan]); } else if( m_chan[chan] > m_neutral[chan] ) { return (double)(m_chan[chan] - m_neutral[chan]) / (m_maxsat[chan] - m_neutral[chan]); } else { return 0.0; } } void CTxDuino::setRaw( s32 chan, u8 value ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } if(value > 250) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid value: " << value << HERE << "valid channels are 0-250"; } m_chan[chan] = value; } u8 CTxDuino::getRaw( s32 chan ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } return m_chan[chan]; } void CTxDuino::setNeutral( s32 chan, u8 value ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } if(value > 250) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid value: " << value << HERE << "valid channels are 0-250"; } m_neutral[chan] = value; } u8 CTxDuino::getNeutral( s32 chan ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } return m_neutral[chan]; } void CTxDuino::setMinSat( s32 chan, u8 value ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } if(value > 250) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid value: " << value << HERE << "valid channels are 0-250"; } m_minsat[chan] = value; } u8 CTxDuino::getMinSat( s32 chan ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } return m_minsat[chan]; } void CTxDuino::setMaxSat( s32 chan, u8 value ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } if(value > 250) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid value: " << value << HERE << "valid channels are 0-250"; } m_maxsat[chan] = value; } u8 CTxDuino::getMaxSat( s32 chan ) { using std::stringstream; if(chan < 0 || chan > 7) { stringstream message( stringstream::in | stringstream::out ); message << "Invalid channel number: " << chan << HERE << "valid channels are 0-7"; } return m_maxsat[chan]; } std::string CTxDuino::getName() { return m_devName; } } |
A re-write of the serialTest.exe
program that sends sinusoidal commands to the plane using this new class demonstrates its use.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /** * file serialTest.cpp * date: Oct 27, 2009 * brief: * * detail: * This is a simple test program that demonstrates how to connect to and * write commands to the arduino transmitter interface using windows. * * the TxDuino is an interface into the futaba FP-TP-FM transmitter module, * which accepts an RC PPM input. This signal contains a maximum of 8 * servo channels. */ #include <iostream> #include <iomanip> #include <cmath> #include "CTxDuino.h" #include "constants.h" using namespace std; using namespace txduino; int main( int argc, char** argv ) { // check to ensure that the command line included a device to open if( argc < 2 ) { cout << "Usage: serialTest.exe [Device Name]n" " where [Device Name] is the name of the COM port file onn " " windows (i.e. \\.\COM8), or the name of the serialn " " device on *nix (i.e. /dev/tty8)n" << endl; return -1; } // grab a pointer to the device to open char* strDevName = argv[1]; // create the txduino device CTxDuino tx(strDevName); // send a sinusoidal input on all channels (except for channel 3, which is // usually the throttle) for 10 seconds for(int i=0; i < 1000; i++) { for(int j=0; j < 8; j++) tx.setRaw(j, (unsigned char) (125.0 + 75.0 * sin( 2.0 * PI * i / 100.0 )) ); tx.setRaw(2, 0); for(int j=0; j < 8; j++) cout << setw(3) << (int)tx.getRaw(j) << " | "; cout << endl; tx.send(); #ifdef TXD_MIGNW Sleep(1); #endif #ifdef TXD_LINUX usleep(0.001); #endif } return 0; } |