Jon Freeman / Mbed 2 deprecated Alternator2020_06

Dependencies:   mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*******************************************************************************
00002         DON'T FORGET TO REMOVE SOLDER LINKS SB16 AND SB18 ON NUCLEO-L432KC BOARD
00003 *******************************************************************************/
00004 #include "mbed.h"
00005 #include "Alternator.h"
00006 #include "BufferedSerial.h"
00007 #include "I2CEeprom.h"
00008 #include "LM75B.h"              //  New I2C temp sensor code March 2020 (to suit possible next board issue, harmless otherwise)
00009 #include "rpm.h"
00010 #include "field.h"
00011 #include "gps_mod.h"
00012 
00013 //#include "baro.h"
00014 
00015 #ifdef  TARGET_NUCLEO_L432KC    //  24LC and LM75 work
00016 //    #define SDA_PIN D0    //  good
00017 //    #define SCL_PIN D1
00018     #define SDA_PIN D4      //  good
00019     #define SCL_PIN D5
00020 #endif
00021 
00022 /*******************************************************************************
00023         DON'T FORGET TO REMOVE SOLDER LINKS SB16 AND SB18 ON L432KC BOARD
00024 *******************************************************************************/
00025 //During test LED across field has been useful visual aid. Incorporate similar on new board.
00026 /*
00027     *   May 2020 NOTE input circuit to analogue in driver pot zeners input to 3v6, then pot reduces by about 1/3.
00028     *   This makes input reading only about 0.0 to 0.66
00029     *   Temp bodge, mult by 1.5
00030     
00031     *   Two voltages now measured. Link voltage (alternator output), and field supply (which may come from battery when main output low)
00032 */
00033 
00034 /*
00035     Alternator Regulator
00036     Jon Freeman
00037     June 2019 - June 2020
00038     
00039     ** Prototype built using Nucleo L432KC. Having solved i2c problem, this looks good for final product
00040     
00041     **  main loop frequency upped from 32Hz to 100Hz **
00042 
00043     WHAT THIS PROGRAMME DOES - Controls 4 stroke petrol engine driving vehicle alternator with new custom regulator
00044     
00045     Electronics powered by higher voltage of small 12v backup battery, or alternator output
00046         Note only Field+ and MAX5035 supplied thus, all else powered from MAX outputs.
00047     Starting engine provides rectified tickle from magneto to enable MAX5035 creating +5 and +3v3 supplies.
00048     Alternative, selected by jumper position, is external switch - battery+ to MAX enable circuit. ** Review this **
00049     Anytime engine revs measured < TICKOVER_RPM (or some such) RPM, field current OFF (by pwm 0) , see speed related pwm limit table
00050     
00051     BEGIN
00052         Loop forever at 100 Hz   {
00053             Read engine RPM by monitoring engine tacho signal present on engine On/Off switch line
00054             Adjust Alternator field current max limit according to RPM (analogue regulator limits output voltage)
00055             Measure system voltage (just in case this is ever useful)
00056             Respond to any commands arriving at serial port (setup and test link to laptop)
00057             Flash LED at 8 Hz as proof of life
00058         }
00059     END
00060 
00061     INPUTS  AnalogIn x 2 - Ammeter chip - current and offset AnalogIns
00062     INPUT   AnalogIn - System voltage for info only.
00063     INPUT   AnalogIn - ExtRevDemand
00064     INPUT   AnalogIn - DriverPot
00065     INPUT   Pulse engine speed indicator, speed checked against EEPROM data to select max pwm duty ratio for this speed
00066     INPUT   Final pwm gate drive wired back to InterruptIn ** MAYBE USEFUL OR NOT ** Could read this back via serial to laptop
00067     OUTPUT  pwm to MCP1630. This is clock to pwm chip. Also limits max duty ratio
00068     RS232 serial via USB to setup eeprom data
00069 */
00070 
00071 /**
00072 *   Jumpers fitted to small mbed Nucleo boards - D5 - A5 and D4 - A4 CHECK - yes
00073 */
00074 //#ifdef  TARGET_NUCLEO_L432KC    //  Has to be, quite settled now on this, having solved i2c problems
00075 BufferedSerial  pc      (USBTX, USBRX, 4096, 4, NULL); //  Comms port to pc or terminal using USB lead
00076 //BufferedSerial  LocalCom    (PA_9, PA_10);  //  New March 2019 - Taken out for i2c test 6/6/2020
00077 
00078 //  INPUTS :
00079 AnalogIn    Ain_Link_Volts  (A6);   //  Sniff of alternator output, not used in control loop as done using analogue MCP1630
00080 AnalogIn    Ammeter_In      (A0);   //  Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
00081 
00082 //  Nov 2019. Not convinced Ext_Rev_Demand is useful    ** July 2020 - repurposed, voltmeter Field_Supply_V
00083 //AnalogIn    Ext_Rev_Demand  (D3);   //  Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
00084 AnalogIn    Field_Supply_V  (D3);   //  Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
00085 
00086 AnalogIn    Driver_Pot      (A1);   //  Moved 31/07/2020 from A3 to free up A3 for use as AnalogOut
00087 
00088 BufferedSerial  gps_module  (D1, D0, 2048, 4, NULL);   //  For gps - added July 2020
00089 
00090 /*
00091     MODULE PIN USAGE    -   Updated Aug 2020
00092 1   PA_9 D1     LocalCom Tx
00093 2   PA_10 D0    LocalCom Rx GPS maybe
00094 3   NRST        
00095 4   GND     
00096 5   PA12_D2     InterruptIn VEXT PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
00097 6   PB_0 D3     AnalogIn Field supply voltage
00098 7   PB_7 D4     SDA i2c to 24LC memory
00099 8   PB_6 D5     SCL i2c to 24LC memory
00100 9   PB_12 D6    DigitalOut  CHARGE_PUMP new Aug 2020
00101 10  N.C.        
00102 11  N.C.        
00103 12  PA_8 D9     InterruptIn pulse_tacho from engine magneto, used to measure rpm
00104 13  PA_11 D10   Servo
00105 14  PB_5 D11    NEW June 2019 - Output engine tacho cleaned-up, brought out to testpoint 4 NOT REALLY USEFUL
00106 15  PB_4 D12    Scope_probe NOT REALLY USEFUL
00107 16  PB_3 D13    LED    Onboard LED
00108 17  3V3         
00109 18  AREF        
00110 19  PA_0 A0     AnalogIn    Driver Pot
00111 20  PA_1 A1     AnalogIn    Ammeter_In
00112 21  PA_3 A2     PwmOut      PWM_OSC_IN Timebase for pwm, also determines max duty ratio
00113 //22  PA_4 A3     AnalogOut   A_OUT control signal to following traction motor ESC
00114 22  PA_4 A3     AnalogOut   REF_VAR reference voltage to MCP1630, allows software to set alternator output voltage
00115 23  PA_5 A4     AnalogOut   A_OUT control signal to following traction motor ESC
00116 24  PA_6 A5     Spare
00117 25  PA_7 A6     AnalogIn    V_Sample system link voltage
00118 26  PA_2 A7     Not useable, taken by uart
00119 27  5V          
00120 28  NRST        
00121 29  GND         
00122 30  VIN         
00123 */
00124 
00125 //  Test 6/6/2020 to get i2c working
00126 //I2C i2c                     (D0, D1);   //  For 24LC64 eeprom correct
00127 //I2C i2c                     (D1, D0);   //  For 24LC64 eeprom DEFINITELY WRONG
00128 //  Test 6/6/2020 to get i2c working
00129 
00130 //InterruptIn pulse_tacho     (D9);  //  Signal from engine magneto (clipped by I limit resistor and 3v3 zener)
00131 //                      Note D9 still used but taken to rpm class object
00132 //InterruptIn VEXT            (D2);     //  PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
00133 //                      Note D2 still used but taken to field class object
00134 //  OUTPUTS :
00135 AnalogOut   REF_VAR (A4);    //  Variable REF to MCP1630 enables software control of output voltage - NEW Aug 2020
00136 AnalogOut   A_OUT   (A3);    //  Control voltage out to traction motor ESCs
00137 DigitalOut  Scope_probe     (D12);   //  Handy pin to hang scope probe onto while developing code
00138 DigitalOut  myled           (LED1);        //  Green LED on board is PB_3 D13
00139 //PwmOut      PWM_OSC_IN      (A2);   //  Can alter prescaler can not use A5    NOW DONE IN CLASS
00140 //PwmOut      A_OUT           (A2);   //  Can alter prescaler can not use A5    PIN STOLEN BY PWM_OSC_IN
00141 
00142 //PwmOut      Test_RPM    (PA_6);
00143 Timer   microsecs;      //  64 bit counter, rolls over in half million years
00144 Ticker  loop_timer;     //  Device to cause periodic interrupts, used to sync iterations of main programme loop - slow
00145 
00146 extern  char *  get_mode_text   (uint32_t mode)  ;
00147 
00148 DigitalOut  CHARGE_PUMP (D6);
00149 I2CEeprom       eeprom  (SDA_PIN, SCL_PIN, 0xa0, eeprom_page_size, 8192, 100000);
00150 extern  ee_settings_2020 user_settings  ;
00151 Engine_Manager  Engine  (D9, D11, D10); //  Pins are magneto in, cleaned magneto out, servo
00152 FieldControl    Field   (A2, D2);       //  PWM pin for MCP1630 PWM_OSC_IN, InterruptIn for signal out of MCP1630 VEXTFB
00153 PCT2075         temp_sensor( SDA_PIN, SCL_PIN );    //  or LM75B temp_sensor( p?, p? );  Added March 2020
00154 
00155 //class   MPL3115A2   baro    ;
00156 
00157 //  SYSTEM CONSTANTS
00158 /*  Please Do Not Alter these */
00159 const   int     MAIN_LOOP_REPEAT_TIME_US    = 10000;    //  10000 us, with TACHO_TAB_SIZE = 100 means tacho_ticks_per_time is tacho_ticks_per_second
00160 /*  End of Please Do Not Alter these */
00161 /*  Global variable declarations */
00162 uint32_t    sys_timer100Hz      = 0;    //  gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US
00163 uint32_t    seconds = 0;
00164 double      link_volt_reading        = 0.0;    //  Global updated by interrupt driven read of Battery Volts at rate of 100 Hz
00165 double      field_volt_reading       = 0.0;    //  Global updated by interrupt driven read of Battery Volts at rate of 100 Hz
00166 double      amp_reading = 0.0;
00167 bool        loop_flag   = false;    //  made true in ISR_loop_timer, picked up and made false again in main programme loop
00168 bool        flag_25Hz   = false;    //  As loop_flag but repeats 25 times per sec
00169 bool        flag_12Hz5  = false;    //  As loop_flag but repeats 12.5 times per sec
00170 bool        flag_1Hz    = false;    //  As loop_flag but repeats 1 times per sec
00171 bool        query_toggle    = false;
00172 
00173 bool        flag_link_V_rd  = false;
00174 bool        flag_field_V_rd = false;
00175 bool        flag_A_rd   = false;
00176 bool        flag_Pot_rd = false;
00177 
00178 bool        auto_test_flag  = false;
00179 
00180 bool        charge_pump_enable = true;
00181 
00182 enum    {SAFE_NOTHING, POT_SERVO_DIRECT, VARIABLE_VOLTAGE, FIXED_VOLTAGE, ENG_REVS_CTRL, POT_SETS_ENGINE_RPM, CURRENT_FEEDBACK_CTRL, AUTO_TEST}  ;
00183 /*  End of Global variable declarations */
00184 
00185 //void    ISR_fast_interrupt  ()  {   //  here at 10 times main loop repeat rate (i.e. 1000Hz, 1.0ms)
00186 void    ISR_fast_interrupt  ()  {
00187     static  uint32_t t = 0, u25 = 0;
00188     Scope_probe = 1;    //  To show how much time spent in interrupt handler
00189     if  (charge_pump_enable)
00190         CHARGE_PUMP = !CHARGE_PUMP;
00191     switch  (t) {
00192         case    0:      //  Alternator output voltage
00193             flag_link_V_rd = true;
00194             break;
00195         case    1:      //  Ammeter
00196             flag_A_rd = true;
00197             break;
00198         case    2:      //  Driver's Pot
00199             flag_Pot_rd = true;
00200             break;
00201         case    3:      //  Field supply voltage
00202             flag_field_V_rd = true;
00203             break;
00204 //        case    4:
00205 //            driver_reading  >>= 1;                                 //  Result = Result / 2
00206 //            driver_reading  += Driver_Pot.read_u16();
00207 //            break;
00208         case    5:
00209             loop_flag = true;   //  set flag to allow main programme loop to proceed
00210             sys_timer100Hz++;        //  Just a handy measure of elapsed time for anything to use
00211             if  ((sys_timer100Hz & 0x03) == 0)  {  //  is now 12.5Hz, not 8
00212                 flag_25Hz  = true; //  flag gets set 25 times per sec. Other code may clear flag and make use of this
00213                 u25++;
00214                 if  (u25 == 25) {
00215                     u25 = 0;
00216                     flag_1Hz = true;
00217                     seconds++;
00218                 }
00219             }
00220         default:
00221             break;
00222     }
00223     t++;
00224     if  (t > 9)
00225         t = 0;
00226     Scope_probe = 0;    //  To show how much time spent in interrupt handler
00227 }
00228 
00229 //  ****    End of Interrupt Service Routines   ****
00230 
00231 /*double  Read_Ext_Rev_Req    ()
00232 {
00233     double  rv = (double) ext_rev_req;
00234     return  rv / 4096.0;
00235 }*/
00236 /*
00237 double  Read_Driver_Pot    ()
00238 {
00239     double  rv = (double) driver_reading;
00240     return  rv / 4096.0;
00241 }*/
00242 
00243 double  Read_Link_Volts   ()
00244 {
00245     return  link_volt_reading * 39.9;    //  divisor fiddled to make voltage reading correct !
00246 }
00247 
00248 double  Read_Field_Volts   ()
00249 {
00250 //    return  field_volt_reading * 42.85;    //  divisor fiddled to make voltage reading correct !
00251     return  field_volt_reading * 40.12;    //  divisor fiddled to make voltage reading correct !
00252 }
00253 
00254 double  Read_Ammeter    ()
00255 {
00256     return  amp_reading * 93.28; //  Amp range corrected here
00257 }
00258 
00259 
00260 void    query_system    (parameters & a)    {
00261     query_toggle = !query_toggle;
00262 }
00263 
00264 void    set_v_out_opamp    (double a) {   //  0 to 1.0 sets opamp output in range 0 to 5v, charge pump permitting
00265     A_OUT = a;
00266 }
00267 void    set_v_out_opamp    (parameters & a) {   //  0 to 1.0 sets opamp output in range 0 to 5v, charge pump permitting
00268     A_OUT = a.dbl[0] / 100.0;
00269 }
00270 
00271 void    charge_pump_override    (int a) {   //  0 disables, !0 enables charge pump
00272     if  (a == 0)
00273         charge_pump_enable = false;
00274     else
00275         charge_pump_enable = true;
00276 }
00277 void    charge_pump_override    (parameters & a) {   //  0 disables, !0 enables charge pump
00278     charge_pump_override    ((int)a.dbl[0]);
00279 }
00280 
00281 void    set_pwm (double d)   {    //  Range 0.0 to 1.0  called from cli
00282     Field.set_pwm   (d);
00283 }
00284 
00285 double  get_temperature ()  {
00286     return  (double) temp_sensor;
00287 }
00288 
00289 void    maketable   ()  {
00290     Field.maketable ();
00291 }
00292 
00293 int32_t set_engine_RPM_lit  (uint32_t   RPMrequest) {   //  Returns actual speed
00294     return  Engine.set_RPM_literal  (RPMrequest);
00295 }
00296 
00297 int32_t set_engine_RPM_pct  (uint32_t   RPMrequest) {   //  Returns actual speed
00298     return  Engine.set_RPM_percent  (RPMrequest);
00299 }
00300 
00301 void    auto_test_initiate  (int bulb_count)  {
00302     if  (Engine.running())  {
00303         auto_test_flag = true;
00304         pc.printf   ("Requesting Auto-Test for load of %d lamps\r\n", bulb_count);
00305     }
00306     else    {
00307         pc.printf   ("Engine not running. Can't perform auto test\r\n");
00308         auto_test_flag = false;
00309     }
00310 }
00311 
00312 void    is_eng_running  ()  {
00313     pc.printf   ("Engine%sRunning\r\n", Engine.running() ? " IS " : " NOT ");
00314 }
00315 
00316 extern  void    command_line_interpreter    ()  ;   //  Comms with optional pc or device using serial port through board USB socket
00317 
00318 enum    {AUTO_TEST_INACTIVE, AUTO_TEST_BEGIN, AUTO_TEST_ABORT, AUTO_TEST_IN_PROGRESS    }   ;
00319 
00320 //  Programme Entry Point
00321 int main()
00322 {
00323     const   double PI   = (2.0 * acos(0.0));
00324     const   double  filt = 0.2;
00325     const   double  ampfilt = 0.2;
00326     const   double  vfilt = 0.2;
00327     //  local variable declarations
00328     double  driver_pot = 0.0, dtmp;
00329 //    double  theta = 0.0;
00330     int32_t temp, startup_delay, print_position = 0;
00331     int32_t field_pct = 0, auto_test_timer = 0, auto_test_state = AUTO_TEST_INACTIVE, auto_test_step = 0;
00332     bool    up_and_running = false;
00333     char    text[64];
00334     
00335     A_OUT = 0.0;
00336     REF_VAR = 0.0;
00337     microsecs.reset()   ;   //  timer = 0
00338     microsecs.start ()  ;   //  64 bit, counts micro seconds and times out in half million years
00339 
00340 #ifdef GPS_
00341     gps_mod gps;
00342 #endif
00343 //- Clear the screen, move to (0,0):
00344 //  \033[2J
00345     pc.printf   ("\033[2JAlternator Regulator 2020, Jon Freeman\r\n");
00346     user_settings.load   ()  ;   //  Fetch values from eeprom
00347     //  Setup Complete ! Can now start main control forever loop.
00348     loop_timer.attach_us    (&ISR_fast_interrupt, MAIN_LOOP_REPEAT_TIME_US / 10);    //  Start periodic interrupt generator 1000us at Feb 2020
00349 
00350     Field.maketable ()  ;   //  Here to ensure eeprom has been setup
00351     Field.set_for_speed (0);
00352     Engine.Set_Speed_Lever (((double)user_settings.rd(WARMUP_SERVO_POS)) / 100.0);
00353     startup_delay = user_settings.rd(WARM_UP_DELAY);
00354     pc.printf   ("Operating Mode is [%s]\r\n", get_mode_text    (user_settings.rd(OP_MODE)));
00355 
00356 
00357 //***** START OF MAIN LOOP
00358     while   (1) {      //  Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
00359         while   (!loop_flag)  {         //  Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
00360 #ifdef  GPS_
00361 //            while   (gps_module.readable())
00362 //                pc.putc (gps_module.getc());
00363 #endif
00364             command_line_interpreter    ()  ;   //  Proceed beyond here once loop_timer ticker ISR has set loop_flag true
00365             //  A to D converters all read at 100 Hz
00366             if  (flag_link_V_rd) {          //  Reads main alternator output and/or traction battery voltage
00367                 flag_link_V_rd = false;
00368                 link_volt_reading    *= (1.0 - vfilt);                                 //
00369                 link_volt_reading    += vfilt * (double) Ain_Link_Volts.read();     //  Volt fiddle factor NOT corrected here
00370             }
00371             if  (flag_Pot_rd)   {           //  Reads Driver's speed control potentiometer
00372                 flag_Pot_rd = false;
00373                 driver_pot *= (1.0 - filt);
00374                 driver_pot += filt * ((double)Driver_Pot.read() * 1.5);     //  Includes bodge around zener over-clipping input
00375             }
00376             if  (flag_A_rd) {               //  Reads ammeter - user wires this to suit their purpose
00377                 flag_A_rd = false;
00378                 amp_reading *= (1.0 - ampfilt);
00379                 amp_reading += ampfilt * ((double) Ammeter_In.read() - 0.495); //  Amp range NOT corrected here BUT OFFSET IS
00380             }
00381             if  (flag_field_V_rd) {         //  Reads 'Field Positive' supply - from battery via diode, also alternator rectifier out
00382                 flag_field_V_rd = false;
00383                 field_volt_reading    *= (1.0 - vfilt);                                 //
00384                 field_volt_reading    += vfilt * (double) Field_Supply_V.read();     //  Volt fiddle factor NOT corrected here
00385             }
00386         }               //  Jun 2019 pass here 100 times per sec
00387 //  BEGIN 100Hz stuff
00388         loop_flag = false;          //  Clear flag set by ticker interrupt handler
00389         Engine.manager_core   ();   //  This belongs right here, update regularly, keeps 'filtered()' fresh and keeps engine to set rpm
00390 #ifdef GPS_
00391         gps.update  ();
00392 #endif
00393 /*        theta += 0.05;
00394         if  (theta > PI)
00395             theta -= 2.0 * PI;
00396         sinout = 0.5 + sin(theta) / 2.0;
00397         cosout = 0.5 + cos(theta) / 2.0;
00398 */
00399 //  END 100Hz stuff
00400         if  (flag_25Hz)  {
00401             flag_25Hz = false;
00402 //  BEGIN   25Hz stuff
00403 
00404 //  END 25Hz stuff
00405 //  BEGIN   12.5Hz stuff
00406             flag_12Hz5 = !flag_12Hz5;
00407             if  (flag_12Hz5)  {   //  Do any even stuff to be done 12.5 times per second
00408 //                if  (up_and_running && Engine.running())  {
00409                 if  (up_and_running)  {
00410                     switch  (user_settings.rd(OP_MODE))  {
00411 /*
00412 enum    {SAFE_NOTHING,          //  
00413         POT_SERVO_DIRECT,       //  
00414         VARIABLE_VOLTAGE,       //  Batteryless, controllerless Low Cost Loco - alternator connects direct to DC motors
00415         FIXED_VOLTAGE,          //  
00416         ENG_REVS_CTRL,          //  
00417         POT_SETS_ENGINE_RPM,    //  
00418         CURRENT_FEEDBACK_CTRL,  //  
00419         AUTO_TEST            }; //  
00420     "0\tSafe nothing mode for cli cmd testing",
00421     "1\tPot to Servo direct, field OFF",
00422     "2\tVariable voltage",
00423     "3\tFixed voltage",
00424     "4\tEngine Revs Control",
00425     "5\tSet Engine to Driver's Pot",
00426     "6\tControl Engine by Current Load",
00427 */
00428                         case    SAFE_NOTHING:           //  Safe nothing mode for cli cmd testing
00429                                     //  Use this to test command line commands e.g. Set_Speed_Lever, direct field setting etc
00430                             break;
00431 
00432                         case    POT_SERVO_DIRECT:       //  Driver_pot --> servo direct.  Field OFF
00433 //                            Engine.Set_Speed_Lever    (driver_pot);
00434                             Engine.Set_Speed_Lever  (driver_pot);
00435                             REF_VAR = driver_pot;
00436 //                            Field.set_for_speed   (0);     //  Safe, no output
00437                             Field.set_for_speed   (3000);     //  Safe, no output
00438                             break;
00439 
00440                         case    VARIABLE_VOLTAGE:                          //  Variable Voltage
00441                             Engine.Set_Speed_Lever    (driver_pot);   //  Driver_pot --> servo direct.  Field ON
00442                             if  (driver_pot > DRIVER_NEUTRAL)   // if pot not close to zero
00443                                 Field.set_for_speed   (Engine.RPM_latest());     //  according to RPM
00444                             else
00445                                 Field.set_for_speed   (0);     //  Field OFF
00446                             break;
00447 
00448                         case    FIXED_VOLTAGE:          //  Fixed Voltage
00449                             Field.set_for_speed   (Engine.RPM_latest());     //  according to RPM
00450                             break;
00451 
00452                         case    ENG_REVS_CTRL:          //  Engine revs control - Pot to control revs over range tickover to MAX_RPM_LIMIT
00453                             Field.set_for_speed (Engine.RPM_latest());
00454                             break;
00455 
00456                         case    POT_SETS_ENGINE_RPM:    //  Set engine to driver pot
00457                             dtmp = driver_pot * (MAX_RPM_LIMIT - TICKOVER_RPM) + TICKOVER_RPM;
00458                             temp = (int32_t) dtmp;
00459                             Engine.set_RPM_literal  (temp);    //  this sets engine speed controller
00460                             Field.set_for_speed   (Engine.RPM_latest());     //  according to RPM
00461                             break;
00462 
00463 //                        case    CURRENT_MODE:  //  Set engine speed determined by current drawn
00464                         case    CURRENT_FEEDBACK_CTRL:  //  Set engine speed determined by current drawn
00465                             temp = 0;   //  an integer.  Engine set to tickover when no power demand
00466                             if  (driver_pot > DRIVER_NEUTRAL)   // if pot not close to zero
00467                                 temp = 1 + (int32_t)abs(Read_Ammeter() * 8.0); //  Sets max amps to 100 / 8.0
00468                             Engine.set_RPM_percent  (temp);    //  this sets engine speed controller
00469                             Field.set_for_speed (Engine.RPM_latest());    //  according to RPM
00470                             break;
00471 
00472                         case    AUTO_TEST:  //  cli command may initiate test sequence implemented here.  Wait for flag to proceed.
00473                             switch  (auto_test_state)   {
00474                                 case    AUTO_TEST_INACTIVE:
00475                                     if  (auto_test_flag)    //  cli has requested auto test sequence
00476                                         auto_test_state = AUTO_TEST_BEGIN;
00477                                     break;
00478 
00479                                 case    AUTO_TEST_BEGIN:    //  set engine, field etc, then initiate settling time delay
00480                                     Engine.set_RPM_percent  (1);    //  this sets engine speed controller for min useful revs
00481                                     Field.set_for_speed (0);
00482                                     pc.printf   ("Starting auto test sequence, user field limit values :\r\n");
00483                                     for (int i = 0; i < 21; i++)
00484                                         pc.printf   ("%d, ", user_settings.rd(i));
00485                                     pc.printf   ("\r\n");
00486                                     auto_test_step  = 0;
00487                                     auto_test_timer = 0;
00488                                     auto_test_state = AUTO_TEST_IN_PROGRESS;
00489                                     break;
00490 
00491                                 case    AUTO_TEST_IN_PROGRESS:  //  take sets of readings, then timeout back to INACTIVE
00492                                     field_pct = Field.set_for_speed (Engine.RPM_latest());    //  according to RPM
00493                                     switch  (auto_test_timer++) {   //  When active, get here @ 12.5Hz
00494                                         case    30: case    40: case    50: case    60:  //  take readings at these times
00495                                         case    35: case    45: case    55: case    65:
00496 //                                            pc.printf   ("\tTaking auto_test readings %d, Volts, Amps, RPM req, RPM got, servo position, measured duty ratio\r\n", auto_test_timer);
00497                                             /*
00498                                             Need to collect here,
00499                                             Volts, Amps, RPM got latest, RPM got filtered, servo position, measured duty ratio, lut pcent
00500                                             */
00501                                             pc.printf   ("\t%.2f, %.2f, %.2f, %d, %d, %.2f, %.3f, %d\r\n", Read_Link_Volts(), Read_Field_Volts(), 
00502                                                                 Read_Ammeter(), Engine.RPM_latest(), Engine.RPM_filtered(),
00503                                                                 Engine.get_servo_position(), Field.get_duty_ratio(), field_pct);
00504                                             break;
00505                                         case    66:     //  After final set of readings
00506                                             auto_test_step++;
00507                                             if  (auto_test_step > 10)
00508                                                 auto_test_state = AUTO_TEST_ABORT;
00509                                             else    {   //  set conditions for next set of readings
00510                                                 temp = Engine.RPM_percent_to_actual(auto_test_step * 10);
00511                                                 Engine.set_RPM_percent  (auto_test_step * 10);
00512                                                 auto_test_timer = 0;
00513                                                 pc.printf   ("Setting rig for %d percent, %d RPM\r\n", auto_test_step * 10, temp);
00514                                             }
00515                                             break;
00516                                         default:
00517                                             break;
00518                                     }
00519                                     break;
00520 
00521                                 case    AUTO_TEST_ABORT:    //  Here at test end or because auto_test_flag made false somewhere somehow
00522                                     Engine.set_RPM_percent  (0);    //  this sets engine speed controller
00523                                     Field.set_for_speed (0);
00524                                     auto_test_state = AUTO_TEST_INACTIVE;
00525                                     auto_test_flag = false;
00526                                     pc.printf   ("Ending auto test sequence\r\n");
00527                                     break;
00528                                 default:
00529                                     break;
00530                             }   //  END OF SWITCH auto_test_state
00531                             break;
00532                         default:
00533                             user_settings.wr    (0, OP_MODE); //  set to safe non-mode 0
00534                             break;
00535                     }
00536                 }
00537                 else    {   //  Engine not running
00538                     Field.set_for_speed   (0);     //  according to RPM
00539                 }
00540             }
00541             else    {               //  Do odd 12.5 times per sec stuff
00542                 flag_12Hz5  = false;
00543                 myled = !myled;
00544             }   //  End of if(flag_12Hz5)
00545 //  END 12.5Hz stuff
00546             if  (flag_1Hz)  {
00547 //  BEGIN   1Hz stuff
00548                 flag_1Hz = false;
00549                 if  (!up_and_running)   {
00550                     if  (startup_delay == 0)    {
00551                         up_and_running = true;
00552                         pc.printf   ("Warmup ended, starting proper ops\r\n");
00553                         Engine.Set_Speed_Lever (0.0);
00554                     }
00555                     else    {
00556                         pc.printf   ("In Startup warmup delay %d\r", startup_delay--);
00557                     }
00558                 }
00559                 if  (query_toggle)  {
00560                     sprintf (text, "\033[%d;0HI=%.1fA, V=%.2fV, ", 20 + print_position, Read_Ammeter() , Read_Link_Volts());
00561                     pc.printf   ("%sRPM %d, rpm_set %d, pot %.3f, servo %.3f  \r\n", text, Engine.RPM_latest(), Engine.get_RPM_requested (), driver_pot, Engine.get_servo_position());
00562                     print_position++;
00563                     if  (print_position > 10)
00564                         print_position = 0;
00565                 }
00566 //printf("\033[6;3HHello\n");
00567 //                pc.printf   ("\033[0;1HSecs %d  \r\n", seconds);
00568 //                pc.printf   ("Temp = %.1f\r", get_temperature());
00569 //            gps.update();
00570 #ifdef GPS_
00571             if  (gps.new_data())    {
00572                 myled = !myled;
00573                 pc.printf("\033[0;1H%s, %s, %s      \r\n", gps.time(), gps.latitude(), gps.longitude());
00574                 pc.printf("alt ^%s^, sats %s lat mer %f, lon mer %f     \r\n", gps.altitude(), gps.sat_count(), gps.lat_merged(), gps.lon_merged());
00575                 pc.printf("%s, heading %s, mph %s      \r\n", gps.date(), gps.heading(), gps.mph());
00576                 pc.printf("%s\r\n   \n   .\r\n   ", gps.message(1));
00577             }
00578 #endif
00579 //            while   (gps_module.readable())
00580 //                pc.putc (gps_module.getc());
00581 //  END 1Hz stuff
00582             }   //  eo once per second stuff
00583         }   //  End of 100Hz stuff
00584     }       //  End of main programme loop
00585 }           //  End of main function - end of programme
00586