00001 
00002 #ifndef INCLUDED_Config_h
00003 #define INCLUDED_Config_h
00004 
00005 #include "Shared/plist.h"
00006 #include "Shared/string_util.h"
00007 #include "Shared/RobotInfo.h"
00008 extern "C" {
00009 #include <jpeglib.h>
00010 }
00011 #ifdef PLATFORM_APERIOS
00012 #  include <OPENR/OPrimitiveControl.h>
00013 #else
00014 typedef unsigned int OSpeakerVolume; 
00015 const OSpeakerVolume ospkvolinfdB = 0x8000; 
00016 const OSpeakerVolume ospkvol25dB  = 0xe700; 
00017 const OSpeakerVolume ospkvol18dB  = 0xee00; 
00018 const OSpeakerVolume ospkvol10dB  = 0xf600; 
00019 #endif
00020 #include <vector>
00021 #include <string>
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 class ConfigDictionary : public plist::Dictionary {
00037 public:
00038   ConfigDictionary() : plist::Dictionary(false)
00039   {
00040     if(curModel.size()==0)
00041       curModel=RobotName;
00042   }
00043   
00044 protected:
00045   
00046   virtual bool loadXMLNode(const std::string& key, xmlNode* val, const std::string& comment);
00047   virtual bool saveOverXMLNode(xmlNode* k, xmlNode* val, const std::string& key, std::string comment, const std::string& indentStr, std::set<std::string>& seen) const;
00048 
00049 
00050   static bool matchNoCase(const std::string& model, const std::string& pattern);
00051   
00052   static const std::string msPrefix; 
00053   static const std::string msSep; 
00054   
00055   static std::string curModel; 
00056   static void initCurModel(); 
00057 };
00058 
00059 
00060 
00061 
00062 
00063 template<typename T>
00064 class OutputConfig : public ConfigDictionary {
00065 public:
00066 
00067   OutputConfig(unsigned int firstOffset, unsigned int numOutputsToStore, const T& defValue)
00068   : ConfigDictionary(), offset(firstOffset), outputs(numOutputsToStore,defValue)
00069   {
00070     for(unsigned int i=0; i<numOutputsToStore; ++i)
00071       addEntry(outputNames[i+firstOffset],outputs[i]);
00072   }
00073 
00074   virtual ObjectBase& getEntry(const std::string& name) {
00075     std::string::size_type n = name.find_last_not_of('~')+1;
00076     return ConfigDictionary::getEntry((n==name.size()) ? name : name.substr(0,n));
00077   }
00078 
00079   T& getEntry(size_t index) { return outputs[index]; }
00080 
00081   T& operator[](size_t index) { return outputs[index]; }
00082   using ConfigDictionary::operator[];
00083   
00084 
00085   void saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const;
00086   using ConfigDictionary::saveXML;
00087   
00088 protected:
00089 
00090   bool loadXMLNode(const std::string& key, xmlNode* val, const std::string& comment) {
00091     std::string::size_type n = key.find_last_not_of('~')+1;
00092     return ConfigDictionary::loadXMLNode((n==key.size()) ? key : key.substr(0,n), val, comment);
00093   }
00094   
00095   unsigned int offset; 
00096   std::vector<T> outputs; 
00097 };
00098 
00099 
00100 class Config : public ConfigDictionary {
00101 public:
00102   Config(const std::string& filename="") : ConfigDictionary(),
00103     behaviors(), wireless(), main(), controller(), vision(), motion(this), sound(this), fsRoot()
00104   {
00105     addEntry("wireless",wireless);
00106     addEntry("vision",vision);
00107     addEntry("main",main);
00108     addEntry("behaviors",behaviors);
00109     addEntry("controller",controller);
00110     addEntry("motion",motion);
00111     addEntry("sound",sound);
00112     if(filename.size()!=0)
00113       loadFile(filename.c_str());
00114   }
00115   
00116   enum transports { UDP, TCP }; 
00117   static const unsigned int NUM_TRANSPORTS=2; 
00118   static const char * transport_names[NUM_TRANSPORTS+1]; 
00119   
00120   void setFileSystemRoot(const std::string& fsr); 
00121   const std::string& getFileSystemRoot() const { return fsRoot; } 
00122   
00123 
00124   std::string portPath(const std::string& path) const;
00125   
00126 
00127   std::string makePath(const std::string& name) const { return searchPath(name,"config"); }
00128 
00129 
00130   std::string searchPath(const std::string& name, const std::string& root) const;
00131   
00132   
00133   
00134   
00135 
00136   
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145   class behaviors_config : public ConfigDictionary {
00146   public:
00147 
00148     behaviors_config() : ConfigDictionary(), flash_bytes(4), flash_on_start(true)
00149     {
00150       
00151       
00152       setUnusedWarning(false);
00153       
00154       addEntry("flash_bytes",flash_bytes,"how many bytes of the address to flash\n"
00155                "You probably already know the first 3 bytes for your network,\n"
00156                "so you might only want the last byte for brevity.\n"
00157                "(valid values are 1 through 4) ");
00158       addEntry("flash_on_start",flash_on_start,"whether or not to automatically trigger on boot\n"
00159                "Will use a priority of kEmergencyPriority+1 in order to override\n"
00160                "the emergency stop's status animation ");
00161     }
00162     plist::Primitive<unsigned int> flash_bytes; 
00163     plist::Primitive<bool> flash_on_start;      
00164   } behaviors;
00165 
00166   
00167   
00168   
00169 
00170   
00171   class wireless_config : public ConfigDictionary {
00172   public:
00173 
00174     wireless_config () : ConfigDictionary(), id(1) {
00175       addEntry("id",id,"id number (in case you have more than one AIBO)");
00176     }
00177     plist::Primitive<int> id; 
00178   } wireless;
00179   
00180   
00181   
00182   
00183 
00184   
00185   class main_config : public ConfigDictionary {
00186   public:
00187 
00188     main_config()
00189       : ConfigDictionary(), seed_rng(true), console_port(10001), consoleMode(CONTROLLER,consoleModeNames), stderr_port(10002),
00190       wsjoints_port(10031),wspids_port(10032),gamepadControl_port(10041),headControl_port(10052),armControl_port(10054),
00191       walkControl_port(10050),estopControl_port(10053),stewart_port(10055),aibo3d_port(10051),
00192       wmmonitor_port(10061), use_VT100(true), worldState_interval(0)
00193     {
00194       addEntry("seed_rng",seed_rng,"if true, will call srand with timestamp data, mangled by current sensor data");
00195       addEntry("console_port",console_port,"port to send/receive \"console\" information on (separate from system console)");
00196       addEntry("consoleMode",consoleMode,"determines how input on console_port is interpreted\n"+consoleMode.getDescription()+"\n"
00197                "  'controller' will pass it as input to the Controller (assumes same syntax as ControllerGUI)\n"
00198                "  'textmsg' will broadcast it as a TextMsgEvent (textmsgEGID)\n"
00199                "  'auto' is the original mode, which uses 'textmsg' if the ControllerGUI is connected, and 'controller' otherwise ");
00200       addEntry("stderr_port",stderr_port,"port to send error information to");
00201       addEntry("wsjoints_port",wsjoints_port,"port to send joint positions on");
00202       addEntry("wspids_port",wspids_port,"port to send pid info on");
00203       addEntry("gamepad", gamepadControl_port, "port to receive gamepad data\n");
00204       addEntry("headControl_port",headControl_port,"port for receiving head commands");
00205                         addEntry("armControl_port",armControl_port,"port for receiving arm commands");
00206       addEntry("walkControl_port",walkControl_port,"port for receiving walk commands");
00207       addEntry("estopControl_port",estopControl_port,"port for receiving walk commands");
00208       addEntry("stewart_port",stewart_port,"port for running a stewart platform style of control");
00209       addEntry("aibo3d_port",aibo3d_port,"port for send/receive of joint positions from Aibo 3D GUI");
00210       addEntry("wmmonitor_port",wmmonitor_port,"port for monitoring Watchable Memory");
00211       addEntry("use_VT100",use_VT100,"if true, enables VT100 console codes (currently only in Controller menus - 1.3)");
00212       addEntry("worldState_interval",worldState_interval,"time (in milliseconds) to wait between sending WorldState updates over wireless");
00213     }
00214     plist::Primitive<bool> seed_rng;     
00215     plist::Primitive<int> console_port;  
00216 
00217     enum consoleMode_t {
00218       CONTROLLER, 
00219       TEXTMSG, 
00220       AUTO 
00221     };
00222     static const unsigned int NUM_CONSOLE_MODES=3; 
00223     static const char* consoleModeNames[NUM_CONSOLE_MODES+1]; 
00224 
00225     plist::NamedEnumeration<consoleMode_t> consoleMode; 
00226     plist::Primitive<int> stderr_port;   
00227     plist::Primitive<int> wsjoints_port; 
00228     plist::Primitive<int> wspids_port;   
00229     plist::Primitive<int> gamepadControl_port; 
00230     plist::Primitive<int> headControl_port;    
00231                 plist::Primitive<int> armControl_port;     
00232     plist::Primitive<int> walkControl_port;    
00233     plist::Primitive<int> estopControl_port;     
00234     plist::Primitive<int> stewart_port;  
00235     plist::Primitive<int> aibo3d_port;   
00236     plist::Primitive<int> wmmonitor_port; 
00237     plist::Primitive<bool> use_VT100;    
00238     plist::Primitive<unsigned int> worldState_interval; 
00239   } main;
00240 
00241   
00242   
00243   
00244 
00245   
00246   class controller_config : public ConfigDictionary {
00247   public:
00248 
00249     controller_config() : ConfigDictionary(), gui_port(10020), select_snd(), next_snd(), prev_snd(), read_snd(), cancel_snd(), error_snd()
00250     {
00251       addEntry("gui_port",gui_port,"port to listen for the GUI to connect to aibo on");
00252       addEntry("select_snd",select_snd,"sound file to use for \"select\" action");
00253       addEntry("next_snd",next_snd,"sound file to use for \"next\" action");
00254       addEntry("prev_snd",prev_snd,"sound file to use for \"prev\" action");
00255       addEntry("read_snd",read_snd,"sound file to use for \"read from std-in\" action");
00256       addEntry("cancel_snd",cancel_snd,"sound file to use for \"cancel\" action");
00257       addEntry("error_snd",error_snd,"sound file to use to signal errors");
00258     }
00259   
00260     plist::Primitive<int> gui_port;        
00261     plist::Primitive<std::string> select_snd; 
00262     plist::Primitive<std::string> next_snd;   
00263     plist::Primitive<std::string> prev_snd;   
00264     plist::Primitive<std::string> read_snd;   
00265     plist::Primitive<std::string> cancel_snd; 
00266     plist::Primitive<std::string> error_snd; 
00267   } controller;
00268 
00269   
00270   
00271   
00272 
00273   
00274   class vision_config : public ConfigDictionary {
00275   public:
00276 
00277     vision_config() : ConfigDictionary(), 
00278           white_balance(WB_FLUORESCENT), gain(GAIN_MID), shutter_speed(SHUTTER_MID), resolution(1),
00279       thresh(), colors("config/default.col"), restore_image(true), region_calc_total(true),
00280       jpeg_dct_method(JDCT_IFAST,dct_method_names), aspectRatio(CameraResolutionX/(float)CameraResolutionY),
00281       x_range(), y_range(), x_focalLen(), y_focalLen(), 
00282           rawcam(), depthcam(), segcam(), regioncam(),
00283       aspectRatioListener(aspectRatio,*this,&vision_config::aspectRatioChanged)
00284     {
00285       white_balance.addNameForVal("indoor",WB_INDOOR);
00286       white_balance.addNameForVal("outdoor",WB_OUTDOOR);
00287       white_balance.addNameForVal("fluorescent",WB_FLUORESCENT);
00288       white_balance.addNameForVal("flourescent",WB_FLUORESCENT); 
00289       addEntry("white_balance",white_balance,"white balance shifts color spectrum in the image\n"+white_balance.getDescription());
00290       
00291       gain.addNameForVal("low",GAIN_LOW);
00292       gain.addNameForVal("mid",GAIN_MID);
00293       gain.addNameForVal("med",GAIN_MID);
00294       gain.addNameForVal("medium",GAIN_MID);
00295       gain.addNameForVal("high",GAIN_HIGH);
00296       addEntry("gain",gain,"Increasing gain will brighten the image, at the expense of more graininess/noise\n"+gain.getDescription());
00297       
00298       shutter_speed.addNameForVal("slow",SHUTTER_SLOW);
00299       shutter_speed.addNameForVal("low",SHUTTER_SLOW);
00300       shutter_speed.addNameForVal("mid",SHUTTER_MID);
00301       shutter_speed.addNameForVal("med",SHUTTER_MID);
00302       shutter_speed.addNameForVal("medium",SHUTTER_MID);
00303       shutter_speed.addNameForVal("fast",SHUTTER_FAST);
00304       shutter_speed.addNameForVal("high",SHUTTER_FAST);
00305       addEntry("shutter_speed",shutter_speed,"slower shutter will brighten image, but increases motion blur\n"+shutter_speed.getDescription());
00306       
00307       addEntry("resolution",resolution,"the resolution that object recognition system will run at.\nThis counts down from the maximum resolution layer, so higher numbers mean lower resolution. ");
00308       addEntry("thresh",thresh,"Threshold (.tm) files define the mapping from full color to indexed color.\n"
00309                "You can uncomment more than one of these - they will be loaded into separate\n"
00310                "channels of the segmenter.  The only cost of loading multiple threshold files is\n"
00311                "memory - the CPU cost of performing segmentation is only incurred if/when\n"
00312                "the channel is actually accessed for the first time for a given frame. ");
00313       addEntry("colors",colors,"The colors definition (.col) file gives names and a \"typical\" color for display.\n"
00314                "The indexes numbers it contains correspond to indexes in the .tm file\n"
00315                "This file is common to all .tm files; when doing new color segmentations,\n"
00316                "make sure you define colors in the same order as listed here! ");
00317       addEntry("restore_image",restore_image,"Apparently someone at Sony thought it would be a good idea to replace some\n"
00318                "pixels in each camera image with information like the frame number and CDT count.\n"
00319                "If non-zero, will replace those pixels with the actual image pixel value in RawCamGenerator ");
00320       addEntry("region_calc_total",region_calc_total,"When true, this will fill in the CMVision::color_class_state::total_area\n"
00321                "field for each color following region labeling.  If false, the total_area\n"
00322                "will stay 0 (or whatever the last value was), but you save a little CPU. ");
00323       addEntry("jpeg_dct_method",jpeg_dct_method,"pick between dct methods for jpeg compression\n"+jpeg_dct_method.getDescription());
00324       
00325       
00326 
00327 
00328 
00329 
00330       
00331       addEntry("rawcam",rawcam);
00332       addEntry("depthcam", depthcam);
00333       addEntry("segcam",segcam);
00334       addEntry("regioncam",regioncam);
00335     }
00336     
00337 #ifdef PLATFORM_APERIOS
00338 
00339     enum white_balance_levels {
00340       WB_INDOOR=ocamparamWB_INDOOR_MODE,
00341       WB_OUTDOOR=ocamparamWB_OUTDOOR_MODE,
00342       WB_FLUORESCENT=ocamparamWB_FL_MODE
00343     };
00344 #else
00345 
00346     enum white_balance_levels { WB_INDOOR=1, WB_OUTDOOR, WB_FLUORESCENT };
00347 #endif
00348     plist::NamedEnumeration<white_balance_levels> white_balance; 
00349     
00350 #ifdef PLATFORM_APERIOS
00351 
00352     enum gain_levels {
00353       GAIN_LOW=ocamparamGAIN_LOW,
00354       GAIN_MID=ocamparamGAIN_MID,
00355       GAIN_HIGH=ocamparamGAIN_HIGH
00356     };
00357 #else
00358 
00359     enum gain_levels { GAIN_LOW=1, GAIN_MID, GAIN_HIGH };
00360 #endif
00361     plist::NamedEnumeration<gain_levels> gain; 
00362 
00363 #ifdef PLATFORM_APERIOS
00364 
00365     enum shutter_speeds {
00366       SHUTTER_SLOW=ocamparamSHUTTER_SLOW,
00367       SHUTTER_MID=ocamparamSHUTTER_MID,
00368       SHUTTER_FAST=ocamparamSHUTTER_FAST
00369     };
00370 #else
00371 
00372     enum shutter_speeds { SHUTTER_SLOW=1, SHUTTER_MID, SHUTTER_FAST };
00373 #endif
00374     plist::NamedEnumeration<shutter_speeds> shutter_speed; 
00375     
00376     enum encoding_t {
00377       ENCODE_COLOR, 
00378       ENCODE_SINGLE_CHANNEL, 
00379       ENCODE_DEPTH,
00380     };
00381     static const unsigned int NUM_ENCODINGS=3; 
00382     static const char * encoding_names[NUM_ENCODINGS+1]; 
00383     
00384     plist::Primitive<int> resolution;       
00385     plist::ArrayOf<plist::Primitive<std::string> > thresh;      
00386     plist::Primitive<std::string> colors;      
00387     plist::Primitive<bool> restore_image;   
00388     plist::Primitive<bool> region_calc_total; 
00389     static const char * dct_method_names[]; 
00390     plist::NamedEnumeration<J_DCT_METHOD> jpeg_dct_method;  
00391     plist::Primitive<float> aspectRatio;    
00392     float x_range;        
00393     float y_range;        
00394     float x_focalLen; 
00395     float y_focalLen; 
00396     
00397 
00398     class StreamingConfig : public ConfigDictionary {
00399     public:
00400       explicit StreamingConfig(int portNum) : ConfigDictionary(), port(portNum), transport(Config::UDP,transport_names), interval(0)
00401       {
00402         addEntry("port",port,"the port number to open for sending data over");
00403         addEntry("transport",transport,"the IP protocol to use when sending data");
00404         addEntry("interval",interval,"minimum amount of time (in milliseconds) which must pass between frames\nE.g. 200 yields just under 5 frames per second, 0 is as fast as possible");
00405       }
00406       plist::Primitive<unsigned short> port;
00407       plist::NamedEnumeration<Config::transports> transport;
00408       plist::Primitive<unsigned int> interval;
00409     };
00410     
00411 
00412     class RawCamConfig : public StreamingConfig {
00413     public:
00414       RawCamConfig() : StreamingConfig(10011),
00415         encoding(ENCODE_COLOR,encoding_names), channel(0), compression(COMPRESS_JPEG,compression_names), compress_quality(85), y_skip(2), uv_skip(3)
00416       {
00417         addEntry("encoding",encoding,"holds whether to send color or single channel\n"+encoding.getDescription());
00418         addEntry("channel",channel,"if encoding is single channel, this indicates the channel to send");
00419         addEntry("compression",compression,"the type of compression to apply the image\n"+compression.getDescription());
00420         addEntry("compress_quality",compress_quality,"0-100, compression quality (currently only used by jpeg)");
00421         addEntry("y_skip",y_skip,"resolution level to transmit y channel\nAlso used as the resolution level when in single-channel encoding mode ");
00422         addEntry("uv_skip",uv_skip,"resolution level to transmit uv channel at when using 'color' encoding mode");
00423       }
00424 
00425       
00426       plist::NamedEnumeration<Config::vision_config::encoding_t> encoding; 
00427       plist::Primitive<int> channel;    
00428 
00429 
00430       enum compression_t {
00431         COMPRESS_NONE, 
00432         COMPRESS_JPEG, 
00433         COMPRESS_PNG, 
00434       };
00435       static const unsigned int NUM_COMPRESSIONS=4; 
00436       static const char * compression_names[NUM_COMPRESSIONS+1]; 
00437       plist::NamedEnumeration<compression_t> compression;
00438 
00439       plist::Primitive<unsigned int> compress_quality;
00440       plist::Primitive<unsigned int> y_skip;     
00441       plist::Primitive<unsigned int> uv_skip;    
00442     } rawcam;
00443 
00444     class DepthCamConfig : public StreamingConfig {
00445     public:
00446       DepthCamConfig() : StreamingConfig(10014), compression(COMPRESS_JPEG, compression_names), compress_quality(85), y0_skip(2), y1_skip(2)
00447       {
00448         transport = Config::TCP;
00449         addEntry("compression",compression,"what compression to use on the segmented image"+compression.getDescription());
00450         addEntry("compress_quality",compress_quality,"0-100, compression quality (currently only used by jpeg)");
00451         addEntry("y0_skip",y0_skip,"resolution level to transmit y channel\nAlso used as the resolution level when in single-channel encoding mode ");
00452         addEntry("y1_skip",y1_skip,"resolution level to transmit uv channel at when using 'color' encoding mode");
00453       }
00454 
00455       enum compression_t {
00456         COMPRESS_NONE, 
00457         COMPRESS_JPEG, 
00458         COMPRESS_PNG   
00459       };
00460       static const unsigned int NUM_COMPRESSIONS=4; 
00461       static const char * compression_names[NUM_COMPRESSIONS+1]; 
00462       plist::NamedEnumeration<compression_t> compression;
00463       plist::Primitive<unsigned int> compress_quality;
00464       plist::Primitive<unsigned int> y0_skip;     
00465       plist::Primitive<unsigned int> y1_skip; 
00466     } depthcam;
00467     
00468 
00469     class SegCamConfig : public StreamingConfig {
00470     public:
00471       SegCamConfig() : StreamingConfig(10012), skip(1), channel(0), compression(COMPRESS_RLE, compression_names)
00472       {
00473         addEntry("skip",skip,"resolution level to transmit segmented images at");
00474         addEntry("channel",channel,"channel of RLEGenerator to send (i.e. which threshold map to use");
00475         addEntry("compression",compression,"what compression to use on the segmented image"+compression.getDescription());
00476       }
00477       plist::Primitive<unsigned int> skip;       
00478       plist::Primitive<unsigned int> channel;    
00479       
00480 
00481       enum compression_t {
00482         COMPRESS_NONE, 
00483         COMPRESS_RLE   
00484       };
00485       static const unsigned int NUM_COMPRESSIONS=4; 
00486       static const char * compression_names[NUM_COMPRESSIONS+1]; 
00487       plist::NamedEnumeration<compression_t> compression;
00488     } segcam;
00489     
00490 
00491     class RegionCamConfig : public StreamingConfig {
00492     public:
00493       RegionCamConfig() : StreamingConfig(10013), skip(1) {
00494         addEntry("skip",skip,"resolution level to extract regions from");
00495       }
00496       plist::Primitive<unsigned int> skip; 
00497     } regioncam;
00498     
00499 
00500 
00501 
00502 
00503 
00504 
00505 
00506 
00507 
00508 
00509 
00510 
00511     void computeRay(float x, float y, float& r_x, float& r_y, float& r_z);
00512       
00513 
00514 
00515 
00516 
00517 
00518 
00519     void computePixel(float r_x, float r_y, float r_z, float& x, float& y);
00520 
00521     
00522 
00523 
00524 
00525 
00526 
00527 
00528     void computePixelCorrected(float r_x, float r_y, float r_z, float& x, float &y);
00529     
00530   protected:
00531     void aspectRatioChanged();
00532     plist::PrimitiveCallbackMember<vision_config> aspectRatioListener;
00533         
00534   } vision;
00535   
00536   
00537   
00538 
00539   class motion_config : public ConfigDictionary {
00540   public:
00541 
00542     motion_config(Config* c)
00543     : ConfigDictionary(), thisconfig(c), root("data/motion"), walk("walk.prm"), kinematics(std::string(RobotInfo::RobotName).append(".kin")),
00544         calibration_scale(PIDJointOffset, NumPIDJoints,1), calibration_offset(PIDJointOffset, NumPIDJoints, 0), 
00545         estop_on_snd(), estop_off_snd(), 
00546       max_head_tilt_speed(0), max_head_pan_speed(0), max_head_roll_speed(0), inf_walk_accel(false),
00547       console_port(10003), stderr_port(10004)
00548     {
00549       addEntry("root",root,"path on memory stick to \"motion\" files - for instance, position (.pos) and motion sequence (.mot)\n"
00550                "Any motion related paths which are not absolute (i.e. do not start with '/')\n"
00551                "will be assumed to be relative to this directory ");
00552       addEntry("walk",walk,"the walk parameter file to load by default for new WalkMC's");
00553       addEntry("kinematics",kinematics,"the ROBOOP format kinematics description file to load");
00554       addEntry("calibration_scale",calibration_scale,"Multiplier from desired position to command for each PID joint, applied after calibration_offset.");
00555       addEntry("calibration_offset",calibration_offset,"These values indicate the offset from user specified zero point to the\n"
00556                "physical system's zero point.  Added before calibration_scale when\n"
00557                "converting from user's desired position to command to send to hardware.");
00558       addEntry("estop_on_snd",estop_on_snd,"sound file to use when e-stop turned on");
00559       addEntry("estop_off_snd",estop_off_snd,"sound file to use when e-stop turned off");
00560       addEntry("max_head_tilt_speed",max_head_tilt_speed,"max speed for the head joints, used by HeadPointerMC; rad/s");
00561       addEntry("max_head_pan_speed",max_head_pan_speed,"max speed for the head joints, used by HeadPointerMC; rad/s");
00562       addEntry("max_head_roll_speed",max_head_roll_speed,"max speed for the head joints, used by HeadPointerMC; rad/s");
00563       addEntry("inf_walk_accel",inf_walk_accel,"if true, walks should attempt to switch directions immediately; otherwise they should do some kind of software acceleration to more smoothly switch direction");
00564       addEntry("console_port",console_port,"port to send/receive \"console\" information on (separate from system console)");
00565       addEntry("stderr_port",stderr_port,"port to send error information to");
00566     }
00567     
00568 
00569     std::string makePath(const std::string& name) { return thisconfig->searchPath(name, root); }
00570     
00571     Config* thisconfig;  
00572     plist::Primitive<std::string> root;       
00573     plist::Primitive<std::string> walk;       
00574     plist::Primitive<std::string> kinematics;  
00575     OutputConfig<plist::Primitive<float> > calibration_scale; 
00576     OutputConfig<plist::Primitive<float> > calibration_offset; 
00577     plist::Primitive<std::string> estop_on_snd;  
00578     plist::Primitive<std::string> estop_off_snd; 
00579     plist::Primitive<float> max_head_tilt_speed; 
00580     plist::Primitive<float> max_head_pan_speed; 
00581     plist::Primitive<float> max_head_roll_speed; 
00582     plist::Primitive<bool> inf_walk_accel; 
00583     plist::Primitive<int> console_port;  
00584     plist::Primitive<int> stderr_port;   
00585     
00586   private:
00587     motion_config(const motion_config&); 
00588     motion_config& operator=(const motion_config&); 
00589   } motion;
00590 
00591   
00592   
00593 
00594   class sound_config : public ConfigDictionary {
00595   public:
00596 
00597     sound_config(Config* c) : ConfigDictionary(), thisconfig(c), root("data/sound"), verbose(0), volume(HIGH), sample_rate(16000),
00598       sample_bits(16), preload(), pitchConfidenceThreshold(.6f), streaming()
00599     {
00600       addEntry("root",root,"path to sound clips");
00601       addEntry("verbose",verbose,"Controls diagnostic information on the console:\n  0 - none\n  1 - report when sounds begin to play\n  2 - also report when sounds finish playing\n  3- also report when sounds are preloaded and released");
00602       volume.addNameForVal("mute",MUTE);
00603       volume.addNameForVal("level_1",LOW);
00604       volume.addNameForVal("low",LOW);
00605       volume.addNameForVal("level_2",MID);
00606       volume.addNameForVal("mid",MID);
00607       volume.addNameForVal("level_3",HIGH);
00608       volume.addNameForVal("high",HIGH);
00609       volume.setStrict(false);
00610       addEntry("volume",volume,"volume in decibels - the value is interpreted as a signed short, where\n"
00611           "0x8000 is mute, 0xFFFF is full volume (low=0xE700, mid=0xEE00, high=0xF600)\n"
00612           "If you directly set the decibel level, be warned sony recommends against going above 0xF600\n"
00613           "However, I believe the commercial software on the ERS-7 runs at 0xFF00.\n"
00614           "Going above 0xF800 on a ERS-210 causes distortion (clipping) - full volume on a ERS-7 sounds fine though.\n"+volume.getDescription());
00615       addEntry("sample_rate",sample_rate,"sample rate to send to system, currently only 8000 or 16000 supported");
00616       addEntry("sample_bits",sample_bits,"sample bit depth, either 8 or 16");
00617       addEntry("preload",preload,"list of sounds to preload at boot");
00618       addEntry("pitchConfidenceThreshold",pitchConfidenceThreshold,"confidence threshold required to generate a pitch event [0-1]");
00619       addEntry("streaming",streaming);
00620     }
00621   
00622 
00623     std::string makePath(const std::string& name) { 
00624       if(name[0]=='/')
00625         return thisconfig->portPath(name);
00626       if(root[root.size()-1]=='/')
00627         return thisconfig->portPath(root+name);
00628       else
00629         return thisconfig->portPath(root+"/"+name);
00630     }
00631   
00632     Config* thisconfig;  
00633     plist::Primitive<std::string> root;         
00634     
00635 
00636 
00637 
00638 
00639 
00640     plist::Primitive<int> verbose;
00641     
00642 
00643 
00644     enum volume_levels { MUTE=ospkvolinfdB, LOW=ospkvol25dB, MID=ospkvol18dB, HIGH=ospkvol10dB };
00645     plist::NamedEnumeration<volume_levels> volume;      
00646     
00647     plist::Primitive<unsigned int> sample_rate; 
00648     plist::Primitive<unsigned int> sample_bits; 
00649     plist::ArrayOf<plist::Primitive<std::string> > preload; 
00650     plist::Primitive<float> pitchConfidenceThreshold; 
00651     
00652 
00653     class streaming_config : public ConfigDictionary {
00654     public:
00655 
00656       streaming_config() : ConfigDictionary(), mic_port(10070), mic_sample_rate(16000),
00657         mic_sample_bits(16), mic_stereo(true),
00658         speaker_port(10071), speaker_frame_length(64),
00659         speaker_max_delay(1000)
00660       {
00661         addEntry("mic_port",mic_port,"port for streaming microphone samples");
00662         addEntry("mic_sample_rate",mic_sample_rate,"sample rate from the microphone");
00663         addEntry("mic_sample_bits",mic_sample_bits,"sample bit depth from the microphone (either 8 or 16)");
00664         addEntry("mic_stereo",mic_stereo,"whether to stream stereo or mono from the microphone");
00665         
00666         addEntry("speaker_port",speaker_port,"port for streaming speaker samples");
00667         addEntry("speaker_frame_length",speaker_frame_length,"length of frame sent to the speaker (ms)");
00668         addEntry("speaker_max_delay",speaker_max_delay,"maximum delay (ms) during playback");
00669       }
00670       plist::Primitive<unsigned int> mic_port;        
00671       plist::Primitive<unsigned int> mic_sample_rate; 
00672       plist::Primitive<unsigned int> mic_sample_bits; 
00673       plist::Primitive<bool> mic_stereo; 
00674       
00675       plist::Primitive<unsigned int> speaker_port;    
00676       plist::Primitive<unsigned int> speaker_frame_length; 
00677       plist::Primitive<unsigned int> speaker_max_delay; 
00678     } streaming;
00679   private:
00680     sound_config(const sound_config&); 
00681     sound_config& operator=(const sound_config&); 
00682   } sound;
00683 
00684   
00685   
00686   virtual void saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const;
00687   using ConfigDictionary::saveXML;
00688   virtual unsigned int loadBuffer(const char buf[], unsigned int len, const char* filename=NULL);
00689   virtual unsigned int loadFile(const char* filename);
00690   virtual unsigned int loadFileStream(FILE* f, const char* filename=NULL);
00691   
00692 
00693 
00694   void* setValue(const std::string& section, std::string key, const std::string& value);
00695   
00696 protected:
00697   static const char * xmlIntro1;
00698   static const char * xmlIntro2;
00699   static const char * xmlIntro3;
00700   
00701   static const std::locale& curLocale;
00702   static char localeToLower(char c) { return std::tolower(c,curLocale); };
00703   
00704   unsigned int loadOldFormat(const char buf[], unsigned int len);
00705   unsigned int loadOldFormat(FILE* f);
00706   void parseLine(const char buf[], unsigned int lineno, std::vector<std::string>& modelStack, bool& ignoring, std::string& section);
00707   
00708 
00709 
00710   std::string fsRoot;
00711 };
00712 
00713 template<typename T>
00714 void OutputConfig<T>::saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const {
00715   
00716   ConfigDictionary::saveXML(node,true,seen);
00717   
00718   if(!onlyOverwrite && seen.size()!=dict.size()) {
00719     
00720     for(xmlNode* cur=xNodeGetLastChild(node); cur!=NULL && xNodeIsText(cur); cur=xNodeGetLastChild(node)) {
00721       xmlUnlinkNode(cur);
00722       xmlFreeNode(cur);
00723     }
00724     size_t longestKeyLen = getLongestKeyLen(NULL,1);
00725     std::string indentStr=getIndentationPrefix(node);
00726     
00727     for(unsigned int i=0; i<outputs.size(); ++i) {
00728       if(seen.find(outputNames[i+offset])==seen.end())
00729         saveXMLNode(node,outputNames[i+offset],&outputs[i],indentStr,longestKeyLen);
00730     }
00731     std::string parentIndent;
00732     if(indentStr.size()>=perIndent().size())
00733       parentIndent=indentStr.substr(perIndent().size());
00734     xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+parentIndent).c_str()));
00735   }
00736 }
00737 
00738 
00739 extern Config* config;
00740 
00741 
00742 
00743 
00744 
00745 
00746 
00747 #endif