The test routine for shellchat "cheats" and accesses the I2C block
to test the RTC during factory operations. This is not aesthetic
and is also potentially a security hole since we don't want less
trusted stuff willy-nilly playing with i2c.
Rewrite to
1) remove i2c references from shellchat
2) replace RTC calls with the newer non-dangerous llio calls that are
limited to read out the initialized time variables.
It's crappy because it uses a busy wait loop to poll the udp
rx socket in order to accurately emulate the Xous async callback
feature (which is _not_ emulated for Tcp, for example).
It's more accurate because this emulation happens. But it's a lot
more complicated to implement it because zero-cost async UDP callbacks
aren't really a host-native feature (but they are a Xous-native feature!),
and I didn't want to .. pull in tokio or mio code surface into
the Xous hosted mode, seemed a bit like crushing a fly by dropping
a house on it. Maybe that's a fine solution in Oz, but Xous doesn't live in Oz.
Total bodge -- we lop off the TCP stack at the Xous API level, and
substitute it with a native host TCP stack.
Caveat hacker: this means that a lot of OS-specific net properties
will carry through to the hosted mode emulation. This is adequate
for "smoke testing" a build but do not be shocked, *shocked* if
there are more bugs to be found because of some weird host integration
issue.
since xous 0.9.5, we've had a Box and we've had threads, so now we
can put the callback in a Box and pass it to a thread, instead
of relying on an `unsafe` work-around to get the callback function
pointer into the thread's environment.
also remove async write callbacks: in practice, these aren't used
Downside of this refactor is that threads for handling the
callbacks are not spawned on demand, they are spawned at boot,
leading to about an extra 68k of RAM used (most of it being
consumed in the codec block, actually). Some of this is also
probably extra object code because we're using more of the stdlib
primitives, which carry some weight.
If the connection manager isn't paused while a user sets up a network,
it could decide that the currently partially configured status is
crap and then overwrite it with a saved configuration.
Pause the connection manager and make the user aware of this situation.
It's not a good time to bug the EC to do network stuff when it's updating
itself.
...might even want to send the network into a disconnected state,
but, let's start with just turning off the connection manager
for now.
Spent a couple hours chasing down a "bug" which is acutally just
something about how http works that I don't understand. TCP was
working just fine but there is ... idk some sort of keep alive
thing that occupies a socket so the "web server" blocks waiting
for a read. Anyways, I guess the "right" way to solve that would
be to make a multi-threaded web server
OH GOD STOP
right. it's just a demo to prove that TCP works. done.
Open an issue if you find a problem with TCP kthx!
Good enough so that if you type `net server` and you hit the IP
address of the device, it'll respond with something like
Hello from Precursor!
I have been up for 86087 ms.
There's still all kinds of bugs, I'm sure. But ... I'm also not
sure /why/ you would want a web server on Precursor. This is more
just to make sure that the TCP stack isn't totally broken.
The "web server" as it may be is quite broken and doesn't parse
any headers and probably sends a bogus amount of data because
I can't figure out if the content length includes some new lines
or not. But really, this just isn't in scope. Works with Chrome,
Firefox shows the status page and then says "connection reset" and hides
all the information. Whatever, browser compatibility is well beyond
my pay grade!
Still not there....to get it reporting in a user-visible fashion
I'm realizing I'm going to have to build a dedicated facility in
Xous to track this because otherwise I have to trigger the
automatic rebuild of a "heavy" program that would naturally
encapsulate such information.
Maybe for now, though, at least over the serial port I can
get a somewhat relevant string???
I wrote in a commit yesterday how there was no ROI on doing this
yet somehow I kept on doing it. I blame poor impulse control.
Turns out there was a series of race conditions and bugs that
caused this thing to "mostly work" on the first go at it but
really hard to debug and get very right.
1. Litex UART has a weird undocumented API. You advance the Rx
FIFO by writing `1` to the PENDING bit, and no other way. However,
you determine if there are any more characters to receive by
reading the EMPTY bit and seeing if it is 1. The previous method
wrote `1` to the PENDING bit and then used the PENDING bit to
see if a character was available, under the theory that the
PENDING bit would be set again if there was still a character.
This is somewhat true, except that the PENDING bit is set only
some amount of time later which is about comparable to a few
CPU instructions, so if you had a fast loop path the PENDING
bit would show as cleared and you'd exit, which would cause
no further interrupts to fire because the interrupt was
effecitvely not acknowledged.
This isn't written up anywhere but I figured this out by
just reading the source code for Litex UART and BIOS:
e8be391504/litex/soc/cores/uart.py (L264-L279)ccd3ab17be/litex/soc/software/libbase/uart.c (L38-L44)
2. I had the Key Injector IP block in the `sys` domain, which
would have its clock cut when the CPU went to sleep, which would
cause input characters to disappear when the CPU went into power
saving. moving this to "always on" domain fixes that.
3. I had the UART PHY in the always on block (so you could
send or receive exactly one character), but not the
separate UART block (which contained the FIFOs).
The UART block would also go into power
savings, and this would cause FIFO entries to go missing.
4. Escape sequences get sent as a burst of characters. The Key Injector
originally did not have a FIFO of its own, so it would only
remember the *last* key of the sequence that was written, causing
some keys to be dropped occassionally. Adding a 16-deep FIFO
to the injector fixes this.
5. The code I had to read out the injector's results was designed with
the "strobe" bit (to indicate that the FIFO had characters) in the
same regsiter as the character itself. Thus the loop that 1. checked
if the fifo was empty then 2. read and forwarded the character
would actually perform two reads from the FIFO. However, this "mostly worked"
I think because the FIFO retains the last value that was written
even when it was empty, so if only one character was read at a time
everything was fine. It only didn't work when you stuffed two characters
in there, as you'd drop the first one. Reading the FIFO once and
then interpreting the code with a bitmask fixes this.
6. The escape sequences, in their full glory with no dropped characters,
required a refactored parsing routine, which I have now added.
7. backspace->delete mappings, the bane of computer engineers since 1960.
OK. very bald yak. Here I lay down the shears next to several
mooshi pillows stuffed with the finest Yak hair.