Shop OBEX P1 Docs P2 Docs Learn Events
Hackable Badge Spin tests — Parallax Forums

Hackable Badge Spin tests

I started to play around with my Hackable Badge, this time I am using the JonnyMac Spin drivers. I have renamed a few objects, to make them more generic, JonnyMac gets full credit at the end of the files. This strictly for use with the PropellerIDE.

The hb_base.spin file is the start point. This basically sets up a program that you can use to test out the Hackable Badge LEDs and RGBs, plus the PropellerIDE terminal screen. To use the terminal, you open the screen, and then you set the COM port, the same one that is open for the IDE session. I keep looking at the code and I am trying to figure out a more coherent(simpler?) way of doing this, that is programming the Hackable Badge.

The project that this is leading to, is using the QuickStart+HIB IR component to provide information via the IR too the Hackable Badge. So the next step for hb_base.spin is to code it too use IR to get messages from the QuickStart+HIB device, and have it displayed on the terminal screen while using the Hackable Badge. Then later on use the oled screen for the display.

<COMMENTARY>
When I was using the C version for this, I was a little disappointed that the coding style was not more modular. The lib file was very very difficult to follow, let alone trying to extract some snippets of code and make it viable for, lets say the QuickStart+HIB device. It seems like C development for the Hackable Badge has stalled.

As for the Spin version, it seems to lack an object(s) for the battery state, Real Time Clock, and more colors for the RGBs. I know, why don't I do it? Well probably because my skills are very limited, plus the fact that there is an official Spin pack for this, what's the point of getting the files all scattered, it is hard enough to deal with the OBEX.
<END>

When I get the two devices talking to each other, using the IR, then I will attach the zip file that will contain the code for the QuickStart+HIB device. Hopefully this will make using the Hackable Badge a little easier.

Ray

Comments

  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-01 13:21
    Please remove my name from any objects you modify and redistribute. I do not require attribution, and refuse to be held accountable errors that may be introduced by modifications that are not my own.

    The code that I wrote for the badge includes several libraries that I routinely deploy in commercial applications. One is called jm_time.spin. The purpose of this object is time-oriented processes. In addition to standard delays (milliseconds, and microseconds with limits), it allows one to handle long-term timing events (this allows me to use Propeller bandwidth that would otherwise be dead during very long delays). I think it's important to note that this object is independent of system frequency. You know... flexible.

    I also use an object called jm_io_basic.spin. Shockingly, this deals with simple IO processes: making a pin high or low, an input (and reading it), toggling a pin, etc.

    Let's examine your "better" solution, shall we: an object called tools.spin. It's short enough to embed here.
    '' tools.spin
    
    PUB wait(time)
    
      waitcnt((80_000_000 * time) + cnt)
    
    PUB waitms(time)
      waitcnt(((80_000_000 / 1000) * time) + cnt)
    
    PUB high(pin)
    
      DIRA[pin] := %1
      OUTA[pin] := 1
    
    PUB low(pin)
    
      DIRA[pin] := %1
      OUTA[pin] := 0
    
    Interesting what you consider "better." An object name with no indication of what kind of tools it provides. I guess your idea of "a little easier" means no documentation comments in the object. I know, it's a lot of trouble to add comments to code; it's so much easier to complain about code written by others in the forums.

    The wait() method has a parameter called time. Okay, how is the newcomer to understand that this is in seconds, and only if the system is running at 80MHz, and only works if the seconds is 53 or less (at 80MHz)? Please, explain how this is "better." I can be convinced, but with evidence, not whinging about my code being difficult.

    The waitms() method suffers from the same flaw (in my opinion): it is locked to a system frequency of 80MHz. And both methods suffer from the call to cnt being last in the expression -- this adds overhead to the call (my code accounts for method call overhead).

    Here are "simple" changes that you might consider that do not suffer the problems in the original code.
    pub wait_secs(secs) | t
    
      t := cnt
      repeat secs
        waitcnt(t += clkfreq)
    
    
    pub wait_ms(ms) | t
    
      t := cnt
      repeat ms
        waitcnt(t += clkfreq / 1000)
    
    Even without documenation comments, it's pretty obvious what's going on. Both are independent of clock frequency, and have an input range of 1 to POSX.

    The high() and low() methods are fine, but assume that the new user understands what those mean.

    I cannot stop you from using my objects, but I will take you to task every time you insinuate that my code is a problem, that you need to protect the Propeller community from me by modifying my objects that are not to your liking, and that you have a "better" way. When you do step up show me a better way, I will say "Thank you" and incorporate what I learned into my own code. In point-of-fact, a Nuts & Volts reader graciously made a excellent suggestion that I incorporated into my jm_time.spin object. I thanked him and implemented the suggestion; the object is a bit better and both of us are happy.
  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-08-31 17:46
    <COMMENTARY>I wish the forums would allow me to attach a file to an existing post.</COMMENTARY>

    I've attached the objects here that were referenced above.

  • Continuing with the Spin Hackable Badge tests, I got the IR working for the two units. This is in the simplest form.

    In my QS+HIB device, qs_base.spin program, I added this:
    repeat
          IRIO.str(string("Got it?"))
          tlib.wait(2)
    
    which is sending(Tx) the string every two seconds.

    In the hb_base.spin program, I added this:
          if IRIO.rxcheck < 0  ' Buffer is empty?
            buffer := IRIO.rx  ' Get contents of buffer.
            ser0.tx(buffer)    ' Display buffer to terminal.
    
    It is receiving(Rx) the string and displaying it on the PropellerIDE terminal. I guess now it would be a good time to implement the oled screen on the Hackable Badge, and see if I can get it to display there and the terminal, just to see if the results are the same.

    Ray
  • I have run into a very interesting problem.

    Since I had the QS+HIB and the Hackable Badge working using the IR with the Spin methods, I thought I would try getting the Hackable Badge with the C version of IR to talk too the QS+HIB with Spin methods. Hmm, did not work, either C does not know what Spin is doing or Spin does not know what C is doing. The strangest part is that the C IR code is Spin code that was converted using spin2cpp. I guess what I need is a CtoSpin program that would convert the C IR functions to Spin so that would be compatible on a Spin based board(QS+HIB). And I thought that working with this stuff would be simple.

    Not sure what the next step is, to much inconsistency for me to grapple with at the moment.

    Ray

  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-02 14:48
    was converted using spin2cpp
    Quoting Jamie from MythBusters: Well, there's your problem.

    How do you know the conversion was accurate? If you want badge code in C, why not translate the [fully vetted] Spin code yourself? I translate loads of useful C code to Spin, so I assume one can go the other direction.
    And I thought that working with this stuff would be simple.
    It is simple -- but it's not always easy. Details matter.
  • I think that I have found the discrepancy, the C IR function is expecting a string(bytes?), with termination, while the Spin IR method is sending a decimal string, not sure about the termination, if any is needed.

    I am not absolutely sure about this, but it sounds reasonable to me. This is a big mess, IMO, for others it probably is not.

    So how do I build a "tool chest" that would contain accessible tools that could be used by Spin, C, PropBasic, and others. Is that even possible? Probably a reasonable concept, but that should have been done a long time ago, again if even feasible. Maybe that discussion should be explored in another thread.

    In the mean time...?

    Ray
  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-03 15:45
    The Spin badge code works. If the C version -- which I did not write -- does not play nicely with the Spin version then you should take that up with the person who wrote the C code. Crimony, the badge code is not complicated. I am continually mystified by those claiming to be C programmers not able to do a clean port from Spin to C. Would one be wrong to believe that C for the Propeller does not support all the same features as Spin? That would make it pointless, so I don't believe it to be true, especially since there are C programmers who have successfully ported some of my complicated objects (e.g., WS2812 driver).
    So how do I build a "tool chest" that would contain accessible tools that could be used by Spin, C, PropBasic, and others. Is that even possible?
    If you're suggesting that you can have a single library file that will work with all three languages, I think you're mistaken. Pick a language and master it. If you decide to provide tools for others and want to do that in more than one language, you have to be a master at more than one language. Master may be a bit strong -- I'm no master at C but I understand it well enough to port C to Spin.

    What you could do if take a library that you like from one language and port it to another. This should not be news. The Arduino infestation means that from time-to-time a nice library is available for some interesting part. I have translated many of those libraries to Spin for my own use. Mind you, this is not a blind, 1-for-1 translation: first I seek to understand the library, then I do a basic port, and then I modifying/improve it to my liking.

    What I don't understand is why you want to rob yourself of the joy of creation by expecting/demanding others create every library you want in every language you want. I really enjoy creating my own libraries for my projects, and sharing them with others. Maybe I'm odd (okay, there's no maybe, but that has nothing to do with the joy I get from writing and sharing libraries).
  • I can agree there. I got a ton of satisfaction the first (and only) time I heard my driver was useful to someone. Then Parallax updated OBEX and it vanished lol.

    First time writing assembly. Told myself I wouldn't sleep until I figured it out. Got it done at 7AM :)

    Something pretty cool about writing more down in the guts of the hardware instead of using black box commands that get you results yet you have no idea how it all works.
  • So, moving on, I tried to do some experimentation with the Hackable Badge touch pads, no success just yet.

    Using the jm_touchpads driver, I was trying to figure out how to use:
    pub start(count, p_pins, dms) | idx
    
    '' Setup object for input of count pins
    '' -- count is # pins to scan
    '' -- p_pins is a pointer to a list of pins (byte array)
    ''    * pins in list are arranged MSB to LSB
    '' -- ms is the discharge timing in milliseconds
    
    My method is:
    CON
    ' touch buttons (left)
      BTN_5    = 17 
      BTN_4    = 16
      BTN_3    = 15  
    ' touch buttons (right)
      BTN_0    = 27
      BTN_1    = 26
      BTN_2    = 25
    ' touch button bottom of oled
      BTN_OS   =  5
    
      repeat
        tpads.start(1,BTN_0,50)
        if tpads.read_pads == BTN_0
          set_1_blue(BLUE_0)  ' Blue LED upper right
          tlib.wait(1)
          set_1_blue(BLUE_off)
    
    Of course this is just a code snippet, and touching the touchpad does not do anything.

    My aim is to have a good working example of being able to touch the upper right touchpad and have the LED next to it go on/off. The one thing I do like about the C lib version, it does have a lot of workable examples for the functions that are available.

    Ray
  • @Seairth wrote a badge menu which might include some code snippets along the lines your are thinking Ray:

    forums.parallax.com/discussion/162110/badge-a-menu-system

    I'm fairly sure he also had another thread around that time, in which he spent a fair time looking at different ways to read the buttons with varying accuracy/success. That research might well be included in the badge-menu code though.
  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-05 18:19
    Of course this is just a code snippet, and touching the touchpad does not do anything.
    Well, not with your code, because it is expecting a pin # while the read_pads() method returns a mask that contains n bits (as defined in the start() method).

    There are futher problems -- for example, your parameters for the .start() method
    tpads.start(1,BTN_0,50)
    
    Here's the code you're invoking:
    pub start(count, p_pins, dms) | idx
    
    '' Setup object for input of count pins
    '' -- count is # pins to scan
    '' -- p_pins is a pointer to a list of pins (byte array)
    ''    * pins in list are arranged MSB to LSB
    '' -- ms is the discharge timing in milliseconds
    
      longmove(@pincount, @count, 3)                                ' copy parameters
    
      pinsmask := 0                                                 ' build mask of input pins
      repeat idx from 0 to pincount-1 
        pinsmask |= 1 << byte[p_pinslist][pincount-1-idx]
    
    Note that the second parameter is required to be a pointer to a list of pins -- not a pin #.
    Using the jm_touchpads driver, I was trying to figure out how to use:
    Funny... there's an example right in the demo code:
       pads.start(TPCount, @TPPins, TPDischarge)
    
    You'll find a DAT block which defines the touchpads on the badge -- elements in this block are used by the pads.start() method.
    dat { touch pads configuration }
    
      TPCount       byte    7
      TPPins        byte    BTN_OS, BTN_5, BTN_4, BTN_3, BTN_2, BTN_1, BTN_0
      TPDischarge   byte    15
    
    You'll also find this set of constants that define the button positions in the pads.read_pads() mask:
    con { buttons masks }
      
      PB0_MASK  = %0_000_001                                         ' upper right
      PB1_MASK  = %0_000_010                                         ' middle right
      PB2_MASK  = %0_000_100                                         ' lower right
      PB3_MASK  = %0_001_000                                         ' lower left
      PB4_MASK  = %0_010_000                                         ' middle left
      PB5_MASK  = %0_100_000                                         ' upper left
      PB6_MASK  = %1_000_000                                         ' open source logo
    
    I wrote the code the way that I did...
    1) because the badge layout did not allow the pads to be connected to contiguous pins
    2) to allow the programmer to treat the touchpads as a simple group of inputs using the read_pad() method

    With a bit of effort (yes, I know that means thought and work), a willing programmer could create a support method that reads the touchpads and returns the pin # if touched. As it is possible for no pins to be touched, or multiple pins to be touched, and zero is valid pin #, we will return -1 if no pads or multiple pads are touched.
    pub which_pad
    
    '' Returns pin # of touched pad
    '' -- result is -1 if no pads or multiple pads touched
    
      case pads.read_pads  
        PB0_MASK : return BTN_0
        PB1_MASK : return BTN_1   
        PB2_MASK : return BTN_2   
        PB3_MASK : return BTN_3   
        PB4_MASK : return BTN_4   
        PB5_MASK : return BTN_5   
        PB6_MASK : return BTN_OS
        other    : return -1
    
    My aim is to have a good working example...
    They exist -- you simply refuse to study them.
Sign In or Register to comment.