00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: P_SensorConfig.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.41 $ $Date: 2019年01月17日 21:21:01 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * This is Paul's new Tracker code -- pgrayson@ks.uiuc.edu 00019 ***************************************************************************/ 00020 00021 #include <stdio.h> 00022 #include <stdlib.h> 00023 #include "P_SensorConfig.h" 00024 #include "Inform.h" 00025 #include "utilities.h" 00026 00027 00028 // This function goes through all the vmdsensors files, opens them and calls 00029 // a functio defined by "behavior" for each one, and then closes the files. 00030 // It passes along the pointer "params" to the called function. 00031 // This mechanism is a bit clumsy, but it best accomodated the re-use of 00032 // the previous code. 00033 enum Scanning_Behaviors { PARSE_FOR_NAMES, PARSE_FOR_DEVICE }; 00034 00035 void SensorConfig::ScanSensorFiles (int behavior, SensorConfig *sensor, void* params) { 00036 JString sensorfile; 00037 FILE *file; 00038 int found_sensorfile=FALSE; //keeps track of whether we found a sensor file 00039 00040 #if !defined(_MSC_VER) 00041 // First try looking for a .vmdsensors file in the user's 00042 // UNIX home directory 00043 sensorfile = getenv("HOME"); 00044 sensorfile += "/.vmdsensors"; 00045 if ( (file = fopen(sensorfile,"r")) ) { 00046 found_sensorfile=TRUE; 00047 switch (behavior) { 00048 case PARSE_FOR_DEVICE: 00049 sensor->parseconfigfordevice(file, params); 00050 break; 00051 case PARSE_FOR_NAMES: 00052 parseconfigfornames(file, params); 00053 break; 00054 } 00055 fclose(file); 00056 } 00057 #endif 00058 00059 // Then, try path pointed to by the VMDSENSORS env. variable 00060 if (!found_sensorfile) { 00061 char *sensorfile_str = getenv("VMDSENSORS"); 00062 if (sensorfile_str && (file = fopen(sensorfile_str,"r"))) { 00063 found_sensorfile=TRUE; 00064 switch (behavior) { 00065 case PARSE_FOR_DEVICE: 00066 sensor->parseconfigfordevice(file, params); 00067 break; 00068 case PARSE_FOR_NAMES: 00069 parseconfigfornames(file, params); 00070 break; 00071 } 00072 fclose(file); 00073 } 00074 } 00075 00076 // If we couldn't find a file in the home dir or VMDSENSORS env. variable 00077 // then try finding one in the VMD installation area. 00078 if (!found_sensorfile) { 00079 sensorfile = getenv("VMDDIR"); 00080 #if defined(_MSC_VER) 00081 sensorfile += "\\.vmdsensors"; 00082 #else 00083 sensorfile += "/.vmdsensors"; 00084 #endif 00085 if ((file = fopen(sensorfile,"r"))) { 00086 switch (behavior) { 00087 case PARSE_FOR_DEVICE: 00088 sensor->parseconfigfordevice(file, params); 00089 break; 00090 case PARSE_FOR_NAMES: 00091 parseconfigfornames(file, params); 00092 break; 00093 } 00094 fclose(file); 00095 } 00096 } 00097 00098 } 00099 00100 00101 static int splitline(FILE *f, JString *argv, int maxarg) { 00102 int argc, pos; 00103 char buf[128], word[128]; 00104 memset(buf, 0, sizeof(buf)); 00105 memset(word, 0, sizeof(word)); 00106 00107 if(!fgets(buf, sizeof(buf), f)) return -1; 00108 00109 argc = 0; 00110 pos = 0; 00111 while (argc<maxarg && pos<100 && buf[pos]!=0 && buf[pos]!='\n' 00112 && buf[pos]!='\r') { 00113 00114 if (buf[pos]!=' ' && buf[pos]!='\t') { 00115 sscanf(buf+pos, "%99s", word); 00116 pos += strlen(word); 00117 argv[argc] = (JString)word; 00118 argc++; 00119 } else { 00120 pos++; 00121 } 00122 } 00123 00124 return argc; 00125 } 00126 00127 00128 static int need_args(int argc,int need, int line) { 00129 if (need!=argc) { 00130 msgErr << "SensorConfig: Wrong number of arguments at line " << line << "." << sendmsg; 00131 msgErr << "Expected " << need << ", got " << argc << "." << sendmsg; 00132 return 1; 00133 } 00134 return 0; 00135 } 00136 00137 float SensorConfig::getfloat(const char *from, float defalt) { 00138 int ret; 00139 float f; 00140 ret=sscanf(from,"%f",&f); 00141 if(!ret) { 00142 msgErr << "SensorConfig: Error parsing float at line " << line << sendmsg; 00143 return defalt; 00144 } 00145 return f; 00146 } 00147 00148 int SensorConfig::needargs(int argc,int need) { 00149 return need_args(argc,need,line); 00150 } 00151 00152 00153 void SensorConfig::parseconfigfordevice(FILE *file, void *) { 00154 // now we have an open configuration file, search for device lines 00155 int found=FALSE, argc; 00156 line = 0; 00157 JString argv[20]; 00158 while ((argc=splitline(file, argv, 20))>=0) { 00159 line++; 00160 00161 if (!argc) continue; 00162 if (argv[0][0]=='#') continue; // this line is a comment 00163 00164 if (!compare(argv[0],"device")) { // found a device 00165 if (found) break; // done reading info about our device 00166 if (needargs(argc,3)) return; 00167 if (!compare(argv[1],device)) { // found our device 00168 // Comment out chatty options for now, until we can reduce the number 00169 // of times we have to read the .vmdsensors file. 00170 // msgInfo << "Found device '" << argv[1] << "'" << " on line " << line << "." << sendmsg; 00171 found = TRUE; 00172 USL = argv[2]; 00173 continue; // we start parsing the options on the next line 00174 } 00175 } 00176 00177 if (!found) continue; 00178 00179 // Comment out chatty options for now, until we can reduce the number 00180 // of times we have to read the .vmdsensors file. 00181 // msgInfo << "Reading option '" << argv[0] << "'" << sendmsg; 00182 00183 if (!compare(argv[0],"scale")) { 00184 if (needargs(argc,2)) return; 00185 scale = getfloat(argv[1],1); 00186 } 00187 else if (!compare(argv[0],"maxforce")) { 00188 // XXX Maxforce doesn't seem to work at the moment, causing dangerously 00189 // high forces to be sent to the haptic device. Disabling for now until 00190 // the reason is discovered. 00191 #if 0 00192 if (needargs(argc,2)) return; 00193 maxforce = getfloat(argv[1],1); 00194 #else 00195 msgInfo << "Sorry, maxforce parameter not currently implemented." 00196 << sendmsg; 00197 #endif 00198 } 00199 else if (!compare(argv[0],"offset")) { 00200 int i; 00201 if (needargs(argc,4)) return; 00202 for (i=0;i<3;i++) 00203 offset[i] = getfloat(argv[1+i],0); 00204 } 00205 else if (!compare(argv[0],"rot")) { 00206 int i; 00207 if (needargs(argc,11)) return; 00208 if (!compare(argv[1],"right")) 00209 for (i=0;i<9;i++) 00210 right_rot.mat[i+i/3] = getfloat(argv[2+i],right_rot.mat[i+i/3]); 00211 else 00212 for (i=0;i<9;i++) 00213 left_rot.mat[i+i/3] = getfloat(argv[2+i],right_rot.mat[i+i/3]); 00214 } 00215 else msgErr << "Error: Unrecognized tool option on line " << line << sendmsg; 00216 } 00217 00218 if (USL=="") msgErr << "Device " << device << " not found." << sendmsg; 00219 else parseUSL(); 00220 } 00221 00222 00223 SensorConfig::SensorConfig(const char *thedevice) { 00224 00225 if (thedevice==NULL) return; 00226 00227 USL = ""; 00228 strcpy(nums,""); 00229 strcpy(name,""); 00230 strcpy(place,""); 00231 strcpy(type,""); 00232 strcpy(device,thedevice); 00233 offset[0] = offset[1] = offset[2] = 0; 00234 scale = 1; 00235 maxforce = -1; // default is to not enforce a maximum 00236 right_rot.identity(); 00237 left_rot.identity(); 00238 00239 ScanSensorFiles(PARSE_FOR_DEVICE, this, NULL); 00240 } 00241 00242 00243 int SensorConfig::parseUSL() { 00244 int ret; 00245 strcpy(nums,"0"); // fill in default of zero 00246 00247 ret = sscanf(USL,"%20[^:]://%100[^/]/%100[^:]:%101s", 00248 type, place, name, nums); 00249 00250 if(ret<3) { 00251 msgErr << "USL on line " << line << " is not of the form: " 00252 << "type://place/name[:num,num,...]" << sendmsg; 00253 return 0; // if we get anything less than blah://blah/blah 00254 } 00255 00256 read_sensor_nums(); 00257 00258 return 1; 00259 } 00260 00261 void SensorConfig::read_sensor_nums() { 00262 char *s=strdup(nums); 00263 char *r=s; 00264 00265 for (int cur=0; cur<= 200; cur++) { 00266 if(s[cur]==',' || s[cur]==0) { 00267 int tmp = 0; 00268 sscanf(r,"%d",&tmp); 00269 sensors.append(tmp); 00270 r = s + cur + 1; 00271 if(s[cur]==0) break; 00272 s[cur]=0; 00273 } 00274 } 00275 00276 free(s); 00277 } 00278 00279 00280 // Used as a callback in SensorConfig::getnames() 00281 void SensorConfig::parseconfigfornames(FILE *f, void *ret_void) { 00282 int argc, line=0; 00283 JString argv[20]; 00284 00285 while ((argc=splitline(f, argv, 20))>=0) { 00286 line++; 00287 00288 if(!argc) continue; 00289 if(argv[0][0]=='#') continue; // this line is a comment 00290 00291 if(!compare(argv[0],"device")) { // found a device 00292 if(need_args(argc,3,line)) continue; 00293 JString *newname = new JString(argv[1]); 00294 ((ResizeArray<JString *>*) ret_void)->append(newname); 00295 } 00296 } 00297 } 00298 00299 00300 ResizeArray<JString *> *SensorConfig::getnames() { 00301 ResizeArray<JString *> *ret = new ResizeArray<JString *>; 00302 00303 ScanSensorFiles(PARSE_FOR_NAMES, NULL, (void*)ret); 00304 return ret; 00305 } 00306 00307 00308 const char *SensorConfig::getUSL() const { 00309 return USL; 00310 } 00311 00312 float SensorConfig::getscale() const { 00313 return scale; 00314 } 00315 00316 float SensorConfig::getmaxforce() const { 00317 return maxforce; 00318 } 00319 00320 const float *SensorConfig::getoffset() const { 00321 return offset; 00322 } 00323 00324 const Matrix4 *SensorConfig::getright_rot() const { 00325 return &right_rot; 00326 } 00327 00328 const Matrix4 *SensorConfig::getleft_rot() const { 00329 return &left_rot; 00330 } 00331 00332 const char *SensorConfig::getdevice() const { return device; } 00333 const char *SensorConfig::gettype() const { return type; } 00334 const char *SensorConfig::getplace() const { return place; } 00335 const char *SensorConfig::getname() const { return name; } 00336 const char *SensorConfig::getnums() const { return nums; } 00337 const ResizeArray<int> *SensorConfig::getsensors() const { return &sensors; } 00338 00339 SensorConfig::~SensorConfig() { 00340 } 00341 00342 int SensorConfig::have_one_sensor() const { 00343 if (sensors.num() != 1) { 00344 msgErr << "Please specify exactly one sensor." << sendmsg; 00345 return 0; 00346 } 00347 return 1; 00348 } 00349 00350 void SensorConfig::make_vrpn_address(char *buf) const { 00351 // As of VRPN 7.15 enforcing TCP-only connections is supported 00352 // by appending @tcp to the device name and using an USL in 00353 // format Device@tcp://machine:port instead of Device@machine:port. 00354 // Create a new style USL when the name contains @tcp. 00355 if (strstr(name,"@tcp")) 00356 sprintf(buf, "%s://%s", name, place); 00357 else 00358 sprintf(buf, "%s@%s", name, place); 00359 } 00360 00361 int SensorConfig::require_local() const { 00362 if(strcmp(place,"local")) { 00363 msgErr << "Sorry, this local device requires place name \"local\"." 00364 << sendmsg; 00365 return 0; 00366 } 00367 return 1; 00368 } 00369 00370 int SensorConfig::require_cave_name() const { 00371 if(!require_local()) return 0; 00372 if(strcmp(name,"cave")) { 00373 msgErr << "Sorry, the device name for the CAVE is \"cave\"." << sendmsg; 00374 return 0; 00375 } 00376 return 1; 00377 } 00378 00379 int SensorConfig::require_freevr_name() const { 00380 if(!require_local()) return 0; 00381 if(strcmp(name,"freevr")) { 00382 msgErr << "Sorry, the device name for FreeVR is \"freevr\"." << sendmsg; 00383 return 0; 00384 } 00385 return 1; 00386 } 00387