(Teletype) Monitoring Live Variables (Done)

Even that would be a great addition.
Limited, but definitely useful.

Just some quick thoughts…

  • Having to modify your script in order to monitor a variable or debug it is problematic in a language that limits how long a line is.
  • Screen updates are expensive (in computation terms) and slow, the current architecture of the Teletype only updates the screen on demand. We might want a toggle to enable and disable the display.
  • I haven’t had time to really get my head around what’s been discussed here (sorry), but it seems like it adds a lot of extra code complexity for little benefit.

My suggestion would be to go for something much simpler.

Have a live mode toggle to display the contents of variables A, B, C, D, X, Y, Z, T on the screen in the blank area.

Layout as follows:

(icons)
A      B      C      D
1234   -1234  1234   1234
X      Y      Z      T
10     -120   23444  1234
(blank)
(previous result)
> X

I think but haven’t checked that there are enough horizontal pixels to display 4 numbers. We might want to use a custom fixed width 3x5 font for them (I can’t remember if the all the numbers are 3x5 or not).

Reasons why I think this is good:

  • Those 8 variables are the main ones we’re interested in.
  • It’s simple, just one key stroke to remember.
  • The implementation (which I can go in to detail later) is easy, and follows on from how other parts of the code work.
  • Doesn’t require modifying your scripts.
6 Likes

I like this idea for its simplicity and it looks very much how I always dreamed about it. Nice layout and clear labeling.

Also while thinking about it and going through this thread I wondered if something like programmable AUX slots could be a compromise. Something that would look like the above as a default but you could reprogram for example D with a command like WATCH DRUNK (or WATCH anything else…) to keep track over the less common variables / parameters or complex functions / counters without having to write them into another variable first.

But if this is to complicated or cpu consuming and could make tt unstable again I would be very happy with the simple version proposed by @sam try to carefully choose variables with regard to monitorizability.

I see debugging as a live activity, so it doesn’t need to follow the script. Turn them on from the command line when you need them.

Line length is already a faced limitation in the language with all mods. You can’t L 1 4 the most complex statement. You can’t IF X the most complex statement. You won’t be able to WA 1 (as an alias) the most complex statement. :man_shrugging:

Besides, it seems that the system you’re proposing is far more limited, so it’s disingenuous to point out this downside. (“Pinching is painful, let’s stab instead!”)

Re: computational cost: I wonder if the following scenelet poses any risk to stability currently:

I: M 25
M: P 0 O
* Open Tracker Screen *

Re: toggle, WATCH.SHOW 0 or something would work, and I’m not opposed to a keystroke.

Beside the interface drawing code and the operator implementation, you’re looking at a couple of memcpy() and a memcmp() bracketing run_script_with_exec_state. Then, the live screen display code checks the dirty flag, conditionally running N post-commands, where N is the number of active watches.

I disagree. I would be interested in monitoring a lot of different things. Pattern indices, queue length. I can only think of a handful that I wouldn’t want to monitor, and those are only getters because the language doesn’t differentiate between (for lack of better terms) a function and a subroutine. E.g., @STEP.

Neither does WATCH, as mentioned, if you consider debugging a live exercise.

Actually, because you would have to capture the operator DRUNK and not the result of calling DRUNK, the syntax would have to be WATCH: DRUNK to capture the operator as the post-command. You have essentially proposed a more-limited version of WATCH because all of the other slots are static.

Implementing a custom AUX slot requires 100% of the work of the system I advocated. So you’re basically getting all the code complexity for little benefit.


Compromise

  • Use the WATCH-as-mod approach, allowing great flexibility.
  • Use a toggle key / command to hide / show the display
  • By default, populate the cells with A, B, C, etc.
  • Allow users to change the post-commands in any cell by cell number.

Technical Solution to O, FLIP, IN, etc.

Shadow these variables in the scene state. Update the low-level getters to optionally draw from the shadowed value when the shadow flag is set, i.e.: when the screen draw routine is calling process_command().

Remote Getters (i2c, etc.)

WATCH: could easily just drop post-commands with any obviously problematic operators, which would be especially easy if we maintained an order of the operator table with all i2c ops at the end.

edit: actually, with a little bit of RAM, all last-known-ii-requests could be cached and shadowed with only changes to tele_ii_rx() and tele_ii_tx()! If you haven’t used it, why are you watching it?

(note that I understand the concern for computational overhead and could design this to be lightweight in that regard)

1 Like

So that statement wasn’t aimed directly at your solution. More at those suggesting we insert “print” style statements into commands that add to a log.

Stability no (not any more). But I strongly suspect it messes with CV timing.

As I understand it, WATCH would allow you to specific a custom command that’s output is displayed in a cell on the live screen? Right? (Please excuse me if I’ve got this completely wrong, not enough time…)

How does a WATCH'd command know that it needs to run to update it’s value on the live screen. Display updates are demand based, it’s not continuously updated.

Also as you mention there are several OPs that modify state… what to do about them in a systematic manor? (e.g. P.RM, P.POP, S.ALL, etc, etc) Some that are slow (IN, PARAM, anything i2c). How will that interact with SCRIPT and sub commands?

that’s exactly what i was suggesting…

having WATCH as a pre would add a burden on both the system and adding new ops. this functionality is already doable by setting a pattern value and watching that instead with the benefit that the script itself decides when is a good time to update the watched value.

1 Like

So this is on my radar. A scheduler redesign will be required to ensure that there is any predictability in CV behaviour given the breadth and scope of what a user script can do.

CV slew resolution is my biggest qualm with teletype, and I am highly motivated to solve it while permitting maximum CPU load for user purposes via scripts and improving the timing of critical functions.

I think those are excellent candidates for ineligibility for use with WATCH and should generate a syntax error if attempted. They are “subroutines” as opposed to “getter functions” and should be excluded.

Easy to shadow, as mentioned.

WATCH N: SCRIPT M should also be a syntax error. Sub-commands are fine but probably nonsensical. Only one of them can leave a “return” value on the stack.

  1. Adding core variable ops, yes. (None on my radar except CHAOS, I don’t think)
  2. Adding any i2c ops, no. Every single i2c response/request can be cached from a single place with a one-time change.

Concerns about system performance (CPU consumption)

I am concerned about the overhead of this feature (and any feature), but I feel that it’s necessary to quantify those concerns as opposed to raising potentialities as a specter.

Of course, to do this requires profiling of teletype. I’ll concede that until I am comfortable profiling and load-testing the CPU, that such a complex feature should not be added to a release branch.

Therefore: WATCH as advanced in my posts will not see release until profiling, a prerequisite to the scheduler change, which is a prerequisite to the R (Repeat) feature, a 3.0 target feature.


Simpler Live Display Option

I am willing to do the A B C D X Y Z T display for the next release, on the condition that we leave the functionality open to transforming into WATCH in the future.

1 Like

it wouldn’t be just i2c ops. there are other ops that change some state without scripts being involved. having to maintain a list of things that are supported by WATCH is error prone.

also i think having a pre op that changes the meaning of the sub command is something we should avoid.

2 Likes

Please do!
Any live monitoring will be helpful.
And thank you again for taking this on.

1 Like

Just quoting this back at you…

Also, updating the validation code to disallow illegal OPs in WATCH, adding caching to i2c, updating other OPs to add shadowing. Shirley this is getting complex?

This would mean that any newcomers wanting to add an OP would need to consider the watch system when adding it.

3 Likes

i really can’t emphasize strong enough that having a pre that changes the meaning of the sub command just raises a huge red flag for me.

2 Likes

I agree that a PRE goes beyond what I was initially suggesting.

Again, I do think that for the time being, the live monitoring of ONLY the variables is a reasonable approach.

Honestly, even if the value checking as it is implemented now (displaying the single static value on keystroke) was simply altered to having that one value being monitored dynamically, that would be of huge help!

1 Like

Are there any where it would really matter? Consider that anything that happens in a WATCH statement occurs in a dummy scene_state and is thrown away. Hardware interaction will not occur, enforced by a scene_state.is_watch flag. Shadowing will occur on i2c req/resp, O, FLIP, and any getter with a hidden variable.

I don’t know what could really go wrong in that scheme, besides the aforementioned CPU overhead and ~7-8k RAM. Maybe I’m missing something?

Alright, can you make one of those nice annotated images for what @sam described here:

That would get me 50% there. The code is trivial, figuring out the screen addresses is really hard for me. I fear I suffer from discalculia a bit, because just figuring those numbers out would probably take me 2 hours and I’d still get it wrong.

Adding to the aforementioned list of display characteristics, I’d like to add:

  • The display should be centered for aesthetics (I think, feel free to tell me otherwise)
  • Cell titles should be centered (see above)
  • Because we have the room, we can add small decoration, such as maybe cell grid lines to make it less sparse. Lines, dashed lines, whatever looks good.
2 Likes

Screen rendering is easiest done on a line by line basis. There are 8 lines:

Thus my example also has 8 lines. The absolute simplest way to do it, is just to construct a string and render it to the line. See the various screen_refresh_* functions to get a good idea how to do it.

Otherwise, see screen_refresh_pattern in pattern_mode.c for something on a grid already (still works with 8 lines though).

Oh yeah, I understand it. I’m just not good or fast at figuring out offsets in my head or on paper. I always really suck at math in my head, have always been slow doing it on paper, and I’ve been a programmer for so long, I don’t really even try anymore.

I also commonly transpose numbers in my head and even when typing.

For instance, I can think uint32_t in my head but actually type uint16_t. My brain recognizes that it’s wrong right away, but I’m baffled that I could have made that typo.

Will do!

Will post later today.

Looking this scheme over, I note that it requires no list of excluded operators. Some operators would not make sense, but none of them can actually do anything bad.

If anyone can think of an operator that is not handled by this scheme, I’d be interested to know which. All of the aforementioned (S.ALL, P.RM, etc.) would work on the dummy scene and have absolutely no effect beyond chewing some CPU and maybe changing the scene_state that subsequent watch commands in that screen refresh.

The few exceptions that I can think of:

  • SCRIPT N (subroutines should be masked)
  • SCENE N (ditto)
  • KILL (ditto)

So you’d need to memcpy the active scene to a dummy watch scene before executing each watch command?

I’d start by looking through teletype_io.h as to what OPs manipulate data outside of a scene. Remember with sub commands, OPs with side effects can still be run: WATCH: CV 1 1; X.

Also could you explicitly state how you determine when each watch should be re-evaluated (or link me to where it’s discussed). At the moment it seems like it needs to be after any event that can modify the scene. That may lead to memcpy (or memcmp) being run a lot. I have no idea if that’s an issue or not.

@sliderule here are some mock-ups for the Variable Monitoring screen.
I made 4 sample layouts, and used version D to make a photo approximation. I am not sure which is my favorite. I like certain things about each one.

3 Likes