Jump to content

Archived

This topic is now archived and is closed to further replies.

Recommended Posts

Guest VAPilot

After getting my airspeed gauge to work with help from this forum, Thanks, I thought I might try a ECAM, as that uses needles and strings, so I am trying to code an A380 upper ecam.The needle bit is easy after doing the airspeed gauge, but getting the string to show is proving more difficult. The code I have compiles, with 2 warnings but shows up in FS9. The needle bit works as it should do, but the string just shows up %3d. I have seen a few other post with this problem and tried some of the suggestion, but nothing seem to work, I still get 2 warnings when compiling and the string show %3d in FS9. HelpThe Warningsc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(26) : warning C4133: 'function' : incompatible types - from 'PCHAR' to 'LPWSTR'c:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(26) : warning C4133: 'function' : incompatible types - from 'char [4]' to 'LPCWSTR'The Code//A380 Upper ECAMchar upper_ecam_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER upper_ecam_list;extern MOUSERECT upper_ecam_mouse_rect[];GAUGE_HEADER_FS700 ( GAUGE_W, upper_ecam_gauge_name, &upper_ecam_list, upper_ecam_mouse_rect, NULL, 0, 0, 0 );FAILURE_RECORD upper_ecam_fail[] = { {FAIL_SYSTEM_ELECTRICAL_PANELS, FAIL_ACTION_ZERO}, {FAIL_NONE, FAIL_ACTION_NONE}};//Engine 1 N1#define GAUGE_MIN_ENGINE1N1 0#define GAUGE_MAX_ENGINE1N1 110//StringSTRING_UPDATE_CALLBACK engine1stringn1_cb;FLOAT64 FSAPI engine1stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; wsprintf (pelement->string,"%3d", (UINT32)val); return val;} MAKE_STRING( engine1_n1_string, NULL, NULL, IMAGE_USE_ERASE | bright, 0, 48,116, 48,20, 3, TURB_ENGINE_1_CORRECTED_N1, DISPLAY_UNITS, MODULE_VAR_NONE, RGB (191,121,82), RGB (0,0,0), RGB (191,121,82), GLASS, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER | DT_SINGLELINE, NULL, engine1stringn1_cb )PELEMENT_HEADER engine1_n1_string_plist[] = { (PELEMENT_HEADER) &engine1_n1_string.header, NULL};//NeedleNONLINEARITY engine1_n1_nonlinearity[] = { {{35, 129}, 00.000000, 0}, {{41, 88}, 50.000000, 0}, {{105, 98}, 100.000000, 0},};NEEDLE_UPDATE_CALLBACK engine1needlen1_cb;MODULE_VAR curr_engine1needlen1 = {TURB_ENGINE_1_CORRECTED_N1};double engine1needlen1_ret = 0;FLOAT64 FSAPI engine1needlen1_cb (PELEMENT_NEEDLE pelement){ lookup_var(&curr_engine1needlen1); engine1needlen1_ret = curr_engine1needlen1.var_value.n; if ( engine1needlen1_ret > GAUGE_MAX_ENGINE1N1 ) engine1needlen1_ret = GAUGE_MAX_ENGINE1N1; if ( engine1needlen1_ret < GAUGE_MIN_ENGINE1N1 ) engine1needlen1_ret = GAUGE_MIN_ENGINE1N1; return engine1needlen1_ret;}MAKE_NEEDLE( engine1_n1_needle, N1_NEEDLE, engine1_n1_string_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | bright | anti_alias, 0, 70,112, 1,2, TURB_ENGINE_1_CORRECTED_N1, engine1needlen1_cb, engine1_n1_nonlinearity, 0 )PELEMENT_HEADER engine1_n1_needle_plist[] = { (PELEMENT_HEADER) &engine1_n1_needle.header, NULL};MAKE_STATIC( upper_ecam_background, UPPER_ECAM_BACKGROUND, engine1_n1_needle_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | bright | anti_alias, 0, 0,0 )PELEMENT_HEADER upper_ecam_list = &upper_ecam_background.header;MOUSE_BEGIN( upper_ecam_mouse_rect,HELPID_GAUGE_EICAS, 0, 0 ) MOUSE_END #undef GAUGE_NAME#undef GAUGEHDR_VAR_NAME#undef GAUGE_WRussell

Share this post


Link to post
Share on other sites

Your problem is in this:FLOAT64 FSAPI engine1stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; wsprintf (pelement->string,"%3d", (UINT32)val); return val;}It should be:FLOAT64 FSAPI engine1stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; wsprintf (pelement->string,"%3.0f", val); return val;}val =s a FLOAT64 which is NOT a whole integer. the use of %3d tells wsprintf you want to format an integer value. Typecasting as a UINT32 isn't gonna work I'm afraid.

Share this post


Link to post
Share on other sites
Guest VAPilot

Tried your code Ed, and still get the same results, compiles with 2 warnings and when loaded in FS9, shows %3.The Warningsc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(26) : warning C4133: 'function' : incompatible types - from 'PCHAR' to 'LPWSTR'c:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(26) : warning C4133: 'function' : incompatible types - from 'char [6]' to 'LPCWSTR'Could this be something to do with the way I set up Visual C++ 2008 ?Russell

Share this post


Link to post
Share on other sites
Guest VAPilot

Finally got it to work. The warning was due to me having UNICODE set, changed it to NOT SET and no warning message, but it still did not work. After looking around the forum I found, another post with the same problem, and they use sprintf instead of wprintf. So tried this:FLOAT64 FSAPI engine1stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; sprintf (pelement->string,"%03.0f", val); return val;}and it worked, but compiled with 1 warning. Changed charater to MULTI-BYTE, and added #define _CRT_SECURE_NO_WARNINGS, as per the online help suggested and now have no warning message and works as it should do in FS9.After doing a bit of investigating I have sprintf in my stdio.h file, but no wsprintf. So I am guessing that is why wsprintf does not work for me when it works for others. Can this line be added to my stdio.h file or can I download a different stdio.h file, so I can use wsprintf ?

Share this post


Link to post
Share on other sites

Ok, I didn't notice the wsprintf versus sprintf.wsprintf is for wide strings... that's for strings where each character is defined by two bytes. Unicode is just that.wsprintf is available if you have Unicode enabled. sprintf is also available if you have unicode enabled.

Share this post


Link to post
Share on other sites
Guest VAPilot

Thanks for the help Ed. I hope someone can help me with this as well. Still sort of a string problem.EGT Token Variable is in Rankine, so I need to changed that to degrees celsisus. I have done this in the nonlinearity for the needle like this:NONLINEARITY engine1_egt_nonlinearity[] = { {{12, 217}, RANKINE_TO_CELSIUS (00.000000), 0}, {{108, 217}, RANKINE_TO_CELSIUS (1000.000000), 0},};I then need a callback for the needle and the string. How do you do convertions in a PELEMENT_STRING, PELEMENT_NEEDLE ?I have looked at the SDK, and Dai bible, and can not see how to do it. I did have a go and came up with this,FLOAT64 FSAPI engine1stringegt_cb (PELEMENT_STRING pelement){ FLOAT64 val = (pelement->source_var[0].var_value.n); if (val > 1000) val = 1000; else if (val < 0) val = 0; val = val*9/5 +32; sprintf (pelement->string,"%3.1f", val); return val;}it compiles and shows in FS9, but with engine off temp is over 900.Russell

Share this post


Link to post
Share on other sites

Well, that's certainly an odd approach. Why not simply do the conversion immediately following a lookup in the PRE_UPDATE routine?case PANEL_SERVICE_PRE_UPDATE: /* Fetch Variables */ lookup_var(&GENERAL_ENGINE1_OIL_TEMPvar); OT_eng1 = RANKINE_TO_CELSIUS(GENERAL_ENGINE1_OIL_TEMPvar.var_value.n); lookup_var(&GENERAL_ENGINE2_OIL_TEMPvar); OT_eng2 = RANKINE_TO_CELSIUS(GENERAL_ENGINE2_OIL_TEMPvar.var_value.n);break;

Share this post


Link to post
Share on other sites

I see you've tied your needle directly to the variable... which is ok, but seriously restricts your ability to go beyond the absolute basics in gauge programming.It is "best practice" to define variables like this:FLOAT64 l_eng_egt;FLOAT64 r_eng_egt;Then in your main gauge callback, during the PANEL_SERVICE_PRE_UPDATE you want to read all the variables you need for your gauge, like Bill posted above.In your needle's callback you simply assign the value of the appropriate engine's EGT value to the return FLOAT64 value for the callback... job done.It also ensures that your needle and your string are using the exact same variable (important if you code in failure logic!!!).

Share this post


Link to post
Share on other sites
Guest VAPilot

Tried the way described and keep getting compiler errors. To make things less complex I have just tried adding the engine1 egt string. I will change the way I have done the engines N1 if I can get the EGT to work. What have I done wrong ? //A380 Upper ECAMchar upper_ecam_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER upper_ecam_list;extern MOUSERECT upper_ecam_mouse_rect[];GAUGE_HEADER_FS700 ( GAUGE_W, upper_ecam_gauge_name, &upper_ecam_list, upper_ecam_mouse_rect, NULL, 0, 0, 0 );FAILURE_RECORD upper_ecam_fail[] = { {FAIL_SYSTEM_ELECTRICAL_PANELS, FAIL_ACTION_NO_DRAW}, {FAIL_NONE, FAIL_ACTION_NONE}};#define GAUGE_MIN_ENGINE1N1 0#define GAUGE_MAX_ENGINE1N1 110#define GAUGE_MIN_ENGINE2N1 0#define GAUGE_MAX_ENGINE2N1 110#define GAUGE_MIN_ENGINE3N1 0#define GAUGE_MAX_ENGINE3N1 110#define GAUGE_MIN_ENGINE4N1 0#define GAUGE_MAX_ENGINE4N1 110//Engine 1 EGTFLOAT64 FSAPI engine1stringegt_cb (PELEMENT_STRING pelement ){ FLOAT64 engine1egt; sprintf (pelement->string,"%3.1f", val); return val;}MAKE_STRING( engine1_egt_string, NULL, upper_ecam_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 40,208, 50,30, 4, GENERAL_ENGINE1_EGT, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, engine1stringegt_cb )PELEMENT_HEADER engine1_egt_string_plist[] = { (PELEMENT_HEADER) &engine1_egt_string.header, NULL};//Engine 4 N1//StringSTRING_UPDATE_CALLBACK engine4stringn1_cb;FLOAT64 FSAPI engine4stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; sprintf (pelement->string,"%3.1f", val); return val;}MAKE_STRING( engine4_n1_string, engine1_egt_string_plist, upper_ecam_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 429,112, 50,30, 4, TURB_ENGINE_4_CORRECTED_N1, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, engine4stringn1_cb )PELEMENT_HEADER engine4_n1_string_plist[] = { (PELEMENT_HEADER) &engine4_n1_string.header, NULL};//NeedleNONLINEARITY engine4_n1_nonlinearity[] = { {{400, 130}, 00.000000, 0}, {{398, 62}, 50.000000, 0}, {{462, 63}, 100.000000, 0},};NEEDLE_UPDATE_CALLBACK engine4needlen1_cb;MODULE_VAR curr_engine4needlen1 = {TURB_ENGINE_4_CORRECTED_N1};double engine4needlen1_ret = 0;FLOAT64 FSAPI engine4needlen1_cb (PELEMENT_NEEDLE pelement){ lookup_var(&curr_engine4needlen1); engine4needlen1_ret = curr_engine4needlen1.var_value.n; if ( engine4needlen1_ret > GAUGE_MAX_ENGINE4N1 ) engine4needlen1_ret = GAUGE_MAX_ENGINE4N1; if ( engine4needlen1_ret < GAUGE_MIN_ENGINE4N1 ) engine4needlen1_ret = GAUGE_MIN_ENGINE4N1; return engine4needlen1_ret;}MAKE_NEEDLE( engine4_n1_needle, N1_NEEDLE, engine4_n1_string_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT7 | BIT2, 0, 428,90, 0,1, TURB_ENGINE_4_CORRECTED_N1, engine4needlen1_cb, engine4_n1_nonlinearity, 0 )PELEMENT_HEADER engine4_n1_needle_plist[] = { (PELEMENT_HEADER) &engine4_n1_needle.header, NULL};//Engine 3 N1//StringSTRING_UPDATE_CALLBACK engine3stringn1_cb;FLOAT64 FSAPI engine3stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; sprintf (pelement->string,"%3.1f", val); return val;} MAKE_STRING( engine3_n1_string, engine4_n1_needle_plist, upper_ecam_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 319,112, 50,30, 4, TURB_ENGINE_3_CORRECTED_N1, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, engine3stringn1_cb )PELEMENT_HEADER engine3_n1_string_plist[] = { (PELEMENT_HEADER) &engine3_n1_string.header, NULL};//NeedleNONLINEARITY engine3_n1_nonlinearity[] = { {{290, 130}, 00.000000, 0}, {{288, 62}, 50.000000, 0}, {{352, 63}, 100.000000, 0},};NEEDLE_UPDATE_CALLBACK engine3needlen1_cb;MODULE_VAR curr_engine3needlen1 = {TURB_ENGINE_3_CORRECTED_N1};double engine3needlen1_ret = 0;FLOAT64 FSAPI engine3needlen1_cb (PELEMENT_NEEDLE pelement){ lookup_var(&curr_engine3needlen1); engine3needlen1_ret = curr_engine3needlen1.var_value.n; if ( engine3needlen1_ret > GAUGE_MAX_ENGINE3N1 ) engine3needlen1_ret = GAUGE_MAX_ENGINE3N1; if ( engine3needlen1_ret < GAUGE_MIN_ENGINE3N1 ) engine3needlen1_ret = GAUGE_MIN_ENGINE3N1; return engine3needlen1_ret;}MAKE_NEEDLE( engine3_n1_needle, N1_NEEDLE, engine3_n1_string_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT7 | BIT2, 0, 318,90, 0,1, TURB_ENGINE_3_CORRECTED_N1, engine3needlen1_cb, engine3_n1_nonlinearity, 0 )PELEMENT_HEADER engine3_n1_needle_plist[] = { (PELEMENT_HEADER) &engine3_n1_needle.header, NULL};//Engine 2 N1//StringSTRING_UPDATE_CALLBACK engine2stringn1_cb;FLOAT64 FSAPI engine2stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; sprintf (pelement->string,"%3.1f", val); return val;} MAKE_STRING( engine2_n1_string, engine3_n1_needle_plist, upper_ecam_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 170,112, 50,30, 4, TURB_ENGINE_2_CORRECTED_N1, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, engine2stringn1_cb )PELEMENT_HEADER engine2_n1_string_plist[] = { (PELEMENT_HEADER) &engine2_n1_string.header, NULL};//NeedleNONLINEARITY engine2_n1_nonlinearity[] = { {{141, 130}, 00.000000, 0}, {{139, 62}, 50.000000, 0}, {{203, 63}, 100.000000, 0},};NEEDLE_UPDATE_CALLBACK engine2needlen1_cb;MODULE_VAR curr_engine2needlen1 = {TURB_ENGINE_2_CORRECTED_N1};double engine2needlen1_ret = 0;FLOAT64 FSAPI engine2needlen1_cb (PELEMENT_NEEDLE pelement){ lookup_var(&curr_engine2needlen1); engine2needlen1_ret = curr_engine2needlen1.var_value.n; if ( engine2needlen1_ret > GAUGE_MAX_ENGINE2N1 ) engine2needlen1_ret = GAUGE_MAX_ENGINE2N1; if ( engine2needlen1_ret < GAUGE_MIN_ENGINE2N1 ) engine2needlen1_ret = GAUGE_MIN_ENGINE2N1; return engine2needlen1_ret;}MAKE_NEEDLE( engine2_n1_needle, N1_NEEDLE, engine2_n1_string_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT7 | BIT2, 0, 169,90, 0,1, TURB_ENGINE_2_CORRECTED_N1, engine2needlen1_cb, engine2_n1_nonlinearity, 0 )PELEMENT_HEADER engine2_n1_needle_plist[] = { (PELEMENT_HEADER) &engine2_n1_needle.header, NULL};//Engine 1 N1//StringSTRING_UPDATE_CALLBACK engine1stringn1_cb;FLOAT64 FSAPI engine1stringn1_cb (PELEMENT_STRING pelement ){ FLOAT64 val=pelement->source_var[0].var_value.n; sprintf (pelement->string,"%3.1f", val); return val;} MAKE_STRING( engine1_n1_string, engine2_n1_needle_plist, upper_ecam_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 60,112, 50,30, 4, TURB_ENGINE_1_CORRECTED_N1, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, engine1stringn1_cb )PELEMENT_HEADER engine1_n1_string_plist[] = { (PELEMENT_HEADER) &engine1_n1_string.header, NULL};//NeedleNONLINEARITY engine1_n1_nonlinearity[] = { {{31, 130}, 00.000000, 0}, {{29, 62}, 50.000000, 0}, {{93, 63}, 100.000000, 0},};NEEDLE_UPDATE_CALLBACK engine1needlen1_cb;MODULE_VAR curr_engine1needlen1 = {TURB_ENGINE_1_CORRECTED_N1};double engine1needlen1_ret = 0;FLOAT64 FSAPI engine1needlen1_cb (PELEMENT_NEEDLE pelement){ lookup_var(&curr_engine1needlen1); engine1needlen1_ret = curr_engine1needlen1.var_value.n; if ( engine1needlen1_ret > GAUGE_MAX_ENGINE1N1 ) engine1needlen1_ret = GAUGE_MAX_ENGINE1N1; if ( engine1needlen1_ret < GAUGE_MIN_ENGINE1N1 ) engine1needlen1_ret = GAUGE_MIN_ENGINE1N1; return engine1needlen1_ret;}MAKE_NEEDLE( engine1_n1_needle, N1_NEEDLE, engine1_n1_string_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT7 | BIT2, 0, 60,90, 0,1, TURB_ENGINE_1_CORRECTED_N1, engine1needlen1_cb, engine1_n1_nonlinearity, 0 )PELEMENT_HEADER engine1_n1_needle_plist[] = { (PELEMENT_HEADER) &engine1_n1_needle.header, NULL};//BackgroundMAKE_STATIC( upper_ecam_background, UPPER_ECAM_BACKGROUND, engine1_n1_needle_plist, upper_ecam_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT2, 0, 0,0 )PELEMENT_HEADER upper_ecam_list = &upper_ecam_background.header;MOUSE_BEGIN( upper_ecam_mouse_rect,TOOLTIPTEXT_ENG1_EGT_CELSIUS, 0, 0 ) MOUSE_END//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FSAPI upper_ecam_update (PGAUGEHDR pgauge, int service_id, UINT32 extra_data){ switch(service_id){/* "install_routine()" */ case PANEL_SERVICE_PRE_INSTALL: break;/* "initialize_routine()" */ case PANEL_SERVICE_PRE_INITIALIZE: break;/* "update_routine()" */ case PANEL_SERVICE_PRE_UPDATE:/* fetch variables */ lookup_var(&GENERAL_ENGINE1_EGTvar); engine1egt = RANKINE_TO_CELSIUS(GENERAL_ENGINE1_EGTvar.var_value.n); break;/* "draw_routine()" */ case PANEL_SERVICE_PRE_DRAW: break;/* "kill_routine()" */ case PANEL_SERVICE_PRE_KILL: break;}} #undef GAUGE_NAME#undef GAUGEHDR_VAR_NAME#undef GAUGE_WErrors/Warningsc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(29) : error C2065: 'val' : undeclared identifierc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(31) : error C2065: 'val' : undeclared identifierc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(420) : error C2065: 'GENERAL_ENGINE1_EGTvar' : undeclared identifierc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(420) : warning C4133: 'function' : incompatible types - from 'int *' to 'PMODULE_VAR'c:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(421) : error C2065: 'engine1egt' : undeclared identifierc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(421) : error C2065: 'GENERAL_ENGINE1_EGTvar' : undeclared identifierc:documents and settingsrussell howardmy documentsgaugesa380subgaugesupper ecam.c(421) : error C2224: left of '.var_value' must have struct/union typeRussell

Share this post


Link to post
Share on other sites

c:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(29) : errorC2065: 'val' : undeclared identifierc:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(31) : errorC2065: 'val' : undeclared identifierThe varaible val isn't declared... instead you declared engine1egt;c:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(420) : errorC2065: 'GENERAL_ENGINE1_EGTvar' : undeclared identifierc:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(420) : warningC4133: 'function' : incompatible types - from 'int *' to'PMODULE_VAR'c:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(421) : errorC2065: 'engine1egt' : undeclared identifierc:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(421) : errorC2065: 'GENERAL_ENGINE1_EGTvar' : undeclared identifierc:documents and settingsrussell howardmydocumentsgaugesa380subgaugesupper ecam.c(421) : errorC2224: left of '.var_value' must have struct/union typeYou didn't declare the GENERAL_ENGINE1_EGTvar variable anywhere. You're also trying to assign it to egine1egt which is actually declared in one of your callback functions which means it's not visible to your main gauge callback function.Without trying to come across as rude... do you write software or are you a beginner?

Share this post


Link to post
Share on other sites
Guest VAPilot

I am a beginner, who is about to give up.Programed XML for gauges since FS2002, always wanted to have a go at C++, so was giving it a try. Use a needle in my airspeed gauge, so wanted to have a go at strings next. An ecam seemed the right choice. Maybe 4 engines was a bit adventurous for my first go. Thanks, Bill and Ed for taking the time to post, but I think it is best to give up now, before I make an even bigger #### of myself. Russell

Share this post


Link to post
Share on other sites

>I am a beginner, who is about to give up.>>Programed XML for gauges since FS2002, always wanted to have a>go at C++, so was giving it a try. Use a needle in my airspeed>gauge, so wanted to have a go at strings next. An ecam seemed>the right choice. Maybe 4 engines was a bit adventurous for my>first go. >>Thanks, Bill and Ed for taking the time to post, but I think>it is best to give up now, before I make an even bigger ####>of myself. >>Russell Nah... you're doing fine... knowing your knowledge level helps us know how much detail we need to provide in our answers... that's all. :)So... don't give up, and feel free to keep asking.

Share this post


Link to post
Share on other sites
Guest VAPilot

Thanks Ed, Forget my last post not giving up that easy. Surprising what sleep can do.To make this easier for me, and so I don`t get lost in code, lets start again. I have bitmaps from an A319 eicas/ecam which I used in an XML gauge, so will use them. I have sorted the code and bitmaps out and compiled it using the background image only. Checked it works in FS. So I now need to work out the code for the needles and strings, using the method you and Bill recommended.I need to add this: case PANEL_SERVICE_PRE_UPDATE:/* Fetch Variables */lookup_var(&TURB_ENGINE_1_CORRECTED_N1var);engine1n1 = (TURB_ENGINE_1_CORRECTED_N1var.var_value.n);break;to the code below I also need to add the code for the string, which I can do, then I am lost. Do I need to add GAUGE_CALLBACK to my header ? Does the callback have to be put in a PELEMENT_NEEDLE/ PELEMENT_STRING ? Do I need to use a MODULE_VAR ie MODULE_VAR engine1n1 = {TURB_ENGINE_1_CORRECTED_N1}; like I did in the airspeed gauge ? The new code so it only displays the background//A319 upper eicaschar upper_eicas_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER upper_eicas_list;extern MOUSERECT upper_eicas_mouse_rect[];GAUGE_HEADER_FS700 ( GAUGE_W, upper_eicas_gauge_name, &upper_eicas_list, upper_eicas_mouse_rect, NULL, 0, 0, 0 );FAILURE_RECORD upper_eicas_fail[] = { {FAIL_SYSTEM_ELECTRICAL_PANELS, FAIL_ACTION_NO_DRAW}, {FAIL_NONE, FAIL_ACTION_NONE}};MAKE_STATIC( upper_eicas_background, UPPER_EICAS_BACKGROUND, NULL, upper_eicas_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT2 | BIT7, 0, 0,0 )PELEMENT_HEADER upper_eicas_list = &upper_eicas_background.header;MOUSE_BEGIN( upper_eicas_mouse_rect,HELPID_GAUGE_EICAS, 0, 0 ) MOUSE_END//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FSAPI upper_eicas_update (PGAUGEHDR pgauge, int service_id, UINT32 extra_data){ switch(service_id){/* "install_routine()" */ case PANEL_SERVICE_PRE_INSTALL: break;/* "initialize_routine()" */ case PANEL_SERVICE_PRE_INITIALIZE: break;/* "update_routine()" */ case PANEL_SERVICE_PRE_UPDATE: break;/* "draw_routine()" */ case PANEL_SERVICE_PRE_DRAW: break;/* "kill_routine()" */ case PANEL_SERVICE_PRE_KILL: break;}} #undef GAUGE_NAME#undef GAUGEHDR_VAR_NAME#undef GAUGE_W

Share this post


Link to post
Share on other sites

I need to add this: case PANEL_SERVICE_PRE_UPDATE:/* Fetch Variables */lookup_var(&TURB_ENGINE_1_CORRECTED_N1var);engine1n1 = (TURB_ENGINE_1_CORRECTED_N1var.var_value.n);break;to the code below I also need to add the code for the string,which I can do, then I am lost. Do I need to addGAUGE_CALLBACK to my header ? Does the callback have to beput in a PELEMENT_NEEDLE/ PELEMENT_STRING ? Do I need to usea MODULE_VAR ie MODULE_VAR engine1n1 ={TURB_ENGINE_1_CORRECTED_N1}; like I did in the airspeedgauge ? The new code so it only displays the background//A319 upper eicaschar upper_eicas_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER upper_eicas_list;extern MOUSERECT upper_eicas_mouse_rect[];// Added by EdGAUGE_CALLBACK upper_eicas_callback//// Modified by Ed/*GAUGE_HEADER_FS700 ( GAUGE_W, upper_eicas_gauge_name,&upper_eicas_list, upper_eicas_mouse_rect, NULL, 0, 0, 0);*/GAUGE_HEADER_FS700 ( GAUGE_W, upper_eicas_gauge_name,&upper_eicas_list, upper_eicas_mouse_rect, upper_eicas_callback, 0, 0, 0);FAILURE_RECORD upper_eicas_fail[] = { {FAIL_SYSTEM_ELECTRICAL_PANELS, FAIL_ACTION_NO_DRAW}, {FAIL_NONE, FAIL_ACTION_NONE}};MAKE_STATIC( upper_eicas_background, UPPER_EICAS_BACKGROUND, NULL, upper_eicas_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT2 | BIT7, 0, 0,0 )PELEMENT_HEADER upper_eicas_list =&upper_eicas_background.header;MOUSE_BEGIN( upper_eicas_mouse_rect,HELPID_GAUGE_EICAS, 0, 0) MOUSE_END////////////////////////////////////////////////////////// void FSAPI upper_eicas_update (PGAUGEHDR pgauge, intservice_id, UINT32 extra_data){ switch(service_id){/* "install_routine()" */ case PANEL_SERVICE_PRE_INSTALL: break;/* "initialize_routine()" */ case PANEL_SERVICE_PRE_INITIALIZE: break;/* "update_routine()" */ case PANEL_SERVICE_PRE_UPDATE: break;/* "draw_routine()" */ case PANEL_SERVICE_PRE_DRAW: break;/* "kill_routine()" */ case PANEL_SERVICE_PRE_KILL: break;}} #undef GAUGE_NAME#undef GAUGEHDR_VAR_NAME#undef GAUGE_WTry the above code... look for the comments I added to see the changes.

Share this post


Link to post
Share on other sites
Guest VAPilot

I have added the code you added as well as adding the string code, but how do I declare the GENERAL_ENGINE1_EGTvar variable ?Code with changes and string code added//A319 upper eicaschar upper_eicas_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER upper_eicas_list;extern MOUSERECT upper_eicas_mouse_rect[];GAUGE_CALLBACK upper_eicas_callback;GAUGE_HEADER_FS700 ( GAUGE_W, upper_eicas_gauge_name, &upper_eicas_list, upper_eicas_mouse_rect, upper_eicas_callback, 0, 0, 0 );FAILURE_RECORD upper_eicas_fail[] = { {FAIL_SYSTEM_ELECTRICAL_PANELS, FAIL_ACTION_NO_DRAW}, {FAIL_NONE, FAIL_ACTION_NONE}};MAKE_STRING( engine1n1string, NULL, upper_eicas_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 59,94, 50,30, 4, TURB_ENGINE_1_CORRECTED_N1, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, NULL ) // callback goes here when I have one PELEMENT_HEADER engine1n1string_plist[] = { (PELEMENT_HEADER) &engine1n1string.header, NULL};MAKE_STATIC( upper_eicas_background, UPPER_EICAS_BACKGROUND, engine1n1string_plist, upper_eicas_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT2 | BIT7, 0, 0,0 )PELEMENT_HEADER upper_eicas_list = &upper_eicas_background.header;MOUSE_BEGIN( upper_eicas_mouse_rect,HELPID_GAUGE_EICAS, 0, 0 ) MOUSE_END//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FSAPI upper_eicas_update (PGAUGEHDR pgauge, int service_id, UINT32 extra_data){ switch(service_id){/* "install_routine()" */ case PANEL_SERVICE_PRE_INSTALL: break;/* "initialize_routine()" */ case PANEL_SERVICE_PRE_INITIALIZE: break;/* "update_routine()" */ case PANEL_SERVICE_PRE_UPDATE: /* Fetch Variables */ lookup_var(&TURB_ENGINE_1_CORRECTED_N1var); engine1n1 = (TURB_ENGINE_1_CORRECTED_N1var.var_value.n); break;/* "draw_routine()" */ case PANEL_SERVICE_PRE_DRAW: break;/* "kill_routine()" */ case PANEL_SERVICE_PRE_KILL: break;}} #undef GAUGE_NAME#undef GAUGEHDR_VAR_NAME#undef GAUGE_W

Share this post


Link to post
Share on other sites

Hey... cut back the length of the line full of the '/' characters. They seriously overextend the web page. LOLOk... in your gauge file you should have at least 3 files... a file with the extention of .h, a file with the extention of .rc and a file with the extension of .c or .cpp (if it's a C++ file).In your .h file (header file) add the following:MODULE_VAR TURB_ENGINE_1_CORRECTED_N1var = {TURB_ENGINE_1_CORRECTED_N1};The header file is used for variable and defines typically. The .c/.cpp file is used for actual function code typically.The .rc file is used for resources: copyright info/bitmaps/etc.

Share this post


Link to post
Share on other sites
Guest VAPilot

Got it to work :)Thanks for all the help Ed, last night I was ready to jack it in, tonight I want to learn more. I think it was Bill who said it (Programming) causes premature graying of the hair, I can now see why.The code for those who might be looking at a later date.In the Header File:MODULE_VAR TURB_ENGINE_1_CORRECTED_N1var = {TURB_ENGINE_1_CORRECTED_N1};Subgauge code, minus the ///// :)//A319 upper eicaschar upper_eicas_gauge_name[] = GAUGE_NAME;extern PELEMENT_HEADER upper_eicas_list;extern MOUSERECT upper_eicas_mouse_rect[];GAUGE_CALLBACK upper_eicas_callback;GAUGE_HEADER_FS700 ( GAUGE_W, upper_eicas_gauge_name, &upper_eicas_list, upper_eicas_mouse_rect, upper_eicas_callback, 0, 0, 0 );FAILURE_RECORD upper_eicas_fail[] = { {FAIL_SYSTEM_ELECTRICAL_PANELS, FAIL_ACTION_NO_DRAW}, {FAIL_NONE, FAIL_ACTION_NONE}};FLOAT64 engine1n1;// Engine 1 N1//StringSTRING_UPDATE_CALLBACK engine1n1string_cb;FLOAT64 FSAPI engine1n1string_cb (PELEMENT_STRING pelement ){ engine1n1 = TURB_ENGINE_1_CORRECTED_N1var.var_value.n; sprintf (pelement->string,"%3.1f", engine1n1); return engine1n1;}MAKE_STRING( engine1n1string, NULL, upper_eicas_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 32,46, 45,24, 4, TURB_ENGINE_1_CORRECTED_N1, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, engine1n1string_cb ) PELEMENT_HEADER engine1n1string_plist[] = { (PELEMENT_HEADER) &engine1n1string.header, NULL};//NeedleNONLINEARITY engine1n1_nonlinearity[] = { {{21, 66}, 00.000000, 0}, {{25, 21}, 50.000000, 0}, {{85, 30}, 100.000000, 0},};FLOAT64 FSAPI engine1n1needle_cb (PELEMENT_NEEDLE pelement ){ engine1n1 = TURB_ENGINE_1_CORRECTED_N1var.var_value.n; return engine1n1;}MAKE_NEEDLE( engine1n1needle, N1_NEEDLE, engine1n1string_plist, upper_eicas_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT7 | BIT2, 0, 52,44, 0,1, TURB_ENGINE_1_CORRECTED_N1, engine1n1needle_cb, engine1n1_nonlinearity, 0 )PELEMENT_HEADER engine1n1needle_plist[] = { (PELEMENT_HEADER) &engine1n1needle.header, NULL};//BackgroundMAKE_STATIC( upper_eicas_background, UPPER_EICAS_BACKGROUND, engine1n1needle_plist, upper_eicas_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | BIT2 | BIT7, 0, 0,0 )PELEMENT_HEADER upper_eicas_list = &upper_eicas_background.header;MOUSE_BEGIN( upper_eicas_mouse_rect,HELPID_GAUGE_EICAS, 0, 0 ) MOUSE_END void FSAPI upper_eicas_callback (PGAUGEHDR pgauge, int service_id, UINT32 extra_data){ switch(service_id){/* "install_routine()" */ case PANEL_SERVICE_PRE_INSTALL: break;/* "initialize_routine()" */ case PANEL_SERVICE_PRE_INITIALIZE: break;/* "update_routine()" */ case PANEL_SERVICE_PRE_UPDATE: /* Fetch Variables */ lookup_var(&TURB_ENGINE_1_CORRECTED_N1var); engine1n1 = (TURB_ENGINE_1_CORRECTED_N1var.var_value.n); break;/* "draw_routine()" */ case PANEL_SERVICE_PRE_DRAW: break;/* "kill_routine()" */ case PANEL_SERVICE_PRE_KILL: break;}} #undef GAUGE_NAME#undef GAUGEHDR_VAR_NAME#undef GAUGE_W

Share this post


Link to post
Share on other sites

Actually, that is not a "subgauge" code at all.I truly think you'd be better off settling on a boilerplate format which at minimum consists of these files, even if you're actually only planning to have one "subgauge":Main.c// #includes, #define and GAUGE_TABLE entries at a minimumMain.h// Version info, preprocessor instructions, bitmap resource numbersMain.rc// VS_VERSION_INFO, Company String Data, Bitmap filenames and pathsSubGaugenn.c// contains all code relevant to a specific sub-gauge.Write to me at n4gix@comcast.net and I will send you the SDK sample gauges already set up as a MSVCC solution. If may prove helpful to you as an example to study.

Share this post


Link to post
Share on other sites
Guest VAPilot

This is sort of a string problem, so thought I would post it here, instead of starting another post/topic.Have now got all the engine gauges on the ecias working ie N1, EGT etc, even managed to sort out the Total fuel quantity and fuel flow in KGS. So as I have got this far I might as well finish it. I want a string to display PARK BRK in the eicas, when the parking brakes are on. When they are off the string should not be displayed.The only token variable I have found for parking brakes is PARKING_BRAKE_POS, 0 being off and 32 being full on. I have then delcared this in the header like I have done the others, and then in a FLOAT64 in the subguge (I have not read the stuff Bill sent me yet) :). I have seen a few code where I think the string has been controlled by codes in the pelement string, so have given this a go but althought the gauge compiles, and works in FS, i just get a bunch of numbers.The relivant bits of code;HeaderMODULE_VAR PARKING_BRAKE_POSvar = {PARKING_BRAKE_POS};FLOAT64 parkingbrakeon;//Parking Brake On //PARK BRK//StringSTRING_UPDATE_CALLBACK parkingbrakeonstring_cb;FLOAT64 FSAPI parkingbrakeonstring_cb (PELEMENT_STRING pelement ){ if( parkingbrakeon == 1){ parkingbrakeon = (PARKING_BRAKE_POSvar.var_value.n); wsprintf (pelement->string,"%8d", "PARK BRK");}else{ wsprintf (pelement->string,"%8d", "");} return parkingbrakeon;}MAKE_STRING( parkingbrakeonstring, NULL, upper_eicas_fail, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT2, 0, 218,216, 45,24, 8, PARKING_BRAKE_POS, MODULE_VAR_NONE, MODULE_VAR_NONE, RGB (0,255,0), RGB (0,0,0), RGB (0,255,0), ARIAL, GAUGE_WEIGHT_DEFAULT, GAUGE_CHARSET, 0, DT_CENTER | DT_VCENTER, NULL, parkingbrakeonstring_cb ) PELEMENT_HEADER parkingbrakeonstring_plist[] = { (PELEMENT_HEADER) &parkingbrakeonstring.header, NULL};lookup_var(&PARKING_BRAKE_POSvar); parkingbrakeon = (PARKING_BRAKE_POSvar.var_value.n);I have tried using sprintf as well as wsprintf, but still get the same results. I am proberly going completly the wrong way about this, but could not just post can not do this, had to give it a go first. Would it be better for me to learn how to grab XML variables so I could use BRAKE PARKING POSITION,bool ?Russell

Share this post


Link to post
Share on other sites

Try this for your callback:FLOAT64 FSAPI parkingbrakeonstring_cb (PELEMENT_STRING pelement ){lookup_var(&PARKING_BRAKE_POSvar);if( PARKING_BRAKE_POSvar.var_value.n > 0){sprintf (pelement->string,"%s", "PARK BRK");}else{sprintf (pelement->string,"%s","");}return 0;}You need the %s specification to print an actual string. The %8d is for an 8 character integer value.Doug

Share this post


Link to post
Share on other sites
Guest VAPilot

Thanks Doug works perfectly.I will also use this code for flap handle position for the flap indicator numbers ie 1,2 etc as I use a string for that, but for the flap indicator its self I need to alter bitmaps for certain flap positions, my first thought was to use Element_Icon, and make each one visible when ceratin conditions are met. There are 5 bitmaps in total so when flap are set to 3 bitmap 3 is the only one visible. Is this the best way or is there a better way ?

Share this post


Link to post
Share on other sites
Guest VAPilot

I thought Dougs code with a bit of altering would work for the Flap Handle position string, but so far it does not.What I want it to do is display the flap handle position, ie flaps handle pos 1, string show 1.The code I have displays 4 all of the time except when the flap handle is in position 5 when is does show 5.The codeFLOAT64 FSAPI flaphandlepositionstring_cb (PELEMENT_STRING pelement ){ lookup_var(&FLAPS_HANDLE_POSvar); if( FLAPS_HANDLE_POSvar.var_value.n < 3276){ sprintf (pelement->string,"%s", "");}else lookup_var(&FLAPS_HANDLE_POSvar); if( FLAPS_HANDLE_POSvar.var_value.n > 0 <6552 ){ sprintf (pelement->string,"%s", "1");}else lookup_var(&FLAPS_HANDLE_POSvar); if( FLAPS_HANDLE_POSvar.var_value.n > 3276 < 9828){ sprintf (pelement->string,"%s", "2");}else lookup_var(&FLAPS_HANDLE_POSvar); if( FLAPS_HANDLE_POSvar.var_value.n > 6552 < 13104 ){ sprintf (pelement->string,"%s", "3");}else lookup_var(&FLAPS_HANDLE_POSvar); if( FLAPS_HANDLE_POSvar.var_value.n > 9828 < 16384 ){ sprintf (pelement->string,"%s", "4");}else lookup_var(&FLAPS_HANDLE_POSvar); if( FLAPS_HANDLE_POSvar.var_value.n > 13104 ){ sprintf (pelement->string,"%s", "5");} return 0;}

Share this post


Link to post
Share on other sites

Ok... don't take this wrong... that's some scary code. ;)First... FLAPS_HANDLE_POS is for the physical flaps control on the panel. Is that what your gauge should report... or should it actually report the physical flaps position? If it's the latter, you need TRAILING_EDGE_FLAPS0_LEFT_ANGLE or TRAILING_EDGE_FLAPS0_RIGHT_ANGLE.In your code you're repeatedly calling "lookup_var". No need... one call does it all for each update loop. Also... this code:"if( FLAPS_HANDLE_POSvar.var_value.n > 0 <6552 )" literally won't work. If you're looking to evaluate between a min and max like this... it has to be written this way:if( FLAPS_HANDLE_POSvar.var_value.n > 0 && FLAPS_HANDLE_POSvar.var_value.n <6552 )However, here's a better method of writing what you wrote:FLOAT64 FSAPI flaphandlepositionstring_cb (PELEMENT_STRING pelement ){lookup_var(&FLAPS_HANDLE_POSvar);if( FLAPS_HANDLE_POSvar.var_value.n < 3276){sprintf (pelement->string,"%s", "");}else if( FLAPS_HANDLE_POSvar.var_value.n < 6552 ){sprintf (pelement->string,"%s", "1");}else if( FLAPS_HANDLE_POSvar.var_value.n < 9828){sprintf (pelement->string,"%s", "2");}else if( FLAPS_HANDLE_POSvar.var_value.n < 13104 ){sprintf (pelement->string,"%s", "3");}else if( FLAPS_HANDLE_POSvar.var_value.n < 16384 ){sprintf (pelement->string,"%s", "4");}else{sprintf (pelement->string,"%s", "5");}return 0;} Another consideration... creating a local variable to store the value of FLAPS_HANDLE_POSvar. For the most part, it's no big deal... but the larger and more complex a gauge system becomes... the bigger the impact of performance has for repeatedly calling a variable like FLAPS_HANDLE_POSvar. It deals with near/far pointers to data... and is something you'll need to pay attention to sooner or later.

Share this post


Link to post
Share on other sites

Russell,Do yourself a favour - go out and buy an introductory C++ textbook. No point in guessing at syntax.You can also get help at places like http://www.cplusplus.com/ and MSDN, but having a real book in front of you is often very helpful. If nothing else, it will give you something large and heavy to throw across the room when your gauge fails to compile for the 97th straight time... }( Doug

Share this post


Link to post
Share on other sites
Guest VAPilot

Thanks for the code and advice Ed. I did want it for the Flap Handle Position, so it shows the handle position on the eicas, I will use TRAILING_EDGE_FLAPS0_LEFT_ANGLE or TRAILING_EDGE_FLAPS0_RIGHT_ANGLE for the 5 bitmaps that I use to show the physical flaps position. I now have the last bit of code I need to finish this. I will then be taking Doug advice and buying a big book, so I can throw it across the room when it compiles ok, but does not work in FS :)Thanks to everyone who posted.Russell

Share this post


Link to post
Share on other sites

×
×
  • Create New...