November 28, 2024, 01:27:33 AM

News:

Be sure to checkout our Vixen interfaces in the Library forum -- if you want PC automation at near zero cost, EFX-TEK and Vixen is a great combination of tools.


Quick question on how HC-8+ reads its code

Started by JoshHHA2014, October 22, 2015, 12:42:25 PM

Previous topic - Next topic

JoshHHA2014

Let me know if I have this correctly.

If I have a repeating loop routine on my main program for a prop and a subroutine was activated from there, does the HC-8+ process my main program loop while running the activated subroutine in the script? If it does, how many subroutines can run with my main repeating loop still being watched for inputs/bits?

JonnyMac

October 22, 2015, 04:26:15 PM #1 Last Edit: October 22, 2015, 04:31:50 PM by JonnyMac
That depends on how you construct the code. You can certainly create subroutines (they're called methods in the Propeller world) that "block" the main program until they're finished, or you can create variations that are called and run in their own processor, allowing the main process to immediately get back to its own business. You can even construct a method that can detect if it is running independently and shut itself down when finished.

For example, here's a method that can do that:

pub blinker(pin, onms, offms, cycles)

  repeat cycles
    io.high(pin)
    time.pause(onms)
    io.low(pin)
    time.pause(offms)

  if (cogid > 0)
    cogstop(cogid)


To call this like a standard (blocking) method, we would do this

  blinker(OUT0, 250, 750, 5)

In this case we will blink OUT0 using a cycle that lasts 1000ms (250ms on + 750ms off), so the main routine will be "blocked" for 5s. Since this is being called from as a routine in the main (0) cog, the cogstop() instruction will not run.

If, however, we want this to run without a major interruption of the main routine, we would do this:

  cognew(blinker(OUT0, 250, 750, 5), @bkgstack)

Now we're launching that routine into another cog where it can run independently and in parallel with the main cog. Launching takes a fraction of a millisecond, so we won't notice. When the routine is done it will kill itself with the cogstop() instruction because it is not running in cog 0.

Note that we need a small stack (for temporary variables) when launching a method into its own cog. I tend to start with an array of longs that has 32 elements.

I know that this stuff can seem hairy at first, but once you understand it, the Propeller is amazingly powerful while still being easy to program.
Jon McPhalen
EFX-TEK Hollywood Office

JoshHHA2014

October 23, 2015, 09:25:09 AM #2 Last Edit: October 23, 2015, 10:01:46 AM by JoshHHA2014
Okay, I see what you are saying but can you put it into a better understanding using the code I have written?

I have these methods in my main block:


pub main | t
  setup_io                              'setup HC-8+ IO pins
  com1.start(SIO, SIO, %1100, 38_400)   'half-duplex for HC-8+ comms
                                        'Note: Set "BR" dip switch to the on position
  pause(1)                              'let all cogs start
 

repeat



                                                   
     'RESET BUTTON
'    --------------
     
    if ttl_bit(Reset_PB) == 1
        low(Trap_LEDs)
        pause(100)
        low(Intro_video)
        pause(100)
        low(Won_Video)
        pause(100)
        hc8_digital_select(%00, %00000000, %11111111)
        pause(100)
        outb[reset] := 1
        outb[reset2] := 0
        outb[intro] := 0
        outb[game] := 0
        outb[bypass] := 1
        outb[opendoor] := 0
        outb[t1pb] := 0
        outb[t2pb] := 0
        outb[t3pb] := 0
        outb[t4pb] := 0
        outb[t5pb] := 0
        outb[motion] := 0
        outb[motion2] := 0
        outb[motion3] := 0
        outb[wgame] := 0
        outb[lgame] := 0       
        introtimer := 0
        gametimer := 0
        motiontimer := 0
        byptimer := 0       
        high(Mag_Lock)
        pause(50)
        high(Door_Cylinder)
        pause(100)
        high(Video_Reset)
        pause(100)
        low(Video_Reset)
        pause(50)
       

     'BYPASS PUSH BUTTON
'    --------------------

    if ttl_bit(Exit_Byp_PB) == 1

        if outb[bypass] == 1
          low(Mag_Lock)
          pause(50)
          low(Door_Cylinder)
          pause(100)
          byptimer := 0
          outb[bypass] := 0

        if outb[bypass] == 0 and byptimer > 20
           high(Mag_Lock)
           pause(50)
           high(Door_Cylinder)
           pause(100)
           byptimer := 0
           outb[bypass] := 1
           
    if outb[bypass] == 0
      byptimer := byptimer + 1

    if outb[opendoor] == 1

      low(Mag_Lock)
      pause(50)                                     
      low(Door_Cylinder)
      pause(50)

      motiontimer := motiontimer + 1

      if motiontimer == 1 or motiontimer < 150
        high(Room_LED)
        pause(250)
        low(Room_LED)
        pause(250)                       
     
      if motiontimer > 150 or motiontimer == 150
        high(Room_LED)
        pause(100)
        low(Room_LED)
        pause(100)

      if ttl_bit(Motion_Sensor) == 0
          outb[motion] := 0
          outb[motion2] := 0
          outb[motion3] := 0
          pause(3000)

    pause(100)                        'run loop every 100ms


Now these are just bits of my main block loop.
How would I go about simplifying those methods on cog0 and having the routine process on a different cog?
Looking to break down cog0's methods because currently running everything off one cog I believe.

Also what does "@bkgstack" and "@stack0" meaning?

JonnyMac

October 23, 2015, 03:33:51 PM #3 Last Edit: October 23, 2015, 04:30:12 PM by JonnyMac
QuoteOkay, I see what you are saying but can you put it into a better understanding using the code I have written?

I will happily help out, but that code is only meaningful to you. Without an English description of what you want, I may not be able to sort it out.

What I can say is that you really want to start writing is small, easy-to-digest chunks. For example, in your main loop there is a TON of code which makes it very hard to read. I would encourage you to do something like this:

pub main

  if (ttl_pin(true) == REST_BTN)
    reset_all

pub reset_all
 
  ' code for reset


In fact, I often build programs with empty methods just to get an overall build of the program.

And I STRONGLY suggest you do not use the OUTB variables with the Propeller 1 -- this will cause problems porting code to the Propeller 2 and makes code a bit unreadable.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

Jon,

I did Josh's base program last year and used OUTB variables in it, since it was easy to do at the time and been using this in my programs and couldn't find better way to at a single bit. So, how would you write the code based off your statement here and make it portable to the Propeller 2?
QuoteAnd I STRONGLY suggest you do not use the OUTB variables with the Propeller 1 -- this will cause problems porting code to the Propeller 2 and makes code a bit unreadable.
William Stefan
The Basic Stamp Nut

JonnyMac

If you really do need to save a bit you can do it in a long and use a bit mask to access. For example, these simple routines will let you treat a long as 32 bits.

pub wr_bit(bit, pos, p_var) | mask

'' Write bit into position long at p_var
'' -- bit is 0 or 1
'' -- pos is position, 0..31
'' -- p_var is pointer to long
'' -- returns modified value at p_var

  mask := |< pos                                                 ' create mask for position
  if (bit & 1)                                                   ' if 1
    long[p_var] |= mask                                          '  write 1 to position
  else                                                           ' else
    long[p_var] &= mask                                          '  write 0 to position

  return long[p_var]                                             ' return modified value


pub rd_bit(pos, value)

'' Read bit from position of value
'' -- pos is position, 0..31
'' -- returns 0 or 1

  return (value >> pos) & 1


I know you're trying conserve memory, but there are times when this become stepping over a dollar to pick up a dime. Remember, Spin is an interpreted language, and accessing anything but a long takes a little extra time and code -- what you think you're saving in variable space you're eating up in code space.

Again, I would love to see the spec on this project so that I could write a version that would show different ways to master the Propeller.



Jon McPhalen
EFX-TEK Hollywood Office

bsnut

Jon,

Here's the original spec that went off of. I also can provide the edited spin code and answers to questions that I asked Josh.
QuoteSpecifications\Show Sequence

Eight People enter the room, once door closes the game starts by door sensor. Exit door is magnetically locked before they enter. A 20 second introduction video starts with directions. A new 20 second game timer will start at end of video.

During the game timer 4 sets of buttons will light up on 4 bench seats with 4 sets of hammers above them. If they don't push buttons at same time then their hammer goes off a couple times, air cannon goes off, and a 3-5 second air chisel vibrates their seats. But each set of buttons can only set the prop off once. If they push all buttons at the same time all the hammers go crazy, air cannons go off, chisels vibrate seats, and victory video will play. If the timer runs out deadly gas will pour into the room (fog machine), hammers go crazy, air cannons go off, and chisels vibrate seats. At the end of either outcome the exit door magnet will disengage and an air cylinder will open the door.

Now once exit door has opened a motion sensor in room will help indicate when room is clear. An indicator LED outside entrance door will start slowly blinking when motion sensor sees motion. If still motion after 15 seconds, indicator LED will flash faster for traffic flow management. Once room is empty exit door will close, magnet lock engages, and LED indicator turns on solid. At that point once the entrance door has been opened for more than a second the program should restart, waiting for door to shut for game start.

Also there is a button on the exit door that will disengage magnet and open door at any time. This will be used only as a bypass in case of an emergency.


Inputs

- Start door sensor

- Front Trap 1 Buttons
- Back Trap 1 Buttons

- Front Trap 2 Buttons
- Back Trap 2 Buttons

- Room motion sensor for exit door

- Exit door bypass button


Outputs

- LEDS in Trap Buttons

- Intro Video

- Air Cannon Trap 1
- Air Cannon Trap 2

- Air Chisel Trap 1
- Air Chisel Trap 2

- Trap 1 Front Hammer
- Trap 1 Back Hammer

- Trap 2 Front Hammer
- Trap 2 Back Hammer

- Fog Machine

- Won Game Video

- Indicator LED (Outside entrance door)

- Exit door magnet

- Exit door cylinder
William Stefan
The Basic Stamp Nut

JonnyMac

October 24, 2015, 04:26:11 PM #7 Last Edit: October 24, 2015, 04:48:07 PM by JonnyMac
That's really not very much to go on which explains why I'm not able to follow the code.

The root word of specification is "specific" and there are no specifics about control signals to any of the outputs, or which process run in serial versus parallel mode.

I know I'm a nag about these things, but one cannot write good code without a really good specification. That's the hard part, though: coming up with a good spec that another person can implement. This is why I write my own code!

I'll keep reading -- hopefully something will click. More information is appreciated.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

Jon,

Below is the questions that I asked Josh about his specifcation
Quote
1) How are the buttons going to work when someone pushed their button and what happens when someone doesn't push their button?

During the game, each set of buttons can set the prop off once. Nothing at all should happen during the game if the buttons aren't being pressed and before the game timer starts the buttons LEDs shouldn't be active and shouldn't be able to do anything yet. If they are pressed at the same time than it should create the "Won Game" event.


2) Is the "Exit Bypass" button a maintain or momentary push button and how is it planned to be used? Does the person need to push the button to close the exit door after it was pushed?

Don't fully understand what you mean by "maintain or momentary push button" but the button will probably just be a regular prop push button. The button should be able to open the exit door at any point during the show for emergencies and shouldn't interrupt the game.  It would be preferred that the exit door stay open until the bypass button is pressed again to close it, yes.


3) What happens when the game timer runs out of time? Is this considered a loss game and loss game stuff happens?

Exactly! The hammers should go crazy (should set them off and on a couple times simulating hammers swinging down at them), both air cannons go off, chisels vibrate the chairs a little longer than during the game, and the fog machine should go off for 4-5 seconds (deadly gas filling the room).
Do you want me to email you the last version code or post it here? 
William Stefan
The Basic Stamp Nut

JonnyMac

October 24, 2015, 10:20:48 PM #9 Last Edit: October 24, 2015, 10:25:05 PM by JonnyMac
QuoteDo you want me to email you the last version code or post it here?

No. I want to write my interpretation of their spec and then compare notes.

Even with those questions, there is far too little information to write a proper program. Sadly, we're getting away from the topic at hand, but this just proves the point I continually nag about: without good information, there can be no good responses.

I'll say it again, writing a spec is very difficult. We were begged to create the original EZ-8 by an OEM. I probably spend 20+ hours on the phone with him making sure that I understood everything he wanted. It is human nature for any of us to assume that if we know/understand something, everyone else does or can with just the slightest bit of information. That's not the case.
Jon McPhalen
EFX-TEK Hollywood Office