Sending the RISC OS boot messages to an I2C device
Phil Pemberton (7989) 71 posts |
I’ve been building a rack-mounted A4000 from a spare motherboard I picked up, and finally got around to building the “version 2” soft power on/off board with LCD/VFD interface this weekend. At the moment it displays a static message, but can also display text sent over I2C. I’ve written a module which listens for the “shutdown complete” service call and turns the power off – and this works great. Now I’d like to send the “RISC OS 4096K, Acorn ADFS” boot messages and the output from !Boot to the display — but I’m having trouble with this. I figured the easy way was to use OS_Claim to claim the WrchV vector, then send an I2C byte with IIC_Control every time a character is printed to the screen – but when I call the IIC_Control SWI from the vector, the machine locks up (only the cursor moves). Is there a way to do what I want? Thanks |
Rick Murray (539) 13839 posts |
I’m not an expert, but… low level VDU stuff is a bit finicky, and it may not like working in such a manner. |
Paolo Fabio Zaino (28) 1882 posts |
@ Phil Just a thought, have you tried to buffer the characters (instead of send them as soon as you receive them) and then sending them at regular intervals (or later time), maybe via call backs or setting up an OS event to trigger periodically (using OS_Byte or similar) and check if there are characters in the buffer to send over I2C? Basically avoid doing the call from the vector. Just my 0.2c |
Rick Murray (539) 13839 posts |
đ€· Am I talking to myself again? đ |
Stuart Swales (8827) 1357 posts |
I’d suggest that summats wrong with IIC_Control if it can’t be called from WrchV. Double-check that vector code! |
Paolo Fabio Zaino (28) 1882 posts |
Oh you should see when I am coding on RO lol ROOL may have removed the swearing from the sources, but here the old habits are still going strong! XD |
Rick Murray (539) 13839 posts |
You did remember to stash R14 around the call to IIC_Control, right? You’re in SVC mode… ;) |
Phil Pemberton (7989) 71 posts |
Addressing all of these …
That was my first idea, but I figured I could send from the vector to start with, then add the buffering later.
I’m pretty sure it’s right:
Saved it right at the start of the function! |
Stuart Swales (8827) 1357 posts |
Why buffer at all?
You meant ADD R1, R12, #w_txbuf surely? I would paranoically clear V after the XIIC_Control too. |
Phil Pemberton (7989) 71 posts |
I2C packet overheads. Each packet needs a start sequence, addressing byte, and stop sequence. For a single-byte transfer, that’s slightly under 50% efficiency – which improves the more bytes you send. Also buffering the data from WrchV means it’ll return faster, and the I2C transaction can be done somewhere less time critical (e.g. some kind of timer tick vector)
I tried that, and it earned me a “Bad immediate constant” error … and now I’ve just realised why that doesn’t work. I borrowed a chunk of code to allocate the workspace from a post by Steve Fryatt (https://www.riscosopen.org/forum/forums/11/topics/16298?page=3#posts-119636) and it’s got a bug which makes it return wrong addresses if you allocate a 4-byte block, then a 64-byte one like I did. I was going to post a bit about the wrapper code from Chapter 10 “Interrupts” under “Calling SWIs” (http://www.riscos.com/support/developers/prm/interrupts.html) but it seems that’s unnecessary. Now I’m getting the text sent to the display perfectly at the F12 prompt, but when the WIMP is running it prints absolute heaps of garbage when I interact with the desktop. Ideally I need to filter out the noise from the WIMP and only display what’s printed at the star-prompt. … It also slows the desktop to an absolute crawl, but that’s not a huge surprise given how much noise it’s printing when I move windows around. |
Rick Murray (539) 13839 posts |
Yup, it’s amazing how much UI stuff goes through WrchV. It turns up in Spool files as well.
What comes to mind is to hammer OS_Byte 1. Specifically OS_Byte 117, which will return the VDU status flags in R1, and if bit 5 is set then you’re in VDU 5 mode. In that case, probably best to just discard the data as I can’t imagine stuff printed in VDU5 mode would make much sense. Obviously this won’t work with TaskWindows (but then mine use ZapRedraw so that isn’t even an issue). 1 Even that will be faster than spewing unwanted junk through IIC. |
Stuart Swales (8827) 1357 posts |
If actually gets worse if you sit on WrchV! OS_Plot has to send the VDU sequence, etc. |
Phil Pemberton (7989) 71 posts |
I thought I had it working, but it seems like it works intermittently. Sometimes it crashes, sometimes it runs and works. I can’t figure out the pattern. Would anyone mind taking a look at this and seeing if any errors stand out? I’m happy for suggestions for a better way to do this — I started implementing buffering (there are some placeholders for this) but stopped when I couldn’t think of somewhere to print out the contents of the buffer.
Also, DarkLord on the Stardot Discord has provided a better implementation of FNworkspace which aligns to 4 bytes:
|
Rick Murray (539) 13839 posts |
870 ; Save the workspace 880 STR R2, [R12] 890 900 ; Make R12 point to the workspace 910 MOV R12, R2 Aren’t these two back to front? |
Stuart Swales (8827) 1357 posts |
You will of course get R0=4 and R0=5 in the middle of other VDU sequences! If you’re going to do it this way, you’d have to have a table of VDU control sequence lengths so you can skip that number of subsequent values. |
Simon Willcocks (1499) 513 posts |
At a glance, that looks OK; the allocated address gets stored in the private word, then r12 becomes the wsptr. |
Rick Murray (539) 13839 posts |
That’s why I said to spam OS_Byte 117 to read the VDU5 status, it saves having to try to make assumptions about what passes through WrchV. |
Phil Pemberton (7989) 71 posts |
I’ve changed the code to hit OS_Byte 117 … and it seems like that crashes it too! After bisecting it, I found that ending the vector with:
crashes the machine. The fix is to change it to:
Which restores LR then returns, clearing the V-bit as part of the return. Still two instructions but no crash. Doing that and adding code to check OS_Byte 117 seems to be doing mostly what I need, but for two issues:
I think I need to have a ponder about how to buffer the incoming characters and send them in larger blocks. The obvious answer is to do the send in WrchV, but that just means it’ll delay at the end of the line, or whenever the buffer fills up. I’d rather do it somewhere less time-critical. |
nemo (145) 2545 posts |
Sorry I didnât notice this earlier. There are many problems.
If you want to filter out VDU sequences (OS_Plots, graphics and text windows, cursor movements, clear screens, beeps etc) then you need to do a bit more work. Itâs not just the VDU5 state that you need to look at â crucially you need to check the VDUQueueDepth read via OS_Byte,218,0,-1. So read VDU Status and if that says VDU4 (if thatâs what you want) then read the VDUQueueDepth and if thatâs zero you can redirect your byte if itâs a printable (and maybe LF) but youâll probably also want to map VDU9 to space and perhaps even be clever about 8 and 127 if youâre buffering. Finally, WrchV doesnât need flags preserved, so to cope with a SWI returning V just do So youâll want to do something more like:
Which youâll notice uses no workspace and is CPU agnostic. The Knuthian Defence applies â proceed with caution. [Yes, UTF-16 is a RISC OS Alphabet. Yes it means R0 isnât a byte in WrchV. Yes thereâs a way to cope in general. Iâll write that up elsewhere.] |
nemo (145) 2545 posts |
You may be thinking that this is a lot of stuff to do to work out if you should be doing something with WrchV, and youâd be right. eg all of these have to do this kind of thing: Itâs almost like VDUStatus and VDUQueueDepth should have been part of the WrchV API! Those of you with sharp eyes will note that some of those modules have set their R12 sensibly. RO5 broke the API for reading the MOSVars address (fix module on my site), but the VDU Workspace must be inferred from what you are allowed to read â an exercise for the reader. |
nemo (145) 2545 posts |
To cope with Alphabets that arenât 8bit, use Service_International,332: I wrote about the complexities of the ill-defined WrchV in the ReadMe for my ArthurASCII module:
The Kernel WrchV handler treats R0 as 8bit and simply ignores the rest. This was correct (but undefined) for the Alphabets available in 1987. However, it is not correct in general, and is certainly wrong for Alphabet 117 – “UTF16”. For the record, WrchV claimants MUST preserve R0 for their caller; IGNORE extraneous bits when recognising codepoints; and NEED NOT pass those on to the vector tail. Out-of-band codes such as -1 MUST NOT be special-cased, as there may one day be a fully 32bit Alphabet for which this is a valid codepoint. For stateful Alphabets such as UTF-8, control codes 0 and 27 are DEFINED to act as flush and reset respectively without other side-effects (ie 192,0 will treat 192 as a Fallback character, whereas 192,27 discards the 192 undisplayed). It is intolerable having to read and check the current Alphabet number for every character code that passes down WrchV (though it is strictly necessary for correct character code interpretation), so some code intercepts ByteV in order to spot Alphabet changes to cache locally. In light of this inefficient API, the UTF8Alphabet module introduced an Alphabet Change Service (&43,&10C) to push Alphabet (and Fallback) changes to interested modules. This module relies on that API to spot changes to the Alphabet after initialisation. Having said that, I advise against the use of UTF-16 as an Alphabet because it has significant implications for many APIs, not least OS_ReadC and ReadLineV. Having OS_ASCII recognise CR correctly when in UTF-16 is therefore an exercise in errant pedantry – I know you would expect no less. |