This is a copy of the Reference Standard PID controller ala controlguru.com

Dependents:   PIDHeater Printer PIDHeater82 UltiSaverController

Fork of PID by Arnaud Suire

Committer:
unix_guru
Date:
Wed Jan 27 21:32:11 2016 +0000
Revision:
2:55bf0f813bb4
Parent:
1:117e0c36eb22
Child:
3:316f974b7f98
minor updates to comply with Brett Beauregard's Arduino PID library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
arnaudsuire 0:d58c1b8d63d9 1 /**
unix_guru 2:55bf0f813bb4 2 * @author Aaron Berk
unix_guru 2:55bf0f813bb4 3 *
unix_guru 2:55bf0f813bb4 4 * @section LICENSE
unix_guru 2:55bf0f813bb4 5 *
unix_guru 2:55bf0f813bb4 6 * Copyright (c) 2010 ARM Limited
unix_guru 2:55bf0f813bb4 7 *
unix_guru 2:55bf0f813bb4 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
unix_guru 2:55bf0f813bb4 9 * of this software and associated documentation files (the "Software"), to deal
unix_guru 2:55bf0f813bb4 10 * in the Software without restriction, including without limitation the rights
unix_guru 2:55bf0f813bb4 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
unix_guru 2:55bf0f813bb4 12 * copies of the Software, and to permit persons to whom the Software is
unix_guru 2:55bf0f813bb4 13 * furnished to do so, subject to the following conditions:
unix_guru 2:55bf0f813bb4 14 *
unix_guru 2:55bf0f813bb4 15 * The above copyright notice and this permission notice shall be included in
unix_guru 2:55bf0f813bb4 16 * all copies or substantial portions of the Software.
unix_guru 2:55bf0f813bb4 17 *
unix_guru 2:55bf0f813bb4 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
unix_guru 2:55bf0f813bb4 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
unix_guru 2:55bf0f813bb4 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
unix_guru 2:55bf0f813bb4 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
unix_guru 2:55bf0f813bb4 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
unix_guru 2:55bf0f813bb4 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
unix_guru 2:55bf0f813bb4 24 * THE SOFTWARE.
unix_guru 2:55bf0f813bb4 25 *
unix_guru 2:55bf0f813bb4 26 * @section DESCRIPTION
unix_guru 2:55bf0f813bb4 27 *
unix_guru 2:55bf0f813bb4 28 * A PID controller is a widely used feedback controller commonly found in
unix_guru 2:55bf0f813bb4 29 * industry.
unix_guru 2:55bf0f813bb4 30 *
unix_guru 2:55bf0f813bb4 31 * This library is a port of Brett Beauregard's Arduino PID library:
unix_guru 2:55bf0f813bb4 32 *
unix_guru 2:55bf0f813bb4 33 * http://www.arduino.cc/playground/Code/PIDLibrary
unix_guru 2:55bf0f813bb4 34 *
unix_guru 2:55bf0f813bb4 35 * The wikipedia article on PID controllers is a good place to start on
unix_guru 2:55bf0f813bb4 36 * understanding how they work:
unix_guru 2:55bf0f813bb4 37 *
unix_guru 2:55bf0f813bb4 38 * http://en.wikipedia.org/wiki/PID_controller
unix_guru 2:55bf0f813bb4 39 *
unix_guru 2:55bf0f813bb4 40 * For a clear and elegant explanation of how to implement and tune a
unix_guru 2:55bf0f813bb4 41 * controller, the controlguru website by Douglas J. Cooper (who also happened
unix_guru 2:55bf0f813bb4 42 * to be Brett's controls professor) is an excellent reference:
unix_guru 2:55bf0f813bb4 43 *
unix_guru 2:55bf0f813bb4 44 * http://www.controlguru.com/
unix_guru 2:55bf0f813bb4 45 */
unix_guru 2:55bf0f813bb4 46
unix_guru 2:55bf0f813bb4 47 /**
unix_guru 2:55bf0f813bb4 48 * Includes
unix_guru 2:55bf0f813bb4 49 */
arnaudsuire 0:d58c1b8d63d9 50 #include "PID.h"
unix_guru 2:55bf0f813bb4 51
arnaudsuire 0:d58c1b8d63d9 52 PID::PID(float Kc, float tauI, float tauD, float interval) {
unix_guru 2:55bf0f813bb4 53
arnaudsuire 0:d58c1b8d63d9 54 usingFeedForward = false;
unix_guru 2:55bf0f813bb4 55 inAuto = false;
unix_guru 2:55bf0f813bb4 56
unix_guru 2:55bf0f813bb4 57 //Default the limits to the full range of I/O: 3.3V
unix_guru 2:55bf0f813bb4 58 //Make sure to set these to more appropriate limits for
unix_guru 2:55bf0f813bb4 59 //your application.
unix_guru 2:55bf0f813bb4 60 setInputLimits(0.0, 3.3);
unix_guru 2:55bf0f813bb4 61 setOutputLimits(0.0, 3.3);
unix_guru 2:55bf0f813bb4 62
arnaudsuire 0:d58c1b8d63d9 63 tSample_ = interval;
unix_guru 2:55bf0f813bb4 64
arnaudsuire 0:d58c1b8d63d9 65 setTunings(Kc, tauI, tauD);
unix_guru 2:55bf0f813bb4 66
unix_guru 2:55bf0f813bb4 67 setPoint_ = 0.0;
unix_guru 2:55bf0f813bb4 68 processVariable_ = 0.0;
unix_guru 2:55bf0f813bb4 69 prevProcessVariable_ = 0.0;
unix_guru 2:55bf0f813bb4 70 controllerOutput_ = 0.0;
arnaudsuire 0:d58c1b8d63d9 71 prevControllerOutput_ = 0.0;
unix_guru 2:55bf0f813bb4 72
arnaudsuire 0:d58c1b8d63d9 73 accError_ = 0.0;
unix_guru 2:55bf0f813bb4 74 bias_ = 0.0;
unix_guru 2:55bf0f813bb4 75
arnaudsuire 0:d58c1b8d63d9 76 realOutput_ = 0.0;
unix_guru 2:55bf0f813bb4 77
arnaudsuire 0:d58c1b8d63d9 78 }
unix_guru 2:55bf0f813bb4 79
arnaudsuire 0:d58c1b8d63d9 80 void PID::setInputLimits(float inMin, float inMax) {
unix_guru 2:55bf0f813bb4 81
arnaudsuire 0:d58c1b8d63d9 82 //Make sure we haven't been given impossible values.
arnaudsuire 0:d58c1b8d63d9 83 if (inMin >= inMax) {
arnaudsuire 0:d58c1b8d63d9 84 return;
arnaudsuire 0:d58c1b8d63d9 85 }
unix_guru 2:55bf0f813bb4 86
arnaudsuire 0:d58c1b8d63d9 87 //Rescale the working variables to reflect the changes.
arnaudsuire 0:d58c1b8d63d9 88 prevProcessVariable_ *= (inMax - inMin) / inSpan_;
unix_guru 2:55bf0f813bb4 89 accError_ *= (inMax - inMin) / inSpan_;
unix_guru 2:55bf0f813bb4 90
arnaudsuire 0:d58c1b8d63d9 91 //Make sure the working variables are within the new limits.
arnaudsuire 0:d58c1b8d63d9 92 if (prevProcessVariable_ > 1) {
arnaudsuire 0:d58c1b8d63d9 93 prevProcessVariable_ = 1;
unix_guru 2:55bf0f813bb4 94 } else if (prevProcessVariable_ < 0) {
arnaudsuire 0:d58c1b8d63d9 95 prevProcessVariable_ = 0;
arnaudsuire 0:d58c1b8d63d9 96 }
unix_guru 2:55bf0f813bb4 97
unix_guru 2:55bf0f813bb4 98 inMin_ = inMin;
unix_guru 2:55bf0f813bb4 99 inMax_ = inMax;
arnaudsuire 0:d58c1b8d63d9 100 inSpan_ = inMax - inMin;
unix_guru 2:55bf0f813bb4 101
arnaudsuire 0:d58c1b8d63d9 102 }
unix_guru 2:55bf0f813bb4 103
arnaudsuire 0:d58c1b8d63d9 104 void PID::setOutputLimits(float outMin, float outMax) {
unix_guru 2:55bf0f813bb4 105
arnaudsuire 0:d58c1b8d63d9 106 //Make sure we haven't been given impossible values.
arnaudsuire 0:d58c1b8d63d9 107 if (outMin >= outMax) {
arnaudsuire 0:d58c1b8d63d9 108 return;
arnaudsuire 0:d58c1b8d63d9 109 }
unix_guru 2:55bf0f813bb4 110
arnaudsuire 0:d58c1b8d63d9 111 //Rescale the working variables to reflect the changes.
arnaudsuire 0:d58c1b8d63d9 112 prevControllerOutput_ *= (outMax - outMin) / outSpan_;
unix_guru 2:55bf0f813bb4 113
arnaudsuire 0:d58c1b8d63d9 114 //Make sure the working variables are within the new limits.
arnaudsuire 0:d58c1b8d63d9 115 if (prevControllerOutput_ > 1) {
arnaudsuire 0:d58c1b8d63d9 116 prevControllerOutput_ = 1;
unix_guru 2:55bf0f813bb4 117 } else if (prevControllerOutput_ < 0) {
arnaudsuire 0:d58c1b8d63d9 118 prevControllerOutput_ = 0;
arnaudsuire 0:d58c1b8d63d9 119 }
unix_guru 2:55bf0f813bb4 120
unix_guru 2:55bf0f813bb4 121 outMin_ = outMin;
unix_guru 2:55bf0f813bb4 122 outMax_ = outMax;
arnaudsuire 0:d58c1b8d63d9 123 outSpan_ = outMax - outMin;
unix_guru 2:55bf0f813bb4 124
arnaudsuire 0:d58c1b8d63d9 125 }
unix_guru 2:55bf0f813bb4 126
arnaudsuire 0:d58c1b8d63d9 127 void PID::setTunings(float Kc, float tauI, float tauD) {
unix_guru 2:55bf0f813bb4 128
arnaudsuire 0:d58c1b8d63d9 129 //Verify that the tunings make sense.
arnaudsuire 0:d58c1b8d63d9 130 if (Kc == 0.0 || tauI < 0.0 || tauD < 0.0) {
arnaudsuire 0:d58c1b8d63d9 131 return;
arnaudsuire 0:d58c1b8d63d9 132 }
unix_guru 2:55bf0f813bb4 133
arnaudsuire 0:d58c1b8d63d9 134 //Store raw values to hand back to user on request.
arnaudsuire 0:d58c1b8d63d9 135 pParam_ = Kc;
arnaudsuire 0:d58c1b8d63d9 136 iParam_ = tauI;
arnaudsuire 0:d58c1b8d63d9 137 dParam_ = tauD;
unix_guru 2:55bf0f813bb4 138
arnaudsuire 0:d58c1b8d63d9 139 float tempTauR;
unix_guru 2:55bf0f813bb4 140
arnaudsuire 0:d58c1b8d63d9 141 if (tauI == 0.0) {
arnaudsuire 0:d58c1b8d63d9 142 tempTauR = 0.0;
unix_guru 2:55bf0f813bb4 143 } else {
arnaudsuire 0:d58c1b8d63d9 144 tempTauR = (1.0 / tauI) * tSample_;
arnaudsuire 0:d58c1b8d63d9 145 }
unix_guru 2:55bf0f813bb4 146
arnaudsuire 0:d58c1b8d63d9 147 //For "bumpless transfer" we need to rescale the accumulated error.
unix_guru 2:55bf0f813bb4 148 if (inAuto) {
unix_guru 2:55bf0f813bb4 149 if (tempTauR == 0.0) {
unix_guru 2:55bf0f813bb4 150 accError_ = 0.0;
unix_guru 2:55bf0f813bb4 151 } else {
arnaudsuire 0:d58c1b8d63d9 152 accError_ *= (Kc_ * tauR_) / (Kc * tempTauR);
unix_guru 2:55bf0f813bb4 153 }
unix_guru 2:55bf0f813bb4 154 }
unix_guru 2:55bf0f813bb4 155
unix_guru 2:55bf0f813bb4 156 Kc_ = Kc;
arnaudsuire 0:d58c1b8d63d9 157 tauR_ = tempTauR;
arnaudsuire 0:d58c1b8d63d9 158 tauD_ = tauD / tSample_;
unix_guru 2:55bf0f813bb4 159
arnaudsuire 0:d58c1b8d63d9 160 }
unix_guru 2:55bf0f813bb4 161
arnaudsuire 0:d58c1b8d63d9 162 void PID::reset(void) {
unix_guru 2:55bf0f813bb4 163
arnaudsuire 0:d58c1b8d63d9 164 float scaledBias = 0.0;
unix_guru 2:55bf0f813bb4 165
arnaudsuire 0:d58c1b8d63d9 166 if (usingFeedForward) {
arnaudsuire 0:d58c1b8d63d9 167 scaledBias = (bias_ - outMin_) / outSpan_;
unix_guru 2:55bf0f813bb4 168 } else {
arnaudsuire 0:d58c1b8d63d9 169 scaledBias = (realOutput_ - outMin_) / outSpan_;
arnaudsuire 0:d58c1b8d63d9 170 }
unix_guru 2:55bf0f813bb4 171
arnaudsuire 0:d58c1b8d63d9 172 prevControllerOutput_ = scaledBias;
unix_guru 2:55bf0f813bb4 173 prevProcessVariable_ = (processVariable_ - inMin_) / inSpan_;
unix_guru 2:55bf0f813bb4 174
arnaudsuire 0:d58c1b8d63d9 175 //Clear any error in the integral.
arnaudsuire 0:d58c1b8d63d9 176 accError_ = 0;
unix_guru 2:55bf0f813bb4 177
arnaudsuire 0:d58c1b8d63d9 178 }
unix_guru 2:55bf0f813bb4 179
arnaudsuire 0:d58c1b8d63d9 180 void PID::setMode(int mode) {
unix_guru 2:55bf0f813bb4 181
arnaudsuire 0:d58c1b8d63d9 182 //We were in manual, and we just got set to auto.
arnaudsuire 0:d58c1b8d63d9 183 //Reset the controller internals.
arnaudsuire 0:d58c1b8d63d9 184 if (mode != 0 && !inAuto) {
arnaudsuire 0:d58c1b8d63d9 185 reset();
arnaudsuire 0:d58c1b8d63d9 186 }
unix_guru 2:55bf0f813bb4 187
arnaudsuire 0:d58c1b8d63d9 188 inAuto = (mode != 0);
unix_guru 2:55bf0f813bb4 189
unix_guru 1:117e0c36eb22 190 }
unix_guru 2:55bf0f813bb4 191
arnaudsuire 0:d58c1b8d63d9 192 void PID::setInterval(float interval) {
unix_guru 2:55bf0f813bb4 193
arnaudsuire 0:d58c1b8d63d9 194 if (interval > 0) {
arnaudsuire 0:d58c1b8d63d9 195 //Convert the time-based tunings to reflect this change.
unix_guru 2:55bf0f813bb4 196 tauR_ *= (interval / tSample_);
arnaudsuire 0:d58c1b8d63d9 197 accError_ *= (tSample_ / interval);
unix_guru 2:55bf0f813bb4 198 tauD_ *= (interval / tSample_);
unix_guru 2:55bf0f813bb4 199 tSample_ = interval;
arnaudsuire 0:d58c1b8d63d9 200 }
unix_guru 2:55bf0f813bb4 201
arnaudsuire 0:d58c1b8d63d9 202 }
unix_guru 2:55bf0f813bb4 203
arnaudsuire 0:d58c1b8d63d9 204 void PID::setSetPoint(float sp) {
unix_guru 2:55bf0f813bb4 205
arnaudsuire 0:d58c1b8d63d9 206 setPoint_ = sp;
unix_guru 2:55bf0f813bb4 207
arnaudsuire 0:d58c1b8d63d9 208 }
unix_guru 2:55bf0f813bb4 209
arnaudsuire 0:d58c1b8d63d9 210 void PID::setProcessValue(float pv) {
unix_guru 2:55bf0f813bb4 211
arnaudsuire 0:d58c1b8d63d9 212 processVariable_ = pv;
unix_guru 2:55bf0f813bb4 213
arnaudsuire 0:d58c1b8d63d9 214 }
unix_guru 2:55bf0f813bb4 215
arnaudsuire 0:d58c1b8d63d9 216 void PID::setBias(float bias){
unix_guru 2:55bf0f813bb4 217
arnaudsuire 0:d58c1b8d63d9 218 bias_ = bias;
arnaudsuire 0:d58c1b8d63d9 219 usingFeedForward = 1;
unix_guru 2:55bf0f813bb4 220
arnaudsuire 0:d58c1b8d63d9 221 }
unix_guru 2:55bf0f813bb4 222
unix_guru 2:55bf0f813bb4 223 float PID::compute() {
unix_guru 2:55bf0f813bb4 224
arnaudsuire 0:d58c1b8d63d9 225 //Pull in the input and setpoint, and scale them into percent span.
arnaudsuire 0:d58c1b8d63d9 226 float scaledPV = (processVariable_ - inMin_) / inSpan_;
unix_guru 2:55bf0f813bb4 227
arnaudsuire 0:d58c1b8d63d9 228 if (scaledPV > 1.0) {
arnaudsuire 0:d58c1b8d63d9 229 scaledPV = 1.0;
unix_guru 2:55bf0f813bb4 230 } else if (scaledPV < 0.0) {
arnaudsuire 0:d58c1b8d63d9 231 scaledPV = 0.0;
arnaudsuire 0:d58c1b8d63d9 232 }
unix_guru 2:55bf0f813bb4 233
arnaudsuire 0:d58c1b8d63d9 234 float scaledSP = (setPoint_ - inMin_) / inSpan_;
arnaudsuire 0:d58c1b8d63d9 235 if (scaledSP > 1.0) {
arnaudsuire 0:d58c1b8d63d9 236 scaledSP = 1;
unix_guru 2:55bf0f813bb4 237 } else if (scaledSP < 0.0) {
arnaudsuire 0:d58c1b8d63d9 238 scaledSP = 0;
arnaudsuire 0:d58c1b8d63d9 239 }
unix_guru 2:55bf0f813bb4 240
arnaudsuire 0:d58c1b8d63d9 241 float error = scaledSP - scaledPV;
unix_guru 2:55bf0f813bb4 242
arnaudsuire 0:d58c1b8d63d9 243 //Check and see if the output is pegged at a limit and only
arnaudsuire 0:d58c1b8d63d9 244 //integrate if it is not. This is to prevent reset-windup.
arnaudsuire 0:d58c1b8d63d9 245 if (!(prevControllerOutput_ >= 1 && error > 0) && !(prevControllerOutput_ <= 0 && error < 0)) {
arnaudsuire 0:d58c1b8d63d9 246 accError_ += error;
arnaudsuire 0:d58c1b8d63d9 247 }
unix_guru 2:55bf0f813bb4 248
arnaudsuire 0:d58c1b8d63d9 249 //Compute the current slope of the input signal.
arnaudsuire 0:d58c1b8d63d9 250 float dMeas = (scaledPV - prevProcessVariable_) / tSample_;
unix_guru 2:55bf0f813bb4 251
arnaudsuire 0:d58c1b8d63d9 252 float scaledBias = 0.0;
unix_guru 2:55bf0f813bb4 253
arnaudsuire 0:d58c1b8d63d9 254 if (usingFeedForward) {
arnaudsuire 0:d58c1b8d63d9 255 scaledBias = (bias_ - outMin_) / outSpan_;
arnaudsuire 0:d58c1b8d63d9 256 }
unix_guru 2:55bf0f813bb4 257
arnaudsuire 0:d58c1b8d63d9 258 //Perform the PID calculation.
arnaudsuire 0:d58c1b8d63d9 259 controllerOutput_ = scaledBias + Kc_ * (error + (tauR_ * accError_) - (tauD_ * dMeas));
unix_guru 2:55bf0f813bb4 260
arnaudsuire 0:d58c1b8d63d9 261 //Make sure the computed output is within output constraints.
arnaudsuire 0:d58c1b8d63d9 262 if (controllerOutput_ < 0.0) {
arnaudsuire 0:d58c1b8d63d9 263 controllerOutput_ = 0.0;
unix_guru 2:55bf0f813bb4 264 } else if (controllerOutput_ > 1.0) {
arnaudsuire 0:d58c1b8d63d9 265 controllerOutput_ = 1.0;
arnaudsuire 0:d58c1b8d63d9 266 }
unix_guru 2:55bf0f813bb4 267
arnaudsuire 0:d58c1b8d63d9 268 //Remember this output for the windup check next time.
arnaudsuire 0:d58c1b8d63d9 269 prevControllerOutput_ = controllerOutput_;
arnaudsuire 0:d58c1b8d63d9 270 //Remember the input for the derivative calculation next time.
unix_guru 2:55bf0f813bb4 271 prevProcessVariable_ = scaledPV;
unix_guru 2:55bf0f813bb4 272
arnaudsuire 0:d58c1b8d63d9 273 //Scale the output from percent span back out to a real world number.
arnaudsuire 0:d58c1b8d63d9 274 return ((controllerOutput_ * outSpan_) + outMin_);
unix_guru 2:55bf0f813bb4 275
arnaudsuire 0:d58c1b8d63d9 276 }
unix_guru 2:55bf0f813bb4 277
arnaudsuire 0:d58c1b8d63d9 278 float PID::getInMin() {
unix_guru 2:55bf0f813bb4 279
arnaudsuire 0:d58c1b8d63d9 280 return inMin_;
unix_guru 2:55bf0f813bb4 281
arnaudsuire 0:d58c1b8d63d9 282 }
unix_guru 2:55bf0f813bb4 283
arnaudsuire 0:d58c1b8d63d9 284 float PID::getInMax() {
unix_guru 2:55bf0f813bb4 285
arnaudsuire 0:d58c1b8d63d9 286 return inMax_;
unix_guru 2:55bf0f813bb4 287
arnaudsuire 0:d58c1b8d63d9 288 }
unix_guru 2:55bf0f813bb4 289
arnaudsuire 0:d58c1b8d63d9 290 float PID::getOutMin() {
unix_guru 2:55bf0f813bb4 291
arnaudsuire 0:d58c1b8d63d9 292 return outMin_;
unix_guru 2:55bf0f813bb4 293
unix_guru 2:55bf0f813bb4 294 }
unix_guru 2:55bf0f813bb4 295
unix_guru 2:55bf0f813bb4 296 float PID::getOutMax() {
unix_guru 2:55bf0f813bb4 297
unix_guru 2:55bf0f813bb4 298 return outMax_;
unix_guru 2:55bf0f813bb4 299
unix_guru 2:55bf0f813bb4 300 }
unix_guru 2:55bf0f813bb4 301
unix_guru 2:55bf0f813bb4 302 float PID::getInterval() {
unix_guru 2:55bf0f813bb4 303
unix_guru 2:55bf0f813bb4 304 return tSample_;
unix_guru 2:55bf0f813bb4 305
arnaudsuire 0:d58c1b8d63d9 306 }
unix_guru 2:55bf0f813bb4 307
unix_guru 2:55bf0f813bb4 308 float PID::getPParam() {
unix_guru 2:55bf0f813bb4 309
unix_guru 2:55bf0f813bb4 310 return pParam_;
unix_guru 2:55bf0f813bb4 311
unix_guru 2:55bf0f813bb4 312 }
unix_guru 2:55bf0f813bb4 313
unix_guru 2:55bf0f813bb4 314 float PID::getIParam() {
unix_guru 2:55bf0f813bb4 315
unix_guru 2:55bf0f813bb4 316 return iParam_;
unix_guru 2:55bf0f813bb4 317
unix_guru 2:55bf0f813bb4 318 }
unix_guru 2:55bf0f813bb4 319
unix_guru 2:55bf0f813bb4 320 float PID::getDParam() {
unix_guru 2:55bf0f813bb4 321
unix_guru 2:55bf0f813bb4 322 return dParam_;
unix_guru 2:55bf0f813bb4 323
unix_guru 2:55bf0f813bb4 324 }
unix_guru 2:55bf0f813bb4 325
unix_guru 2:55bf0f813bb4 326
arnaudsuire 0:d58c1b8d63d9 327
arnaudsuire 0:d58c1b8d63d9 328
unix_guru 2:55bf0f813bb4 329
arnaudsuire 0:d58c1b8d63d9 330
arnaudsuire 0:d58c1b8d63d9 331
unix_guru 2:55bf0f813bb4 332
arnaudsuire 0:d58c1b8d63d9 333
arnaudsuire 0:d58c1b8d63d9 334
arnaudsuire 0:d58c1b8d63d9 335
arnaudsuire 0:d58c1b8d63d9 336
arnaudsuire 0:d58c1b8d63d9 337