Gold Standard Specification

Object Exchange Gold Standard Specification
Parallax Semiconductor has a minimum set of requirements that an object written for the Parallax Propeller must meet in order to be certified as a “gold object” and accepted into the gold library. At a core level, a Gold Standard object should implement well-written code, include proper documentation, and function as described in the object’s description. The standard defined here maximizes functionality, readability, and consistency. Exceptions to the guidelines outlined here may exist on an object-to-object basis, if warranted, so reviewers should exercise their best judgment when reviewing an object.

Launching a Cog
Any object that launches a cog should have a public “start” method that takes care of any required initializations and a public “stop” method that shuts the running cog down gracefully. An object should have the ability to stop any running cog that it starts.

  • Dynamically launch a new cog with the cognew command. Save the value returned from cognew,which is the starting cog’s ID, for later user when stopping the cog.
  • To stop a cog, use the cogstop command with the cog’s saved ID, or use cogid if the cog is stopping itself.
  • Remember, sometimes code is designed so that a launched cog runs to completion, meaning that the cog has no more instructions to execute and then terminates. In any case, update any dependent variables to reflect the termination of a cog.

Using Locks
An object that utilizes the Propeller’s lock features should make use of the locknew command to dynamically choose a new lock. If an object is to reach a terminus where the lock is no longer needed, it should use the lockret command to return the checked out lock.

Commenting in an Object
A gold object should employ professionally commented code. Each public method in an object should begin with a document comment that describes the intended results of that method call.

  • Use documentation type comments '' or {{ }} for method descriptions. Do not use documentation type comments in private methods.
  • Use code type comments ' or { } to provide additional information on a line-by-line basis.
  • Comment a line of code when its operation is important or unclear.
  • If necessary, include a schematic drawing in the object’s description of the required connections needed to interface the Propeller with related hardware, using the Parallax font.
  • Give a comment example of how to call each method and the intended results of that method call. Try to provide a method call example that characterizes the implemented functionality of that method.
  • If a wiring schematic is included with the object, match the interfaced pins on the Propeller to the commented example of how to call each method.
  • Include a short description of each method argument and the method’s return value.
  • Try to limit large block comments to a width of 92 characters.

Method Naming
When choosing method names, the name of a method should concisely reflect the functionality that its code produces. A method’s name should always start with a capital letter and subsequent words, if needed, should start with a capital letter; this style is often called camel case. It is helpful to keep a probable symbol name (nickname) in mind for the object. For example, a simple object that lets a developer pause a cog’s execution might be nicknamed time and call a method named PauseMS. The resulting time.PauseMS(duration)call gives additional context to the developer as to the functionality of the time object and PauseMS method, without requiring the developer to look at the object’s source code to understand what the method call will do.

Variable Naming
When choosing variable names, the name of the variable should reflect the general use of that variable. Try to make the variable name descriptive yet concise. Variable names should always start with a lower-case character or underscore separator. If using more than one word in the variable name, capitalize the first letter of following words or use an underscore separator to make each word stand out. Capitalize the first letter of an acronym, except when the acronym starts the variable name. For example: high_time_ms, numberOfRotations, ledArrayorbigLed.

Commands and Reserved Keywords
All uses of reserved keywords and commands should remain in lower-case form, except PUB, PRI, VAR, CON, OBJ, and DAT.

White Space and Indentations
In Spin code, indent each new block level of code by two spaces. In Propeller Assembly, instructions should be indented enough to allow for label names, instruction conditions, the instruction itself, and instruction effects to fit neatly on a line. Each assembly instruction should be in line with the preceding instruction. Use white space and indentations to keep the code functional and easily readable. Try to keep large block comments limited to 92 characters wide as this makes printing the object convenient.

Constant Declarations
Completely capitalize all constants defined in a CON section.

Demo Code
An object should include at least one demonstration program. The demo program should illustrate a very simple example of how to properly use the object. (i.e.: you hook it up like this, run this program, and these are the results you will see). Additional demo programs can be included with the object to demonstrate advanced features of the object. For all demo programs, connection references between the Propeller and the external peripheral should remain consistent with the code comments. Demo programs should use the Parallax Serial Terminal as the standard method for user input and program output. This way, a developer can achieve expected results from the demo programs.

Licensing
Any object in the gold OBEX must be released under the MIT license. Include the MIT license at the bottom of the object in a dat section.

Sample Gold Standard Object

{{{
Object file:   LED_Blinker.spin
Version:       1.0
Date:          March 21, 2011
Author:        Daniel Harris
Email:         dharris@parallax.com

Description:
This is a simple object that uses the Propeller to blink an LED on a given pin.
The user can get and set the period and duty rate of the LED with the provided
interfacing methods.

=============================================
        Connection Diagram
=============================================

        ┌──────┐   
        │      │   R0   D0      
        │    Px├───────┐
        │      │           │
        └──────┘           
        Propeller
           MCU
        (P8X32A)

Components:
R0 = 100Ω
D0 = Blue LED, 3.2V @ 20mA
Px = Desired Propeller Pin

=============================================                  
}}

CON

VAR
' Object's global variable declarations
  long cog_number
  long led_pin
  long high_time_ms, low_time_ms

  'New cog's stack space declaration
  long stack_space[20]
  

PUB Stop
{{
  Stops blinking the LED and frees the running cog.

  parameters:  none                                                    
  return:      none

  example usage:    blinker.Stop
  expected results: This will stop the cog if it has been started
}}

  if cog_number                 'if cog_number is non-zero, then...
    dira[led_pin]~              '  set led_pin to input
    cogstop(cog_number~ - 1)    '  Stop the running cog and post clear cog_number

PUB Start(pin)
{{
  This method starts the object.  Call it to start the LED blinking on 'pin'
  
  parameters:    pin = the propeller pin to blink an LED on (range: 0-31)
  return:        true if a cog is started, false if not started

  example usage:     blinker.Start(0)
  expected results:  This will start a cog dedicated to blinking an LED on pin P0.
}}

  'A call to the Stop method to make sure that an already running cog gets correctly shut down.
  'This prevents multiple instances of this object from being started.
  Stop

  'start the new cog and save the number of the cog started.
  cog_number := cognew(RunBlinkingLed, @stack_space) + 1

  led_pin := pin                'save the desired pin to blink.

  'Set some default values to start off with.  Will blink at 50% duty
  'cycle over a period of 1 second.
  high_time_ms := 500
  low_time_ms  := 500

  return (cog_number > 0)       'Will return true(-1) if a cog was started
                                'or false(0) if a cog was not available.

PUB SetBlinkRate(new_duty, new_period)
{{
  Sets the blink rate of the LED.

  parameters:  new_duty = the desired duty rate (range: $00-$FF)
               new_period = the desired period of blink rate.
  return:      none

  example usage:    blinker.SetBlinkRate($40, 750)
  expected results: This sets a 25% duty cycle over a 3/4 second (750 ms) period.
}}

  new_duty &= $FF               'Make sure that the new duty cycle is no
                                'larger than 8 bits.
                                
  'Calculate the necessary wait times
  high_time_ms := (new_duty * new_period)/(256)
  low_time_ms  := ((256 - new_duty) * new_period)/(256)

PUB GetBlinkPeriod
{{  Gets the blink period of the LED.

  parameters:  none
  return:      the period of the blinking LED, in ms

  example usage:    blink_period := blinker.GetBlinkPeriod
  expected results: Saves the period of the blinking LED into blink_period
}}

  return (high_time_ms + low_time_ms)

PUB GetBlinkDuty
{{
  Gets the duty rate of the LED.

  parameters:  none
  return:      the duty rate of the blinking LED, between $00 - $FF

  example usage:    duty := blinker.GetBlinkDuty
  expected results: Saves the duty rate of the blinking LED into duty
}}

  return (256 * high_time_ms) / (high_time_ms + low_time_ms)

PRI RunBlinkingLed
{
  This method executes independently inside its own cog.
  It uses two global variables, high_time_ms and low_time_ms
  to pause the cog's execution while the pin is high or low,
  respectively.

  parameters:  none
  return:      none
}

  dira[led_pin]~~               'set pin to output

  repeat
    outa[led_pin]~~             'turn the LED on
    PauseMS(high_time_ms)       'wait a bit
    outa[led_pin]~              'turn the LED off
    PauseMS(low_time_ms)        'wait a bit
  

PRI PauseMS(Duration)
{
  Pause execution for 'duration' milliseconds.
  This routine is based on the set clock frequency.

  parameters:  Duration = number of milliseconds to delay                                                                                               
  return:      none
}
  waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
{{

                               TERMS OF USE: MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}}

AttachmentSize
Gold-Standard.zip11.48 KB