halmodule.txt
1 [[cha:halmodule]] 2 3 = Creating Userspace Python Components 4 5 == Basic usage 6 7 A userspace component begins by creating its pins and parameters, then 8 enters a loop which will periodically drive all the outputs from the 9 inputs. The following component copies the value seen on its input pin 10 ('passthrough.in') to its output pin ('passthrough.out') approximately 11 once per second. 12 13 [source,c] 14 ---- 15 #!/usr/bin/env python 16 import hal, time 17 h = hal.component("passthrough") 18 h.newpin("in", hal.HAL_FLOAT, hal.HAL_IN) 19 h.newpin("out", hal.HAL_FLOAT, hal.HAL_OUT) 20 h.ready() 21 try: 22 while 1: 23 time.sleep(1) 24 h['out'] = h['in'] 25 except KeyboardInterrupt: 26 raise SystemExit 27 ---- 28 29 Copy the above listing into a file named "passthrough", make it 30 executable ('chmod +x'), and place it on your '$PATH'. Then try it out: 31 32 ---- 33 halrun 34 35 halcmd: loadusr passthrough 36 37 halcmd: show pin 38 39 Component Pins: 40 Owner Type Dir Value Name 41 03 float IN 0 passthrough.in 42 03 float OUT 0 passthrough.out 43 44 halcmd: setp passthrough.in 3.14 45 46 halcmd: show pin 47 48 Component Pins: 49 Owner Type Dir Value Name 50 03 float IN 3.14 passthrough.in 51 03 float OUT 3.14 passthrough.out 52 ---- 53 54 == Userspace components and delays 55 56 If you typed “show pin” quickly, you may see that 'passthrough.out' 57 still had its old value of 0. This is because of the call to 58 'time.sleep(1)', which makes the assignment to the output pin occur at 59 most once per second. Because this is a userspace component, the actual 60 delay between assignments can be much longer if the 61 memory used by the passthrough component is swapped to disk, the 62 assignment could be delayed until that memory is swapped back in. 63 64 Thus, userspace components are suitable for user-interactive elements 65 such as control panels (delays in the range of milliseconds are not 66 noticed, and longer delays are acceptable), but not for sending step 67 pulses to a stepper driver board (delays must always be in the range of 68 microseconds, no matter what). 69 70 == Create pins and parameters 71 72 ---- 73 h = hal.component("passthrough") 74 ---- 75 76 The component itself is created by a call to the constructor 77 'hal.component'. The arguments are the HAL component name and 78 (optionally) the 79 prefix used for pin and parameter names. If the prefix is not 80 specified, the component name is used. 81 82 ---- 83 h.newpin("in", hal.HAL_FLOAT, hal.HAL_IN) 84 ---- 85 86 Then pins are created by calls to methods on the component object. The 87 arguments are: pin name suffix, pin type, and pin direction. For 88 parameters, the arguments are: parameter name suffix, parameter type, 89 and parameter direction. 90 91 .HAL Option Names 92 [width="100%",cols="<3s,4*<"] 93 |=========================================================== 94 |Pin and Parameter Types: |HAL_BIT |HAL_FLOAT |HAL_S32 |HAL_U32 95 |Pin Directions: |HAL_IN |HAL_OUT |HAL_IO | 96 |Parameter Directions: |HAL_RO |HAL_RW | | 97 |=========================================================== 98 99 The full pin or parameter name is formed by joining the prefix and the 100 suffix with a ".", so in the example the pin created is called 101 'passthrough.in'. 102 103 ---- 104 h.ready() 105 ---- 106 107 Once all the pins and parameters have been created, call the 108 '.ready()' method. 109 110 === Changing the prefix 111 112 The prefix can be changed by calling the '.setprefix()' method. The 113 current prefix can be retrieved by calling the '.getprefix()' method. 114 115 == Reading and writing pins and parameters 116 117 For pins and parameters which are also proper Python identifiers, the 118 value may be accessed or set using the attribute syntax: 119 120 ---- 121 h.out = h.in 122 ---- 123 124 For all pins, whether or not they are also proper Python identifiers, 125 the value may be accessed or set using the subscript syntax: 126 127 ---- 128 h['out'] = h['in'] 129 ---- 130 131 === Driving output (HAL_OUT) pins 132 133 Periodically, usually in response to a timer, all HAL_OUT pins should 134 be "driven" by assigning them a new value. This should be done whether 135 or not the value is different than the last one assigned. When a pin is 136 connected to a signal, its old output value is not copied into the 137 signal, so the proper value will only appear on the signal once the 138 component assigns a new value. 139 140 === Driving bidirectional (HAL_IO) pins 141 142 The above rule does not apply to bidirectional pins. Instead, a 143 bidirectional pin should only be driven by the component when the 144 component wishes to change the value. For instance, in the canonical 145 encoder interface, the encoder component only sets the 'index-enable' 146 pin to *FALSE* (when an index pulse is seen and the old value is 147 *TRUE*), but never sets it to *TRUE*. Repeatedly driving the pin 148 *FALSE* might cause the other connected component to act as though 149 another index pulse had been seen. 150 151 == Exiting 152 153 A 'halcmd unload' request for the component is delivered as a 154 'KeyboardInterrupt' exception. When an unload request arrives, the 155 process should either 156 exit in a short time, or call the '.exit()' method on the component 157 if substantial work (such as reading or 158 writing files) must be done to complete the shutdown process. 159 160 == Helpful Functions 161 162 === component_exists 163 164 Does the specified component exist at this time. + 165 Example: + 166 hal.component_exists("testpanel") + 167 168 === component_is_ready 169 Is the specified component ready at this time. + 170 Example: + 171 hal.component_is_ready("testpanel") + 172 173 === get_msg_level 174 175 Get the current Realtime msg level. + 176 177 === set_msg_level 178 179 set the current Realtime msg level. + 180 used for debugging information. + 181 182 === connect 183 184 Connect a pin to a signal. + 185 example: + 186 hal.connect("pinname","signal_name") 187 188 === get_value 189 190 read a pin, param or signal directly. + 191 example: + 192 value = hal.get_value("iocontrol.0.emc-enable-in") + 193 194 === new_signal 195 Create a New signal of the type specified. + 196 example" + 197 hal.new_sig("signalname",hal.HAL_BIT) 198 199 === pin_has_writer 200 201 Does the specified pin have a driving pin connected. + 202 Returns True or False. + 203 204 === sampler_base 205 206 TODO + 207 208 === stream_base 209 210 TODO + 211 212 === stream 213 214 TODO + 215 216 === set_p 217 218 Set a pin value. + 219 example: + 220 hal.set_p("pinname","10") + 221 222 == Constants 223 224 Use These To specify details rather then the value they hold. 225 226 * HAL_BIT 227 228 * HAL_FLOAT 229 230 * HAL_S32 231 232 * HAL_U32 233 234 * HAL_IN 235 236 * HAL_OUT 237 238 * HAL_RO 239 240 * HAL_RW 241 242 * MSG_NONE 243 244 * MSG_ALL 245 246 * MSG_DBG 247 248 * MSG_ERR 249 250 * MSG_INFO 251 252 * MSG_WARN 253 254 == System Information 255 256 Read these to aquire information about the realtime system. 257 258 * is_kernelspace 259 260 * is_rt 261 262 * is_sim 263 264 * is_userspace 265 266 == Project ideas 267 268 * Create an external control panel with buttons, switches, and 269 indicators. Connect everything to a microcontroller, and connect the 270 microcontroller to the PC using a serial interface. Python has a very 271 capable serial interface module called 272 http://pyserial.sourceforge.net/[pyserial] 273 (Ubuntu package name “python-serial”, in the universe repository) 274 * Attach a http://lcdproc.omnipotent.net/[LCDProc]-compatible LCD module 275 and use it to display a digital readout with information of your choice 276 (Ubuntu package name “lcdproc”, in the universe repository) 277 * Create a virtual control panel using any GUI library supported by 278 Python (gtk, qt, wxwindows, etc) 279 280