Code for 'Smart Regulator' featured in 'Model Engineer', November 2020 on. Contains all work to August 2020 including all code described. Top level algorithm development is quite spares, leaving some work for you! Any questions - jon@jons-workshop.com

Dependencies:   mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM

Committer:
JonFreeman
Date:
Mon Jun 08 13:46:52 2020 +0000
Revision:
2:8e7b51353f32
Parent:
1:450090bdb6f4
Child:
3:43cb067ecd00
About to revamp i2c

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 0:77803b3ee157 1 /*
JonFreeman 0:77803b3ee157 2 Command Line Interpreter code module.
JonFreeman 0:77803b3ee157 3 Purpose -
JonFreeman 0:77803b3ee157 4 Provides easy interface to pc terminal programme for use during programme development, debug etc.
JonFreeman 0:77803b3ee157 5 Also usable as comms subsystem in finished code for accepting commands, reporting data etc.
JonFreeman 0:77803b3ee157 6 */
JonFreeman 0:77803b3ee157 7 #include "mbed.h"
JonFreeman 0:77803b3ee157 8 #include "Alternator.h"
JonFreeman 0:77803b3ee157 9 //#include "BufferedSerial.h"
JonFreeman 0:77803b3ee157 10 #include <cctype>
JonFreeman 0:77803b3ee157 11 using namespace std;
JonFreeman 0:77803b3ee157 12
JonFreeman 1:450090bdb6f4 13 extern eeprom_settings user_settings ;
JonFreeman 0:77803b3ee157 14 //eeprom_settings mode ;
JonFreeman 0:77803b3ee157 15
JonFreeman 1:450090bdb6f4 16 //extern int ver, vef, measured_pw_us;
JonFreeman 1:450090bdb6f4 17 extern void set_throttle_limit (struct parameters & a) ;
JonFreeman 2:8e7b51353f32 18 //extern void speed_control_factor_set (struct parameters & a) ;
JonFreeman 1:450090bdb6f4 19 extern void query_system (struct parameters & a) ;
JonFreeman 0:77803b3ee157 20 extern uint32_t ReadEngineRPM () ;
JonFreeman 0:77803b3ee157 21 extern double Read_BatteryVolts () ;
JonFreeman 2:8e7b51353f32 22 //extern void Read_Ammeter (double *) ;
JonFreeman 0:77803b3ee157 23
JonFreeman 0:77803b3ee157 24
JonFreeman 0:77803b3ee157 25
JonFreeman 0:77803b3ee157 26
JonFreeman 0:77803b3ee157 27
JonFreeman 0:77803b3ee157 28 // WithOUT RTOS
JonFreeman 0:77803b3ee157 29 //extern BufferedSerial pc;
JonFreeman 1:450090bdb6f4 30
JonFreeman 1:450090bdb6f4 31 #ifdef TARGET_NUCLEO_L432KC //
JonFreeman 0:77803b3ee157 32 extern Serial pc;
JonFreeman 1:450090bdb6f4 33 #else
JonFreeman 1:450090bdb6f4 34 extern BufferedSerial pc;
JonFreeman 1:450090bdb6f4 35 #endif
JonFreeman 1:450090bdb6f4 36 //extern double test_pot; // These used in knifeandfork code testing only
JonFreeman 2:8e7b51353f32 37 extern void maketable () ;
JonFreeman 2:8e7b51353f32 38
JonFreeman 2:8e7b51353f32 39 void table_tweak_cmd (struct parameters & a) { // Requires two params. First '20', '25' etc representing hundreds RPM. Second 0 to 99 percent
JonFreeman 2:8e7b51353f32 40 char txt[100];
JonFreeman 2:8e7b51353f32 41 uint32_t d[3];
JonFreeman 2:8e7b51353f32 42 txt[0] = 0;
JonFreeman 2:8e7b51353f32 43 if (a.numof_dbls != 2)
JonFreeman 2:8e7b51353f32 44 sprintf (txt, "Need 2 params, got %d, ", a.numof_dbls);
JonFreeman 2:8e7b51353f32 45 else {
JonFreeman 2:8e7b51353f32 46 d[2] = (uint32_t)a.dbl[0];
JonFreeman 2:8e7b51353f32 47 d[0] = d[2] / 5;
JonFreeman 2:8e7b51353f32 48 d[1] = (uint32_t)a.dbl[1];
JonFreeman 2:8e7b51353f32 49 if (d[0] > 16 || d[1] > 99 || d[2] != d[0] * 5)
JonFreeman 2:8e7b51353f32 50 sprintf (txt + strlen(txt), "Param out of range %d, %d, ", d[2], d[1]);
JonFreeman 2:8e7b51353f32 51 else {
JonFreeman 2:8e7b51353f32 52 pc.printf ("Off to reset table %d RPM, %d percent\r\n", d[2] * 100, d[1]);
JonFreeman 2:8e7b51353f32 53 user_settings.wr ((char)d[1], d[0]);
JonFreeman 2:8e7b51353f32 54 user_settings.save ();
JonFreeman 2:8e7b51353f32 55 maketable ();
JonFreeman 2:8e7b51353f32 56 }
JonFreeman 2:8e7b51353f32 57 }
JonFreeman 2:8e7b51353f32 58 if (txt[0])
JonFreeman 2:8e7b51353f32 59 pc.printf ("Errors in table_tweak_cmd - %s\r\n", txt);
JonFreeman 2:8e7b51353f32 60 else
JonFreeman 2:8e7b51353f32 61 pc.printf ("Good in table_tweak_cmd, RPM=%d, percentage=%d\r\n", d[0] * 500, d[1]);
JonFreeman 2:8e7b51353f32 62 }
JonFreeman 0:77803b3ee157 63
JonFreeman 0:77803b3ee157 64 //extern int numof_eeprom_options2 ;
JonFreeman 0:77803b3ee157 65 //extern struct optpar const option_list2[] ;
JonFreeman 0:77803b3ee157 66 extern struct optpar option_list2[] ;
JonFreeman 0:77803b3ee157 67
JonFreeman 0:77803b3ee157 68 /**void mode_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents
JonFreeman 0:77803b3ee157 69 * mode_cmd called only from pc comms. No sense calling from Touch Screen Controller
JonFreeman 0:77803b3ee157 70 *
JonFreeman 0:77803b3ee157 71 * Called without parameters - Lists to pc terminal current settings
JonFreeman 0:77803b3ee157 72 *
JonFreeman 0:77803b3ee157 73 */
JonFreeman 0:77803b3ee157 74 void mode19_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents
JonFreeman 0:77803b3ee157 75 {
JonFreeman 1:450090bdb6f4 76
JonFreeman 0:77803b3ee157 77 char temps[36];
JonFreeman 0:77803b3ee157 78 int i;
JonFreeman 0:77803b3ee157 79 pc.printf ("\r\nmode - Set system data in EEPROM - Jan 2019\r\nSyntax 'mode' with no parameters lists current state.\r\n");
JonFreeman 0:77803b3ee157 80 if (a.numof_dbls) { // If more than 0 parameters supplied
JonFreeman 0:77803b3ee157 81 for (i = 0; i < a.numof_dbls; i++)
JonFreeman 0:77803b3ee157 82 temps[i] = (char)a.dbl[i]; // recast doubles to char
JonFreeman 0:77803b3ee157 83 while (i < 33)
JonFreeman 0:77803b3ee157 84 temps[i++] = 0;
JonFreeman 0:77803b3ee157 85 i = (int)a.dbl[0];
JonFreeman 0:77803b3ee157 86 switch (i) {
JonFreeman 0:77803b3ee157 87 case 0: case 1: case 2: case 3: case 4:
JonFreeman 0:77803b3ee157 88 case 5: case 6: case 7: case 8:
JonFreeman 0:77803b3ee157 89 if (temps[1] >= option_list2[i].min && temps[1] <= option_list2[i].max)
JonFreeman 1:450090bdb6f4 90 user_settings.wr(temps[1], RPM0 + i);
JonFreeman 0:77803b3ee157 91 break;
JonFreeman 0:77803b3ee157 92 case 37: // set pwm scale factor
JonFreeman 0:77803b3ee157 93 if (temps[1] >= option_list2[PWM_SCALE].min && temps[1] <= option_list2[PWM_SCALE].max)
JonFreeman 1:450090bdb6f4 94 user_settings.wr(temps[1], PWM_SCALE);
JonFreeman 0:77803b3ee157 95 break;
JonFreeman 0:77803b3ee157 96 case 83: // set to defaults
JonFreeman 1:450090bdb6f4 97 user_settings.set_defaults ();
JonFreeman 0:77803b3ee157 98 break;
JonFreeman 0:77803b3ee157 99 case 9: // 9 Save settings
JonFreeman 1:450090bdb6f4 100 user_settings.save ();
JonFreeman 0:77803b3ee157 101 pc.printf ("Saving settings to EEPROM\r\n");
JonFreeman 0:77803b3ee157 102 break;
JonFreeman 0:77803b3ee157 103 default:
JonFreeman 0:77803b3ee157 104 break;
JonFreeman 0:77803b3ee157 105 } // endof switch
JonFreeman 0:77803b3ee157 106 } // endof // If more than 0 parameters supplied
JonFreeman 0:77803b3ee157 107 else {
JonFreeman 0:77803b3ee157 108 pc.printf ("No Changes\r\n");
JonFreeman 0:77803b3ee157 109 }
JonFreeman 1:450090bdb6f4 110 pc.printf ("mode 0\t%s, [%d]\r\n", option_list2[0].t, user_settings.rd(RPM0));
JonFreeman 1:450090bdb6f4 111 pc.printf ("mode 1\t%s, [%d]\r\n", option_list2[1].t, user_settings.rd(RPM1));
JonFreeman 1:450090bdb6f4 112 pc.printf ("mode 2\t%s, [%d]\r\n", option_list2[2].t, user_settings.rd(RPM2));
JonFreeman 1:450090bdb6f4 113 pc.printf ("mode 3\t%s, [%d]\r\n", option_list2[3].t, user_settings.rd(RPM3));
JonFreeman 1:450090bdb6f4 114 pc.printf ("mode 4\t%s, [%d]\r\n", option_list2[4].t, user_settings.rd(RPM4));
JonFreeman 1:450090bdb6f4 115 pc.printf ("mode 5\t%s, [%d]\r\n", option_list2[5].t, user_settings.rd(RPM5));
JonFreeman 1:450090bdb6f4 116 pc.printf ("mode 6\t%s, [%d]\r\n", option_list2[6].t, user_settings.rd(RPM6));
JonFreeman 1:450090bdb6f4 117 pc.printf ("mode 7\t%s, [%d]\r\n", option_list2[7].t, user_settings.rd(RPM7));
JonFreeman 1:450090bdb6f4 118 pc.printf ("mode 8\t%s, [%d]\r\n", option_list2[8].t, user_settings.rd(RPM8));
JonFreeman 0:77803b3ee157 119
JonFreeman 1:450090bdb6f4 120 pc.printf ("mode 37\t%s, [%d]\r\n", option_list2[PWM_SCALE].t, user_settings.rd(PWM_SCALE));
JonFreeman 0:77803b3ee157 121 pc.printf ("mode 83\tSet to defaults\r\n");
JonFreeman 0:77803b3ee157 122 pc.printf ("mode 9\tSave settings\r\r\n");
JonFreeman 0:77803b3ee157 123
JonFreeman 0:77803b3ee157 124 }
JonFreeman 0:77803b3ee157 125
JonFreeman 2:8e7b51353f32 126 /*void gpcmd (struct parameters & a) {
JonFreeman 1:450090bdb6f4 127 pc.printf ("pwm=%.3f\r\n", user_settings.get_pwm ((int)a.dbl[0]));
JonFreeman 2:8e7b51353f32 128 }*/
JonFreeman 0:77803b3ee157 129
JonFreeman 1:450090bdb6f4 130 extern VEXT_Data Field;
JonFreeman 1:450090bdb6f4 131
JonFreeman 2:8e7b51353f32 132 void rfcmd (struct parameters & a) { // Note casts all wrong here, values are 64 bit
JonFreeman 2:8e7b51353f32 133 pc.printf ("Field.measured_period = %u", (uint32_t)Field.measured_period);
JonFreeman 2:8e7b51353f32 134 pc.printf (", Field.measured_pw_us = %u, duty_cycle = %.3f\r\n", (uint32_t)Field.measured_pw_us, Field.duty_cycle());
JonFreeman 0:77803b3ee157 135 }
JonFreeman 0:77803b3ee157 136
JonFreeman 2:8e7b51353f32 137 //extern void set_RPM_demand (uint32_t d) ;
JonFreeman 0:77803b3ee157 138
JonFreeman 2:8e7b51353f32 139 /*void set_rpm_cmd (struct parameters & a) {
JonFreeman 0:77803b3ee157 140 pc.printf ("setting RPM to %d\r\n",(int)a.dbl[0]);
JonFreeman 0:77803b3ee157 141 set_RPM_demand ((uint32_t)a.dbl[0]);
JonFreeman 2:8e7b51353f32 142 }*/
JonFreeman 0:77803b3ee157 143
JonFreeman 2:8e7b51353f32 144 /*void speedcmd (struct parameters & a) {
JonFreeman 0:77803b3ee157 145 int s = ReadEngineRPM ();
JonFreeman 1:450090bdb6f4 146 pc.printf ("speed %d, pwm %.3f\r\n", s, user_settings.get_pwm(s));
JonFreeman 2:8e7b51353f32 147 }*/
JonFreeman 0:77803b3ee157 148
JonFreeman 0:77803b3ee157 149 void vcmd (struct parameters & a) {
JonFreeman 0:77803b3ee157 150 pc.printf ("volts %.2f\r\n", Read_BatteryVolts());
JonFreeman 0:77803b3ee157 151 }
JonFreeman 0:77803b3ee157 152
JonFreeman 2:8e7b51353f32 153 /*void icmd (struct parameters & a) {
JonFreeman 1:450090bdb6f4 154 double results[4];
JonFreeman 1:450090bdb6f4 155 //double * ampsptr =
JonFreeman 1:450090bdb6f4 156 Read_Ammeter(results) ;
JonFreeman 1:450090bdb6f4 157 pc.printf ("amps %.3f, offset %.3f\r\n", results[0], results[1]);
JonFreeman 2:8e7b51353f32 158 }*/
JonFreeman 1:450090bdb6f4 159
JonFreeman 0:77803b3ee157 160 extern void set_servo (double p) ; // Only for test, called from cli
JonFreeman 0:77803b3ee157 161
JonFreeman 0:77803b3ee157 162 void set_servo_cmd (struct parameters & a) {
JonFreeman 0:77803b3ee157 163 double p = a.dbl[0] / 100.0;
JonFreeman 0:77803b3ee157 164 pc.printf ("servo %.2f\r\n", p);
JonFreeman 0:77803b3ee157 165 set_servo (p);
JonFreeman 0:77803b3ee157 166 }
JonFreeman 0:77803b3ee157 167
JonFreeman 1:450090bdb6f4 168 extern bool set_pwm (double) ; // Range 0.0 to 1.0
JonFreeman 1:450090bdb6f4 169 void p_cmd (struct parameters & a) {
JonFreeman 1:450090bdb6f4 170 // int32_t i = (int32_t)a.dbl[0];
JonFreeman 1:450090bdb6f4 171 pc.printf ("Setting PWM to %d percent\r\n", (int)(a.dbl[0] * 100.0));
JonFreeman 1:450090bdb6f4 172 set_pwm (a.dbl[0]);
JonFreeman 1:450090bdb6f4 173 }
JonFreeman 1:450090bdb6f4 174
JonFreeman 0:77803b3ee157 175 void null_cmd (struct parameters & a) {
JonFreeman 0:77803b3ee157 176 pc.printf ("At null_cmd, parameters : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
JonFreeman 0:77803b3ee157 177 }
JonFreeman 0:77803b3ee157 178
JonFreeman 0:77803b3ee157 179 void menucmd (struct parameters & a);
JonFreeman 0:77803b3ee157 180
JonFreeman 0:77803b3ee157 181 struct kb_command {
JonFreeman 0:77803b3ee157 182 const char * cmd_word; // points to text e.g. "menu"
JonFreeman 0:77803b3ee157 183 const char * explan;
JonFreeman 0:77803b3ee157 184 void (*f)(struct parameters &); // points to function
JonFreeman 0:77803b3ee157 185 } ;
JonFreeman 0:77803b3ee157 186
JonFreeman 0:77803b3ee157 187 struct kb_command const command_list[] = {
JonFreeman 0:77803b3ee157 188 {"?", "Lists available commands, same as ls", menucmd},
JonFreeman 2:8e7b51353f32 189 {"tt", "Table Tweak - 2 params RPM/100, percentage 0-99", table_tweak_cmd},
JonFreeman 0:77803b3ee157 190 {"rf", "Check rise and fall on VEXT", rfcmd},
JonFreeman 2:8e7b51353f32 191 // {"s", "Speed, RPM", speedcmd},
JonFreeman 0:77803b3ee157 192 {"v", "Read Battery volts", vcmd},
JonFreeman 2:8e7b51353f32 193 // {"i", "Read Ammeter", icmd},
JonFreeman 1:450090bdb6f4 194 {"p", "Set PWM 0 to 2400???", p_cmd},
JonFreeman 1:450090bdb6f4 195 {"q", "Query system - toggle message stream on/off", query_system},
JonFreeman 2:8e7b51353f32 196 // {"gp","Get pwm from RPM", gpcmd},
JonFreeman 0:77803b3ee157 197 {"mode", "See or set eeprom values", mode19_cmd},
JonFreeman 0:77803b3ee157 198 {"nu", "do nothing", null_cmd},
JonFreeman 1:450090bdb6f4 199 #ifndef SPEED_CONTROL_ENABLE // Includes engine revs servo control loop
JonFreeman 0:77803b3ee157 200 {"ser","set throttle servo direct 0 - 99", set_servo_cmd},
JonFreeman 1:450090bdb6f4 201 #endif
JonFreeman 2:8e7b51353f32 202 // {"sf","set speed control factor", speed_control_factor_set},
JonFreeman 2:8e7b51353f32 203 // {"sv","set engine RPM demand 2500 - 6000", set_rpm_cmd},
JonFreeman 1:450090bdb6f4 204 {"tl","set throttle_limit 0.0-1.0", set_throttle_limit},
JonFreeman 0:77803b3ee157 205 };
JonFreeman 0:77803b3ee157 206
JonFreeman 0:77803b3ee157 207 const int numof_menu_items = sizeof(command_list) / sizeof(kb_command);
JonFreeman 0:77803b3ee157 208 void menucmd (struct parameters & a)
JonFreeman 0:77803b3ee157 209 {
JonFreeman 1:450090bdb6f4 210 pc.printf("\r\nIntelligent Alternator Controller - Jon Freeman 2020\r\nAt menucmd function - listing commands:-\r\n");
JonFreeman 0:77803b3ee157 211 for(int i = 0; i < numof_menu_items; i++)
JonFreeman 0:77803b3ee157 212 pc.printf("[%s]\t\t%s\r\n", command_list[i].cmd_word, command_list[i].explan);
JonFreeman 0:77803b3ee157 213 pc.printf("End of List of Commands\r\n");
JonFreeman 0:77803b3ee157 214 }
JonFreeman 0:77803b3ee157 215
JonFreeman 0:77803b3ee157 216 void command_line_interpreter ()
JonFreeman 0:77803b3ee157 217 {
JonFreeman 1:450090bdb6f4 218
JonFreeman 0:77803b3ee157 219 const int MAX_CMD_LEN = 120;
JonFreeman 0:77803b3ee157 220 static char cmd_line[MAX_CMD_LEN + 4];
JonFreeman 0:77803b3ee157 221 static int cl_index = 0;
JonFreeman 0:77803b3ee157 222 int ch;
JonFreeman 0:77803b3ee157 223 char * pEnd;
JonFreeman 0:77803b3ee157 224 static struct parameters param_block ;
JonFreeman 0:77803b3ee157 225 while (pc.readable()) {
JonFreeman 0:77803b3ee157 226 ch = tolower(pc.getc());
JonFreeman 0:77803b3ee157 227 // pc.printf("%c", ch);
JonFreeman 0:77803b3ee157 228 if (cl_index > MAX_CMD_LEN) { // trap out stupidly long command lines
JonFreeman 0:77803b3ee157 229 pc.printf ("Error!! Stupidly long cmd line\r\n");
JonFreeman 0:77803b3ee157 230 cl_index = 0;
JonFreeman 0:77803b3ee157 231 }
JonFreeman 0:77803b3ee157 232 if (ch == '\r' || ch >= ' ' && ch <= 'z')
JonFreeman 0:77803b3ee157 233 pc.printf("%c", ch);
JonFreeman 0:77803b3ee157 234 else { // Using <Ctrl>+ 'F', 'B' for Y, 'L', 'R' for X, 'U', 'D' for Z
JonFreeman 0:77803b3ee157 235 cl_index = 0; // 6 2 12 18 21 4
JonFreeman 0:77803b3ee157 236 pc.printf("[%d]", ch);
JonFreeman 0:77803b3ee157 237 //nudger (ch); // was used on cnc to nudge axes a tad
JonFreeman 0:77803b3ee157 238 }
JonFreeman 0:77803b3ee157 239 if(ch != '\r') // was this the 'Enter' key?
JonFreeman 0:77803b3ee157 240 cmd_line[cl_index++] = ch; // added char to command being assembled
JonFreeman 0:77803b3ee157 241 else { // key was CR, may or may not be command to lookup
JonFreeman 0:77803b3ee157 242 cmd_line[cl_index] = 0; // null terminate command string
JonFreeman 0:77803b3ee157 243 if(cl_index) { // If have got some chars to lookup
JonFreeman 0:77803b3ee157 244 int i, wrdlen;
JonFreeman 0:77803b3ee157 245 for (i = 0; i < numof_menu_items; i++) { // Look for input match in command list
JonFreeman 0:77803b3ee157 246 wrdlen = strlen(command_list[i].cmd_word);
JonFreeman 0:77803b3ee157 247 if(strncmp(command_list[i].cmd_word, cmd_line, wrdlen) == 0 && !isalpha(cmd_line[wrdlen])) { // If match found
JonFreeman 0:77803b3ee157 248 for (int k = 0; k < MAX_PARAMS; k++) {
JonFreeman 0:77803b3ee157 249 param_block.dbl[k] = 0.0;
JonFreeman 0:77803b3ee157 250 }
JonFreeman 0:77803b3ee157 251 param_block.position_in_list = i;
JonFreeman 0:77803b3ee157 252 param_block.last_time = clock ();
JonFreeman 0:77803b3ee157 253 param_block.numof_dbls = 0;
JonFreeman 0:77803b3ee157 254 pEnd = cmd_line + wrdlen;
JonFreeman 0:77803b3ee157 255 while (*pEnd) { // Assemble all numerics as doubles
JonFreeman 0:77803b3ee157 256 param_block.dbl[param_block.numof_dbls++] = strtod (pEnd, &pEnd);
JonFreeman 0:77803b3ee157 257 while (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd) {
JonFreeman 0:77803b3ee157 258 pEnd++;
JonFreeman 0:77803b3ee157 259 }
JonFreeman 0:77803b3ee157 260 }
JonFreeman 0:77803b3ee157 261 pc.printf ("\r\n");
JonFreeman 0:77803b3ee157 262 // for (int k = 0; k < param_block.numof_dbls; k++)
JonFreeman 0:77803b3ee157 263 // pc.printf ("Read %.3f\r\n", param_block.dbl[k]);
JonFreeman 0:77803b3ee157 264 param_block.times[i] = clock();
JonFreeman 0:77803b3ee157 265 command_list[i].f(param_block); // execute command
JonFreeman 0:77803b3ee157 266 i = numof_menu_items + 1; // to exit for loop
JonFreeman 0:77803b3ee157 267 } // end of match found
JonFreeman 0:77803b3ee157 268 } // End of for numof_menu_items
JonFreeman 0:77803b3ee157 269 if(i == numof_menu_items)
JonFreeman 0:77803b3ee157 270 pc.printf("No Match Found for CMD [%s]\r\n", cmd_line);
JonFreeman 0:77803b3ee157 271 } // End of If have got some chars to lookup
JonFreeman 0:77803b3ee157 272 pc.printf("\r\n>");
JonFreeman 0:77803b3ee157 273 cl_index = 0;
JonFreeman 0:77803b3ee157 274 } // End of else key was CR, may or may not be command to lookup
JonFreeman 0:77803b3ee157 275 } // End of while (pc.readable())
JonFreeman 1:450090bdb6f4 276
JonFreeman 0:77803b3ee157 277 }
JonFreeman 0:77803b3ee157 278
JonFreeman 0:77803b3ee157 279