mailto: blog -at- heyrick -dot- eu

Navi: Previous entry Display calendar Next entry
Switch to desktop version

FYI! Last read at 18:14 on 2024/11/21.

ROOL forums and off-topic posts

Just a quick note - I am likely to be a little less helpful around there. This is because I had seen the forums as a place not only for help and assistance with RISC OS and related matters, but also with the "Aldershot" forum for non-RISC OS related stuff, to discuss random things with people who were reasonably intelligent and held similar interests. Recently, it was brought to everybody's attention that such "off topic" content is too difficult for some people to skip over (as if everything else posted is always of great interest to everybody - some things are specific to certain problems or situations and just won't apply to others; if one can skip that, why not other stuff of no interest?). When I pointed this out, the reply was that I was the major creator of off-topic content. Okay, point made. I'll give up participating in the off-topic stuff, as I very much doubt anybody is going to tweak the forum code to display Recent Posts with and without it (for those who don't want).
Now me saying I'm going to be less helpful is not me in a strop or sulking. It is a natural consequence of if I'm going to consider the forum from now on purely as a place for help and assistance regarding RISC OS, then I don't really need that much help, so I will only be visiting the forum once or twice a day, if that. Instead of once or twice an hour when I wasn't otherwise occupied (yeah, I know, sad...).
Funnily enough, in the ~week I've cut back on participation, I suddenly find I have more time free to do other things. ☺

It is worth noting that David Boddie said (in a topic that was not only off-topic itself, but went on longer than the Islamophobia topic that triggered it):

For example, there may well have been people who joined the discussion about Brexit with the idea that, because they share similar computing preferences to the others in the forum, they would agree on that topic as well. As a result of that discussion, perhaps they don’t feel like participating here so much.
The two obvious points to raise are firstly that Brexit is going to have a huge impact on the United Kingdom. Not one single day goes by that something to do with it is mentioned in the news. Plus, the winning result was slightly over half, which means slightly under half are opposed to this, and I think anybody with a brain should be opposed to the shambolic way negotiations are being handled. Pretending Brexit doesn't exist won't cause it to go away, and I'd rather discuss aspects of it with intelligent people than those who are going to shout down every plausible problem with it by quoting their choice selection of mantra. Yes, there are other places to talk about it. But if you look at the sorts of comments you get in the Daily Mail, Express, etc - there are not so many places where anybody is even remotely interested in discussing it in a proper adult manner.
Secondly, it is rather childish of a person to assume that "because you like X, you'll like Y as well". I know one of the forum members is Big On Beer (not as in drinking, as in appreciating its qualities). I hate the stuff. I wrote the code below to a selection of Nightwish, Within Temptation and Kalafina (yes, really). Some people might me "oh my God, learn to enjoy Radio Two". We all have something in common, which is good, but it is ridiculous to expect other people to be facsimiles of ourselves.
I liked the forums because the average member wasn't a halfwit. Wander into Usenet, you'll meet plenty of people who would struggle to quality as even a quarterwit. Fancy trying to discuss something reasonable with them? No thanks.

The thing is, though, that the indirect chilling effect of frowning on off-topic messages has had a negative effect on the forums. In a topic about Omniclient, Chris Mahoney was asking about whether or not Omni can deal with NFS shares. It seems that Sunfish could do it but was a bit crashy. He ended with:

It’s better than it was, but is still crashing frequently. But this isn’t a Sunfish thread so I’ll leave it for now!
He didn't start a new thread. Now the problem here is that while Chris was indeed posting to a thread entitled "An idiot's guide to OmniClient", he had a very specific requirement that he wanted to achieve - to get his RISC OS machine talking to an NFS share. If Omni isn't up to it, then obviously the thread is going to deviate to alternative options. And if the alternative is crash-prone, is it so bad to see if there is anything that could help? For all we know, it could be a simple setting - maybe something obscure like the ShareFSWindow trick. Instead, continuing was deemed "off topic" and the discussion ended. Chris is probably still using a crashy Sunfish, his problem wasn't properly resolved, and if anybody else has a similar need, there's only half an answer to point them at...

Well, I guess I should have posted this to the forum...but it would have been off-topic...

 

ARGH! WE'RE ALL GOING TO DIE! ARGH!

In a topic on Aldershot (that I didn't participate in because...), Xavier Louis Tardy said:
I prefer to play ‘Doctor Doom’ and bring this info, even if not that serious, than keeping it for myself and hear later on that you have suffered from my keeping it for myself, so please read this :
http://enenews.com/fears-of-a-major-nuclear-accident-reuters-radioactivity-levels-surged-to-1000-times-normal-in-russia-ap-extremely-high -contamination-concerns-over-govt-cover-up

Which is fair enough, and it has already been covered in the press (anomalous radiation readings and nobody knows why). My own thought at the time was to wonder if the Chernobyl sarcophagus had failed.

He then continued:

I do not think I need to tell you not to eat anything fresh growing in the air, and no mushrooms, sage, thym, whatever and no milk ...
and staying inside, closing all ventilations too, could be not that stupid after all.
The youngest the weakest, as you know with cell replications.

Which is just scare-mongering. Our ability to detect radiation means that we can easily detect that which will have less of a health impact than sleeping in a house built of granite. That isn't to say there is no danger - however it must be borne in mind that quite a few of the nuclear tests that took place in Nevada in the latter half of the last century were specifically conducted so that the radioactive cloud would dump its isotopes in eastern Nevada, all over Utah, into Idaho, Oregon, and Washington. Why? To measure and understand the effects of radiation on the populace. You gotta love the US government's pragmatic "screw you" approach to the well-being of its citizens. And yes, isotopes were found in food, bodies, and birth defects happened as well. Some of them bad enough (estimated 10,000-75,000 cases of thyroid cancer and potentially 2,000 cases of leukaemia) to led to an eventual ban on such testing. After 41 years, 100 above ground detonations, and 921 underground (venting to the exterior) detonations. After all of that, the Nevada site is a radioactive wasteland, but Utah is still inhabited, as are many places downwind of the test site. Around the same time frame, the Russian site at Novaya Zemlya was host to around 130 tests, including the above-ground detonation of the Tsar Bomba, stepped back from its theoretical 100MT yield to a mere 50MT yield. It pretty much destroyed everything in a 100km radius of the detonation site - the mushroom cloud reached 64km (~40 miles) high, with a width of around 95km (~60 miles) and a base of 40km (~25 miles). To give an idea of the power of this bomb, a thermal pulse was observed at a distance of 270km (~170 miles), an air shock wave was observed 700km (~430 miles) away, and windows were broken a staggering 900km (560 miles) away. Despite a detonation of approximately 4km up, and the cushioning effect of the bombs own blast wave being reflected back at itself, the seismic effects registered a little over 5, and sensors continued reporting the shock waves for three trips around the world. As you can imagine, that detonation in 1961 dumped radiation across the northern hemisphere.

Consequently, the radiation that is in existence today, while not exactly an encouraging thing, is a far cry from the '50s and '60s when both sides of the Cold War were actively detonating nuclear weapons above ground.

As to the second quote of Xavier, I think we have a lot more to fear from fresh produce being sprayed by Imidazole compounds (mould retardant), synthetic weedkillers that were ultimately derived from variations of Agent Orange, washed with unclean (faeces contaminated) water...
Milk? Shall we discuss the antibiotics? Shall we discuss the hormones given to cows to keep them producing milk? If you have a wife or girlfriend, are her breasts full of milk? Probably not, it's a thing called lactation and it happens so animals (from cats to humans) can nourish their young. Human females lactate after giving birth. Well, it's the same with cows. Only since cow milk is useful to humans, humans have found ways of ensuring that the cows always have full udders.
Closing all ventilation in a modern home is not smart. Too many plastics and other synthetic materials.

Better advice? Keep an eye on the story in case it turns out to be terrorists bringing in materials to set off a dirty bomb in some European capital, otherwise continue pretty much as before.
And eat organically produced food...

 

FirmwareID

A little while back, on the RISC OS forum, I posted a small program to identify RISC OS ROM images. It was in response to a question regarding how to ID the various images.

We are greatly helped in this endeavour by the fact that the core kernel (the 'hidden' "RISC OS" module) is never compressed, so we don't need to mess around with decompressing the ROM or reading an information block which may or may not be present. We simply perform some rudimentary pattern matching to identify what machine the particular ROM is for, then some more pattern matching to find the RISC OS module to extract the version and the build date.

The source code, with comments, runs to about 30K. The program built from it is a compact 2208 bytes, a little over 2K.

 

Stylistic notes:

 

Okay then, let's get on with it!

As always, we begin with comments describing the program, what it does, how to use it, and the licence that applies to the source. In this case, the program is open source, released under the CDDL - which is like the famous GPL, only proper "open".

; FirmwareID  v0.02
; ==========
;
; Little program to identify a RISC OS firmware.
;
; Syntax: FirmwareID 
;
;
; CDDL HEADER START
;
; The contents of this file are subject to the terms of the Common Development and Distribution License (the "Licence").
; You may not use this file except in compliance with the Licence.
;
; You can obtain a copy of the licence at:
; https://www.riscosopen.org/viewer/view/~checkout~/cddl/RiscOS/Sources/FileSys/SDFS/SDFS/LICENCE?rev=1.1.1.1
; See the Licence for the specific language governing permissions and limitations under the Licence.
;
; When distributing Covered Code, include this CDDL HEADER in each file and include the Licence file. If applicable, add the
; following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information:
; Portions Copyright [yyyy] [name of copyright owner]
;
; CDDL HEADER END
;
; Copyright 2017 Richard Murray.  All rights reserved.
; Use is subject to license terms.
;

The next thing to set up is the AREA name (required for applications that are to be linked, and no, the XX-McXXface joke isn't going to die away just yet.
Then we call in the SWI name definitions file. This is copy-pasted from the one supplied with the DDE, you'll find it (in DDE28) at ...Sources.DDE-Examples.ObjAsm.AsmHdrs.h.SWINames.

If you don't have the DDE and want to try building this with GCC or Nick Roberts' assembler, you can use the SWI definitions that I built for DeskLib32. Pick up a copy here.
It is not directly compatible. Every SWI name is prefixed by "SWI_" and there are no X-form SWIs, you need to add the "XOS_Bit" to the number. For instance "XOS_File" would become "(SWI_OS_File + XOS_Bit)". But it's better than nothering if you don't have a list of SWI definitions to hand...

        AREA    |codey$mccodeface|, CODE, A32bit ; no, that joke isn't going to go away...

        GET     ^.h.swinames

Next, define some values. We set up TRUE and FALSE, then number the detected devices, and the vector state. Finally, we give names to registers R9 through R12, which hold global state.

        ; Define that which is truth and that which is fake news
TRUE    * 1
FALSE   * 0                       ; I was tempted to call this one "BREXIT" or "TRUMP" or something

        ; Detected builds
UNKNOWN * 0
IOMD    * 1
IYONIX  * 2
OMAP3   * 3
OMAP4   * 4
TITANIC * 5                       ; Titanium didn't fit, Titanic did ;-)
PI      * 6
PIPICO  * 7
        ; Detected vector placement
VECIRLV * 0                       ; Means CP15 instruction not found, so vector stuff irrelevant on this machine
VECLOW  * 1                       ; Low vector (old-style) OS
VECHIGH * 2                       ; High vector (new-fangled) OS

        ; Global register allocations
WrkEnd  RN  9                     ; Pointer to END of workspace
WrkPtr  RN 10                     ; Pointer into workspace (64K) [note: NOT pointer TO workspace!]
FlSize  RN 11                     ; File size (for Pico detection)
FlName  RN 12                     ; Pointer to filename (from OS_GetEnv, READ ONLY)

Now we're on to the program proper. ENTRY tells the linker where the program starts (as it automatically adds a valid AIF header for us).
The next section of code looks at how much memory we have. If our program is a little over 2K, we use a 64K buffer, and some stack space, we will request 72K (perhaps 68K would be enough, but it's better to err on the side of caution).
One complication is that the OS_GetEnv returns our memory limit. That is to say, the physical location of the end of our available memory. This is a complication as every application starts at the address &8000, not at zero, so the value will be 32K larger than the actual amount of memory available. The addressing range from zero to 32K is traditionally used for system workspace and various buffers and stuff, however on a high vector ROM build, there just won't be anything there. Essentially, the first 32K is off limits to applications.
If there isn't enough memory, we call the Wimp_SlotSize command to give ourselves 72K. If this fails (no memory or Wimp not present (as in Pico)), we bail out. Otherwise we call OS_GetEnv again to read the updated end address.
This address is where we place the stack, for the stack descends from the topmost address downwards. In theory it would crash into the top of the file workspace, however since we have a 72K allocation, 64K workspace, and a program a little over 2K, this means we have a little under 6K for the stack. That's way more than we need, so everything is fine.

        ; Allons-y! [would you like a jellybaby?]
entry_point
        ENTRY


; ************************************************
; *                                              *
; * INITIALISE - Set up memory and validate file *
; *                                              *
; ************************************************


        ; Get our memory allocation and parameter
        SWI     XOS_GetEnv
        MOV     R13, R1           ; Stash RAM limit in R13

        ; Do we have enough memory? We need at least 72K.
        ;    <64K workspace> 
        SUB     R1, R1, #(1<<15)  ; Subtract page zero, it's a limit from zero, not a size.
        MOV     R4, #(1<<16)      ; 64K
        ADD     R4, R4, #8192     ; +8K = 72K
        CMP     R1, R4            ; Compare corrected size with how much we want
        BHS     start_continue    ; Memory amount is higher or same, so we're good to go.

        ; If we're here, it's because we have less than 72K available. Ask for more...
        MOV     R0, R4            ; The 72K we want
        MOV     R1, #-1           ; Not interested in the Next slot
        SWI     XWimp_SlotSize
        BVS     not_enough_memory ; Didn't work, abort.

        CMP     R0, R4            ; Did we get 72K? [RISC OS 2 corrupts R4, but nobody is using that, right?]
        BLO     not_enough_memory ; If not, abort.

        SWI     XOS_GetEnv        ; Get updated end of memory and refresh command line pointer
        MOV     R13, R1

        ; Fall through to...

Now we must validate the file. As we expect to be called like:
FirmwareID some.path.to.a.file
we simply scan through the command line looking for a space. If we find a space, what follows is assumed to be a filename.
We print a short message that quotes this filename back to the user (useful in case it fails due to typo or trailing space, etc).
Then we read the catalogue info for the object to verify that it exists and is a file. Anything under 512K is faulted immediately - that value was chosen because RISC OS 3 images saved as four ROMs are saved as 512K chunks.
We remember the file size, we may need it later.

Because we have made it to this point, we stash our return address on the stack. This means we should return by retrieving the value from the stack, not making assumptions about R14. This is especially so as from now we can call functions.

start_continue
        ; Remember our return address
        STR     R14, [R13, #-4]!

        ; Look for a ' ' in command line
        MOV     FlName, R0        ; R12 = Pointer to string
start_where_space
        LDRB    R5, [R12], #1     ; R5 = byte at StringPtr, auto-increment StringPtr after
        CMP     R5, #32
        BEQ     start_found_space ; Continues after the messages
        CMP     R5, #0
        BNE     start_where_space

        ; Fall-through if we get to a terminull without finding a space.
start_file_fail
        ADRL    R0, error_no_file
        SWI     OS_Write0
        LDR     PC, [R13], #4     ; ==> EXIT


start_found_space
        ; Print an init message
        ADRL    R0, msg_init_prefix
        SWI     OS_Write0
        MOV     R0, FlName
        SWI     OS_Write0
        ADRL    R0, msg_init_suffix
        SWI     OS_Write0


        ; Now verify that this is a valid filename
        MOV     R0, #17           ; Read catalogue information for file, no path
        MOV     R1, FlName
        SWI     OS_File
        ; R0 = object type (0-not, 1-file, 2-dir, 3-file/dir)
        ; R2 = load
        ; R3 = exec
        ; R4 = length, we'll want this later
        ; R5 = attributes

        CMP     R0, #1            ; Was it a file? Bork if not.
        BNE     not_a_file        ; (code is above, after error messages)

        MOV     FlSize, R4        ; Preserve file size

        CMP     FlSize, #(1<<19)  ; Anything under 512K is definitely bogus (under 2M is suspect!)
        BLO     file_too_small    ; (code is above after messages)

        ; If we're here, then the command line parameter appears to be a file of at least 512K size.

Now it starts to get interesting. We load the first 64K of the ROM image file into our workspace. On RISC OS 5 builds, this is where the HAL lives. Then we look at the value of the very first word. This tells us a lot.

To make our matching easier, we shift the value sixteen bits to the right, then sixteen bits to the left. This has the effect of discarding the least significant two bytes (represented as "xxxx" above).

If it is a branch, we look to see if it's an Iyonix or not. The Iyonix has a recovery loader located at the start of the ROM image, so if we see that, we know it's an Iyonix ROM. If we don't, we have to keep digging.

If it is a branch of the ARM2/ARM3 type, we bomb out with a message. I suppose we could jump straight to looking for the RISC OS module to identify the version, but we'd also need to look for the Arthur module too, so rather than complicate things, we'll just throw in the towel if we spot this.

If it's not an LDR PC instruction, it is probably a Titanium. We look for "SPRO" as the sixth word, from the embedded message "(C)2014 SPROW". Otherwise, we assume it's the IOMD build, and if this is the case, we need to check for the RISC OS module in the first chunk as the 26 bit builds of RISC OS (3.5 through to the ROLtd Select/Adjust versions) don't have a HAL so the module will appear in the first 64K.

; ********************************************
; *                                          *
; * POKE AROUND WITHIN THE HAL (first chunk) *
; *                                          *
; ********************************************

        ; Okay, so now we have a pointer to a valid file (name in FlName (R12), size in FlSize (R11))
        ; so let's load the first 64K and see what we can see...
        MOV     R0, #0            ; First 64K chunk
        BL      load_chunk

        ; The first 64K is the HAL and some other workspacey stuff. It is here that we
        ; will be identifying the image device information by basic pattern matching.


        ; Set up pointers
        ADRL    WrkPtr, workspace
        ADD     WrkEnd, WrkPtr, #(1<<16)

        MOV     R0, #UNKNOWN      ; Device is unknown until we know otherwise (then it's a known known,
        ADRL    R1, devicetype    ; not an unknown known or a known unknown or... wait, I'm confused...)
        STRB    R0, [R1]


        ; Look at the first word
        LDR     R0, [WrkPtr]
        MOV     R1, R0, LSR#16    ; These two, same as
        MOV     R1, R1, LSL#16    ;   AND R1, R0, #&FFFF0000

        ; It will be:
        ;   &EAE0xxxx -> B     &FFxxxxxx           -> 26 bit Archimedes era
        ;   &EA00xxxx -> B     &xxxxxxxx           -> Modern SoC / Iyonix softload
        ;   &E59Fxxxx -> LDR   PC, &xxxxxxxx       -> IOMD
        ;   &00000000 -> ANDEQ R0, R0, R0, LSL #16 -> Titanium

        ; Is it a modern SoC image or an Iyonix softload?
        LDR     R2, firstword_branch
        CMP     R1, R2
        BEQ     is_it_iyonix         ; IS a branch, but Iyonix does that too, so check this

        ; Is it an Archimdes (ARM2/ARM3) image? You know somebody's gonna try...
        LDR     R2, firstword_archie
        CMP     R1, R2
        BEQ     oh_ffs

        ; Is it an IOMD softload image?
        LDR     R2, firstword_ldrpc
        CMP     R1, R2
        BNE     is_it_titanium       ; NOT an LDR PC, so is it a Titanium?

        ; If here, it's the IOMD build
        ADRL    R0, devicetype
        MOV     R1, #IOMD
        STRB    R1, [R0]
        B       check_for_riscos_here; Image ID'd (IOMD), so see if RISC OS is here.

is_it_titanium
        ; Is it a Titanium FlashROM image?
        LDR     R2, firstword_andeq
        CMP     R1, R2
        BNE     keep_digging_for_device_identity ; Not a Titanium, so let's try harder.

        ; A file of NULLs would match the above test, so look for Sprow ID
        ; I like how he starts the ID string "(C)2014", or: bracket, C, bracket, year (no space).
        ; It's very BBC MOS, isn't it?
        LDR     R1, [WrkPtr, #&14]
        LDR     R2, sixthword_sprow
        CMP     R1, R2
        BNE     keep_digging_for_device_identity ; Not a Titanium, so let's try harder.

        ; If here, it's the Titanium FlashROM build
        ADRL    R0, devicetype
        MOV     R1, #TITANIC
        STRB    R1, [R0]
        B       examine_second_chunk ; Image ID'd (Titanium), so go look at the second chunk

is_it_iyonix
        ; An Iyonix has a recovery loader near the start of the first chunk, so let's whizz
        ; through looking for that.
        ADRL    R0, iyonix_words
        LDMIA   R0, {R3, R4}      ; R3 is first word to check, R4 is second

        MOV     R0, R3            ; Set up to look for the first word
        BL      scan_prepare      ; Start at the beginning

iyonix_keep_going
        BL      scan_workspace    ; Look for it
        BEQ     keep_digging_for_device_identity

        ; First word found, so check the second word
        LDR     R0, [WrkPtr]
        CMP     R0, R4
        BNE     iyonix_keep_going ; Keep on looking


        ; Fall though if tests are good
        ADRL    R0, devicetype
        MOV     R1, #IYONIX
        STRB    R1, [R0]
        B       examine_second_chunk ; ID'd, so go look at the second chunk

As said above, the 26 bit versions of RISC OS for IOMD hardware will not have a HAL, so the hidden "RISC OS" module will appear in the first chunk. So we need to check to see if this is the case, and if it is, jump to looking for the module version and date.

check_for_riscos_here
        ; IOMD build versions of Acorn-era RISC OS have no HAL, so the hidden RISC OS
        ; module is present earlier, in the first chunk. So if we can find the RISC OS
        ; module in this, first, chunk, skip directly to the information reading part
        ; without loading the second chunk. It doesn't matter if we ignore the vector
        ; high/low tests, IOMD doesn't do this anyway.
        ADRL    R0, kernelwords   ; Load kernel ID words
        LDMIA   R0, {R3-R6}
        BL      scan_prepare

early_module_scan_loop
        MOV     R0, R5            ; -> "RISC"
        BL      scan_workspace
        BEQ     examine_second_chunk ; Can't find kernel in IOMD build? Probably a HAL version...

        ; "RISC" found, so check second word to see if it's the module.
        LDR     R1, [WrkPtr]
        CMP     R1, R6            ; -> " OS"
        BNE     early_module_scan_loop ; If not, keep going.
        B       module_early_entry; Otherwise, jump to deal with it.

If the device has not been identified yet (other than an ARM SoC), we will need to dig a little deeper by performing some pattern matching by scanning the HAL.

FirmwareID cannot identify iMX6 ROM images. This is because there are no such images available from the RISC OS Open website.

keep_digging_for_device_identity
        ; We come here after preliminary examination of the device. Device type will be
        ; identified as IOMD, Titanium, or unknown. If unknown, we need to dig deeper.

        ; Look to see if the device has already been identified (IOMD or Titanium).
        ; If it has, skip the identity checks.
        ADRL    R0, devicetype
        LDRB    R1, [R0]
        CMP     R1, #0
        BNE     examine_second_chunk ; If we have a device ID, look for the remaining fun stuff.

        ; Okay, so let's see what this image is for.

        ADRL    R0, devicewords   ; Load device ID words
        LDMIA   R0, {R3-R7}

        ; Is it an OMAP?

        BL      scan_prepare
omap_scan_loop
        MOV     R0, R3            ; -> "OMAP"
        BL      scan_workspace
        BEQ     try_pi            ; No "OMAP" found, so see if it's a Pi

        ; Check second word to see if we can ID which OMAP this is
        LDR     R1, [WrkPtr]
        CMP     R1, R4            ; OMAP3?
        BEQ     is_an_omap3
        CMP     R1, R5            ; OMAP4?
        BEQ     is_an_omap4

        ; Else, keep chugging along
        B       omap_scan_loop


is_an_omap3
        ADR     R0, devicetype
        MOV     R1, #OMAP3
        STRB    R1, [R0]
        B       examine_second_chunk ; Image ID'd (OMAP3), so go look at the second chunk

is_an_omap4
        ADR     R0, devicetype
        MOV     R1, #OMAP4
        STRB    R1, [R0]
        B       examine_second_chunk ; Image ID'd (OMAP4), so go look at the second chunk


try_pi
        ; Let's see if this is a Pi
        BL      scan_prepare
pi_scan_loop
        MOV     R0, R6            ; -> "BCM2"
        BL      scan_workspace
        BEQ     examine_second_chunk ; No idea, give up and look at the second chunk

        ; Verify the second word
        LDR     R1, [WrkPtr]
        CMP     R1, R7
        BNE     pi_scan_loop      ; No match, keep on looking

        ; Else...it IS a Pi
        ; But - wait - it might be the Pico build. Is the ROM exactly 2MB?
        ADR     R0, devicetype
        CMP     FlSize, #(1<<21)
        MOVEQ   R1, #PIPICO       ; Yes, it's a Pico.
        MOVNE   R1, #PI           ; Else it's a regular Pi.
        STRB    R1, [R0]

        ; Fall through to...

On the HAL builds, we now load the second 64K chunk from the file and we search for a specific instruction MCR CP15, 0, R8, C1, C0, which luckily for us, only appears once. If we find this instruction, we check the word prior to see if it is ORR R8, R8, #&2000. If it is, then this is a high vector build of RISC OS.
We know this, from the following part of the kernel startup code (the highlighted instructions are what we're looking for):

        ARM_read_control v5, NE
  [ CacheOff
        ORR     v5, v5, #MMUC_M                 ; MMU on
        ORR     v5, v5, #MMUC_R                 ; ROM mode enable
  |
        ORR     v5, v5, #MMUC_W+MMUC_C+MMUC_M   ; Write buffer, data cache, MMU on
        ORR     v5, v5, #MMUC_R+MMUC_Z          ; ROM mode enable, branch predict enable
  ]
  [ MEMM_Type = "VMSAv6"
        ORR     v5, v5, #MMUC_XP ; Extended pages enabled (v6)
        BIC     v5, v5, #MMUC_TRE+MMUC_AFE ; TEX remap, Access Flag disabled
        BIC     v5, v5, #MMUC_EE+MMUC_TE+MMUC_VE ; Exceptions = nonvectored LE ARM
      [ SupportARMv6 :LAND: NoARMv7
        ; Deal with a couple of ARM11 errata
        ARM_read_ID lr
        LDR     a4, =&FFF0
        AND     lr, lr, a4
        LDR     a4, =&B760
        TEQ     lr, a4
        BNE     %FT01
        ORR     v5, v5, #MMUC_FI ; Erratum 716151: Disable hit-under-miss (enable fast interrupt mode) to
                                   prevent D-cache corruption from D-cache cleaning (the other workaround,
                                   ensuring a DSB exists inbetween the clean op and the next store access
                                   to that cache line, feels a bit heavy-handed since we'd probably have
                                   to disable IRQs to make it fully safe)
        ; Update the aux control register
        MRC     p15, 0, lr, c1, c0, 1
        ; Bit 28: Erratum 714068: Set PHD bit to prevent deadlock from PLI or I-cache invalidate by MVA
        ; Bit 31: Erratum 716151: Set FIO bit to override some of the behaviour implied by FI bit
        ORR     lr, lr, #(1:SHL:28)+(1:SHL:31)
        MCR     p15, 0, lr, c1, c0, 1
        myISB   ,lr
01
      ]
  ]
  [ NoUnaligned
        ORR     v5, v5, #MMUC_A ; Alignment exceptions on
  ]
  [ HiProcVecs
        ORR     v5, v5, #MMUC_V ; High processor vectors enabled
  ]

MMUon_instr
; Note, no RAM access until we've reached MMUon_nol1ptoverlap and the flat
; logical-physical mapping of the ROM has been removed (we can't guarantee that
; the RAM mapping hasn't been clobbered, and SP is currently bogus).
        ARM_write_control v5

However, since the HAL versions of RISC OS use the same basic startup code, this instruction also appears on the IOMD builds of RISC OS, so if this is the case, we simply skip straight to looking for the RISC OS module.

; ***************************************
; *                                     *
; * READ THE VECTOR TYPE (second chunk) *
; *                                     *
; ***************************************


examine_second_chunk
        ; Okay, we're now going to load the second 64K chunk from this image.
        MOV     R0, #1
        BL      load_chunk

        ; The second chunk is the start of the OS image. It contains the generic bring-up code
        ; and the hidden "RISC OS" module (that preceeds "UtilityModule", it's the kernel!).
        ; The init code will tell us if this ROM is low or high vector; and the "RISC OS"
        ; module will give us the OS version and build date.
        ; This stuff is ALWAYS available, so we can read all of this information directly from
        ; the image regardless of whether or not the image is compressed, as the init code cannot
        ; be compressed as it's that which brings up the machine (the HAL is minimal by intent)
        ; and you can't compress the core kernel if it's that which decompresses the rest of the OS!
        ;
        ; That makes OUR job a heck of a lot simpler.


        ; First up, scan the kernel looking to see which vector type we have.
        ; Refer to: https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Kernel/s/HAL?rev=4.8.2.1#l855

        ADRL    R0, kernelwords   ; Load kernel ID words
        LDMIA   R0, {R3-R6}

        BL      scan_prepare
        MOV     R0, R3            ; -> MCR instruction to set up ARMv4 MMU
        BL      scan_workspace
        BEQ     find_riscos_module ; Skip ahead if instruction was not found.

        ; We don't need to loop this, the instruction appears only ONCE in the ROM image(s)

        ; However, it DOES appear in the IOMD build, which has no concept of high vectors (it does other stuff too)
        ; so if this image is for an IOMD device, skip ahead.
        ADR     R0, devicetype
        LDRB    R0, [R0]
        CMP     R0, #IOMD
        BEQ     find_riscos_module

        ; We found the MCR instruction, so initially flag this as a LOW vector build.
        ADRL    R0, vectortype
        MOV     R1, #VECLOW
        STRB    R1, [R0]

        ; Now back up to the word prior and load that
        LDR     R0, [WrkPtr, #-8] ; -8 because we have advanced to the next word
        CMP     R0, R4            ; Is it the ORR instruction?

        ; Okay, so we found the MCR and the ORR. This is a high vector ROM.
        ADREQL  R0, vectortype
        MOVEQ   R1, #VECHIGH
        STREQB  R1, [R0]

        ; Fall through to...

Now to look for the RISC OS module. We either code here directly from the IOMD check (in which case we'll be looking at the first chunk of a 26 bit image) or we fall through from above (in which case it'll be the second chunk of a 32 bit HAL image). We look for "RISC" (&43534952) followed by " OS<tab>" (&09534F20). When we spot that, we skip the second word, and the following tab, and throw the remainder at OS_ReadUnsigned. This will stop at a non-number, so we can read a version such as "5.23" as 5, then 23.
We advance a bit further and then string-copy the date. As explained in the comments, there is - oddly - no SWI call to interpret dates in the official RISC OS format ("dd MMM yyyy"), so instead of trying to make sense of the date, I kept it simple and just copied it verbatim.

; ***************************************
; *                                     *
; * FIND RISC OS VERSION (second chunk) *
; *                                     *
; ***************************************


find_riscos_module
        BL      scan_prepare

module_scan_loop
        MOV     R0, R5            ; -> "RISC"
        BL      scan_workspace
        BEQ     damaged_file      ; Can't find kernel? Damaged file?

        ; "RISC" found, so check second word to see if it's the module.
        LDR     R1, [WrkPtr]
        CMP     R1, R6            ; -> " OS"
        BNE     module_scan_loop  ; If not, keep going.


        ; Okay, we've found the module title of the "RISC OS" module.
        ; Format, as always, is "RISC OS5.23 (dd MMM yyyy)"

module_early_entry
        ADD     WrkPtr, WrkPtr, #5; Skip next word and the following (second) tab. WrkPtr is no longer word-aligned.
                                  ;                                                ================================
        MOV     R0, #10           ; Base 10
        MOV     R1, WrkPtr        ; Address
        SWI     XOS_ReadUnsigned  ; Convert major version (5.xx)
        ADRL    R4, versionmajor
        STRB    R2, [R4]          ; Save it
        ADD     R1, R1, #1        ; Address of terminating character (the '.'), skip over it.
        ; R0 preserved
        SWI     XOS_ReadUnsigned  ; Convert minor version now (x.23)
        ADRL    R4, versionminor
        STRB    R2, [R4]          ; Save it
        ADD     WrkPtr, R1, #2    ; Address of terminating character (the ' '), skip over it and following bracket

        ; I'm going to wimp out of parsing the date (in the standard format "dd MMM yyyy") into an ISO-8601 style
        ; date, as I've not found a command in the OS to convert such a string to ordinals or somesuch.
        ; There is Territory_ConvertTimeStringToOrdinals, and while it supports the conversion of two different date
        ; formats but - interestingly - does not cater for the date format mandated for every module and application
        ; Info window. Oversight much?
        ADR     R1, versiondate
date_loop
        ; Copy a byte
        LDRB    R0, [WrkPtr], #1
        STRB    R0, [R1], #1

        ; Reached the end?
        CMP     R0, #')'
        BNE     date_loop

        ; At the end, so poke a terminull in there instead
        MOV     R0, #0
        STRB    R0, [R1, #-1]

Some of the images are laid out a little differently. An example here is the OMAP3 (Beagleboard) where the code that sets up the vectors is further on in the image. Therefore, if the vector type is not yet known and it is not an IOMD build, load up the third 64K chunk of the file and scan in there. This is basically the same code as the previous vector type checking.

<

; *************************************************
; *                                               *
; * LAST-DITCH READ THE VECTOR TYPE (third chunk) *
; *                                               *
; *************************************************


        ; Some images (OMAP3, for example), are laid out differently. As a last ditch attempt, if
        ; no detected vector type and NOT the IOMD version, load the third chunk and look in there for it.
        ADRL    R0, vectortype
        ADRL    R1, devicetype
        LDRB    R0, [R0]
        LDRB    R1, [R1]

        CMP     R0, #VECIRLV      ; Vector unknown?
        BNE     report_spewage

        CMP     R1, #IOMD         ; Vector irrelevant on IOMD
        BEQ     report_spewage

        ; Load third chunk
        MOV     R0, #2
        BL      load_chunk

        ADR     R0, kernelwords   ; Load kernel ID words again
        LDMIA   R0, {R3-R6}


        BL      scan_prepare
        MOV     R0, R3            ; -> MCR instruction to set up ARMv4 MMU
        BL      scan_workspace
        BEQ     report_spewage    ; Skip ahead if instruction was not found.


        ; We found the MCR instruction, so flag this as a LOW vector build.
        ADRL    R0, vectortype
        MOV     R1, #VECLOW
        STRB    R1, [R0]

        ; Now back up to the word prior and load that
        LDR     R0, [WrkPtr, #-8] ; -8 because we have advanced to the next word
        CMP     R0, R4            ; Is it the ORR instruction?
        BNE     report_spewage    ; If not, drop out - the MCR we want only appears ONCE

        ; Okay, so we found the MCR and the ORR. This is a high vector ROM.
        ADRL    R0, vectortype
        MOV     R1, #VECHIGH
        STRB    R1, [R0]

        ; Fall through to...

Finally, some output. We start with lots of tests to determine what should be printed for the device type. Afterwards, the RISC OS version, using OS_ConvertCardinal1 to turn the numbers we read earlier back into strings for printing. I could have cheated with the first one and output the character of 48+majornumber, but this would fail should we ever hit RISC OS 10. For an example of why such assumptions are bad, go look up why the version of Windows that followed 8.x was 10, not 9. ☺
After writing out the date, we look to see if the vector type is known. If it is not, we exit immediately. If it is, we specify high or low as applicable. Then we exit.

; *****************************
; *                           *
; * REPORT WHAT WE DISCOVERED *
; *                           *
; *****************************


        ; Okay, we're done prodding around in the image. Time to tell the user what we found.
report_spewage

        ; Report the device type.
        ADRL    R0, report_one    ; "This ROM image is "
        SWI     OS_Write0

        ADR     R1, devicetype    ; Check device type
        LDRB    R1, [R1]

        CMP     R1, #TITANIC      ; If not Titanium or Pi...
        ADRLTL  R0, report_two    ; "for an "
        SWILT   OS_Write0

        ADRL    R0, report_type_unknown ; default
        CMP     R1, #IOMD
        ADREQL  R0, report_type_iomd
        CMP     R1, #IYONIX
        ADREQL  R0, report_type_iyonix
        CMP     R1, #OMAP3
        ADREQL  R0, report_type_omap3
        CMP     R1, #OMAP4
        ADREQL  R0, report_type_omap4
        CMP     R1, #TITANIC
        ADREQL  R0, report_type_titanium
        CMP     R1, #PI
        ADREQL  R0, report_type_pi
        CMP     R1, #PIPICO
        ADREQL  R0, report_type_pipico
        SWI     OS_Write0

        ; If Pico, append "for a Raspberry Pi" to it.
        CMP     R1, #PIPICO
        ADREQL  R0, report_type_pi
        SWIEQ   OS_Write0

        ; Now report the version
        ADRL    R0, report_three  ; "This RISC OS version is "
        SWI     OS_Write0
        ADRL    R0, versionmajor  ; Output major version number
        LDRB    R0, [R0]
        ADR     R1, workspace
        MOV     R2, #8
        SWI     OS_ConvertCardinal1
        SWI     OS_Write0
        SWI     OS_WriteI + '.'   ; '.'
        ADRL    R0, versionminor  ; Output minor version number
        LDRB    R0, [R0]
        ADR     R1, workspace
        MOV     R2, #8
        SWI     OS_ConvertCardinal1
        SWI     OS_Write0
        ADRL    R0, report_four   ; ", dated "
        SWI     OS_Write0
        ADR     R0, versiondate
        SWI     OS_Write0
        SWI     OS_WriteI + '.'
        SWI     OS_NewLine

        ; Should we report a vector type?
        ADRL    R1, vectortype    ; Read vector type
        LDRB    R1, [R1]

        CMP     R1, #VECIRLV      ; If irrelevant...
        LDREQ   PC, [R13], #4     ; ...exit now.

        ADRL    R0, report_five   ; "This is a "
        SWI     OS_Write0

        ADRL    R0, report_six    ; "low " (default)

        CMP     R1, #VECHIGH
        ADREQL  R0, report_seven  ; "high "
        SWI     OS_Write0

        ADRL    R0, report_eight  ; "vector build."
        SWI     OS_Write0         ; Does newline.


        LDR     PC, [R13], #4     ; ==> EXIT

; ****************
; *              *
; * ! FINISHED ! *
; *              *
; ****************

As the comment below says, our functions follow. There are a function to load a 64K chunk from the image file, a function to reset the workspace pointer (to set the scan to begin at the start (otherwise it continues)), and a function to scan the workspace for a specific word.
Perhaps the only thing of note here is the word scan routine returns its status in the Z flag, so a BL to the routine can be followed by an BEQ instruction upon the search word not being found.
At the end, some simple routines to output an error message, then exit.

; ********************
; *                  *
; * FUNCTIONS FOLLOW *
; *                  *
; ********************


load_chunk ROUT
        ; Loads a 64K chunk from the file.
        ;
        ; Entry: R0 is chunk to load (counts from zero)
        ; Exit : Chunk loaded (quits if failed)
        ;
        ; Uses : R6 for stashing the file offset (from chunk number)
        ;        R7 for stashing the file handle while the file is open

        STMFD   R13!, {R0-R7, R14}

        ; Work out the starting offset
        MOV     R6, R0, LSL #16   ; Offset = R0 << 16

        ; Open the file
        MOV     R0, #&43          ; Open existing file with read-only access, no path.
        MOV     R1, FlName
        SWI     XOS_Find
        BVS     %FT20             ; Bomb out if can't be opened
        MOV     R7, R0            ; Stash file handle in R7

        MOV     R0, #3            ; Read bytes from given pointer
        MOV     R1, R7            ; File handle
        ADRL    R2, workspace     ; Buffer
        MOV     R3, #(1<<16)      ; 64K
        MOV     R4, R6            ; Where to start from
        SWI     XOS_GBPB
        BVS     %FT10             ; Bomb out (closing file) if couldn't load

        MOV     R0, #0            ; Close file (we only open it when we need to)
        MOV     R1, R7
        SWI     XOS_Find
        LDMFD   R13!, {R0-R7, PC} ; Return to caller

10      MOV     R0, #0            ; Close the file on error
        MOV     R1, R7
        SWI     XOS_Find

20      ADRL    R0, error_file_fail
        SWI     OS_Write0
        LDR     PC, [R13], #4     ; ==> EXIT


scan_prepare
        ; Call this before scan_workspace to start at the beginning.
        ; (not calling it means to resume)
        ADR     WrkPtr, workspace
        MOV     PC, R14


scan_workspace ROUT
        ; Scan the 64K workspace (the loaded chunk) looking for a given signature.
        ; Entry: R0 = Word to look for
        ; Exit : WrkPtr is set to address of found word, or ZERO.
        ;        If not found, Z is set.

        STMFD   R13!, {R0-R1, R14}

10      LDR     R1, [WrkPtr], #4  ; Load word into R1

        CMP     WrkPtr, WrkEnd    ; Reached the end?
        BEQ     %FT20

        CMP     R0, R1            ; What we're looking for?
        BNE     %BT10             ; If not, keep going

        MOVS    R1, #1            ; Ensure Z is NOT set
        LDMFD   R13!, {R0-R1, PC} ; Return to caller


20      ; Got to the end with nothing found
        SUBS    WrkPtr, WrkPtr    ; Set WrkPtr to zero, and the 'Z' flag
        LDMFD   R13!, {R0-R1, PC} ; Return to caller



        ; Routines to output error messages
        ; =================================

not_enough_memory
        ; This is here so we don't need to take a branch if we DO have enough memory.
        ADRL    R0, error_no_memory
        SWI     OS_Write0
        MOV     PC, R14           ; Uses R14 as stack not set up at this point

not_a_file
        ; This is here so we don't need to take a branch if the object IS a file.
        ADRL    R0, error_not_a_file
        SWI     OS_Write0
        LDR     PC, [R13], #4     ; ==> EXIT

file_too_small
        ; This is here so we don't need to take a branch if the file IS big enough.
        ADRL    R0, error_too_small
        SWI     OS_Write0
        LDR     PC, [R13], #4     ; ==> EXIT

oh_ffs  ; <-- This says it all, somebody is trying to ID an emulator image for ARM2/3 era machines.
        ADRL    R0, error_this_stuff_is_mesolithic
        SWI     OS_Write0
        LDR     PC, [R13], #4     ; ==> EXIT

damaged_file
        ; Couldn't locate kernel. Damaged file, or smart-ass user trying to look at "NCOS" image?
        ADRL    R0, error_damaged_file
        SWI     OS_Write0
        LDR     PC, [R13], #4     ; ==> EXIT

And the final part of the file is the data. This is in four parts.

The first four words are where we store our results, four bytes of data for the device type, vector type, and the number that is the major and minor part of the version. That is followed by three words (twelve bytes) for holding a copy of the module date string.

Following this are values for the pattern matching. These are LDM'd into registers. The first five are LDR'd directly. The next two (Iyonix words) are LDM'd into registers, as are the device words (the next five), and also the kernel words (the final four).

Following the matching data are the strings for the status reports and the error messages. They are all null terminated by they are not word-aligned (they don't need to be).

Finally, "workspace" is defined. This is at the end of the program and it is where the 64K chunks of data are loaded. There is a short human-readable ID message stuck here. This is only of value if a person is looking in the file. Otherwise, it is overwritten by the chunks as they are loaded.

The very final line, as explained in the comments, would raise a warning of our program grew so big that we could not afford 128 bytes (32 words) of stack, plus workspace, plus AIF header. This means our program can be up to 7936 bytes. It is currently ~2208 so we have a way to go yet. ☺

; ****************
; *              *
; * DATA FOLLOWS *
; *              *
; ****************


        ; Storage of found things
        ; BYTES
devicetype
        DCB     0                 ; Detected device type
vectortype
        DCB     0                 ; Vectors irrelevant (=0), low (=1), or high (=2)
versionmajor
        DCB     0                 ; RISC OS version major part (5.23 -> 5)
versionminor
        DCB     0                 ; RISC OS version minor part (5.23 -> 23)
        ; WORDS
versiondate
        DCD     0                 ; "2017/11/15"
        DCD     0                 ;  1234567890
        DCD     0                 ; "05 Mar 2017"



        ; Values for basic matching of first (or sixth) word in file
firstword_archie
        DCD     &EAE00000         ; Archimedes!
firstword_branch
        DCD     &EA000000         ; It's a modern SoC that boots an image directly
firstword_ldrpc
        DCD     &E59F0000         ; It's a softloaded IOMD image
firstword_andeq
        DCD     &00000000         ; It's probably a FlashROM image for a Titanium
sixthword_sprow
        DCD     &4F525053         ; Confirmation of Titanium FlashROM image

iyonix_words
        DCD     &61570A0D         ; "Wa"
        DCD     &6E696E72         ; "rnin"


        ; Stuff to match when digging deeper and scanning entire workspace
devicewords
        DCD     &50414D4F         ; "OMAP"
        DCD     &69762033         ; "3 vi"  -> "OMAP3 video controller"
        DCD     &69762034         ; "4 vi"  -> "OMAP4 video controller"
        DCD     &324D4342         ; "BCM2"
        DCD     &20353338         ; "835 "  -> "BCM2835 VDU device"


        ; Stuff to match when rummaging around in the kernel
kernelwords
        DCD     &EE018F10         ; MCR   CP15, 0, R8, C1, C0  -> Set up MMU, HighVec is word prior
        DCD     &E3888A02         ; ORR   R8, R8, #&2000       -> If present, this is High Vector
        DCD     &43534952         ; "RISC"
        DCD     &09534F20         ; " OS"                 -> Find low level "RISC OS" module


        ; Message is:  Examining ""...
msg_init_prefix
        =       "Examining ", 34, 0
msg_init_suffix
        =       34, "...\r\n", 0


        ; The report messages
report_one
        =       "This ROM image is ", 0
report_two
        =       "for an ", 0
report_type_unknown
        =       "unknown device.\r\n", 0
report_type_iomd
        =       "IOMD system.\r\n", 0
report_type_iyonix
        =       "Iyonix.\r\n", 0
report_type_omap3
        =       "OMAP3 board (Beagleboard, etc).\r\n", 0
report_type_omap4
        =       "OMAP4 board (Pandaboard, etc).\r\n", 0
report_type_titanium
        =       "a Titanium FlashROM image.\r\n", 0
report_type_pi
        =       "for a RaspberryPi.\r\n", 0
report_type_pipico
        =       "the Pico version ", 0
report_three
        =       "It is RISC OS ", 0
report_four
        =       ", dated ", 0
report_five
        =       "It is a ", 0
report_six
        =       "low ", 0
report_seven
        =       "high ", 0
report_eight
        =       "vector build.\r\n", 0


        ; All the error messages
error_no_file
        =       "Syntax: FirmwareID \r\n", 0
error_no_memory
        =       "Not enough memory (need 72K).\r\n", 0
error_not_a_file
        =       "Object is not a file.\r\n", 0
error_too_small
        =       "File is too small to be a RISC OS image.\r\n", 0
error_file_fail
        =       "Unable to access file.\r\n", 0
error_this_stuff_is_mesolithic
        =       "Archimedes era ROM images are not supported!\r\n", 0
error_damaged_file
        =       "The ROM image is damaged.\r\n", 0

        ALIGN



; *********************************************************************
; *                                                                   *
; * BEYOND THIS POINT IS WORKSPACE (where the file chunks are loaded) *
; *                                                                   *
; *********************************************************************


workspace
        ; File contents are loaded here.
        ; Expects to have 64K of workspace to use.
        ;
        ; Stack follows, at the very end of memory.
        ;
        ; So if we subtract 64K for workspace, and allow 128 bytes of stack, plus 128 bytes
        ; for the AIF header. This means our program can be up to 7936 bytes in size. Verify.
        ;   PRINT ( (72*1024) - (64*1024) - 128 - 128
        ;      7936

        ; Tail end message - human readable, gets overwritten.
        =       10, 10, "FirmwareID by Rick Murray, 2017/11/19", 10 ; exactly 40 bytes

        ASSERT  ( (workspace - entry_point) < 7936 )

        END

And, as always we must end with "END" and a newline. Because that's how objasm likes it!

 

Ideas for the future:

As always, these ideas are your potential homework. (^_^)

You can download the FirmwareID source code and executable (14K).

 

 

Your comments:

Gavin Wraith, 27th November 2017, 16:17
Rick, your blog's server seems a lot more responsive than ROOL's. Do you mind if I ask a silly technical question? I have a Logitech K260/M210 wireless combo. I bought myself a nano unifying receiver in the naive hope that I might be able to clone the combo's receiver - I have two Rpi3s on my desk. It would have been nice to have a receiver inserted into each machine, to avoid the unplugging and replugging when I switch from using one to t'other. But in vain. Is this because all devices have a unique ID and wireless pairing uses the IDs of both receiver and device?
Rick, 28th November 2017, 22:16
When the forum is in a sulk, even Yahoo! is more responsive... I guess the forum software is called "Beast" for a reason. :-) 
 
I cannot say for certain, but I would imagine that there is some sort of pairing so that one keyboard talks only to one receiver. 
I have the same problem with my Bluetooth keyboard. I use it with my phone and the iPad, and it needs to be paired with each device every single time (if different to the time before). It would have been nice if the keyboard could remember several devices, but then this raises the question that probably applies to your keyboard - if more than one receiver is active, which one is the input sent to? 
David Boddie, 2nd December 2017, 15:44
It's funny that you picked up on my post because I thought I'd managed to kill that discussion thread. Not that I was aiming to do that - it just tends to happen. I actually assumed that people would jump on the Brexit reference and really take the discussion off-topic because, as illustrated in that thread, there are people who just can't help themselves. 
 
The discussion also illustrated the flip side of having the Aldershot forum: it can be used as a way to kill off valid discussions that people don't want to have, even if they are relevant to the topic being discussed. 
 
But your point about being able to discuss Brexit with intelligent people reinforces my other point that you mention: people tend to assume that others are in some way on the same wavelength or that there is common ground. You are assuming that others want to have a rational discussion about a sensitive topic, but it's not necessarily the case. You might find common ground to be able to discuss Brexit in a calm way, then find that some other political issue causes things to get heated. 
 
It's fine to start from the viewpoint that others using the forum are intelligent, reasonable people, but even that tends to trick people into a cosy view that "because you like X, you'll like Y as well" because we're all smart people, right. That also tends to lead to the sort of laziness that excuses people from dropping random stuff into otherwise fairly focused discussions. Although it can be nice that you get to see some personality in people's messages, it can very easily lead to the cosy, chummy, random nonsense that the newsgroups were known for. 
 
So, it was surprising that it reached the possibly correct end result that the news feed should filter out comments in the Aldershot forum. It's a technical solution to a social problem, so it will be only partly effective. Still, it should help some of the people who struggled to keep up with the news feed.

Add a comment (v0.11) [help?]
Your name:

 
Your email (optional):

 
Validation:
Please type 05497 backwards.

 
Your comment:

 

Navi: Previous entry Display calendar Next entry
Switch to desktop version

Search:

See the rest of HeyRick :-)