/****************************************************************************** * * * A M S E x t e n d e r * * * * by Stefan Heule * * member of boolsoft (www.boolsoft.org) * * * * Source Code * * * ******************************************************************************* AMS Extender - A utility for TI's 68k calculaters Copyright (C) 2006-2008 Stefan Heule This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ // ----------------------------------------------------------------- // // --- custom events // ----------------------------------------------------------------- // #define CUSTOM_CM_BACKUP_SETTINGS_ALL_TSR 0x6000 #define CUSTOM_CM_RESTORE_SETTINGS_ALL_TSR 0x6001 #define CUSTOM_CM_BACKUP_SETTINGS_AMSEXT 0x6002 #define CUSTOM_CM_RESTORE_SETTINGS_AMSEXT 0x6003 #define CUSTOM_CM_BACKUP_SETTINGS_EASYCHAR 0x6004 #define CUSTOM_CM_RESTORE_SETTINGS_EASYCHAR 0x6005 // ----------------------------------------------------------------- // // --- defines // ----------------------------------------------------------------- // // 'e' 'v' 'H' 'k' #define EVHK_TAG_HEXA ((long)0x6576486B) // magic marker for trap 4 hook ('A' 'M' 'E' 'x') #define MAGIC_TRAP4HOOK 0x414D4578 // no need for exit or atexit #define NO_EXIT_SUPPORT #define NO_AMS_CHECK // smaller code #define OPTIMIZE_ROM_CALLS #define USE_FLINE_ROM_CALLS // produce code for all models #define USE_TI92PLUS #define USE_V200 #define USE_TI89 #define MIN_AMS 204 #define fatal(s) {ST_showHelp(s);return;} // size of the trap 4 hook #define SIZE_OF_TRAP4HOOK sizeof(trap4hook) // if you change the backup struct, change this macig, too! // "amsext01" -> AMS Extender 0.6.0 beta // -> AMS Extender 0.7.0 beta // "amsext02" -> AMS Extender 0.8.0 beta #define OPTIONS_FILE_MAGIC "amsext02" // name of the backup file #define OPTIONS_FILE_NAME "amsxtcfg" typedef struct _options { unsigned short keydelay; // key delay, delay in 1/20 second unsigned short scrolldelay; // scroll delay, delay in 1/20 second unsigned long cursor_rate; // cursor blink delay, delay in 1/20 second unsigned long apd; // auto power down, 20 * second short auto_add_brackets; // automatically add brackets, 0: off, 1: on unsigned char clock_type; // clock icon, 0: off, 1: 12h, 2: 24h unsigned char battery_type; // battery icon, 0: off, 1: on unsigned char keyboard_layout; // keyboard layout, 0: QWERTY, 1: QWERTZ unsigned char autostart_prgm[18]; // autostart programm, 'name'+'\\'+'folder' or 'name' unsigned char _2nd_MEM[18]; // programm to be executed when 2nd+MEM is pressed unsigned char _2nd_CHAR[18]; // programm to be executed when 2nd+CHAR is pressed unsigned char off_by_on; // turn calc off by pressing on, 0: off, 1: on } OPTIONS; // the preferences OPTIONS pref; // handle's (used for the options dialog) unsigned short a, b, c, d, e, f, g, dlg, pop1, pop2, pop3; // ----------------------------------------------------------------- // // --- header files // ----------------------------------------------------------------- // #include // include all header files #include "messages.h" // multi-language support #include "h220xTSR.h" // Kevin Kofler's hw2 ams2 tsr support #include "eventhook_89.h" // pre-compiled event hook for the ti89 #include "eventhook_v2.h" // pre-compiled event hook for the v200 #include "trap4hook.h" // pre-compiled trap 4 hook for the both // ----------------------------------------------------------------- // // --- prototypes // ----------------------------------------------------------------- // // trap 4 hook stuff unsigned short InstallTrap4Hook(const unsigned char* signature, unsigned short key_delay, unsigned short scroll_delay); void RemoveTrap4Hook(unsigned char* tsr_address); unsigned char* FindTrap4Hook(const unsigned char* signature); void UpdateTrap4HookConfig(unsigned char* tsr_address, unsigned short key_delay, unsigned short scroll_delay); // preferences file short loadBackup(void); short saveBackup(void); void check_for_limits(void); void default_all_settings(void); unsigned char checksum(void* data, unsigned short bytes); // preferences dialog unsigned short execute_config_dialog(void); CALLBACK short Callback(short Message, long Value); CALLBACK HANDLE PopupCallback(short ID); // ----------------------------------------------------------------- // // Main routine, handles the user input and installs or uninstalls // the event/trap 4 hook if necessary. // ----------------------------------------------------------------- // // input (as an argument): // 'r' = restores the config from a file // 'c' = displays an options dialog // local: // signature = 8-byte signature of the trap 4 hook // eventhookHandle = handle of the event hook // p_eventhook = pointer to the event hook // eventhook = pointer to the event hook // eventhook_size = size of the event hook // trap4hook_adr = address of the trap 4 hook // argptr = pointer to the arguments // ev = event // arg = temp argument storage // ----------------------------------------------------------------- // void _main(void) { const unsigned char signature[8] = {'t','r','a','p','4','_','h','k'}; volatile HANDLE eventhookHandle; char *p_eventhook; unsigned char* eventhook; unsigned short eventhook_size; unsigned char* trap4hook_adr; ESI argptr; EVENT ev; const char* arg; // find our trap 4 hook trap4hook_adr = FindTrap4Hook(signature); // load the backup if (!loadBackup()) return; // choose the correct event hook if (TI92PLUS || V200) { eventhook = eventhook_v2; eventhook_size = sizeof(eventhook_v2); } else if (TI89) { eventhook = eventhook_89; eventhook_size = sizeof(eventhook_89); } else fatal(MSG_ERROR_UNKNOWN_CALC); // init the argument pointer InitArgPtr(argptr); // we are just looking for string arguments if (GetArgType(argptr) == STR_TAG) { arg = GetStrnArg(argptr); if (strchr(arg, 'r')) { // send a custom event, that the event hook can update its config ev.Type = CUSTOM_CM_RESTORE_SETTINGS_AMSEXT; EV_sendEvent(TIOS_EV_getAppID("TIHOME"), &ev); // set trap 4 settings if (trap4hook_adr) UpdateTrap4HookConfig(trap4hook_adr, pref.keydelay, pref.scrolldelay); } else if (strchr(arg, 'c')) { // display the config dialog if (execute_config_dialog()) { // save the config if (!saveBackup()) ST_helpMsg(MSG_ERROR_SAVE_CONFIG); // send a custom event, that the event hook can update its config ev.Type = CUSTOM_CM_RESTORE_SETTINGS_AMSEXT; EV_sendEvent(TIOS_EV_getAppID("TIHOME"), &ev); // set trap 4 settings if (trap4hook_adr) UpdateTrap4HookConfig(trap4hook_adr, pref.keydelay, pref.scrolldelay); } } return; } // check wheter the event hook is already installed (originally written by Olivier Armand (ExtendeD)) if (EV_hook) { char *HookPtr = (char*)EV_hook; char *PrevHookPtr = NULL; // points to the previous hook in the linked list while (HookPtr != NULL) { HookPtr -= 16; // point to the header of the hook // if the event hook isn't following Kevin Kofler's convention, // our event hook can't be further in the linked list if(*(long*)HookPtr != EVHK_TAG_HEXA) break; // if this is our event hook, uninstall it :( if(!memcmp(HookPtr, "evHk"TSR_NAME, 12)) { // if our event hook is not the first in the linked list if (PrevHookPtr // Remove our event hook from the linked list : // the next event hook of PrevHookPtr becomes the next hook of HookPtr... // but only if the next event hook follows Kevin's convention ! && (*(long*)(*(char**)(HookPtr+12) - 16) == EVHK_TAG_HEXA)) *(char**)(PrevHookPtr+12) = *(char**)(HookPtr+12); else // Our event hook is the first in the linked list : // EV_hook becomes the event hook after our hook in the list EV_hook = (EVENT_HANDLER)*(char**)(HookPtr+12); // Free the block where the TSR was. // (don't forget to make HookPtr leave the ghost space) HeapFree(HeapPtrToHandle ((void*)((long)HookPtr ^ (HW_VERSION == 2 ? 0x40000 : 0)))); // uninstall trap 4 hook if (trap4hook_adr) RemoveTrap4Hook(trap4hook_adr); // last message fatal(HOOK_NAME" "MSG_UNINSTALLED"."); } // HookPtr is now the previous hook pointer PrevHookPtr = HookPtr; // get the address of the entry point of the next hook HookPtr = *(char**)(HookPtr+12); } } // install Kevin's HW2 AMS 2 TSR support if(!h220xTSR()) fatal(MSG_ERROR_MEMORY); // install our trap 4 hook if (!trap4hook_adr) if (!InstallTrap4Hook(signature, pref.keydelay, pref.scrolldelay)) fatal(MSG_ERROR_MEMORY); // allocate RAM for the event hook if(!(eventhookHandle = HeapAllocHigh(eventhook_size))) { // uninstall the trap 4 hook trap4hook_adr = FindTrap4Hook(signature); if (trap4hook_adr) RemoveTrap4Hook(trap4hook_adr); // exit fatal(MSG_ERROR_MEMORY); } // get a pointer to the actual mem and make it point in the "ghost space" // ghost space is essentially a shadow of regular ram which is not protected very // well by the hardware... subtract 0x40000 to get the real address p_eventhook = HeapDeref(eventhookHandle)+(HW_VERSION == 2 ? 0x40000 : 0); // copy the eventhook array to its new location memcpy(p_eventhook, eventhook, eventhook_size); // save the old address for the uninstall prog and for this hook to call *(unsigned long*)&p_eventhook[12] = (unsigned long)EV_hook; EX_patch(p_eventhook, p_eventhook+eventhook_size); ASM_fastcall(&p_eventhook[16]); EV_hook = (EVENT_HANDLER)&p_eventhook[16]; // last message ST_helpMsg(HOOK_NAME" "HOOK_VERSION" "MSG_INSTALLED"."); } // ----------------------------------------------------------------- // // Installs our trap4 hook // ----------------------------------------------------------------- // // input: // signature = signature of the trap 4 hook // key_delay = key delay // scroll_delay = scroll delay // local: // mem = pointer to the allocated memory for our hook // HookMain = function pointer to the main routine of our // trap 4 hook // return: // 1 if successfully installed, 0 otherwise // ----------------------------------------------------------------- // unsigned short InstallTrap4Hook(const unsigned char* signature, unsigned short key_delay, unsigned short scroll_delay) { unsigned char* mem = HeapAllocPtr(SIZE_OF_TRAP4HOOK+12)+(HW_VERSION == 2 ? 0x40000 : 0); void (*HookMain)(unsigned short, unsigned short, unsigned char); // return if there isn't enought free RAM if (!mem) return 0; // write MAGIC_TSR (4 bytes) at the beginning of memory *mem++ = (MAGIC_TRAP4HOOK >> 24) & 0xff; *mem++ = (MAGIC_TRAP4HOOK >> 16) & 0xff; *mem++ = (MAGIC_TRAP4HOOK >> 8) & 0xff; *mem++ = (MAGIC_TRAP4HOOK ) & 0xff; // copy afterwards the 8 bytes signature to memory memcpy(mem, signature, 8); mem += 8; // ... and the program itself from the pre-compiled array memcpy(mem, trap4hook, SIZE_OF_TRAP4HOOK); // relocate program and execute the program EX_patch(mem, mem+SIZE_OF_TRAP4HOOK); HookMain = (void(*)(unsigned short, unsigned short, unsigned char))(mem); HookMain(key_delay, scroll_delay, 0); return 1; } // ----------------------------------------------------------------- // // Uninstalls the trap 4 hook // ----------------------------------------------------------------- // // input: // tsr_address = pointer to the header (signatur + magic) of // our trap 4 hook // local: // HookMain = function pointer to the main routine of our // trap 4 hook // ----------------------------------------------------------------- // void RemoveTrap4Hook(unsigned char* tsr_address) { void (*HookMain)(unsigned short, unsigned short, unsigned char); // uninstall the trap 4 hook HookMain = (void(*)(unsigned short, unsigned short, unsigned char))(tsr_address+12+(HW_VERSION == 2 ? 0x40000 : 0)); HookMain(0, 0, 0); // fill memory holding signature with zeros memset(tsr_address, 0, 12); // free the allocated memory HeapFreePtr((void*)((long)tsr_address^ (HW_VERSION == 2 ? 0x40000 : 0))); } // ----------------------------------------------------------------- // // Scans the hole RAM to find our trap 4 hook, looking for its magic // (4 bytes) followed by the signature (8 bytes). // ----------------------------------------------------------------- // // input: // signature = signature of the trap 4 hook // local: // end = pointer to the memory location where we search // return: // address of the already installed trap 4 hook or NULL // note: // Scans backwards // ----------------------------------------------------------------- // unsigned char* FindTrap4Hook(const unsigned char* signature) { unsigned char* end = HeapEnd(); while (end) { if (*end == ((MAGIC_TRAP4HOOK >> 24) & 0xff) && *(end+1) == ((MAGIC_TRAP4HOOK >> 16) & 0xff) && *(end+2) == ((MAGIC_TRAP4HOOK >> 8) & 0xff) && *(end+3) == ((MAGIC_TRAP4HOOK ) & 0xff) && !strncmp(end+4, signature, 8)) { // we have found our trap 4 hook return end; } end -= 2; } // if we'll come here our trap 4 hook is not installed return NULL; } // ----------------------------------------------------------------- // // Updates the config of our trap 4 hook // ----------------------------------------------------------------- // // input: // tsr_address = pointer to the header (signatur + magic) of // our trap 4 hook // key_delay = key delay // scroll_delay = scroll delay // local: // HookMain = function pointer to the main routine of our // trap 4 hook // ----------------------------------------------------------------- // void UpdateTrap4HookConfig(unsigned char* tsr_address, unsigned short key_delay, unsigned short scroll_delay) { void (*HookMain)(unsigned short, unsigned short, unsigned char); // update the trap 4 hook config HookMain = (void(*)(unsigned short, unsigned short, unsigned char))(tsr_address+12+(HW_VERSION == 2 ? 0x40000 : 0)); HookMain(key_delay, scroll_delay, 1); } // ----------------------------------------------------------------- // // Executes the config dialog // ----------------------------------------------------------------- // // local: // pulldown_buffer = buffer for the popups // ptr = pointer // dlg_ret_val = return value of the DialogDo function // return: // TRUE if the user pressed ENTER, FALSE otherwise // ----------------------------------------------------------------- // unsigned short execute_config_dialog(void) { short pulldown_buffer[5]; char* ptr; unsigned short dlg_ret_val = 0; a = b = c = d = e = f = g = dlg = pop1 = pop2 = pop3 = 0; if ((a = HeapAlloc(6)) == H_NULL) goto error; if ((b = HeapAlloc(6)) == H_NULL) goto error; if ((c = HeapAlloc(6)) == H_NULL) goto error; if ((d = HeapAlloc(6)) == H_NULL) goto error; if ((e = HeapAlloc(20)) == H_NULL) goto error; if ((f = HeapAlloc(20)) == H_NULL) goto error; if ((g = HeapAlloc(20)) == H_NULL) goto error; if ((pop1 = PopupNew(NULL, 0)) == H_NULL) goto error; if ((pop2 = PopupNew(NULL, 0)) == H_NULL) goto error; if ((pop3 = PopupNew(NULL, 0)) == H_NULL) goto error; // add the texts to the popup's PopupAddText(pop1, -1, MSG_OPTIONS_ON , 0); PopupAddText(pop1, -1, MSG_OPTIONS_OFF, 0); PopupAddText(pop2, -1, MSG_OPTIONS_OFF, 0); PopupAddText(pop2, -1, "12h", 0); PopupAddText(pop2, -1, "24h", 0); PopupAddText(pop3, -1, "QWERTZ", 0); PopupAddText(pop3, -1, "QWERTY", 0); ptr = HeapDeref(a); sprintf(ptr, "%i", pref.keydelay); ptr = HeapDeref(b); sprintf(ptr, "%i", pref.scrolldelay); ptr = HeapDeref(c); sprintf(ptr, "%lu", pref.cursor_rate); ptr = HeapDeref(d); sprintf(ptr, "%lu", pref.apd/20); ptr = HeapDeref(e); strcpy(ptr, pref.autostart_prgm); ptr = HeapDeref(f); strcpy(ptr, pref._2nd_MEM); ptr = HeapDeref(g); strcpy(ptr, pref._2nd_CHAR); // auto add brackets if (pref.auto_add_brackets) pulldown_buffer[0] = 1; else pulldown_buffer[0] = 2; // off by on if (pref.off_by_on) pulldown_buffer[4] = 1; else pulldown_buffer[4] = 2; if (CALCULATOR) { // clock type pulldown_buffer[2] = pref.clock_type+1; // battery if (pref.battery_type) pulldown_buffer[1] = 1; else pulldown_buffer[1] = 2; // keyboard layout if (pref.keyboard_layout) pulldown_buffer[3] = 1; else pulldown_buffer[3] = 2; // new dialog if ((dlg = DialogNew(160, 117, Callback)) == H_NULL) { goto error; } DialogAddScrollRegion(dlg, DF_CLR_ON_REDRAW, 9, 18-2, 160, 90+10, 0, 10, 7, 12, 12); // add all request's DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 18, MSG_OPTIONS_KEYDELAY, 4); DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 30, MSG_OPTIONS_SCROLLDELAY, 4); #if defined(LANG_EN) DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 42, MSG_OPTIONS_CURSOR_BLINK" ", 4); #elif defined(LANG_DE) DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 42, MSG_OPTIONS_CURSOR_BLINK, 4); #endif DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 54, MSG_OPTIONS_APD_TIMER, 4); DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 66, MSG_OPTIONS_AUTOSTART" ", 9); DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 78, MSG_OPTIONS_2ND_MEM" ", 9); DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 90, MSG_OPTIONS_2ND_CHAR" ", 9); // add all pulldown's DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 102, MSG_OPTIONS_AUTO_ADD_BR, PopupCallback, 0); DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 114, MSG_OPTIONS_BATTERY, PopupCallback, 1); DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 126, MSG_OPTIONS_CLOCK, PopupCallback, 2); DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 138, MSG_OPTIONS_OFF_BY_ON, PopupCallback, 4); DialogAddDynamicPulldown(dlg, DF_SCROLLABLE, 10, 150, MSG_OPTIONS_KEYBOARD_LAYOUT, PopupCallback, 3); } else { // new dialog if ((dlg = DialogNew(122, 89, Callback)) == H_NULL) { goto error; } // add the scroll region DialogAddScrollRegion(dlg, DF_CLR_ON_REDRAW, 11, 13, 122, 74, 0, 8, 6, 10, 10); // add all request's DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 15, MSG_OPTIONS_KEYDELAY, 4); DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 25, MSG_OPTIONS_SCROLLDELAY, 4); #if defined(LANG_EN) DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 35, MSG_OPTIONS_CURSOR_BLINK" ", 4); #elif defined(LANG_DE) DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 35, MSG_OPTIONS_CURSOR_BLINK, 4); #endif DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 45, MSG_OPTIONS_APD_TIMER, 4); DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 55, MSG_OPTIONS_AUTOSTART" ", 9); DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 65, MSG_OPTIONS_2ND_MEM" ", 9); DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 75, MSG_OPTIONS_2ND_CHAR" ", 9); // add all pulldown's DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 85, MSG_OPTIONS_AUTO_ADD_BR, PopupCallback, 0); DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 95, MSG_OPTIONS_OFF_BY_ON, PopupCallback, 4); DialogAddXFlags(dlg, 0, XF_NO_ALPHA_LOCK, 0, 0, 0); } // add the title DialogAddTitle(dlg, HOOK_NAME" "HOOK_VERSION" "MSG_OPTIONS, BT_CANCEL, BT_SAVE); if ((dlg_ret_val = DialogDo(dlg, CENTER, CENTER, NULL, pulldown_buffer)) == KEY_ENTER) { // delays pref.keydelay = atoi(HeapDeref(a)); pref.scrolldelay = atoi(HeapDeref(b)); pref.cursor_rate = atoi(HeapDeref(c)); pref.apd = atoi(HeapDeref(d))*20; // check for limits check_for_limits(); // auto add brackets if (pulldown_buffer[0] == 1) pref.auto_add_brackets = 1; else pref.auto_add_brackets = 0; // off by on if (pulldown_buffer[4] == 1) pref.off_by_on = 1; else pref.off_by_on = 0; if (CALCULATOR) { // clock type pref.clock_type = pulldown_buffer[2] - 1; // battery if (pulldown_buffer[1] == 1) pref.battery_type = 1; else pref.battery_type = 0; // keyboard layout if (pulldown_buffer[3] == 1) pref.keyboard_layout = 1; else pref.keyboard_layout = 0; } // autostart / 2nd+MEM strncpy(pref.autostart_prgm, HeapDeref(e), 17); pref.autostart_prgm[17] = 0; strncpy(pref._2nd_MEM, HeapDeref(f), 17); pref._2nd_MEM[17] = 0; strncpy(pref._2nd_CHAR, HeapDeref(g), 17); pref._2nd_CHAR[17] = 0; } error: // free all elements if (a) HeapFree(a); if (b) HeapFree(b); if (c) HeapFree(c); if (d) HeapFree(d); if (e) HeapFree(e); if (f) HeapFree(f); if (g) HeapFree(g); if (dlg) HeapFree(dlg); if (pop1) HeapFree(pop1); if (pop2) HeapFree(pop2); if (pop3) HeapFree(pop3); return (dlg_ret_val == KEY_ESC ? 0 : 1); } // ----------------------------------------------------------------- // // Dialog callback function, used for the options dialog // ----------------------------------------------------------------- // // input: // Message = message // Value = value of this message // return: // Handle of the correct item // ----------------------------------------------------------------- // CALLBACK short Callback(short Message, long Value) { if (Message == DB_GET_EDIT_HANDLE) { if (Value == 1) return a; if (Value == 2) return b; if (Value == 3) return c; if (Value == 4) return d; if (Value == 5) return e; if (Value == 6) return f; if (Value == 7) return g; } return 1; }; // ----------------------------------------------------------------- // // Popup callback function, used for the options dialog // ----------------------------------------------------------------- // // input: // ID = ID of the requested popup // return: // Handle of the correct popup // ----------------------------------------------------------------- // CALLBACK HANDLE PopupCallback(short ID) { if (CALCULATOR) { if (ID == 8 || ID == 9 || ID == 11) { return pop1; } if (ID == 10) { return pop2; } if (ID == 12) { return pop3; } } else { return pop1; } return H_NULL; } // ----------------------------------------------------------------- // // Loads the configuration from a file // ----------------------------------------------------------------- // // local: // backup = config structure // file = file structure // chcksm = file checksum // backup_file_magic = file magic // return: // TRUE, or, in case of an error, FALSE // note: // If there's no config file, a new one with default values will // be created // ----------------------------------------------------------------- // short loadBackup(void) { OPTIONS backup; FILES file; unsigned char chcksm; unsigned char backup_file_magic[strlen(OPTIONS_FILE_MAGIC)+1]; // unarchive the file EM_moveSymFromExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL); // open the backup file if (FOpen(OPTIONS_FILE_NAME, &file, FM_READ, "cfg") != FS_OK) { default_all_settings(); // open the backup file if (FOpen(OPTIONS_FILE_NAME, &file, FM_WRITE, "cfg") != FS_OK) { ST_helpMsg(MSG_ERROR_CREATE_FILE); return FALSE; } // write the file magic if (FWrite((void*)OPTIONS_FILE_MAGIC, strlen(OPTIONS_FILE_MAGIC), &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_WRITE_TO_FILE); return FALSE; } // write backup if (FWrite((void*)&pref, sizeof(OPTIONS), &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_WRITE_TO_FILE); return FALSE; } // calculate checksum unsigned char chcksm = checksum((void*)&pref, sizeof(OPTIONS)); // write the checksum if (FWrite((void*)&chcksm, 1, &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_WRITE_TO_FILE); return FALSE; } FClose(&file); // archive the file EM_moveSymToExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL); return TRUE; } // read the file magic backup_file_magic[strlen(OPTIONS_FILE_MAGIC)] = 0; if (FRead((void*)backup_file_magic, strlen(OPTIONS_FILE_MAGIC), &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_READ_FROM_FILE); return FALSE; } // check file version if (strcmp(OPTIONS_FILE_MAGIC, backup_file_magic) != 0) { FClose(&file); ST_helpMsg(MSG_ERROR_OUTDATED_FILE); return FALSE; } // read the file content if (FRead((void*)&backup, sizeof(OPTIONS), &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_READ_FROM_FILE); return FALSE; } // read the checksum if (FRead((void*)&chcksm, 1, &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_READ_FROM_FILE); return FALSE; } // check checksum if (checksum((void*)&backup, sizeof(OPTIONS)) != chcksm) { FClose(&file); ST_helpMsg(MSG_ERROR_CORRUPTED_FILE); return FALSE; } // close the file FClose(&file); pref = backup; // archive the file EM_moveSymToExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL); return TRUE; } // ----------------------------------------------------------------- // // Calculates a simple 1-byte-checksum of the provided data // ----------------------------------------------------------------- // // local: // md5 = MD5 structure // res = 16 byte MD5 checksum // return: // first byte of MD5 checksum // note: // only one byte of the 16-byte MD5 checksum will be used // ----------------------------------------------------------------- // unsigned char checksum(void* data, unsigned short bytes) { unsigned char res[16]; MD5_CTX md5; // get MD5 hash of the data MD5Init(&md5); MD5Update(&md5, data, bytes); MD5Final(res, &md5); // we just use the first byte of the 16 byte long MD5 hash return res[0]; } // ----------------------------------------------------------------- // // Saves the configuration ot a file // ----------------------------------------------------------------- // // local: // file = file structure // return: // TRUE, or, in case of an error, FALSE // note: // Any old file will be overwritten // ----------------------------------------------------------------- // short saveBackup(void) { FILES file; // unarchive the file EM_moveSymFromExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL); // open the backup file if (FOpen(OPTIONS_FILE_NAME, &file, FM_WRITE, "cfg") != FS_OK) { ST_helpMsg(MSG_ERROR_CREATE_FILE); return FALSE; } // write the file magic if (FWrite((void*)OPTIONS_FILE_MAGIC, strlen(OPTIONS_FILE_MAGIC), &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_WRITE_TO_FILE); return FALSE; } // write backup if (FWrite((void*)&pref, sizeof(OPTIONS), &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_WRITE_TO_FILE); return FALSE; } // calculate checksum unsigned char chcksm = checksum((void*)&pref, sizeof(OPTIONS)); // write the checksum if (FWrite((void*)&chcksm, 1, &file) != FS_OK) { FClose(&file); ST_helpMsg(MSG_ERROR_WRITE_TO_FILE); return FALSE; } FClose(&file); // archive the file EM_moveSymToExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL); return TRUE; } /// ----------------------------------------------------------------- // // Checks for weird values of the configuration // ----------------------------------------------------------------- // // note: // Does not check all options, only the timers // ----------------------------------------------------------------- // void check_for_limits(void) { if (pref.keydelay < 2) pref.keydelay = 2; if (pref.keydelay > 600) pref.keydelay = 600; if (pref.scrolldelay < 2) pref.scrolldelay = 2; if (pref.scrolldelay > 200) pref.scrolldelay = 200; if (pref.cursor_rate < 1) pref.cursor_rate = 1; if (pref.cursor_rate > 200) pref.cursor_rate = 200; if (pref.apd < 20) pref.apd = 20; if (pref.apd > 20*20*60) pref.apd = 20*20*60; } // ----------------------------------------------------------------- // // Sets all settings to their default values // ----------------------------------------------------------------- // // note: // The settings may not directly take influence. You need to // call first. // ----------------------------------------------------------------- // void default_all_settings(void) { pref.scrolldelay = 18; pref.keydelay = 50; pref.cursor_rate = 6; pref.apd = 120*20; pref.auto_add_brackets = 1; pref.clock_type = 0; pref.battery_type = 1; pref.keyboard_layout = 0; pref.autostart_prgm[0] = 0; pref._2nd_MEM[0] = 0; strcpy(pref._2nd_CHAR, "main\\easychar"); pref.off_by_on = 1; }