Shop OBEX P1 Docs P2 Docs Learn Events
NUMBERS saving over sequential variables — Parallax Forums

NUMBERS saving over sequential variables

Keith YoungKeith Young Posts: 569
edited 2011-01-30 00:42 in Propeller 1
When running something such as
astr := NUM.ToStr(anum, NUM#DEC5)
bstr := NUM.ToStr(bnum, NUM#DEC5)
cstr := NUM.ToStr(cnum, NUM#DEC5)
dstr := NUM.ToStr(dnum, NUM#DEC5)
 
DBG.Str(astr)
DBG.Str(bstr)
DBG.Str(cstr)
DBG.Str(dstr)

all of the displayed values will display as I would expect to see the d number. If I comment out the d number, the 3 remaining displayed numbers all show as I expect to see the c number.

I've found a slow, sort of duct tape way, of fixing the issue is to immediately DBG. However I am using TV and I need these numbers to be established before a screen refresh.

I've tried several ways of saying the same thing trying to trick the program in to working but it just doesn't want to without going super slow.

Is this a common problem? Maybe I need to treat these variables in some special way in DAT? For example astr long "55555", 0 or something?

If I find a fix I'll be sure to post it here. I've spent alot of time troubleshooting this error and I expect it to be common.

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-01-28 00:46
    roughwood wrote: »
    Is this a common problem? Maybe I need to treat these variables in some special way in DAT? For example astr long "55555", 0 or something?
    The ToStr method returns the address of the (objects) internal string buffer. If you want to convert several numbers before displaying them, you'll have to copy the string(s) into a safe location (bytemove()) because the next ToStr call will re-use the internal buffer.

    Basically you got what you asked for.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-28 07:42
    As Marko points out, you need a buffer of at least six characters for each of your conversions. Are you using the NUM object for other things? If not, you might want to do a simple custom method to print a value in this format. I don't know what your DBG object is, but I'll assume it has a TX method for a single character
    pub print5(n) | div
    
      n := -9_999 #> n <# 99_999                                    ' limit to 5 characters
    
      if (n < 0)                                                    ' if negative
        dbg.tx("-")                                                 '  print sign
        ||n                                                         '  remove sign  
        div := 1_000
      else
        div := 10_000                                                        
    
      repeat while (div > 0)
        dbg.tx(n / div + "0")                                       ' extract & print digit
        n //= div                                                   ' remove printed digit
        div /= 10                                                   ' update divisor
    
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-28 19:29
    I am using Graphics.Spin but I can give something like that a try also.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-29 09:50
    I've not taken the time to learn Graphics.spin but did manage to cobble up the attached -- maybe it will help.
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-29 13:40
    Yeah that's similar to how I tried it earlier. Basically I'd just copied sections from TV_Text and TV_Terminal. However I need these values to update at least 10 times a second and preferably keep up with a framerate of 30.

    My problem is enhanced also due to the fact that my program uses more space than typical Graphics_Demo styled commands will allow. I am using what PotatoHead was kind enough to point out here http://forums.parallax.com/entry.php?86-Ripple-Draw

    Which basically draws the screen 8 times, so to have to display the text for each update makes everything that much slower.

    I mainly need to update the values right before I run the 8 screen Draws. My ADC is spitting out numbers very quickly, I just need to grab the values right before Draw, and have the displayed values remain the same through all 8 draws.

    If Graphics.Spin had a Dec command or if Numbers.Spin or Simple_Numbers.Spin would just let me save a value I'd be all set hehe. Trying to hack them in to working just hasn't been successful yet.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-29 13:58
    If Graphics.Spin had a Dec command

    It doesn't because it can only print a string, not indiviual characters. If you create enough buffers for your values then the code I showed you can work -- just pass the individual buffer for the desired ADC channel, then print them later. Assuming you don't have negative values and your ADC reading will fit into four digits, you can change my number to string conversion like this:
    pub num4str(n, strbuf) | div
    
      n := 0 #> n <# 9_999                                          ' limit to 4 characters
      bytefill(strbuf, 0, 5)                                        ' clear buffer
    
      case n                                                        ' set divisor for n
          0..9   : div := 1
         10..99  : div := 10
        100..999 : div := 100
        other    : div := 1000                                                       
    
      repeat while (div > 0)
        byte[strbuf++] :=  n / div + "0"                            ' extract & print digit
        n //= div                                                   ' remove printed digit
        div /= 10                                                   ' update divisor
    

    Updated code:
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-29 14:35
    Yeah this is working better and faster than anything I've been able to throw together so far. Thanks for that!
    repeat
        shareds    := shared  
        rudders    := rudder
        ailerons   := aileron       
        elevators  := elevator   
        throttles  := throttle                  
        GR.Setup(2, 12, 128, 96, bitmap_base)            
        Draw                                    
        'frame++        ORIGINAL               
        GR.Setup(2, 12, 128-32, 96, bitmap_base+$600)  'draw strip to the right...
        Draw                             
        'frame++        ORIGINAL
        GR.Setup(2, 12, 128-64, 96, bitmap_base+$C00)  'draw strip to the right...
        Draw                               
        'frame++        ORIGINAL
        GR.Setup(2, 12, 128-96, 96, bitmap_base+$1200)  'draw strip to the right...
        Draw                         
        frame++
        GR.Setup(2, 12, 128-128, 96, bitmap_base+$1800)  'draw strip to the right...
        Draw
        'frame++        ORIGINAL
        GR.Setup(2, 12, 128-160, 96, bitmap_base+$1E00)  'draw strip to the right...
        Draw
        'frame++        ORIGINAL
        GR.Setup(2, 12, 128-192, 96, bitmap_base+$2400)  'draw strip to the right...
        Draw
        'frame++        ORIGINAL
        GR.Setup(2, 12, 128-224, 96, bitmap_base+$2A00)  'draw strip to the right...
        Draw
        'frame++        ORIGINAL
        frame := frame + 3    
     
    PUB Draw 
      
        GR.Clear                  
        num5(shareds, @numstr)
        GR.Text(-100, 80, @numstr)
        GR.Finish                
        num5(rudders, @numstr)
        GR.Text(-100, 70, @numstr)
        GR.Finish   
        num5(ailerons, @numstr)
        GR.Text(-100, 60, @numstr)
        GR.Finish
        num5(elevators, @numstr)
        GR.Text(-100, 50, @numstr)
        GR.Finish 
    

    I was hoping to just do the number to string right at the top so the program wouldn't feel the need to run all those Spin instructions 8 times per screen refresh. Once I add on the rest of the functionality (lines and arcs etc) I think this method of converting 8 times per screen refresh to avoid the issue of NumToStr type command overwriting themselves won't be ideal.

    There's got to be a way to get a permanent value from a number to string. Bytemove wasn't doing the trick either strangely.
  • kuronekokuroneko Posts: 3,623
    edited 2011-01-29 17:40
    roughwood wrote: »
    There's got to be a way to get a permanent value from a number to string. Bytemove wasn't doing the trick either strangely.
    The Numbers object can't give you a permanent value by design (short of taking a copy before the next conversion). If it had another method which takes a user buffer then yes but in its current state no. As for bytemove not working, see example below.
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    CON
      ncnt = 4                                              ' number of conversions
      ccnt = 12                                             ' size of temporary buffer
      
    OBJ
      FDS: "FullDuplexSerial"
      NUM: "Numbers"
    
    VAR
      byte  storage[ncnt*ccnt]                              ' temporary buffers
      
    PUB null | n, str[4]
    
      NUM.Init                                                
      FDS.start(31, 30, %0000, 115200)
      waitcnt(clkfreq*3 + cnt)
      
      [COLOR="blue"]' convert ncnt values[/COLOR]
      repeat n from 0 to constant(ncnt -1)
        bytemove(@storage[n*ccnt], NUM.ToStr(?cnt, NUM#SDEC11), ccnt)
    
      [COLOR="blue"]' display ncnt values[/COLOR]
      repeat n from 0 to constant(ncnt -1)
        FDS.str(@storage[n*ccnt])
        FDS.tx(13)
    
    It converts 4 (ncnt) random numbers (?cnt) which occupy at most 12 characters (ccnt, 11 chars + string terminator). The string generated by ToStr is copied immediately into the temporary storage for this particular number (@storage[n*ccnt]) and displayed later.
  • potatoheadpotatohead Posts: 10,261
    edited 2011-01-29 18:16
    Can you attach a picture of what the finished display screen is supposed to be like? Even a crude sketch will do.

    There are other ways to manage a partially buffered screen. That ripple draw method is a great general purpose case, that will work for most anything, but... It can be improved significantly, depending on what the screen is doing. It's likely a different drawing order, and or some intelligent management of the strips can yield you some screen speed.

    If you've got the buffer space, 4 strips may work better, or the technique could be extended some to smaller regions. So, a full draw, on occasion, with rapid secondary draws to update text values.
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-29 19:45
    HUD%20M2.jpg


    hud.jpg


    Plus warning screens and menu screens. A GUI for GPS waypoint system.

    Video Overlay will also be necassary, but that will likely be done on Backpack on another screen.

    Basically my buddy worked it out to take aerial photography making enough money to pay for the equiptment and a couple beers. So I'm making a plane that can fly to waypoints, be flown by hand or autopilot, have a pan tilt zoom camera, and the camera is expensive so pilot interupt etc is necessary as well as GPS location in case of crash. Lots of menu and probably 2 TV's being driven. One with say 2 way telemetry and the other controling forward looking pilot camera and pan tilt zoom camera for picture taking.

    So there will be a plane with 1-2 Props and ground station with 1-2 Props.
    800 x 557 - 106K
    400 x 315 - 68K
  • potatoheadpotatohead Posts: 10,261
    edited 2011-01-29 23:28
    Here's a color reduced image of the HUD.

    If it were me, I would make a draw routine for the geometry, and I would use 6 or 8 strips. Locate your text elements in the strips, and refrain from mixing them with the geometry. That way, the drawing of text can be decoupled from the geometry. Draw the geometry each screen update, and the text, every few updates. The illusion of a rapid display will be there, and will filter out noise from the text data anyway.

    (unless that's really important)

    I think I would also seriously consider pre-computing the text elements, storing them as images that can just be drawn to the screen quickly. If the text is "ORed" with the geometry, it can overlay it where needed.

    So that's about what is possible with the strips. Draw the center 4 strips or 6 strips constantly, adding in the occasional draw of the side strips for a optimal display draw, using the partial buffer method.

    To get better than that, it's going to need to be individual tiles. Define them in the HUB, draw to them, then "pop" them on the screen, by changing the tile addresses when they are complete. No tearing that way, and fairly high complexity objects can be drawn without the user seeing it.

    The set tile address method, and the window demonstration in my commented graphics_demo.spin show how this is done.

    You might also be able to clone a few areas of the screen too.

    When you get more of the graphics running, and know more about the data, more might be possible to say.
    800 x 557 - 9K
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-29 23:40
    Saving the text to pictures later to be called up, will that take a lot of space? I am OK with incorporating an SD card but my only experience with SD is datalogger.
  • potatoheadpotatohead Posts: 10,261
    edited 2011-01-30 00:03
    It will take some space, but not too much. Maybe 16 bytes or so per digit. Store those, and just copy them to the screen, instead of drawing them with the text method. It's more complicated, but it might be faster. Will have to see once you get more of the screen draw routines working. Just kind of brainstorming right now. Use the tools you've got, and when it starts to suck, then that's the time to start finding outs :)
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-30 00:22
    Should I make a Project thread or something? Cause I made this thread mainly because I figured other people had the same problem with Numbers.Spin and Simple_Numbers.Spin. That and I can see about 57.3 more pitfalls while trying to complete this project.
  • potatoheadpotatohead Posts: 10,261
    edited 2011-01-30 00:32
    LOL!! Up to you. If you want, use your blog. Some of us put stuff there, then call attention to it when we think it makes sense. Others just put it in the forum. Still others keep it all quiet, until it's done, or they need HELP!!

    I didn't want to distract. Sometimes it's fun to think of different ways to do graphics, and that might not be the point. Sure sounds like a great project though. Maybe you will feel about 57.3 times better about finishing it! That's how it works for me.
  • Keith YoungKeith Young Posts: 569
    edited 2011-01-30 00:42
    No I appreciate all the help I can get believe me I'm just not a forum etiquete guru.

    I don't have any direct plan for how to do everything, how to make the menus work. I just have a list of attributes which will both grow and shrink. This project is still very much in the brainstorming phase. Most of what I'm doing right now is making a sort of "cardboard model". Making sure I can control the speed and location of a Servo wirelessly with the joystick. Simulating a loss of aircraft power, then re-establishing communication remotely.

    if communication loss
    autopilot climb to 200ft
    regain communications
    etc

    This will probably take me 4 hours a day till Summer.
Sign In or Register to comment.