Singleton Pattern

The pico engine has one instance of modules. That is when the  pico uses a module provide by the engine, the pico does not have an instance unique to itself, all picos must share that module.  Normally this is something a pico developer does not need to worry about, but when modules are created to control restricted resources, a pico developer must think about read write access to resources. Singleton pattern is a solution for protecting restricted resources. The pattern is to create a single pico for a single resource. An example of this pattern can be found in the pico rover project.

Pico Rover Singleton Pattern

The pico rover has a custom JavaScript module which is a singleton for GPIO pins that control wheels.  Each wheel has a pico which represents that wheel.

 

Wheels.krl

The following code came from wheels.krl. In the example below you can see that each wheel keeps track of the motor it controls by setting an entity variable called motorIndex.  Then in each method call, the wheel pico passes the motorIndex.  This provides write access to a single pico which represents a single GPIO pin or wheel motor.

Wheels.krl
global{
	stop = defaction(){
		motorHat:dc_stop(ent:motorIndex);
	}  
}
rule setMotorIndex { 
	select when rover motorIndex
	always{ 
		ent:motorIndex := event:attr("motorIndex")
	}
}

WheelsController.krl

A controller pico then creates a higher level access point for each wheel pico.
The code below is taken from wheelsController.krl.  The controller has an eci to each wheel. To move the pico rover in any direction you must send wheel directions and speed to each specific wheel pico. The controller creates defaction wrappers to send events to each wheel with correlated information. In this way each pico wheel is used as a type of semaphore to protect each GPIO pin. While the singleton pattern could be circumvented in this example by placing all logic in the controller, this would not scale if more picos that accessed the wheels were added. 

WheelsController.krl
config= { // hard coded eci to wheels, this would be MUCH better as subscriptions.
	"FR":"5tj6Xi4deyAsninzbj7sK",
    "FL":"GyTnMVWqrzVPXWUx2D2NB",
    "BR":"N7j7beQx6VYsR9H81NbGD",
    "BL":"XYv1HUQxcuwXmTHoNS72K"
};

to_motors = defaction(event,attr1,attr2,attr3,attr4){
	every{
    	event:send( 
        	{ "eci": config{"FR"},
              "domain": "rover", "type": event,
              "attrs": attr1
              });
        event:send( 
            { "eci": config{"FL"},
              "domain": "rover", "type": event,
              "attrs": attr2
              });
        event:send( 
            { "eci": config{"BR"},
              "domain": "rover", "type": event,
              "attrs": attr3
              });
        event:send( 
            { "eci": config{"BL"},
              "domain": "rover", "type": event,
              "attrs": attr4
              });
      }
}
run_motors = defaction(dir1,dir2,dir3,dir4){
	to_motors("run", {"direction": dir1},
                     {"direction": dir2},
                     {"direction": dir3},
                     {"direction": dir4} )
    }
fwd   = defaction(){ run_motors("fwd","back","back","fwd") }
back  = defaction(){ run_motors("back","fwd","fwd","back") }
right = defaction(){ run_motors("back","back","back","back") }
left  = defaction(){ run_motors("fwd","fwd","fwd","fwd") } 
stop  = defaction(){ to_motors("stop",{},{},{},{} ) }

Copyright Picolabs | Licensed under Creative Commons.