Shop OBEX P1 Docs P2 Docs Learn Events
Download PropBASIC here... 00.01.14 LAST VERSION FOR BST - Page 22 — Parallax Forums

Download PropBASIC here... 00.01.14 LAST VERSION FOR BST

1192022242529

Comments

  • bsnutbsnut Posts: 521
    edited 2010-12-12 02:15
    Bean,

    I have one question for you and you may have answered it already. Does the Propbasic editor capitalize the instructions(e.g. DO LOOP)? I noticed that the editor hasn't been capitalizing the instructions that I was typing.
  • BeanBean Posts: 8,129
    edited 2010-12-12 07:25
    I assume you are using BST for the editor ?
    BST doesn't capitalize commands, but it does make them bold.

    Bean
  • bsnutbsnut Posts: 521
    edited 2010-12-12 11:36
    Yes, I am using BST as the editor. Is there another editor that will capitalize commands that is freeware and will work with Propbasic.
  • BeanBean Posts: 8,129
    edited 2010-12-13 07:24
    I am working on allowing embedded escape sequences in the next release of PropBasic.
    These will work the same as they do in C. Here is what I have so far:
    \r = 13
    \n = 10
    \\ = 92 (backslash)
    \" = 34 (quote)
    \123 = 123 (must use 3 digits)
    \xab = $AB (must use 2 digits)

    This will allow you to do things like:

    SendStr "Hello There\rThis is PropBasic"

    So far they seem to be working, but I need to do more testing before I release it.

    Bean
  • Brian RileyBrian Riley Posts: 626
    edited 2010-12-13 12:19
    Bean wrote: »
    I am working on allowing embedded escape sequences in the next release of PropBasic.
    These will work the same as they do in C. Here is what I have so far:
    /r = 13
    /n = 10
    // = 47 (backslash)
    /" = 34 (quote)
    /123 = 123 (must use 3 digits)
    /xab = $AB (must use 2 digits)

    This will allow you to do things like:

    SendStr "Hello There/rThis is PropBasic"

    So far they seem to be working, but I need to do more testing before I release it.

    Bean

    "backslash" or "frontslash" for "//" ????? "backslash" is 92.
  • BeanBean Posts: 8,129
    edited 2010-12-13 16:04
    Brian,
    Ooops, you are right, that is a regular slash (frontslash, divide, whatever).
    I fixed the post above.

    [EDIT] WARNING the above is wrong. Please see my post below.

    Thanks.

    Bean
  • BeanBean Posts: 8,129
    edited 2010-12-14 14:12
    Brian,
    Thanks for questioning this. I checked again, and yes it should be a backslash. I had the whole post screwed up. I edited it now.

    I don't know what I was thinking...

    Bean
  • Wolfgang EbersbachWolfgang Ebersbach Posts: 10
    edited 2011-01-24 01:52
    Dear Bean, Brad and JonnyMac,

    first of all many many thanks for your efforts in coding and documenting such a handy tool like propbasic and the BST IDE. I have a lot of hardware projects the propeller seems to be made for, but could not use SPIN due to its slow speed. And (right now) I have not time to learn PASM.

    Thus, I gave PropBaisc a try and within about 10 workhours I managed to cretae analog signals via PWM and RC filter, write data to anHUBFT2232H USB bridge device, transfer data via UART at up to 921600 Bytes/sec and shovel data between COGS via the HUB.

    I did never before had such a qiuck start with any uC !

    Anyhow, I now try to implement the ADC example from the "Propeller counters" Appnote in ProbPasic. The idea was to start by copying the ASM part of the example and replace the Spin pert with ProbBasic.

    BUT: How to pass values from a assembly part back to PropBasic ?

    In the original example, this assembly line seems to pass the value of "asm_sample" back to the Spin part:

    wrlong asm_sample, par 'write the value to main memory

    albeit I cannot see "par" defined anywhere. As I do not know SPIN, I cannot understand this.

    So, I need a hint on how to pass values ot of an assembly block back to Pbasic.

    I do this:

    TASK AdcDemo
    DO
    ASM
    asm_entry mov dira,asm_dira 'make pins 8 (ADC) and 0 (DAC) outputs

    movs ctra,#adcpin 'POS W/FEEDBACK mode for CTRA
    movd ctra,#fbpin
    movi ctra,#%01001_000
    mov frqa,#1
    mov asm_cnt,cnt 'prepare for WAITCNT loop
    add asm_cnt,asm_cycles

    :loop waitcnt asm_cnt,asm_cycles 'wait for next CNT value
    mov asm_sample,phsa 'capture PHSA and get difference
    sub asm_sample,asm_old
    add asm_old,asm_sample
    wrlong asm_sample, par 'write the value to main memory
    jmp #:loop 'wait for next sample period

    ' Data
    asm_cycles long |< bits - 1 'sample time
    asm_dira long |< fbpin 'output mask
    asm_cnt res 1
    asm_old res 1
    asm_sample res 1

    ENDASM
    LOOP
    ENDTASK


    This does compile but how do I get the asm_sample back into the ProbBasic world (or into an HUB variable) ?
    ( ASM part copied 1:1 from the Parallax Example )

    Many thanks,
    Wolfgang
  • BeanBean Posts: 8,129
    edited 2011-01-24 04:46
    Wolfgang,
    The PropBasic compiler handles all the "par" stuff.

    All you need to use is RDLONG, WRLONG. HUB variable are accessible from all tasks.

    Bean
  • Wolfgang EbersbachWolfgang Ebersbach Posts: 10
    edited 2011-01-24 05:25
    Bean,

    many thanks for the reply; Anyhow, as I miss the Assembler basics, I do not yet understand it.

    I understood:
    By creating a hub varaible, I get also a constant with an _ofs as extension, which holds the offset -- from what to what ?
    What is "par" ? it is not declared anywhere.

    I did look at the code ProbBasic compiles from my PropBasic file; I found the method you described:
     mov           __temp1,__UsbBufferWritePointer_ofs     ' RDWORD UsbBufferWritePointer,WrtPtr             ' get buffer pointer
      add           __temp1,par                 
      rdword        WrtPtr,__temp1   
    

    which reads a value from a hub variable. Anyhow, WHAT IS "par" ??
  • Wolfgang EbersbachWolfgang Ebersbach Posts: 10
    edited 2011-01-24 06:40
    Sorry to annoy that much.

    I did try to re-write the ADC demo in pure PropBasic. To check the result, I wanted to output the values via serial port.
    But: Whereas this SEROUT test task works:
    TASK FeedUART
      Baud CON "T921600"
      Tx PIN 30 HIGH
      TXB VAR LONG
    
      DO
        FOR TXB = 0 to 255
          SEROUT Tx,Baud,TXB                                 ' send byte
          PAUSEUS 500
        NEXT
      LOOP
    ENDTASK
    
    

    this does not:
    TASK SendToUART
    
    UartBuff VAR LONG = 0
    Baud CON "T921600"
    Txpin PIN 30 HIGH
    
    DO
      RDLONG AdcValue,UartBuff
      SEROUT Txpin,Baud,UartBuff                                 ' send byte
      PAUSEUS 500
    LOOP
    
    ENDTASK
    
    

    and I have no idea why not...
  • BeanBean Posts: 8,129
    edited 2011-01-24 07:02
    Wolfgang,
    Can you post the whole program that is not working ? Otherwise I must make guesses...

    If you are getting nothing you may have the TX pin defined in the main code. In which case the cog running the main code will be holding the TX pin high and the TASK cog will not be able to toggle it.

    Bean
  • Wolfgang EbersbachWolfgang Ebersbach Posts: 10
    edited 2011-01-26 05:52
    Dear Bean,
    many thanks for your help. Indeed, all my problems mentioned so far have been solved. Regarding the not working "serout" the reason was the double definition of the same pin (in two different tasks).

    No I have a new question, which seems not to be documented so far:

    I read data from an ADC via "shiftin", put it in an hub array varaiable that I use as circular buffer and read this in another task to send it to an FT2232H USB bridge device.

    This all works well. Now I try to optimize: The ADC outputs 16Bit samples. Right now I read 8 bits, store them via WRBYTE to the hub array and in the other task, read them from the hub array and send them to the FT2232. For one sample, I do this two times, because one sample has 16 Bits.

    Now, as the Propeller is 32 bit, I would like tor SHIFTIN 32 bits ( representing two samples with 16 bits each) from the ADC and store them to the HUB array. As all operations on the propeller are 32bit, storing 32bit to the hub memory should be as fast as storing 8 bit to the hub memory.
    OK, but now on the other task, that sends the data to the FT2232H. This device has an 8Bit parallel input I am using.
    Thus, I must send data in 8Bit chunks to this device. Now, if I store the data in 32bit variable but want to send it out in 8 bit chinks, how to do this fast ?
    I guess shifting ?
    Can I do something like "variable << 8" to shift 8 bits to the right ?

    I did:
    USBDATA PIN 7..0 OUTPUT
    and later on:
    USBDATA = CurrentByte
    while CurrentByte as an hub varaible and thus 32bit.
    without thinking and that works. But why ?

    Am I right that if you store n-bit values in a LONG, they are right-aligned ?

    So, to send 32bits in 4 8-bit chunks to 8 output pins named "USBDATA" as above, this thould work :?
    MyData VAR LONG
    MyData = HereComesALongValue
    USBDATA = MyData    ' QUESTION: does this put the lowe 8 bits of USBDATA to the pins and leave the MyData unaffected ? if so:
    MyData >> 8               ' I hope this shift MyData to the right by 8 bits, thus discarding the lower 8 bits and moving the next 8 bits to position 0-8 ? If so:
    USBDATA = MyData
    MyData >> 8
    USBDATA = MyData
    MyData >> 8
    USBDATA = MyData
    
    

    sorry for all this questions, up to now I did only C programming of AVR devices... And I should have this run within this week...

    Wolfgang

    P.s.: I totally agree with your signature below your postings...
  • Wolfgang EbersbachWolfgang Ebersbach Posts: 10
    edited 2011-01-26 05:56
    Oh, btw: Whoever is interested:

    Using two prop pins and one counter as an ADC, circuit as in parallaxs appnote "propeller counters", here the PropBasic version as a TASK:
    '------------ ADC Demo - check the ADC capabilities ------------------
    TASK AdcDemo
    
    
    '---- ADC definitions -----
    adcpin PIN 23                        ' Pin 28 ADC Input
    fbpin PIN 22 OUTPUT             ' Pin 27 feedback
    
    adcval VAR LONG                 ' ADC value
    adcold VAR LONG                 ' old ADC value
    target VAR LONG                  ' sys timer compare target value
    cycles VAR LONG                 ' ADC count cycles
    cycles = 255                         ' cycles = 2^bits -1 ; here 8 bits adc resolution
    
    COUNTERA 72,adcpin,fbpin,1,0    ' pos with feedback mode
    target = cnt + cycles                    ' sync to sys counter
    
    DO
      WAITCNT target,cycles         ' wait for cycles CPU clock cycles; the timera is counting in the meantime, IF APIN is HIGH
      adcval = phsa                        ' get PHSA register value
      adcval = adcval - adcold         ' calc value
      adcold = adcold + adcval
      WRLONG AdcValue,adcval    ' store value to hub ram
    LOOP
    
    ENDTASK
    
    
    
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-02 13:48
    I'm making good progress and learning a ton on my project. But I've kind of been programming and debugging everything in the "dark." Since I'm used to being able to set watch variables and break points on PC software. I'm now looking into how to get debug info out of the Prop.

    I had a couple questions that I was hoping you guys could answer. I searched the forums, etc. but haven't found a clear answer. I know there is PASD that now supports PropBasic, but I haven't been brave enough to jump that far into the deep end for configuring and trying to embed it in my code.

    1. Does PropBasic have an equivalent or "ported version" of the debug command? If it does, is there any info. someone can link me.

    2. If not, I was messing around with using serout to try and send my variables to the PST. But I get nothing even though I see the TX flashing like crazy. See below.

    The L_Sense is a VAR read from a RCTIME photo sensor. I also am trying to do this with Bean's sndmeter code, which I borrowed and tried to change.
    SEROUT TX, Baud, L_Sense
    
    Do I need some sort of conversion syntax like this?
    SEROUT TX, Baud, [DEC L_Sense]
    
    3. Does the RANDOM seed work at the global level or is it per COG? For example if I call random in my sensor COG (1) and loop it for several seeds using one of my sensors inputs. Then use the Random on my main COG (0) code will it get that seed? I'm guessing it won't since they are in separate memory spaces.

    4. Is there any other info. on the STR command, I don't seem to understanding how to use it completely. I found the Basic Stamp manual reference which helped. I'm just not sure how to use the various arguments that you can pass it.

    I can send anyone my source code or attach it if it's necessary to help me. I'm at work so I can't attach it right now, but wanted to hopefully get some feedback.

    Thanks,
    Kevin
  • BeanBean Posts: 8,129
    edited 2011-02-02 14:03
    1. No it doesn't

    2. To output decimal values you need to convert the variable to a string first with the STR command.

    3. The random seed is just a regular variable, so it IS unique to each cog.

    4. See page 33 of the attached document.

    You'll want to do something like:
    ascii  HUB STRING(10) ' Put this at the top with your other variables
    
    ascii = STR L_Sense, 5, 3 ' 5=digits, 3=Signed, leading spaces, Z-string (must be z-string for SEROUT)
    ascii = ascii + 13 ' Append a carriage return (if desired)
    SEROUT TX, Baud, ascii
    

    Thanks for giving PropBasic a try. Let me know if you have more questions.

    Bean
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-02 14:30
    Great Thanks Bean. I figured I was missing something for the Serout and possibly need string out put. But wasn't sure how to put it together.
    Ok I get it now, I couldn't understand when I looked at that, how to use the digit options.
  • SeekerSeeker Posts: 58
    edited 2011-02-03 15:09
    First, thank you for all of your effort creating this great tool, and the help you give to those of us trying to learn. I have read it all... (this thread, probably forgot most) and I am finally using the Prop to do real things. And learning assembly language on the prop... or at least I think I am. Even back to the 6502 it has always been my favorite language next to solder (yes, I am an old hardware geek trying to do software when I have to).

    I do have a question... and I know I can do it in hardware if I want to waste a pin... but is there a way to do a reboot/reset of the prop from within a PropBASIC program? Or even an assembly routine I can add (using asm... endasm)? Basically, instead of 'END' and it goes to sleep... reboot and start over from eeprom.
  • BeanBean Posts: 8,129
    edited 2011-02-04 04:36
    To reboot you can use this:
    __param1 = 128
    \ CLKSET __param1
    

    NOTE: There are two underscores before the param1.

    I will add a CLKSET command to the language at the next update.

    Bean
  • SeekerSeeker Posts: 58
    edited 2011-02-04 13:25
    Bean wrote: »
    To reboot you can use this:
    __param1 = 128
    \ CLKSET __param1
    

    NOTE: There are two underscores before the param1.

    I will add a CLKSET command to the language at the next update.

    Bean

    Perfect.

    Thanks dude, this is exactly what I needed. And now I know another asm command, and how the CLK register works (yes, I have been reading). :)

    Seeker
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-06 15:00
    I'm wondering if I'm doing something wrong I'm trying to work on my project which has a RC Time basic photo resistor sensor and a copy of the Mic circuit from the Prop Demo board.
    I ran into a couple problems that I'm not sure what they are, and thought maybe you guys had some suggestions and using PropBasic.

    1. I'm using the RCTIME and tried the follow code and it takes about 45 secs to get a reading. Is there a built in timeout or way I could speed it up? All I'm getting on this code is 2, if I put it in a separate COG with some additional code to read and write through the HUB then I get a range from 15 - 140000, when I read it on my main COG, but it still have a 40+ sec delay before I see a change.

    The photo resistor has a meter reading that ranged from 5k - 500K ohm on avg. And I'm using a .1uF cap which most of the examples I saw use so I assumed that's ok.
    HIGH Lght
       PauseUs 50 ' 10 - 15 seems to be the saturation (13 - 140k Range)
        RCTIME Lght, 1, Tmp ' Read Lght Sensor Sample
    '      Pause 10
       LOW Lght
       ascii = STR Tmp, 8, 3 ' 5=digits, 3=Signed, leading spaces, Z-string (must be z-string for SEROUT)
        ascii = ascii + 13 ' Append a carriage return (if desired)
        SEROUT TX, T57600, ascii
    
    2. I'm trying to get a reading from Bean's SNDMeter demo, and all I get is 0. I think I converted it correctly. The only difference which maybe my problem, is I didn't have the white paper on the mic that the prop board used so I tried to pick one that seem to have the most common specs. This is from my Sensor Task.
    .
    .
    .
    ' Init S_Drvr Code
        COUNTERA POSFB, MicFB, MicOut, 1, 0
        A_Time = CNT + ADCVALUE
        FOR Tmp = 1 TO 1000 ' Allow ADC circuit to stabilize
            A_Samp = ReadADC
        NEXT
        FOR Tmp = 1 TO 64 ' Get sum of 64 samples to get an average offset value
            A_Samp = ReadADC
            A_Offset = A_Offset + A_Samp
        NEXT
        A_Offset = A_Offset >> 6 ' Divide by 64 because we summed 64 samples
    .
    .
    
    ' Main Loop
    
        DO
    
        ' Get a Mic ADC Sample
            A_Samp = ReadADC ' You must make sure you get back here before the next sample is due
            A_Samp = A_Samp - A_Offset ' Subtract average offset from sample
            A_Samp = ABS A_Samp ' IF sample is negative, then negate it (make it positve)
            WRWord Mic, A_Samp
    
        LOOP
    
    ' Functions for S_Drvr Task
    
        FUNC ReadADC
          WAITCNT A_Time, ADCVALUE
          __Param1 = PHSA - LastSample
          LastSample = LastSample + __Param1
          RETURN __Param1
        ENDFUNC
    
    I've tried a variety of minor changes to the above but still seem to get similar results. Any ideas where to look?

    Thank you as always for your great help!

    -Kevin
  • BeanBean Posts: 8,129
    edited 2011-02-07 04:10
    Kevin,
    Can you post the whole code ? It's alot easier if we have complete code that we can run without having to guess about things.
    Just a quick glance at what you post looks okay to me...

    Thanks,

    Bean
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-07 10:37
    Sorry Bean.

    I was trying to not embarrass myself and confuse you guys less. So I had tried to crop out the extra unrelated code. But I took your sndmeter code and made a fresh pbas file with just some sensor code. I'll attach both files to troubleshoot it. I managed to narrowed it down late last night. My light sensor is working fine, without any delays. It seems to be something with the ReadADC call. I know it's not your code so I'm thinking maybe it's the mic's spec?

    It's weird cause if I comment out your line in the main loop where you call the ReadADC to get a sample, I get serout, but when I add it in, then it just sits there then gives like one line of trash "?????R??" after the 40ish secs. With the line commented out I get two alternating numbers from the serout, about 36654 and 0.

    But yet it calls the function fine in the init part you have, which calls it 1000+ times. I'm stumped.

    The demosensor is just the sensor code extracted separately to test.

    -Kevin

    demosensor.pbas


    P.S. Also, does anyone know of any document that explains how the audio circuit works on the prop demo board. I don't understand fully how it uses the feedback and out lines.
  • BeanBean Posts: 8,129
    edited 2011-02-07 11:11
    Ahhh, you need to call ReadADC before it's next sample time. If you don't it will hang until CNT rolls over (about 50 seconds at 80MHz).
    Probably the SEROUT is taking too much time, preventing you from getting back to ReadADC quickly enough.

    You can make the sample time longer (giving MORE bits of resolution) or try making the SEROUT faster (a faster baud rate).

    P.S. Even better would be to put the ReadADC in it's own TASK that updates a HUB variable. Or put the SEROUT in it's own TASK...
    Bean
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-07 12:07
    In my main program it will run with the other sensors as a separate task. I had just pulled it out to simply not having to handle the HUB transfer. OK, I was misunderstanding how it works. So I was going to slow....lol. I was thinking I would not get a reading if I didn't give it time before polling cycle.

    The sample time would be the 4096 added to the cnt?

    Thank you so much for the help. I need to try and read up more on the counters I don't completely understand how the different count modes work.

    -Kevin
  • BeanBean Posts: 8,129
    edited 2011-02-07 14:11
    Right the sample time is the 4096 that gets added to CNT. That will give you 12 bits of resolution and a sample time of 80MHz/4096=19531 samples per second.

    You can't sample it too fast, it will wait until the next sample is ready before returning from ReadADC.

    It would be pretty easy to make a task that just reads the counter and writes the value to a HUB variable. The main code can set the HUB variable to -1, then wait it to change.

    Bean
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-07 21:44
    Sorry to bug you again Bean.

    I've been messing with it for a couple hours, and I'm still stumped. I have it working now as a separate file, by bumping up the baud rate and changed the sample rate up to 65535 to be able to read it. I only get like low numbers 1-120, if I yell into the mic right in front of it I can get it to spike to 1200ish. Which is very low but at least it works.

    The problem I'm still having is when I put it in a Cog with as a task, I can debug to the point that I know the cog is working and passing data but all I get are 0s. I'm puzzled, cause I even changed it to basically copy and past from the demo one I have working as a separate program from before.

    Would you terribly mind looking through it and see if you spot something I'm missing?

    Thank you so much for your help btw.

    -Kevin

    P.S. On a positive note, I do get super great sampling out of my light sensor now with a 15 - 140000 range. I'm going to pickup another mic from the electronics store tomorrow to see if that helps the low response.
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-07 21:58
    The problem I'm still having is when I put it in a Cog with as a task, I can debug to the point that I know the cog is working and passing data but all I get are 0s. I'm puzzled, cause I even changed it to basically copy and past from the demo one I have working as a separate program from before.
    From looking at the generated PASM code it turns out that you don't set any outputs for the counter to function (pin 9 is only set as an output in the main cog).
  • BeanBean Posts: 8,129
    edited 2011-02-08 04:17
    To expand on what Kuroneko said...

    If you make a pin an OUTPUT in the main cog (or any COG/TASK), it cannot be made an INPUT by another TASK.

    If you make a pin HIGH in the main cog (or any COG/TASK), it cannot be made LOW by another TASK.

    Only use the PIN postfix (OUTPUT, HIGH or LOW) if the PIN is used in that TASK.

    Bean
  • kevin@cachia.comkevin@cachia.com Posts: 23
    edited 2011-02-08 11:25
    Ah ok, amazing it works now. I feel silly I didn't try something simple like trying to read the pasm code, I may have been able to understand it enough to see that.

    I had kind of wondered about where to define certain things like Cons and Pins. I wasn't sure how to format the code. If I should define certain things globally (main code) vs locally in with the tasks. It's weird cause the pwm driver for my LEDs and my photo sensors work in other tasks when the pins are listed in the main part of the COG code. I had looked at some of your demos Bean and they have Pins defined at the top and the tasks down below, so I was modeling after that... lol. Not knowing any better of course.

    I knew the pins are OR'd together from what I understood in the Prop guide. But I wasn't sure how the code is parsed and compiled to pasm.

    So it seems to be better practice to treat the tasks as completely self-contained code?

    Is there any reason that RCTIME would not respond if it's in main program with LMM on?
    I'm trying to do this and when I switch to LMM it seems to hang. I stripped out everything down to this just to narrow it down.
    DEVICE P8X32A, XTAL1, PLL16x
    'XIN 4_915_000 ' Set Clock rate, Board uses a 4.915MHz Crystal
    FREQ 78_640_000 ' MHz Clock rate
    
    'Sensor Vars
    time       VAR LONG
    offset     VAR LONG = 0
    sample     VAR LONG
    lastSample VAR LONG = 0
    temp       VAR LONG
    
    Lght        PIN 16
    
    ' Draw and Color
    
    ascii        HUB String(14) = ""
    
    PROGRAM Start LMM 'MAIN PROGRAM START
    Start:
    
    ' *******
    ' MAIN LOOP
    Main:
       DO
    
      ' Get a Light ADC Sample
    
        HIGH 16
        PauseUs 10 ' 10 - 15 seems to be the saturation (13 - 140k Range)
        RCTIME 16, 1, sample ' Read Lght Sensor Sample
       ascii = STR sample, 10, 3 ' 5=digits, 3=Signed, leading spaces, Z-string (must be z-string for SEROUT)
        ascii = ascii + 13 ' Append a carriage return (if desired)
    
        SEROUT 30, T115200, ascii
    
       LOOP
    END
    
    -Kevin
Sign In or Register to comment.