RMEnsure from Code
Andy S (2979) 504 posts |
I’ve been asked to improve the efficiency of my USBDriver version check (it was a bit of a kludge): /* At time of writing, version 0.25 and up of the USBDriver has a "feature" that sends 5 scroll events per mouse wheel step */ system("Set Paint$ScrollFix 1"); system("RMEnsure USBDriver 0.25 Set Paint$ScrollFix 0"); char scroll = '1'; wimpt_complain (os_swix5 (OS_ReadVarVal, "Paint$ScrollFix", &scroll, sizeof(char), 0, 0 )); system("Unset Paint$ScrollFix"); ftracef1("Paint$ScrollFix: %c\n", scroll); scrollFix = scroll != '0'; I see the usual way to run a *Command from code in RISC OS is SWI OS_CLI (which is wrapped in os_cli()) and I also realise that I can set and unset my variable with SWIs, so this is my first attempt at clean-up (Note: I’ve not tried to run this code): /* At time of writing, version 0.25 and up of the USBDriver has a "feature" that sends 5 scroll events per mouse wheel step */ int scroll = 1; wimpt_complain (os_swix5 (OS_SetVarVal, "Paint$ScrollFix", &scroll, sizeof(int), 0, 1 )); wimpt_complain(os_cli("RMEnsure USBDriver 0.25 Set Paint$ScrollFix 0")); wimpt_complain (os_swix5 (OS_ReadVarVal, "Paint$ScrollFix", &scroll, sizeof(int), 0, 0 )); /* Delete the variable */ wimpt_complain (os_swix5 (OS_SetVarVal, "Paint$ScrollFix", 0, -1, 0, 1 )); ftracef1("Paint$ScrollFix: %c\n", scroll); I was a little surprised to learn that the platform independent system() function is inefficient in RISC OS, causing the program to be swapped out of memory. I would have thought it should be implemented as an alias or wrapper of OS_CLI. I’m asking about the above code as a learning exercise, as ROOL have already suggested a one line way to achieve this (the USBDriver provides an SWI USBDriver_Version). Is there any other way to simplify the above operations further? I gave up looking for an SWI to do RMEnsure before. OS_Module doesn’t seem to support that directly (short of trying to examine the module’s memory), or does it? Other than that, is there any way I can improve my os_cli() call to eliminate my Paint$ScrollFix variable and check a return value more directly? I wanted to find the answers to this myself but the documentation just doesn’t seem to have what I need here sadly. Is there a way to get a return value from a *Command? |
Jeffrey Lee (213) 6048 posts |
os_error *err = os_cli("RMEnsure USBDriver 0.25"); if (err != NULL) { // scroll fix needed } If you do a RMEnsure without a command to execute on failure, it will generate an error instead. So you can check for that and completely avoid using system variables.
Yeah, that’s always been a bugbear of mine. I’ve thought about adding a “get module version number” SWI in the past, but without a RISC OS 5 version of CallASWI (or similar) it would be awkward for developers to make use of because they wouldn’t be able to rely on it being universally available.
Technically using USBDriver_Version would be wrong, since that SWI first appeared in version 0.49 of the module. But since both Paint and USBDriver are typically supplied in ROM (making it very hard to run mismatched versions), you probably don’t need to worry about the case where someone is running a new Paint with an old USBDriver. So you could use USBDriver_Version as a “Is USBDriver loaded?” check and ignore the version number itself (until we implement better scroll behaviour). (The obvious place where Paint won’t be in ROM is RISC OS 3.5, for which you’d be using the Paint supplied in the disc image, but the Castle USB stack won’t run on 3.5, so detecting if USBDriver is loaded should be sufficient) |
Chris Evans (457) 1614 posts |
I’m not sure how many people would do this with Paint but I regularly use a 2017 build of Edit on RISC OS 3.7 & 4.02 RPCs. Paint, Draw, Edit etc are in the RO350Hook directory of current disc image downloads. |
Rick Murray (539) 13840 posts |
The system() call needs to move the current program out of the way. RISC OS has no concept of multiple tasks, so if the thing you were attempting to do called another program, it would overwrite the current (as they all begin at &8000). In this situation, I would be inclined to do something like: __asm { MOV R0, "RMEnsure etc etc" SWI XOS_CLI, {R0}, {}, {LR, PSR} } Because you know it’s a system internal command and is safe. Pick up flags and return registers as required. There is an OS_Module command to return a module version. It’s something annoying like BCD or hex, but it is there. |
Andy S (2979) 504 posts |
Informative as always, thanks Jeffrey. I’ve added a sentence to RMEnsure documentation in the Notes as to me it wasn’t immediately obvious what it does when no command is supplied. |
Andy S (2979) 504 posts |
so if the thing you were attempting to do called another program, it would overwrite the current (as they all begin at &8000). Are you also implying someone could pass a program name to system() to execute (rather than a *Command) but not to OS_CLI? Or rather, that you could pass a program name to either, but in the second case it will erase the current program? |
Andy S (2979) 504 posts |
I’ll keep the RMEnsure version check Chris, so it will work on all configurations of machine. |
Jeffrey Lee (213) 6048 posts |
OS_Module 20? It only works with ROM modules, and you have to go through the enumeration to find the module you want instead of just specifying the module name directly.
This. |
Rick Murray (539) 13840 posts |
The actual RMEnsure parses the version string into a BCD form for comparison: https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Kernel/s/MoreComms?rev=4.8#l498 |