Testprogram for TMC2209-Library. Uses Speed-Control via VACTUAL instead of Step/Dir

Dependencies:   TMCStepper mRotaryEncoder-os

Committer:
charly
Date:
Thu Dec 02 20:30:09 2021 +0000
Revision:
9:babbfb61d347
Parent:
8:f44d70665051
Child:
10:376299814a3b
Before change to STM32L432

Who changed what in which revision?

UserRevisionLine numberNew contents of line
charly 0:3f4cfbeda9d3 1 #include "mbed.h"
charly 0:3f4cfbeda9d3 2 #include "platform/mbed_thread.h"
charly 2:94c5b3f09463 3 #include "TMCStepper.h"
charly 4:12bfa2c1729f 4 #include "mRotaryEncoder.h"
charly 2:94c5b3f09463 5
charly 2:94c5b3f09463 6 /*
charly 2:94c5b3f09463 7 Testprogram for TMCStepper-Library
charly 2:94c5b3f09463 8 TMCStepper based on https://github.com/teemuatlut/TMCStepper for Arduino
charly 2:94c5b3f09463 9 by https://github.com/teemuatlut
charly 2:94c5b3f09463 10 +++++
charly 2:94c5b3f09463 11 Tested with https://github.com/bigtreetech/BIGTREETECH-TMC2209-V1.2
charly 2:94c5b3f09463 12 */
charly 0:3f4cfbeda9d3 13
charly 0:3f4cfbeda9d3 14
charly 8:f44d70665051 15 DigitalOut ledCW(LED1); // Show rotation clockwise
charly 5:7f250f463aa2 16 DigitalOut ledCCW(LED2); // Show rotation counterclockwise
charly 5:7f250f463aa2 17
charly 0:3f4cfbeda9d3 18 //Virtual serial port over USB with 15200 baud 8N1
charly 0:3f4cfbeda9d3 19 static BufferedSerial host(USBTX, USBRX,115200);
charly 0:3f4cfbeda9d3 20
charly 4:12bfa2c1729f 21 //mRotaryEncoder(PinName pinA, PinName pinB, PinName pinSW, PinMode pullMode=PullUp, int debounceTime_us=1000)
charly 5:7f250f463aa2 22 mRotaryEncoder wheel(p16, p17, p18,PullUp,3000); // default 1500
charly 4:12bfa2c1729f 23
charly 2:94c5b3f09463 24 // hardware parameters:
charly 0:3f4cfbeda9d3 25 // MOTOR Steps per Revolution ( 1/8 Microsteps, 200Steps per Rev / 1.8 degrees per FullStep)
charly 0:3f4cfbeda9d3 26 #define MSPR 1600
charly 0:3f4cfbeda9d3 27 // Gear Ratio
charly 0:3f4cfbeda9d3 28 #define GR 288
charly 0:3f4cfbeda9d3 29
charly 0:3f4cfbeda9d3 30 #define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2
charly 5:7f250f463aa2 31 #define R_SENSE 0.11f // R-Sense in OHM. Match to your driver
charly 8:f44d70665051 32 #define MICROSTEPS 256 // # of microsteps
charly 8:f44d70665051 33 #define RMSCURRENT 1000 // RMS current of Stepper Coil in mA
charly 8:f44d70665051 34 #define MAXSPEED 5000 // Maximaum speed (5000 with RMS800 @12V/0.6Amax)
charly 0:3f4cfbeda9d3 35
charly 2:94c5b3f09463 36 // A TMCStepper-object with UART and given address and R-Sense
charly 0:3f4cfbeda9d3 37 //RX, TX, RS, Addr
charly 0:3f4cfbeda9d3 38 TMC2209Stepper stepper(p14, p13, R_SENSE, DRIVER_ADDRESS);
charly 0:3f4cfbeda9d3 39
charly 6:6ad7bc10ac20 40 InterruptIn diag(p21);
charly 8:f44d70665051 41 DigitalOut enn(p22);
charly 6:6ad7bc10ac20 42
charly 5:7f250f463aa2 43 volatile bool enc_pressed = false; // Button of rotaryencoder was pressed
charly 5:7f250f463aa2 44 volatile bool enc_rotated = false; // rotary encoder was totaded left or right
charly 5:7f250f463aa2 45 volatile bool enc_action = false; // any change happened
charly 6:6ad7bc10ac20 46 volatile bool diag_event = false; // DIAG-Pin of TMC
charly 4:12bfa2c1729f 47 int lastGet;
charly 4:12bfa2c1729f 48 int thisGet;
charly 4:12bfa2c1729f 49
charly 4:12bfa2c1729f 50 //interrup-Handler for button on rotary-encoder
charly 4:12bfa2c1729f 51 void trigger_sw() {
charly 4:12bfa2c1729f 52 enc_pressed = true; // just set the flag, rest is done outside isr
charly 4:12bfa2c1729f 53 }
charly 4:12bfa2c1729f 54
charly 4:12bfa2c1729f 55 //interrup-Handler for rotary-encoder rotation
charly 4:12bfa2c1729f 56 void trigger_rotated() {
charly 4:12bfa2c1729f 57 enc_rotated = true; // just set the flag, rest is done outside isr
charly 4:12bfa2c1729f 58 }
charly 4:12bfa2c1729f 59
charly 6:6ad7bc10ac20 60 //interrup-Handler for TMC2209-DIAG-Pin
charly 6:6ad7bc10ac20 61 void trigger_diag() {
charly 6:6ad7bc10ac20 62 diag_event = true; // just set the flag, rest is done outside isr
charly 6:6ad7bc10ac20 63 }
charly 6:6ad7bc10ac20 64
charly 0:3f4cfbeda9d3 65 // Assumes little endian
charly 0:3f4cfbeda9d3 66 void printBits(size_t const size, void const * const ptr)
charly 0:3f4cfbeda9d3 67 {
charly 0:3f4cfbeda9d3 68 unsigned char *b = (unsigned char*) ptr;
charly 0:3f4cfbeda9d3 69 unsigned char byte;
charly 0:3f4cfbeda9d3 70 int i, j;
charly 0:3f4cfbeda9d3 71 // puts("#");
charly 0:3f4cfbeda9d3 72 for (i = size-1; i >= 0; i--) {
charly 0:3f4cfbeda9d3 73 for (j = 7; j >= 0; j--) {
charly 0:3f4cfbeda9d3 74 byte = (b[i] >> j) & 1;
charly 0:3f4cfbeda9d3 75 printf("%u", byte);
charly 0:3f4cfbeda9d3 76 }
charly 0:3f4cfbeda9d3 77 }
charly 0:3f4cfbeda9d3 78 // puts("#");
charly 0:3f4cfbeda9d3 79 }
charly 0:3f4cfbeda9d3 80
charly 0:3f4cfbeda9d3 81 int main()
charly 0:3f4cfbeda9d3 82 {
charly 0:3f4cfbeda9d3 83 printf("\r\nConnected to mbed\r\n");
charly 4:12bfa2c1729f 84
charly 5:7f250f463aa2 85 //Intitiallize RotaryEncoder
charly 4:12bfa2c1729f 86 // call trigger_sw() when button of rotary-encoder is pressed
charly 4:12bfa2c1729f 87 wheel.attachSW(&trigger_sw);
charly 4:12bfa2c1729f 88 // call trigger_rot() when the shaft is rotaded left or right
charly 4:12bfa2c1729f 89 wheel.attachROT(&trigger_rotated);
charly 4:12bfa2c1729f 90 lastGet = 0;
charly 6:6ad7bc10ac20 91 // set enc_rotated, so startup
charly 4:12bfa2c1729f 92 enc_rotated = true;
charly 5:7f250f463aa2 93 enc_action = true;
charly 5:7f250f463aa2 94 ledCW = 1;
charly 5:7f250f463aa2 95 ledCCW = 1;
charly 6:6ad7bc10ac20 96
charly 8:f44d70665051 97 // disable Driver
charly 8:f44d70665051 98 enn=1;
charly 9:babbfb61d347 99 // wait for Hhardware to settle
charly 9:babbfb61d347 100 ThisThread::sleep_for(100ms);
charly 5:7f250f463aa2 101
charly 5:7f250f463aa2 102 // Initialize Stepper
charly 5:7f250f463aa2 103 printf("connecting to TMC-Module...\r\n");
charly 2:94c5b3f09463 104 stepper.begin(); // UART: Init SW UART (if selected) with default baudrate
charly 9:babbfb61d347 105
charly 9:babbfb61d347 106 //read and check version - must be 0x21
charly 9:babbfb61d347 107 uint8_t tmc_version = stepper.version();
charly 9:babbfb61d347 108 printf("TMC-Version: %02X\r\n",tmc_version);
charly 9:babbfb61d347 109 if (tmc_version != 0x21) {
charly 9:babbfb61d347 110 printf("Wrong TMC-Version(not 0x21) or communication error!! STOPPING!!!\r\n");
charly 9:babbfb61d347 111 if (stepper.CRCerror) {
charly 9:babbfb61d347 112 printf("CRC-Error!!!\r\n");
charly 9:babbfb61d347 113 }
charly 9:babbfb61d347 114 while (1) {
charly 9:babbfb61d347 115 ledCW = 1;
charly 9:babbfb61d347 116 ledCCW = 0;
charly 9:babbfb61d347 117 ThisThread::sleep_for(50ms);
charly 9:babbfb61d347 118 ledCW = 0;
charly 9:babbfb61d347 119 ledCCW = 1;
charly 9:babbfb61d347 120 ThisThread::sleep_for(50ms);
charly 9:babbfb61d347 121 };
charly 9:babbfb61d347 122 }
charly 9:babbfb61d347 123
charly 7:51cb60bf3e2d 124 stepper.push(); // initialize all registers??? required?
charly 7:51cb60bf3e2d 125
charly 2:94c5b3f09463 126 stepper.toff(3); // Enables driver in software - 3, 5 ????
charly 2:94c5b3f09463 127 stepper.rms_current(RMSCURRENT); // Set motor RMS current in mA / min 500 for 24V/speed:3000
charly 1:60419aa0c030 128 // 1110, 800
charly 5:7f250f463aa2 129 // working: 800 12V/0,6Amax, Speed up to 5200=4U/min
charly 5:7f250f463aa2 130
charly 0:3f4cfbeda9d3 131 stepper.microsteps(MICROSTEPS); // Set microsteps to 1:Fullstep ... 256: 1/256th
charly 1:60419aa0c030 132 stepper.en_spreadCycle(true); // Toggle spreadCycle on TMC2208/2209/2224: default false, true: much faster!!!!
charly 0:3f4cfbeda9d3 133 stepper.pwm_autoscale(true); // Needed for stealthChop
charly 0:3f4cfbeda9d3 134
charly 8:f44d70665051 135 // enable driver
charly 8:f44d70665051 136 enn = 0;
charly 8:f44d70665051 137
charly 6:6ad7bc10ac20 138 uint8_t gstat = stepper.GSTAT();
charly 6:6ad7bc10ac20 139 printf("GSTAT(): "); printBits(sizeof(gstat),&gstat);printf("\r\n");
charly 6:6ad7bc10ac20 140
charly 8:f44d70665051 141 uint32_t gconf = stepper.GCONF();
charly 8:f44d70665051 142 printf("GCONF(): "); printBits(sizeof(gconf),&gconf);printf("\r\n");
charly 8:f44d70665051 143
charly 5:7f250f463aa2 144 uint32_t status = stepper.DRV_STATUS();
charly 5:7f250f463aa2 145 printf("DRV_STATUS(): "); printBits(sizeof(status),&status);printf("\r\n");
charly 5:7f250f463aa2 146
charly 6:6ad7bc10ac20 147 uint32_t ioin = stepper.IOIN();
charly 6:6ad7bc10ac20 148 printf("IOIN(): "); printBits(sizeof(ioin),&ioin);printf("\r\n");
charly 6:6ad7bc10ac20 149
charly 8:f44d70665051 150 uint8_t ihold = stepper.ihold();
charly 8:f44d70665051 151 printf("IHOLD(): "); printBits(sizeof(ihold),&ihold);printf("\r\n");
charly 8:f44d70665051 152
charly 8:f44d70665051 153 uint8_t irun = stepper.irun();
charly 8:f44d70665051 154 printf("IRUN(): "); printBits(sizeof(irun),&irun);printf("\r\n");
charly 8:f44d70665051 155
charly 8:f44d70665051 156 uint8_t iholddelay = stepper.iholddelay();
charly 8:f44d70665051 157 printf("IHOLDDELAY(): "); printBits(sizeof(iholddelay),&iholddelay);printf("\r\n");
charly 8:f44d70665051 158
charly 8:f44d70665051 159 // do a peep by setting vactual to a too high speed
charly 8:f44d70665051 160
charly 9:babbfb61d347 161 //stepper.VACTUAL(50000*MICROSTEPS);
charly 9:babbfb61d347 162 //ThisThread::sleep_for(1s);
charly 8:f44d70665051 163
charly 8:f44d70665051 164 // initialize Automatic tunig (Chap 6.1)
charly 9:babbfb61d347 165 printf("Start automatic tunig Chap6.1 .....");
charly 8:f44d70665051 166 stepper.VACTUAL(1);
charly 8:f44d70665051 167 stepper.VACTUAL(0);
charly 8:f44d70665051 168 ThisThread::sleep_for(100ms);
charly 8:f44d70665051 169 stepper.VACTUAL(500*MICROSTEPS);
charly 8:f44d70665051 170 ThisThread::sleep_for(2s);
charly 8:f44d70665051 171 stepper.VACTUAL(0);
charly 9:babbfb61d347 172 printf("done\r\n");
charly 8:f44d70665051 173
charly 7:51cb60bf3e2d 174 diag.rise(&trigger_diag);
charly 7:51cb60bf3e2d 175
charly 5:7f250f463aa2 176 //bool shaft = false; //direction CW or CCW
charly 1:60419aa0c030 177
charly 0:3f4cfbeda9d3 178 while(1) {
charly 5:7f250f463aa2 179 /* Spped-UP/Down-Cycles
charly 0:3f4cfbeda9d3 180 // printf("TSTEP(): %i\r\n", stepper.TSTEP());
charly 0:3f4cfbeda9d3 181 uint32_t status = stepper.DRV_STATUS();
charly 0:3f4cfbeda9d3 182 printf("DRV_STATUS(): "); printBits(sizeof(status),&status);printf("\r\n");
charly 0:3f4cfbeda9d3 183 uint32_t ioin = stepper.IOIN();
charly 0:3f4cfbeda9d3 184 printf("IOIN(): "); printBits(sizeof(ioin),&ioin);printf("\r\n");
charly 0:3f4cfbeda9d3 185 // uint32_t otp = stepper.OTP_READ();
charly 0:3f4cfbeda9d3 186 // printf("OTP_READ(): ");printBits(sizeof(otp),&otp);printf("\r\n");
charly 0:3f4cfbeda9d3 187
charly 1:60419aa0c030 188 printf("VACTUAL(): %zu \r\n", stepper.VACTUAL());
charly 0:3f4cfbeda9d3 189 // increase
charly 1:60419aa0c030 190 uint32_t maxspeed = 3000; //max 3400 or 3000
charly 1:60419aa0c030 191 uint32_t actspeed = 0;
charly 0:3f4cfbeda9d3 192 while (actspeed < maxspeed) {
charly 0:3f4cfbeda9d3 193 actspeed += 200;
charly 1:60419aa0c030 194 if (actspeed > maxspeed) {
charly 1:60419aa0c030 195 actspeed = maxspeed;
charly 1:60419aa0c030 196 }
charly 3:209a9c414f54 197 printf("actspeed: %i",actspeed);
charly 0:3f4cfbeda9d3 198 stepper.VACTUAL(actspeed*MICROSTEPS);// Set Speed to value
charly 1:60419aa0c030 199 ThisThread::sleep_for(25ms); //wait
charly 0:3f4cfbeda9d3 200 }
charly 0:3f4cfbeda9d3 201 printf("VACTUAL(): %zu \r\n", stepper.VACTUAL());
charly 3:209a9c414f54 202 ThisThread::sleep_for(5s);
charly 0:3f4cfbeda9d3 203 // decrease
charly 0:3f4cfbeda9d3 204 maxspeed = 0;
charly 0:3f4cfbeda9d3 205 while (actspeed > maxspeed) {
charly 0:3f4cfbeda9d3 206 actspeed -= 200;
charly 1:60419aa0c030 207 if (actspeed < 0) {
charly 1:60419aa0c030 208 actspeed = 0;
charly 1:60419aa0c030 209 }
charly 3:209a9c414f54 210 printf("actspeed: %i",actspeed);
charly 0:3f4cfbeda9d3 211 stepper.VACTUAL(actspeed*MICROSTEPS);// Set Speed to value
charly 1:60419aa0c030 212 ThisThread::sleep_for(25ms); //wait
charly 0:3f4cfbeda9d3 213 }
charly 1:60419aa0c030 214
charly 1:60419aa0c030 215 // stepper.VACTUAL(400*MICROSTEPS);// Set Speed to value
charly 0:3f4cfbeda9d3 216 ThisThread::sleep_for(5s); //wait
charly 1:60419aa0c030 217 // inverse direction
charly 1:60419aa0c030 218 shaft = !shaft;
charly 1:60419aa0c030 219 stepper.shaft(shaft);
charly 2:94c5b3f09463 220 // Read Interace-Count
charly 2:94c5b3f09463 221 printf("IFCNT(): %zu \r\n",stepper.IFCNT());
charly 1:60419aa0c030 222 printf("...\r\n");
charly 4:12bfa2c1729f 223 */
charly 5:7f250f463aa2 224 ////// Control motor-speed by rotary-encoder
charly 5:7f250f463aa2 225
charly 6:6ad7bc10ac20 226 // DIAG-PIN showed Error-Condition?
charly 6:6ad7bc10ac20 227 if (diag_event) {
charly 6:6ad7bc10ac20 228 diag_event = false;
charly 6:6ad7bc10ac20 229 printf("DIAG occured!\r\n");
charly 6:6ad7bc10ac20 230 gstat = stepper.GSTAT();
charly 6:6ad7bc10ac20 231 printf("GSTAT(): "); printBits(sizeof(gstat),&gstat);printf("\r\n");
charly 6:6ad7bc10ac20 232 status = stepper.DRV_STATUS();
charly 6:6ad7bc10ac20 233 printf("DRV_STATUS(): "); printBits(sizeof(status),&status);printf("\r\n");
charly 6:6ad7bc10ac20 234 //safty turn off friver
charly 6:6ad7bc10ac20 235 printf("Shutting Down Motordriver...\r\n");
charly 8:f44d70665051 236 enn=1;
charly 6:6ad7bc10ac20 237 stepper.toff(0);
charly 6:6ad7bc10ac20 238 status = stepper.DRV_STATUS();
charly 6:6ad7bc10ac20 239 printf("DRV_STATUS(): "); printBits(sizeof(status),&status);printf("\r\n");
charly 6:6ad7bc10ac20 240 ioin = stepper.IOIN();
charly 6:6ad7bc10ac20 241 printf("IOIN(): "); printBits(sizeof(ioin),&ioin);printf("\r\n");
charly 8:f44d70665051 242 ihold = stepper.ihold();
charly 8:f44d70665051 243 printf("IHOLD(): "); printBits(sizeof(ihold),&ihold);printf("\r\n");
charly 8:f44d70665051 244 irun = stepper.irun();
charly 8:f44d70665051 245 printf("IRUN(): "); printBits(sizeof(irun),&irun);printf("\r\n");
charly 8:f44d70665051 246 iholddelay = stepper.iholddelay();
charly 8:f44d70665051 247 printf("IHOLDDELAY(): "); printBits(sizeof(iholddelay),&iholddelay);printf("\r\n");
charly 6:6ad7bc10ac20 248 printf("stopping programm - manual RESET required!!!!!!\r\n");
charly 8:f44d70665051 249 while (1) {
charly 8:f44d70665051 250 ledCW = 1;
charly 8:f44d70665051 251 ledCCW = 1;
charly 8:f44d70665051 252 ThisThread::sleep_for(200ms);
charly 8:f44d70665051 253 ledCW = 0;
charly 8:f44d70665051 254 ledCCW = 0;
charly 8:f44d70665051 255 ThisThread::sleep_for(200ms);
charly 8:f44d70665051 256 };
charly 6:6ad7bc10ac20 257
charly 6:6ad7bc10ac20 258 }
charly 6:6ad7bc10ac20 259
charly 4:12bfa2c1729f 260 // shaft has been rotated?
charly 4:12bfa2c1729f 261 if (enc_rotated) {
charly 4:12bfa2c1729f 262 enc_rotated = false;
charly 5:7f250f463aa2 263 enc_action = true;
charly 4:12bfa2c1729f 264 thisGet = wheel.Get();
charly 5:7f250f463aa2 265 if (thisGet*100 > MAXSPEED) { //on upper limit?
charly 5:7f250f463aa2 266 wheel.Set( MAXSPEED/100);
charly 5:7f250f463aa2 267 thisGet = wheel.Get();
charly 5:7f250f463aa2 268 }
charly 5:7f250f463aa2 269 if (thisGet*100 < MAXSPEED*(-1)) { //on lower limit?
charly 5:7f250f463aa2 270 wheel.Set( MAXSPEED*(-1)/100);
charly 5:7f250f463aa2 271 thisGet = wheel.Get();
charly 5:7f250f463aa2 272 }
charly 4:12bfa2c1729f 273 stepper.VACTUAL(thisGet*100*MICROSTEPS);// Set Speed to value
charly 4:12bfa2c1729f 274 printf("actspeed: %i\r\n",thisGet*100);
charly 5:7f250f463aa2 275
charly 4:12bfa2c1729f 276 }
charly 4:12bfa2c1729f 277 // Button pressed?
charly 4:12bfa2c1729f 278 if (enc_pressed) {
charly 4:12bfa2c1729f 279 enc_pressed = false;
charly 5:7f250f463aa2 280 enc_action = true;
charly 4:12bfa2c1729f 281 wheel.Set(0);
charly 4:12bfa2c1729f 282 thisGet = wheel.Get();
charly 4:12bfa2c1729f 283 stepper.VACTUAL(thisGet*100*MICROSTEPS);// Set Speed to value
charly 4:12bfa2c1729f 284 printf("actspeed: %i\r\n",thisGet*100);
charly 7:51cb60bf3e2d 285
charly 7:51cb60bf3e2d 286 gstat = stepper.GSTAT();
charly 7:51cb60bf3e2d 287 printf("GSTAT(): "); printBits(sizeof(gstat),&gstat);printf("\r\n");
charly 8:f44d70665051 288 gconf = stepper.GCONF();
charly 8:f44d70665051 289 printf("GCONF(): "); printBits(sizeof(gconf),&gconf);printf("\r\n");
charly 7:51cb60bf3e2d 290 status = stepper.DRV_STATUS();
charly 7:51cb60bf3e2d 291 printf("DRV_STATUS(): "); printBits(sizeof(status),&status);printf("\r\n");
charly 7:51cb60bf3e2d 292 ioin = stepper.IOIN();
charly 7:51cb60bf3e2d 293 printf("IOIN(): "); printBits(sizeof(ioin),&ioin);printf("\r\n");
charly 8:f44d70665051 294 ihold = stepper.ihold();
charly 8:f44d70665051 295 printf("IHOLD(): "); printBits(sizeof(ihold),&ihold);printf("\r\n");
charly 8:f44d70665051 296 irun = stepper.irun();
charly 8:f44d70665051 297 printf("IRUN(): "); printBits(sizeof(irun),&irun);printf("\r\n");
charly 8:f44d70665051 298 iholddelay = stepper.iholddelay();
charly 8:f44d70665051 299 printf("IHOLDDELAY(): "); printBits(sizeof(iholddelay),&iholddelay);printf("\r\n");
charly 4:12bfa2c1729f 300
charly 4:12bfa2c1729f 301 }
charly 5:7f250f463aa2 302 // anything changed?
charly 5:7f250f463aa2 303 if (enc_action) {
charly 5:7f250f463aa2 304 enc_action = false;
charly 5:7f250f463aa2 305 // show direction of motor on leds
charly 5:7f250f463aa2 306 if (thisGet > 0) {
charly 5:7f250f463aa2 307 ledCW = 1;
charly 5:7f250f463aa2 308 ledCCW= 0;
charly 5:7f250f463aa2 309 }
charly 5:7f250f463aa2 310 if (thisGet < 0) {
charly 5:7f250f463aa2 311 ledCW = 0;
charly 5:7f250f463aa2 312 ledCCW= 1;
charly 5:7f250f463aa2 313 }
charly 5:7f250f463aa2 314 if (thisGet == 0) {
charly 5:7f250f463aa2 315 ledCW = 1;
charly 5:7f250f463aa2 316 ledCCW= 1;
charly 5:7f250f463aa2 317 }
charly 5:7f250f463aa2 318 }
charly 4:12bfa2c1729f 319 } // while 1
charly 0:3f4cfbeda9d3 320 }