fork of what I have been writing

Dependencies:   Crypto

Committer:
kubitz
Date:
Wed Mar 04 15:56:19 2020 +0000
Revision:
10:3669e3d832ed
Parent:
9:4135d0c8dc10
Child:
11:038d3ba0d720
finished serial communication !

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kubitz 5:de6430aee646 1
kubitz 0:19fd8c1944fb 2 #include "mbed.h"
kubitz 0:19fd8c1944fb 3 #include "SHA256.h"
kubitz 6:5f4a954cb8bc 4 #include "rtos.h"
kubitz 9:4135d0c8dc10 5 #include <stdlib.h>
kubitz 10:3669e3d832ed 6 #include <string>
kubitz 7:aef5b29d7a7c 7
kubitz 9:4135d0c8dc10 8 // Mail variables to pass data to threads
kubitz 10:3669e3d832ed 9
kubitz 10:3669e3d832ed 10 Mail<uint64_t, 16> crypto_mail;
kubitz 7:aef5b29d7a7c 11 Mail<uint8_t, 8> inCharQ;
kubitz 9:4135d0c8dc10 12
kubitz 9:4135d0c8dc10 13 // Declaration of threads
kubitz 6:5f4a954cb8bc 14 Thread thread_crypto;
kubitz 9:4135d0c8dc10 15 Thread thread_processor;
kubitz 10:3669e3d832ed 16
kubitz 9:4135d0c8dc10 17 Mutex NewKey_mutex;
kubitz 10:3669e3d832ed 18 Mutex Speed_mutex;
kubitz 10:3669e3d832ed 19 Mutex Music_mutex;
kubitz 10:3669e3d832ed 20 Mutex Rotation_mutex;
kubitz 3:8443825642d1 21
kubitz 9:4135d0c8dc10 22 // Crypto mining variables
kubitz 9:4135d0c8dc10 23 uint8_t sequence[] = {0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64,
kubitz 9:4135d0c8dc10 24 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x73,
kubitz 9:4135d0c8dc10 25 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x75, 0x6E,
kubitz 9:4135d0c8dc10 26 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x20,
kubitz 9:4135d0c8dc10 27 0x61, 0x77, 0x65, 0x73, 0x6F, 0x6D, 0x65, 0x20,
kubitz 9:4135d0c8dc10 28 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x21, 0x20,
kubitz 9:4135d0c8dc10 29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
kubitz 9:4135d0c8dc10 30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
kubitz 9:4135d0c8dc10 31 uint64_t *key = (uint64_t *)&sequence[48];
kubitz 9:4135d0c8dc10 32 uint64_t *nonce = (uint64_t *)&sequence[56];
kubitz 0:19fd8c1944fb 33 uint32_t successful_nonce = 0;
kubitz 0:19fd8c1944fb 34 uint32_t last_nonce_number = 0;
kubitz 9:4135d0c8dc10 35 uint8_t hash[32];
kubitz 9:4135d0c8dc10 36 uint64_t NewKey;
kubitz 5:de6430aee646 37
kubitz 10:3669e3d832ed 38 float NewRotation;
kubitz 10:3669e3d832ed 39 float NewSpeed;
kubitz 10:3669e3d832ed 40
kubitz 9:4135d0c8dc10 41 // Timing variables for printing calculation rate
kubitz 9:4135d0c8dc10 42 Timer timer_nonce;
kubitz 9:4135d0c8dc10 43 uint32_t previous_time;
kubitz 9:4135d0c8dc10 44
kubitz 9:4135d0c8dc10 45 // Serial port variables
kubitz 8:c30a4106d08c 46 // Max size of serial input is 49 + Null character
kubitz 9:4135d0c8dc10 47 char serial_buffer[50];
kubitz 10:3669e3d832ed 48 std::string buffer_serial = "";
kubitz 9:4135d0c8dc10 49 RawSerial pc(USBTX, USBRX);
kubitz 9:4135d0c8dc10 50 char command_category;
kubitz 9:4135d0c8dc10 51 char *trimmed_serial_buffer;
kubitz 9:4135d0c8dc10 52 uint64_t extracted_value_serial_hex;
kubitz 9:4135d0c8dc10 53 uint8_t idx;
kubitz 0:19fd8c1944fb 54 //Photointerrupter input pins
kubitz 0:19fd8c1944fb 55 #define I1pin D3
kubitz 0:19fd8c1944fb 56 #define I2pin D6
kubitz 0:19fd8c1944fb 57 #define I3pin D5
kubitz 0:19fd8c1944fb 58
kubitz 0:19fd8c1944fb 59 //Incremental encoder input pins
kubitz 9:4135d0c8dc10 60 #define CHApin D12
kubitz 9:4135d0c8dc10 61 #define CHBpin D11
kubitz 0:19fd8c1944fb 62
kubitz 0:19fd8c1944fb 63 //Motor Drive output pins //Mask in output byte
kubitz 9:4135d0c8dc10 64 #define L1Lpin D1 //0x01
kubitz 9:4135d0c8dc10 65 #define L1Hpin A3 //0x02
kubitz 9:4135d0c8dc10 66 #define L2Lpin D0 //0x04
kubitz 9:4135d0c8dc10 67 #define L2Hpin A6 //0x08
kubitz 9:4135d0c8dc10 68 #define L3Lpin D10 //0x10
kubitz 9:4135d0c8dc10 69 #define L3Hpin D2 //0x20
kubitz 0:19fd8c1944fb 70
kubitz 0:19fd8c1944fb 71 #define PWMpin D9
kubitz 0:19fd8c1944fb 72
kubitz 0:19fd8c1944fb 73 //Motor current sense
kubitz 9:4135d0c8dc10 74 #define MCSPpin A1
kubitz 9:4135d0c8dc10 75 #define MCSNpin A0
kubitz 0:19fd8c1944fb 76
kubitz 0:19fd8c1944fb 77 //Test outputs
kubitz 0:19fd8c1944fb 78 #define TP0pin D4
kubitz 0:19fd8c1944fb 79 #define TP1pin D13
kubitz 0:19fd8c1944fb 80 #define TP2pin A2
kubitz 0:19fd8c1944fb 81
kubitz 0:19fd8c1944fb 82 //Mapping from sequential drive states to motor phase outputs
kubitz 0:19fd8c1944fb 83 /*
kubitz 0:19fd8c1944fb 84 State L1 L2 L3
kubitz 0:19fd8c1944fb 85 0 H - L
kubitz 0:19fd8c1944fb 86 1 - H L
kubitz 0:19fd8c1944fb 87 2 L H -
kubitz 0:19fd8c1944fb 88 3 L - H
kubitz 0:19fd8c1944fb 89 4 - L H
kubitz 0:19fd8c1944fb 90 5 H L -
kubitz 0:19fd8c1944fb 91 6 - - -
kubitz 0:19fd8c1944fb 92 7 - - -
kubitz 0:19fd8c1944fb 93 */
kubitz 0:19fd8c1944fb 94 //Drive state to output table
kubitz 9:4135d0c8dc10 95 const int8_t driveTable[] = {0x12, 0x18, 0x09, 0x21, 0x24, 0x06, 0x00, 0x00};
kubitz 0:19fd8c1944fb 96
kubitz 0:19fd8c1944fb 97 //Mapping from interrupter inputs to sequential rotor states. 0x00 and 0x07 are not valid
kubitz 9:4135d0c8dc10 98 const int8_t stateMap[] = {0x07, 0x05, 0x03, 0x04, 0x01, 0x00, 0x02, 0x07};
kubitz 0:19fd8c1944fb 99 //const int8_t stateMap[] = {0x07,0x01,0x03,0x02,0x05,0x00,0x04,0x07}; //Alternative if phase order of input or drive is reversed
kubitz 0:19fd8c1944fb 100
kubitz 0:19fd8c1944fb 101 //Phase lead to make motor spin
kubitz 9:4135d0c8dc10 102 const int8_t lead = 2; //2 for forwards, -2 for backwards
kubitz 0:19fd8c1944fb 103
kubitz 0:19fd8c1944fb 104 //Status LED
kubitz 0:19fd8c1944fb 105 DigitalOut led1(LED1);
kubitz 0:19fd8c1944fb 106
kubitz 0:19fd8c1944fb 107 //Photointerrupter inputs
kubitz 0:19fd8c1944fb 108 InterruptIn I1(I1pin);
kubitz 0:19fd8c1944fb 109 InterruptIn I2(I2pin);
kubitz 0:19fd8c1944fb 110 InterruptIn I3(I3pin);
kubitz 0:19fd8c1944fb 111
kubitz 0:19fd8c1944fb 112 //Motor Drive outputs
kubitz 0:19fd8c1944fb 113 DigitalOut L1L(L1Lpin);
kubitz 0:19fd8c1944fb 114 DigitalOut L1H(L1Hpin);
kubitz 0:19fd8c1944fb 115 DigitalOut L2L(L2Lpin);
kubitz 0:19fd8c1944fb 116 DigitalOut L2H(L2Hpin);
kubitz 0:19fd8c1944fb 117 DigitalOut L3L(L3Lpin);
kubitz 0:19fd8c1944fb 118 DigitalOut L3H(L3Hpin);
kubitz 0:19fd8c1944fb 119
kubitz 0:19fd8c1944fb 120 DigitalOut TP1(TP1pin);
kubitz 0:19fd8c1944fb 121 PwmOut MotorPWM(PWMpin);
kubitz 0:19fd8c1944fb 122
kubitz 9:4135d0c8dc10 123 int8_t orState = 0; //Rotot offset at motor state 0
kubitz 0:19fd8c1944fb 124 int8_t intState = 0;
kubitz 0:19fd8c1944fb 125 int8_t intStateOld = 0;
kubitz 0:19fd8c1944fb 126
kubitz 0:19fd8c1944fb 127 //Set a given drive state
kubitz 9:4135d0c8dc10 128 void motorOut(int8_t driveState)
kubitz 9:4135d0c8dc10 129 {
kubitz 9:4135d0c8dc10 130
kubitz 0:19fd8c1944fb 131 //Lookup the output byte from the drive state.
kubitz 0:19fd8c1944fb 132 int8_t driveOut = driveTable[driveState & 0x07];
kubitz 9:4135d0c8dc10 133
kubitz 0:19fd8c1944fb 134 //Turn off first
kubitz 9:4135d0c8dc10 135 if (~driveOut & 0x01)
kubitz 9:4135d0c8dc10 136 L1L = 0;
kubitz 9:4135d0c8dc10 137 if (~driveOut & 0x02)
kubitz 9:4135d0c8dc10 138 L1H = 1;
kubitz 9:4135d0c8dc10 139 if (~driveOut & 0x04)
kubitz 9:4135d0c8dc10 140 L2L = 0;
kubitz 9:4135d0c8dc10 141 if (~driveOut & 0x08)
kubitz 9:4135d0c8dc10 142 L2H = 1;
kubitz 9:4135d0c8dc10 143 if (~driveOut & 0x10)
kubitz 9:4135d0c8dc10 144 L3L = 0;
kubitz 9:4135d0c8dc10 145 if (~driveOut & 0x20)
kubitz 9:4135d0c8dc10 146 L3H = 1;
kubitz 9:4135d0c8dc10 147
kubitz 0:19fd8c1944fb 148 //Then turn on
kubitz 9:4135d0c8dc10 149 if (driveOut & 0x01)
kubitz 9:4135d0c8dc10 150 L1L = 1;
kubitz 9:4135d0c8dc10 151 if (driveOut & 0x02)
kubitz 9:4135d0c8dc10 152 L1H = 0;
kubitz 9:4135d0c8dc10 153 if (driveOut & 0x04)
kubitz 9:4135d0c8dc10 154 L2L = 1;
kubitz 9:4135d0c8dc10 155 if (driveOut & 0x08)
kubitz 9:4135d0c8dc10 156 L2H = 0;
kubitz 9:4135d0c8dc10 157 if (driveOut & 0x10)
kubitz 9:4135d0c8dc10 158 L3L = 1;
kubitz 9:4135d0c8dc10 159 if (driveOut & 0x20)
kubitz 9:4135d0c8dc10 160 L3H = 0;
kubitz 9:4135d0c8dc10 161 }
kubitz 0:19fd8c1944fb 162
kubitz 9:4135d0c8dc10 163 //Convert photointerrupter inputs to a rotor state
kubitz 9:4135d0c8dc10 164 inline int8_t readRotorState()
kubitz 9:4135d0c8dc10 165 {
kubitz 9:4135d0c8dc10 166 return stateMap[I1 + 2 * I2 + 4 * I3];
kubitz 9:4135d0c8dc10 167 }
kubitz 9:4135d0c8dc10 168
kubitz 9:4135d0c8dc10 169 //Basic synchronisation routine
kubitz 9:4135d0c8dc10 170 int8_t motorHome()
kubitz 9:4135d0c8dc10 171 {
kubitz 0:19fd8c1944fb 172 //Put the motor in drive state 0 and wait for it to stabilise
kubitz 0:19fd8c1944fb 173 motorOut(0);
kubitz 0:19fd8c1944fb 174 wait(2.0);
kubitz 9:4135d0c8dc10 175
kubitz 0:19fd8c1944fb 176 //Get the rotor state
kubitz 0:19fd8c1944fb 177 return readRotorState();
kubitz 0:19fd8c1944fb 178 }
kubitz 0:19fd8c1944fb 179
kubitz 9:4135d0c8dc10 180 void move()
kubitz 9:4135d0c8dc10 181 {
kubitz 0:19fd8c1944fb 182 intState = readRotorState();
kubitz 9:4135d0c8dc10 183 motorOut((intState - orState + lead + 6) % 6); //+6 to make sure the remainder is positive
kubitz 0:19fd8c1944fb 184 intStateOld = intState;
kubitz 0:19fd8c1944fb 185 }
kubitz 0:19fd8c1944fb 186
kubitz 6:5f4a954cb8bc 187 // Thread to print successful Hashes
kubitz 9:4135d0c8dc10 188 void thread_crypto_print()
kubitz 9:4135d0c8dc10 189 {
kubitz 9:4135d0c8dc10 190 while (true)
kubitz 9:4135d0c8dc10 191 {
kubitz 7:aef5b29d7a7c 192 osEvent evt = crypto_mail.get();
kubitz 9:4135d0c8dc10 193 if (evt.status == osEventMail)
kubitz 9:4135d0c8dc10 194 {
kubitz 10:3669e3d832ed 195 uint64_t *matching_nonce = (uint64_t *)evt.value.p;
kubitz 10:3669e3d832ed 196 pc.printf("Matching nonce found: %llu \n\r",(long long) *matching_nonce);
kubitz 10:3669e3d832ed 197 crypto_mail.free(matching_nonce);
kubitz 6:5f4a954cb8bc 198 }
kubitz 6:5f4a954cb8bc 199 }
kubitz 6:5f4a954cb8bc 200 }
kubitz 6:5f4a954cb8bc 201
kubitz 10:3669e3d832ed 202 void decode_serial_buffer(std::string serial_buffer)
kubitz 10:3669e3d832ed 203 {
kubitz 10:3669e3d832ed 204 command_category = serial_buffer[0];
kubitz 9:4135d0c8dc10 205 switch (command_category)
kubitz 9:4135d0c8dc10 206 {
kubitz 9:4135d0c8dc10 207 case 'R':
kubitz 9:4135d0c8dc10 208 // Rotation command - R-?\d{1,s4}(\.\d)?
kubitz 10:3669e3d832ed 209 Rotation_mutex.lock();
kubitz 10:3669e3d832ed 210 sscanf(serial_buffer.c_str(), "%c-%f", &command_category, &NewRotation);
kubitz 10:3669e3d832ed 211 pc.printf("You have a new rotation: %f \r\n", NewRotation);
kubitz 10:3669e3d832ed 212 Rotation_mutex.unlock();
kubitz 9:4135d0c8dc10 213
kubitz 9:4135d0c8dc10 214 break;
kubitz 9:4135d0c8dc10 215 case 'V':
kubitz 9:4135d0c8dc10 216 // Speed command - V\d{1,3}(\.\d)?
kubitz 10:3669e3d832ed 217 Speed_mutex.lock();
kubitz 10:3669e3d832ed 218 sscanf(serial_buffer.c_str(), "%c %f", &command_category, &NewSpeed);
kubitz 10:3669e3d832ed 219 pc.printf("You have a new speed: %f \r\n", NewSpeed);
kubitz 10:3669e3d832ed 220 Speed_mutex.unlock();
kubitz 9:4135d0c8dc10 221 // to implement !
kubitz 9:4135d0c8dc10 222 break;
kubitz 9:4135d0c8dc10 223
kubitz 9:4135d0c8dc10 224 case 'K':
kubitz 9:4135d0c8dc10 225 // Bitcoin key command - K[0-9a-fA-F]{16}
kubitz 9:4135d0c8dc10 226 NewKey_mutex.lock();
kubitz 10:3669e3d832ed 227 sscanf(serial_buffer.c_str(), "%c %llx", &command_category, &NewKey);
kubitz 10:3669e3d832ed 228 pc.printf("You have entered a new bitcoin key: %llu \r\n",(long long) NewKey);
kubitz 9:4135d0c8dc10 229 NewKey_mutex.unlock();
kubitz 9:4135d0c8dc10 230 break;
kubitz 9:4135d0c8dc10 231
kubitz 9:4135d0c8dc10 232 case 'T':
kubitz 9:4135d0c8dc10 233 // Melody command - T([A-G][#^]?[1-8]){1,16}
kubitz 10:3669e3d832ed 234 Music_mutex.lock();
kubitz 10:3669e3d832ed 235 pc.printf("You have entered a new melody: --> TO IMPLEMENT <--- \r\n");
kubitz 10:3669e3d832ed 236 Music_mutex.unlock();
kubitz 9:4135d0c8dc10 237 // to implement !
kubitz 8:c30a4106d08c 238
kubitz 9:4135d0c8dc10 239 default:
kubitz 10:3669e3d832ed 240 printf("Input value out of format - please try again! \r\n");
kubitz 7:aef5b29d7a7c 241 }
kubitz 9:4135d0c8dc10 242 }
kubitz 9:4135d0c8dc10 243
kubitz 9:4135d0c8dc10 244 // Thread processor raw serial inputs:
kubitz 9:4135d0c8dc10 245 void thread_processor_callback()
kubitz 9:4135d0c8dc10 246 {
kubitz 9:4135d0c8dc10 247 while (true)
kubitz 9:4135d0c8dc10 248 {
kubitz 9:4135d0c8dc10 249 osEvent evt = inCharQ.get();
kubitz 9:4135d0c8dc10 250 uint8_t *newChar = (uint8_t *)evt.value.p;
kubitz 10:3669e3d832ed 251 buffer_serial += (*newChar);
kubitz 9:4135d0c8dc10 252 //Store the new character
kubitz 10:3669e3d832ed 253 if (buffer_serial.back() == '\r')
kubitz 9:4135d0c8dc10 254 {
kubitz 10:3669e3d832ed 255 buffer_serial += '\0';
kubitz 10:3669e3d832ed 256 decode_serial_buffer(buffer_serial);
kubitz 10:3669e3d832ed 257 buffer_serial = "";
kubitz 9:4135d0c8dc10 258 }
kubitz 9:4135d0c8dc10 259 inCharQ.free(newChar);
kubitz 9:4135d0c8dc10 260 }
kubitz 9:4135d0c8dc10 261 }
kubitz 9:4135d0c8dc10 262
kubitz 9:4135d0c8dc10 263
kubitz 9:4135d0c8dc10 264 // Put message in Mail box for Crypto printing
kubitz 10:3669e3d832ed 265 void putMessageCrypto(uint64_t nonce)
kubitz 9:4135d0c8dc10 266 {
kubitz 10:3669e3d832ed 267 uint64_t *mail = crypto_mail.alloc();
kubitz 10:3669e3d832ed 268 *mail = nonce;
kubitz 7:aef5b29d7a7c 269 crypto_mail.put(mail);
kubitz 9:4135d0c8dc10 270 }
kubitz 9:4135d0c8dc10 271
kubitz 7:aef5b29d7a7c 272 // ISR routine to get charachter from Serial command
kubitz 9:4135d0c8dc10 273 void serialISR()
kubitz 10:3669e3d832ed 274 {
kubitz 9:4135d0c8dc10 275 uint8_t *newChar = inCharQ.alloc();
kubitz 9:4135d0c8dc10 276 *newChar = pc.getc();
kubitz 9:4135d0c8dc10 277 inCharQ.put(newChar);
kubitz 9:4135d0c8dc10 278 }
kubitz 9:4135d0c8dc10 279
kubitz 9:4135d0c8dc10 280 // Attach interrupt routine on serial port
kubitz 6:5f4a954cb8bc 281
kubitz 0:19fd8c1944fb 282 //Main
kubitz 9:4135d0c8dc10 283 int main()
kubitz 9:4135d0c8dc10 284 {
kubitz 9:4135d0c8dc10 285 pc.attach(&serialISR);
kubitz 0:19fd8c1944fb 286 const int32_t PWM_PRD = 2500;
kubitz 0:19fd8c1944fb 287 MotorPWM.period_us(PWM_PRD);
kubitz 0:19fd8c1944fb 288 MotorPWM.pulsewidth_us(PWM_PRD);
kubitz 9:4135d0c8dc10 289
kubitz 0:19fd8c1944fb 290 pc.printf("Hello\n\r");
kubitz 9:4135d0c8dc10 291
kubitz 0:19fd8c1944fb 292 //Run the motor synchronisation
kubitz 0:19fd8c1944fb 293 orState = motorHome();
kubitz 9:4135d0c8dc10 294 pc.printf("Rotor origin: %x\n\r", orState);
kubitz 9:4135d0c8dc10 295
kubitz 0:19fd8c1944fb 296 I1.rise(&move);
kubitz 0:19fd8c1944fb 297 I1.fall(&move);
kubitz 0:19fd8c1944fb 298 I2.rise(&move);
kubitz 0:19fd8c1944fb 299 I2.fall(&move);
kubitz 0:19fd8c1944fb 300 I3.rise(&move);
kubitz 0:19fd8c1944fb 301 I3.fall(&move);
kubitz 8:c30a4106d08c 302
kubitz 9:4135d0c8dc10 303 // Initialize threads and timers
kubitz 9:4135d0c8dc10 304 timer_nonce.start();
kubitz 7:aef5b29d7a7c 305 thread_crypto.start(thread_crypto_print);
kubitz 9:4135d0c8dc10 306 thread_processor.start(thread_processor_callback);
kubitz 9:4135d0c8dc10 307 uint8_t hash[32];
kubitz 5:de6430aee646 308
kubitz 9:4135d0c8dc10 309 while (1)
kubitz 9:4135d0c8dc10 310 {
kubitz 10:3669e3d832ed 311 // Set main as lowest priority thread
kubitz 10:3669e3d832ed 312
kubitz 10:3669e3d832ed 313 NewKey_mutex.lock();
kubitz 10:3669e3d832ed 314 *key = NewKey;
kubitz 10:3669e3d832ed 315 NewKey_mutex.unlock();
kubitz 10:3669e3d832ed 316
kubitz 9:4135d0c8dc10 317 SHA256::computeHash(hash, (uint8_t *)sequence, 64);
kubitz 5:de6430aee646 318 *nonce = *nonce + 1;
kubitz 5:de6430aee646 319
kubitz 9:4135d0c8dc10 320 if ((hash[0] == 0) && (hash[1] == 0))
kubitz 9:4135d0c8dc10 321 {
kubitz 0:19fd8c1944fb 322 last_nonce_number = successful_nonce;
kubitz 10:3669e3d832ed 323 putMessageCrypto(*nonce);
kubitz 0:19fd8c1944fb 324 successful_nonce++;
kubitz 9:4135d0c8dc10 325 }
kubitz 9:4135d0c8dc10 326
kubitz 9:4135d0c8dc10 327 if ((timer_nonce.read_ms() - previous_time) > 1000)
kubitz 9:4135d0c8dc10 328 {
kubitz 9:4135d0c8dc10 329 //pc.printf("Computation Rate: %lu computation /sec\n\r", (*nonce - last_nonce_number));
kubitz 0:19fd8c1944fb 330 last_nonce_number = *nonce;
kubitz 5:de6430aee646 331 previous_time = timer_nonce.read_ms();
kubitz 0:19fd8c1944fb 332 }
kubitz 0:19fd8c1944fb 333 }
kubitz 0:19fd8c1944fb 334
kubitz 9:4135d0c8dc10 335 return 0;
kubitz 9:4135d0c8dc10 336 }