![]() |
Forum Index : Microcontroller and PC projects : CMM2: serial console output limitations
Author | Message | ||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Hi folks, The following is some code I'm working with whilst over-engineering a menu-system for my Scott Adams Adventure Game Interpreter. My intent is to be able to show the menu (and the rest of the UI such as it is) nicely for both Serial and VGA output driven from a single unified API. This also incidentally provides an approximation of multiple "windows" and a character mapped display. Note the attached code does not include any VGA implementation so if you look at the VGA screen you will just see a mess of VT100 escape codes, or you would if I hadn't disabled VGA output. The example here uses it to scroll a bunch of multi-coloured text in a window on the Serial display. My problem is that just occasionally and not (I think) predicatably the display goes wrong and the scroll jumps or bits of text get displayed outside the window area. It may just be arrogance but I don't think this is a "bug" in my code. I think that one thing that could cause such behaviour is if an occasional byte was getting lost in transmission - presumably this is a "thing"? if so what sort of loss rate might I expect ? and can I compensate ? This code is basically my only experience with using a serial terminal and VT100 escape codes and I'm hoping some of the elder statesmen might be able to put me straight if I'm talking twaddle. ' Copyright (c) 2021 Thomas Hugo Williams ' For Colour Maximite 2, MMBasic 5.06 Option Explicit On Option Default None Const chm.BLACK% = 0 Const chm.RED% = 1 Const chm.GREEN% = 2 Const chm.YELLOW% = 3 Const chm.BLUE% = 4 Const chm.MAGENTA% = 5 Const chm.CYAN% = 6 Const chm.WHITE% = 7 Dim chm.col_map$(255) ' map of attribute values to VT100 control codes Dim chm.mem%(5000) ' memory buffer for character and attribute data Dim chm.max_num% ' max number of windows allowed Dim chm.num% ' current number of windows created ' For the currently selected window: Dim chm.id% = -1 ' id Dim chm.a% ' x-coordinate of left hand side Dim chm.b% ' y-coordinate of top Dim chm.w% ' width Dim chm.h% ' height Dim chm.x% ' x cursor-position Dim chm.y% ' y cursor-position Dim chm.at% ' attributes to use for printing Dim chm.pc% ' pointer to the character data Dim chm.pa% ' pointer to the attribute data Cls Option Console Serial Print Chr$(27) "[?25l"; ' hide cursor moses() End Sub moses() chm.init(2) Dim win1% = chm.new_win%(10, 5, 40, 25) Dim i% chm.switch(win1%) : chm.border() chm.bold(1) chm.print_at(0, 0) For i% = 1 To 100 chm.foreground(1 + i% Mod 6) chm.print("Moses supposes his toeses are roses, but moses supposes eroneously.") chm.print(" For nobody's toeses are roses as moses supposes his toeses to be. ") Pause 200 Next End Sub Sub chm.init(max_num%) If max_num% < 1 Or max_num% > 10 Then Error "invalid number of windows: " + Str$(max_num%) Dim chm.a_%(max_num% - 1) Dim chm.b_%(max_num% - 1) Dim chm.w_%(max_num% - 1) Dim chm.h_%(max_num% - 1) Dim chm.x_%(max_num% - 1) Dim chm.y_%(max_num% - 1) Dim chm.pc_%(max_num% - 1) Dim chm.at_%(max_num% - 1) chm.max_num% = max_num% Local i%, s$ For i% = 0 To 255 ' Foreground s$ = Chr$(27) + "[0m" + Chr$(27) + "[" If i% And &b01000000 Then Cat s$, "1;" Select Case i% And &b00000111 Case chm.BLACK% : Cat s$, "30" Case chm.RED% : Cat s$, "31" Case chm.GREEN% : Cat s$, "32" Case chm.YELLOW% : Cat s$, "33" Case chm.BLUE% : Cat s$, "34" Case chm.MAGENTA% : Cat s$, "35" Case chm.CYAN% : Cat s$, "36" Case chm.WHITE% : Cat s$, "37" Case Else : Error "unexpected" End Select Cat s$, "m" + Chr$(27) + "[" ' Background Select Case (i% And &b00111000) >> 3 Case chm.BLACK% : Cat s$, "40" Case chm.RED% : Cat s$, "41" Case chm.GREEN% : Cat s$, "42" Case chm.YELLOW% : Cat s$, "43" Case chm.BLUE% : Cat s$, "44" Case chm.MAGENTA% : Cat s$, "45" Case chm.CYAN% : Cat s$, "46" Case chm.WHITE% : Cat s$, "47" Case Else : Error "unexpected" End Select Cat s$, "m" ' Reverse video If i% And &b10000000 Then Cat s$, Chr$(27) + "[7m" chm.col_map$(i%) = s$ Next End Sub Sub chm.foreground(col%) chm.at% = (chm.at% And &b11111000) Or col% End Sub Sub chm.background(col%) chm.at% = (chm.at% And &b11000111) Or (col% << 3) End Sub Sub chm.bold(z%) chm.at% = (chm.at% And &b10111111) Or (z% << 6) End Sub Sub chm.inverse(z%) chm.at% = (chm.at% And &b01111111) Or (z% << 7) End Sub Function chm.new_win%(x%, y%, w%, h%) If chm.num% > Bound(chm.a_%(), 1) Then Error "maximum number of windows reached: " + Str$(chm.num%) chm.a_%(chm.num%) = x% + 1 ' To account for VT100 using 1,1 as root instead of 0,0. chm.b_%(chm.num%) = y% + 1 chm.w_%(chm.num%) = w% chm.h_%(chm.num%) = h% chm.x_%(chm.num%) = 0 chm.y_%(chm.num%) = 0 If chm.num% = 0 Then chm.pc_%(chm.num%) = Peek(VarAddr chm.mem%()) Else chm.pc_%(chm.num%) = chm.pc_%(chm.num% - 1) + chm.w_%(chm.num% - 1) * chm.h_%(chm.num% - 1) * 2 EndIf chm.at_%(chm.num%) = chm.WHITE% Memory Set chm.pc_%(chm.num%), 32, w% * h% Memory Set chm.pc_%(chm.num%) + w% * h%, chm.WHITE%, w% * h% chm.new_win% = chm.num% Inc chm.num% End Function Sub chm.switch(id%) If chm.id% > -1 Then chm.at_%(chm.id%) = chm.at% chm.x_%(chm.id%) = chm.x% chm.y_%(chm.id%) = chm.y% EndIf chm.id% = id% chm.a% = chm.a_%(id%) chm.b% = chm.b_%(id%) chm.w% = chm.w_%(id%) chm.h% = chm.h_%(id%) chm.x% = chm.x_%(id%) chm.y% = chm.y_%(id%) chm.at% = chm.at_%(id%) chm.pc% = chm.pc_%(id%) chm.pa% = chm.pc% + chm.w% * chm.h% End Sub Sub chm.print(s$) chm.print_at(chm.x%, chm.y%, s$) End Sub Sub chm.print_at(x%, y%, s$) Local x_% = x%, y_% = y% Local i% = 1 Local ls% = Len(s$) Local nc% = Min(chm.w% - x_%, ls% - i% + 1) Local of% Local ps% = Peek(VarAddr s$) Do While nc% > 0 If y_% = chm.h% Then chm.scroll_up() Inc y_%, -1 EndIf of% = y_% * chm.w% + x_% Memory Copy ps% + i%, chm.pc% + of%, nc% Memory Set chm.pa% + of%, chm.at%, nc% Print chm.col_map$(chm.at%); Print Chr$(27) "[" Str$(chm.b% + y_%) ";" Str$(chm.a% + x_%) "H" Mid$(s$, i%, nc%); Inc i%, nc% Inc x_%, nc% If x_% = chm.w% Then x_% = 0 : Inc y_% nc% = Min(chm.w% - x_%, ls% - i% + 1) Loop ' Leaves chm.x% and chm.y% at the last printed char position. chm.x% = x_% chm.y% = y_% End Sub Sub chm.scroll_up() ' Local tmpa%(chm.w%), tmpc%(chm.w%) Local pa% = chm.pa% Local pc% = chm.pc% ' Copy attribute and character data from first line (y = 0) to tmp{a|c}%. ' Memory Copy pa%, Peek(VarAddr tmpa%()), chm.w% ' Memory Copy pc%, Peek(VarAddr tmpc%()), chm.w% Local y% For y% = 1 To chm.h% - 1 ' Copy attribute and character data from line y + 1 to line y. Memory Copy pa% + chm.w%, pa%, chm.w% Memory Copy pc% + chm.w%, pc%, chm.w% Inc pa%, chm.w% Inc pc%, chm.w% Next ' Paste attribute and character data from original first line to last line. ' Memory Copy Peek(VarAddr tmpa%()), pa%, chm.w% ' Memory Copy Peek(VarAddr tmpc%()), pc%, chm.w% Memory Set pa%, chm.WHITE%, chm.w% Memory Set pc%, 32, chm.w% chm.redraw() End Sub Sub chm.redraw() Local a% = -1, b%, x%, y% Local pa% = chm.pa% Local pc% = chm.pc% For y% = 0 To chm.h% - 1 Print Chr$(27) "[" Str$(chm.b% + y%) ";" Str$(chm.a%) "H"; For x% = 0 To chm.w% - 1 b% = Peek(Byte pa% + x%) If a% <> b% Then a% = b% : Print chm.col_map$(a%); Print Chr$(Peek(Byte pc% + x%)); Next x% Inc pa%, chm.w% Inc pc%, chm.w% Next y% End Sub Sub chm.border() Local s1$ = "+" + String$(chm.w%, "-") + "+" Local s2$ = "|" + Space$(chm.w%) + "|") Print Chr$(27) "[" Str$(chm.b% - 1) ";" Str$(chm.a% - 1) "H" s1$ Local i% For i% = 0 To chm.h% - 1 Print Chr$(27) "[" Str$(chm.b% + i%) ";" Str$(chm.a% - 1) "H" s2$ Next Print Chr$(27) "[" Str$(chm.b% + chm.h%) ";" Str$(chm.a% - 1) "H" s1$ End Sub Best wishes, Tom Edited 2021-02-08 10:11 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
No obvious problems with TeraTerm and Windows10 You are sending a lot of data down the serial line and I expect that your terminal can't keep up. Remember that there is no flow control. Jim VK7JH MMedit |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
Output to the console using print is blocking if the output buffer fills so characters are not lost, as Jim identifies the problem must be at the terminal end |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Tom, You could either slow it down or for a test at the receiving end use a logging program which just collects data without showing it so it can keep up (then play the data back). John |
||||
romba6![]() Newbie ![]() Joined: 04/07/2020 Location: United KingdomPosts: 37 |
I've tested this multiple times with Teraterm (no delays set) on laptop and 100% rock solid. I will, if I can!, set it to output on COM2 later where I have an RS232 to another PC. I have learnt a lot from this as I am also messing with VT100 |
||||
Tinine Guru ![]() Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Plus, you spelled erroneously wrong ![]() ![]() |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
I didn't spell it "wrong", I spelt it erroneously. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Thanks for all the comments. I am connecting using PuTTY from a Pi 3, I'll try TeraTerm on my Win10 power-house later but it sounds like my code is probably OK. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
Wrong thread - ignore Edited 2021-02-09 00:55 by matherp |
||||
frnno967 Senior Member ![]() Joined: 02/10/2020 Location: United StatesPosts: 104 |
Try Syncterm. Jay Crutti: Ham Radio Operator, K5JCJ. Computer Enthusiast. Musician. Engineer. |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |