Sign in to follow this  
n4gix

Hobbs Meter C Code

Recommended Posts

Does anyone have working code for a Hobbs Meter? I need to incorporate this in a project and cannot figure out the file I/O operations in C... :(I've read the relevant portion of Dai's latest Gauge Tutorial (v15), but cannot make it work, mainly because it's illustrating storing/reading ADF data from a file using a char type variable and then using "atoi" to convert from alpha to integer. It seems a bit ackward to do this way.I even searched this forum for information, and found a snippet of code from "badderjet" along with a reply from Arne, but unfortunately a "solution" was never posted... :(TIA to anyone who can help me! :)

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

Erm, dump question: how does a Hobbs Meter suppose to work? File I/O isnt't that hard, I offer my assistance.arne Bartels

Share this post


Link to post
Share on other sites

>Erm, dump question: how does a Hobbs Meter suppose to work?>File I/O isnt't that hard, I offer my assistance.>arne BartelsLOL!A "Hobbs Meter" is a simple counter that keeps track of the accumulated time on a machine. In the case of a/c, that would be "engine run time."As it happens, FS9 actually does keep track of "engine time" for every a/c installed, but since I want my a/c to work in FS2k2 at well, I don't want to go that route...I simply want a way to accumulate "engine hours" for eng1 and eng2, write to file "c2hobbs.dat" on exit.On loading a/c (i.e., "first run" section, the file is read in and the two bits of data are assigned to cumtime_eng1 and cumtime_eng2. Of course, some form of "error trapping" is needed in case the file is missing or accidentally deleted.This is what I've tried (w/o success):int FIRST_RUN=0;FILE *accum_time;char time_count=12345;MODULE_VAR PANEL_LIGHTSvar = {PANEL_LIGHTS};MODULE_VAR GENERAL_PANEL_CIRCUIT_ONvar = {GENERAL_PANEL_CIRCUIT_ON};MODULE_VAR TICK18var = {TICK18};MODULE_VAR MODULE_VAR_NONEvar = {MODULE_VAR_NONE};case PANEL_SERVICE_PRE_DRAW:if (FIRST_RUN==0) {FIRST_RUN=1;accum_time = fopen("c2hobbs.dat","w+") ;fprintf(time_count,"%d",accum_time) ; fclose(accum_time) ;return FALSE; }break;FLOAT64 FSAPI callback5( PELEMENT_STRING pelement){float rwert=pelement->source_var[0].var_value.n;rwert = (char)time_count ;sprintf(pelement->string,"%d",rwert);return 0;}The compiler returns this error:Error E2342 esdg_cit_II_oxygyroG.c 71: Type mismatch in parameter '__stream' (wanted 'FILE *', got 'int') in function gaugecallTIA!

Share this post


Link to post
Share on other sites

In fprintf first argument the FILE* then the other:fprintf(accum_time,"%d",time_count);BUT fprintf writes, it doesn't read. In principle I wouldn't use the FIRST_RUN statement.To read from the file at startup use case PANEL_SERVICE_CONNECT_TO_WINDOW:to write at stop use:case PANEL_SERVICE_DISCONNECT:e.g.:...char line[255]="";...case PANEL_SERVICE_CONNECT_TO_WINDOW: accum_time = fopen("c2hobbs.dat","r") ; fgets(line,sizeof(line),accum_time); time_count=atoi(line);//or : fscanf( accum_time, "%d", &time_count ); fclose(accum_time) ; break;case PANEL_SERVICE_DISCONNECT: accum_time = fopen("c2hobbs.dat","w") ; fprintf(accum_time,"%dn",time_count) ; fclose(accum_time) ; break;The fgets,atoi "trick" is just a hack, since I don't know to use the fscanf function properly. For integers fscanf( accum_time, "%d", &time_count ); should do the same job as fgets+atoi.If you want to use .ini style files check GetPrivateProfileString/WritePrivateProfileString .Arne Bartels

Share this post


Link to post
Share on other sites

Thanks Arne, I'll try this and see how it works... :)

Share this post


Link to post
Share on other sites

For the ini-File style I'm typing this from scratch (no tests yet):First you need the full path to your ini file:char pathname[MAX_PATH]="", *path_helper=NULL, line[255]=0;...//Get the filename of the calling module aka fs9.exe.GetModuleFileName(NULL,pathname,sizeof(pathname));//get the position of the last backslash in the pathname:path_helper=strrchr(pathname,'');//cut away the last backslash and the following filename:if(path_helper) *path_helper='0';//Adding the ini filenamesprintf(pathname,"%sinsert_ini_name.ini",pathname);//NOTE no check if the pathname is long enough...//writing:sprintf(line,"%d",time_count);WritePrivateProfileString("Insert_Section_Name","Insert_Key_Name",line,pathname);//reading:GetPrivateProfileString("Insert_Section_Name","Insert_Key_Name",line,sizeof(line),pathname);time_count=atoi(line);Arne Bartels

Share this post


Link to post
Share on other sites

Unfortunately, the following does not read the "c2hobbs.dat" file, and it saves only a 0 (zero) to the "c2hobbs.dat" file when the panel closes... This is set up for the MinGW compiler, so I've used GAUGE_HEADER_FS700 'cause that's what this set up is expecting... :)I've also tried the same code (with GAUGE_HEADER_FS800) in the BCC55 compiler, but my 'string formatting (size)' isn't correct there, undoubtedly due to syntax differences between the two compilers.In any case, does anyone know why this won't READ the "c2hobbs.dat" file?////////////////////////// Begin Code Fragment //////////////////////////////////////////////char esdg_cit_II_hobbs_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER esdg_cit_II_hobbs_list;PELEMENT_STATIC_IMAGE bg_element =NULL;extern MOUSERECT esdg_cit_II_hobbs_mouse_rect[];GAUGE_CALLBACK gaugecall;GAUGE_HEADER_FS700(GAUGE_W, esdg_cit_II_hobbs_gauge_name, &esdg_cit_II_hobbs_list, esdg_cit_II_hobbs_mouse_rect, gaugecall, 0, 0, 0);// Sound declarationstypedef VOID (*TGaugePlaySound)(LPTSTR, LPTSTR,int);typedef VOID (*TGaugeStopSound)(LPTSTR);typedef VOID (*TTerminateSounds)();TGaugePlaySound GaugePlaySound;TGaugeStopSound GaugeStopSound;TTerminateSounds TerminateSounds;HMODULE MGaugeSound;#define GAUGE_CHARSET2 DEFAULT_CHARSET#define GAUGE_FONT_DEFAULT2 "Arial"#define GAUGE_WEIGHT_DEFAULT2 FW_NORMALint FIRST_RUN=0;float time_count;MODULE_VAR TICK18var = {TICK18};char line[255]="";FILE *accum_time;void FSAPI gaugecall(PGAUGEHDR pgauge, int service_id, UINT32 extra_data){switch(service_id){case PANEL_SERVICE_PRE_INITIALIZE:if (MGaugeSound == NULL) {MGaugeSound = LoadLibrary("GaugeSound");}bg_element = (PELEMENT_STATIC_IMAGE)pgauge->elements_list[0];GaugePlaySound = (TGaugePlaySound)GetProcAddress(MGaugeSound,"GaugePlaySound");GaugeStopSound = (TGaugeStopSound)GetProcAddress(MGaugeSound,"GaugeStopSound");TerminateSounds = (TTerminateSounds)GetProcAddress(MGaugeSound,"TerminateSounds");break;case PANEL_SERVICE_PRE_KILL:MGaugeSound = GetModuleHandle("GaugeSound");if (MGaugeSound == NULL) {MGaugeSound = LoadLibrary("GaugeSound");}GaugePlaySound = (TGaugePlaySound)GetProcAddress(MGaugeSound,"GaugePlaySound");GaugeStopSound = (TGaugeStopSound)GetProcAddress(MGaugeSound,"GaugeStopSound");TerminateSounds = (TTerminateSounds)GetProcAddress(MGaugeSound,"TerminateSounds");(TerminateSounds)();FreeLibrary(MGaugeSound);break;case PANEL_SERVICE_PRE_UPDATE:MGaugeSound = GetModuleHandle("GaugeSound");if (MGaugeSound == NULL) {MGaugeSound = LoadLibrary("GaugeSound");}GaugePlaySound = (TGaugePlaySound)GetProcAddress(MGaugeSound,"GaugePlaySound");GaugeStopSound = (TGaugeStopSound)GetProcAddress(MGaugeSound,"GaugeStopSound");TerminateSounds = (TTerminateSounds)GetProcAddress(MGaugeSound,"TerminateSounds");lookup_var(&TICK18var);break;case PANEL_SERVICE_PRE_DRAW:if (FIRST_RUN==0) {FIRST_RUN=1;time_count = 123456 ; }break;case PANEL_SERVICE_PRE_INSTALL:break;case PANEL_SERVICE_CONNECT_TO_WINDOW: accum_time = fopen("c2hobbs.dat","r"); fscanf( accum_time, "%d", &time_count );// fgets(line,sizeof(line),accum_time); //* tried this variation also without success! *//// time_count=atoi(line); //* tried this variation also without success! *// fclose(accum_time) ;break;case PANEL_SERVICE_DISCONNECT: accum_time = fopen("c2hobbs.dat","w"); fprintf(accum_time,"%dn",time_count) ; fclose(accum_time) ;break;}}MOUSE_BEGIN(esdg_cit_II_hobbs_mouse_rect,0,0,0)MOUSE_ENDFAILURE_RECORD fail2[] = {{FAIL_NONE, FAIL_ACTION_NONE}};FAILURE_RECORD fail1[] = {{FAIL_NONE, FAIL_ACTION_NONE}};FLOAT64 FSAPI callback2( PELEMENT_STRING pelement){float rwert=pelement->source_var[0].var_value.n;rwert = (float)time_count + ( TICK18var.var_value.n / 18 ) / 1000 ; sprintf(pelement->string,"%07.1f",rwert);return 0;}MAKE_STRING(String2,NULL,fail2,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7,0,81,68,204,35,1000000,MODULE_VAR_NONE,MODULE_VAR_NONE,MODULE_VAR_NONE,RGB(255,255,255),RGB(0,0,0),RGB(0,0,0),GAUGE_FONT_DEFAULT2,GAUGE_WEIGHT_DEFAULT2,GAUGE_CHARSET2,0,0,NULL,callback2)PELEMENT_HEADER ElementList2[] = {&String2.header,NULL};MAKE_STATIC(Static1,Rec0,&ElementList2,fail1,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7,0,0,0)PELEMENT_HEADER esdg_cit_II_hobbs_list = &Static1.header;

Share this post


Link to post
Share on other sites

>Unfortunately, the following does not read the "c2hobbs.dat">file, and it saves only a 0 (zero) to the "c2hobbs.dat" file>when the panel closes... But why use a separate file? There exist already an hour counter config file under each aircraft, in the user config file area. All you have to do is read the data. Even keeps track of individual engines, if I recall correctly.And, in case of new discoveries: Anyone figured out if any xml parameters will read this? I know about missing file i/o, but maybe that was the task of this single parameter... Hopefully... In a perfect world :)

Share this post


Link to post
Share on other sites

"But why use a separate file? There exist already an hourcounter config file under each aircraft, in the user configfile area. All you have to do is read the data. Even keepstrack of individual engines, if I recall correctly."FS2002 doesn't.

Share this post


Link to post
Share on other sites

Karl, there are several reasons, the first of which - as Mike already mentioned - is "backwards compatibility." While we at ESDG have decided that we will no longer attempt to support Win98 or WinME, we will continue to develop products that will run in FS2k2 as much as possible...The second reason is that if I can get this one issue resolved, then I should be able to read/write any data to a file... :)

Share this post


Link to post
Share on other sites

I have seen some strange lines in your code. i.e. you are giving a value to rwert coming from source_var[0], but in your MAKE_STRING source_var[0] is MODULE_VAR_NONE (?)In this example :{float rwert=pelement->source_var[0].var_value.n;rwert = (float)time_count + ( TICK18var.var_value.n / 18 ) / 1000 ; Why do you give rwert the value from source_var[0], in the second line you are giving a total different value to rwert, so the first value was never used ?Try the following for your Hobbs Meter -----------//initialize variablesFLOAT64 tot_time=0;FILE *accum_time;CHAR time[10];FLOAT64 rwert=0;---------//in the gauge callback function :case PANEL_SERVICE_CONNECT_TO_WINDOW: if((acum_time=fopen("c2hobbs.dat","r"))!=NULL); //check if the file exists { fscanf( accum_time, "%s",time); tot_time=atof(time); } fclose(accum_time) ;break;case PANEL_SERVICE_DISCONNECT: accum_time =fopen("c2hobbs.dat","w"); fprintf(accum_time,"%7.1fn",rwert) ; fclose(accum_time) ;break;-------------------FLOAT64 FSAPI callback2( PELEMENT_STRING pelement){rwert=pelement->source_var[0].var_value.n;rwert+=tot_time;sprintf(pelement->string,"%07.1f",rwert); //the MAKE_STRING will print the total time of engine run timereturn 0;}//Have a look at source_var[0] in this make_stringMAKE_STRING(String2,NULL,fail2,IMAGE_USE_ERASE |IMAGE_USE_TRANSPARENCY |BIT7,0,81,68,204,35,1000000,ENGINE_WORKING_TIME,MODULE_VAR_NONE,MODULE_VAR_NONE,RGB(255,255,255),RGB(0,0,0),RGB(0,0,0),GAUGE_FONT_DEFAULT2,GAUGE_WEIGHT_DEFAULT2,GAUGE_CHARSET2,0,0,NULL,callback2)PELEMENT_HEADER ElementList2[] = {&String2.header,NULL};

Share this post


Link to post
Share on other sites

Thank you. I'll give this a try later tonight or early tomorrow morning.In this line though, did you actually mean "atof" or did you mean to type "atio?" tot_time=atof(time);

Share this post


Link to post
Share on other sites

Maybe I'm just dense as steel, but I cannot see the connection between ENGINE_WORKING_TIME (which is in seconds) and tot_time. How does tot_time get incremented? When I write tot_time back to file, how will the value have changed?I need to "accumulate" the total time for two engines, so eventually I'll have to expand this to read/write two values to file.

Share this post


Link to post
Share on other sites

atof means alfa to float. So you can convert a char into a decimal value. I have used atof because i noticed that rwert gives a decimal value.If you read my code, you will notice that rwert is the value written to the file and rwert is incremented by the value that was read from the file (at the loading of the gauge) by the line:rwert+=tot_time;I have never made a Hobbs Meter so I had no idea that ENGINE_WORKING_TIME gives seconds, but anyway 60 sec is 1 minute and 60 minutes is 1 hour. So adding a line to the code will convert the seconds into hours.I did not find a token variable giving the working time separately for each engine.

Share this post


Link to post
Share on other sites

>I did not find a token variable giving the working time>separately for each engine. Thanks for the note. It's a "day late and a dollar short" though, since I've already finished the gauge... with a lot of help from Christian and some diligent study of C prototypes and on-line manuals! :)In any case, what I wound up doing was using ELAPSED_SECONDS for the variable:FLOAT64 FSAPI callback2( PELEMENT_STRING pelement){float rwert=pelement->source_var[0].var_value.n;if ( TURB_ENGINE_1_CORRECTED_N1var.var_value.n > 10 ) { tot_time = tot_time + ( ELAPSED_SECONDSvar.var_value.n / 2000000 ) / 360 ; } else { tot_time = tot_time ; } rwert = (float)tot_time + eng1_time;sprintf(pelement->string,"%07.1f",rwert);return rwert;}Hobbs meters display total time in hours and 1/10th hours. To obtain this I divided ELAPSED_SECONDS by 2,000,000 to move the decimal point to a sensible place, then divided the result by 360 (1/10th hour interval, or 6 minutes), then added that to eng1_time (read from file), to provide rwert with a value to return to MAKE_STRING... :)For multiple engines it's only necessary to cut-n-paste the callback and MAKE_STRING as many times as needed and edit for each engine's variables.Note that time only accumulates IF the engine is actually running... :)However, since ELAPSED_SECONDS isn't affected by the sim rate, I may need to modify this scheme to take that into account! Otherwise, those who use "fast time" will have bogus Hobbs records... :)The really "pissy thing" though, is that the Hobbs time is already available via XML, but that would mean any gauge written would only work in FS9, which at this point in time isn't acceptable... There are too many folks still running FS2k2 and FS2k!Thanks again for all the 'hints.' :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this