Charles Young's development fork. Going forward I only want to push mature code to main repository.

Dependencies:   mbed

Fork of GEO_COUNTER_L432KC by Geo Electronics "Geo Counter"

Committer:
Charles David Young
Date:
Sat Sep 08 21:37:35 2018 -0700
Revision:
60:6ae1a2390600
Parent:
59:f96a503bd228
Child:
61:00601fb0a3b9
debug

Who changed what in which revision?

UserRevisionLine numberNew contents of line
walter76 2:ac0ed3d84d44 1 // GEO COUNTER V1 firmware
walter76 2:ac0ed3d84d44 2 // This FW provides a basic operation of GEO-COUNTER
walter76 2:ac0ed3d84d44 3 //
walter76 2:ac0ed3d84d44 4 // Latest review: August 27, 2018 - Walter Trovo
walter76 1:75827d765e34 5 //
Charles David Young 47:f004b4612069 6 // Sep 6, 2018: Charles Young: Functioning mode selection - modes partially implemented
Charles David Young 25:0161bf1adc81 7 // Sep 5, 2018: Charles Young: Created LED7segDisplay class
charlesdavidyoung 24:db7494389c03 8 // Sep 5, 2018: Charles Young: Still developing mode selection. LEDs turn off
charlesdavidyoung 24:db7494389c03 9 // when not in mode selection. Pressing once enters mode selection.
charlesdavidyoung 24:db7494389c03 10 // Pressing again enters submode. Temporarily the rotary switch
charlesdavidyoung 24:db7494389c03 11 // adjusts the display brightness. This is just for testing.
charlesdavidyoung 24:db7494389c03 12 // Sep 4, 2018: Charles Young: Created RotarySwitch class to manage mode selection
walter76 1:75827d765e34 13 // Feb 14, 2018: initial release aimed to test the counters, the serial port
walter76 1:75827d765e34 14 // the PWM output and the MAX7219 operation.
walter76 1:75827d765e34 15 // Feb 15, 2018: Removed MAX7219 libray (replaced with custom routine).
walter76 1:75827d765e34 16 // Added 74HC595 routine. Added beep. Added Gate_write
walter76 1:75827d765e34 17 //
walter76 2:ac0ed3d84d44 18
walter76 1:75827d765e34 19
walter76 1:75827d765e34 20 // this block includes key libraries
walter76 1:75827d765e34 21 #include <string> // strings management
charlesdavidyoung 24:db7494389c03 22 #include "RotarySwitch.hpp"
Charles David Young 25:0161bf1adc81 23 #include "LED7segDisplay.hpp"
charlesdavidyoung 20:fb73eaaf0894 24
charlesdavidyoung 24:db7494389c03 25 // Everything associated with the rotary switch and the associated LEDs
charlesdavidyoung 24:db7494389c03 26 // is hidden in this class.
charlesdavidyoung 20:fb73eaaf0894 27 RotarySwitch ModeSwitch;
Charles David Young 25:0161bf1adc81 28 LED7segDisplay DigitsDisplay;
walter76 1:75827d765e34 29
Charles David Young 34:10550b327e3d 30 enum Modes {
Charles David Young 34:10550b327e3d 31 CNT1,
Charles David Young 34:10550b327e3d 32 CNT2,
Charles David Young 34:10550b327e3d 33 PROSPECT,
Charles David Young 34:10550b327e3d 34 NULL1,
Charles David Young 37:6f7bb913e08b 35 NULL2,
Charles David Young 38:1642320d83a0 36 VOLTS,
Charles David Young 38:1642320d83a0 37 VOLUME,
Charles David Young 34:10550b327e3d 38 DIM,
Charles David Young 34:10550b327e3d 39 NumberOfModes
Charles David Young 34:10550b327e3d 40 };
Charles David Young 38:1642320d83a0 41 uint8_t currentMode = CNT1;
Charles David Young 38:1642320d83a0 42 uint8_t currentModeToDisplay = CNT1;
Charles David Young 34:10550b327e3d 43
charlesdavidyoung 5:4f90b458dbdf 44 // LED on processor board
charlesdavidyoung 5:4f90b458dbdf 45 DigitalOut led1(LED1);
walter76 1:75827d765e34 46
walter76 1:75827d765e34 47 // definitions of peripherals and devices
Charles David Young 7:9f975e00600c 48
charlesdavidyoung 17:6eed17197004 49 I2C i2c(D4, D5); // I2C port
charlesdavidyoung 17:6eed17197004 50 Ticker SecTenth_Beat; // .1 second ticker
walter76 1:75827d765e34 51 Ticker Sec_Beat; // 1 second ticker
walter76 1:75827d765e34 52 Serial PC(USBTX, USBRX); // Virtual COM via USB (PC connection)
walter76 1:75827d765e34 53 Serial GPS(D1, D0); // Serial port for GPS module
walter76 0:6d1742703713 54
walter76 0:6d1742703713 55 // Global variables
walter76 1:75827d765e34 56 time_t seconds; // Real-Time Clock (RTC) timestamp
walter76 1:75827d765e34 57 unsigned int value = 0; // displayed value on the 6-digits of the display
Charles David Young 44:a26ca542ae5e 58
walter76 1:75827d765e34 59 uint32_t Count1, Count2; // pulse counters (32-bit)
Charles David Young 46:c7ce8fccb712 60 int32_t TickerCorrection = 0;
Charles David Young 58:d15adb224e5a 61 uint32_t TickerPeriod = 100000;
Charles David Young 53:04999d536e92 62 uint32_t TickerPeriodCount = 0;
Charles David Young 53:04999d536e92 63 const uint32_t TickerPeriodsPerSecond = 1000000/TickerPeriod;
Charles David Young 44:a26ca542ae5e 64 const int16_t TickerCorrectionMax = 99;
Charles David Young 44:a26ca542ae5e 65 const int16_t TickerCorrectionMin = -99;
Charles David Young 44:a26ca542ae5e 66
walter76 1:75827d765e34 67 char Text[40]=""; // used to send messages over the serial port
walter76 1:75827d765e34 68 uint8_t Disp_mode = 0x01, Disp_unit = 0xA0; // status of 1st row and 2nd rows of LEDs
kd5byb 4:b17c6556cf1f 69 bool Stopped = 0; // status of counting activity
charlesdavidyoung 5:4f90b458dbdf 70 bool StartStopPressed = 0;// status of counting activity
walter76 1:75827d765e34 71 double ADC_val; // used to read ADC value
charlesdavidyoung 24:db7494389c03 72 float direction = 0;
walter76 0:6d1742703713 73
Charles David Young 38:1642320d83a0 74 #define maxVolume 10
Charles David Young 38:1642320d83a0 75 uint8_t volume = maxVolume;
Charles David Young 38:1642320d83a0 76
walter76 1:75827d765e34 77 // ----- Prototypes of routines (defined below the main) -------------------
Charles David Young 16:b2e77eb76ab4 78 void UpdateInput(void); // periodically called by the ticker
Charles David Young 16:b2e77eb76ab4 79 void UpdateOutput(void); // periodically called by the ticker
Charles David Young 53:04999d536e92 80 void UpdateIO(void); // periodically called by the ticker
walter76 1:75827d765e34 81 void Count1_up(void); // called every time an edge is detected on TRIG1 pin
walter76 1:75827d765e34 82 void Count2_up(void); // called every time an edge is detected on TRIG2 pin
walter76 1:75827d765e34 83 void Beep(void); // used to generate a short beep (buzzer)
walter76 0:6d1742703713 84
walter76 0:6d1742703713 85 //==============================================================================
walter76 0:6d1742703713 86 //==============================================================================
walter76 0:6d1742703713 87
walter76 0:6d1742703713 88 int main()
walter76 0:6d1742703713 89 {
walter76 0:6d1742703713 90
Charles David Young 28:c81d00ec28a3 91 PC.baud(115200); // set baud-rate of virtual COM port (PC connection)
Charles David Young 28:c81d00ec28a3 92 PC.printf("\nGEO COUNTER V1 2108");
Charles David Young 28:c81d00ec28a3 93 PC.printf(__DATE__);
Charles David Young 28:c81d00ec28a3 94 PC.printf(" ");
Charles David Young 28:c81d00ec28a3 95 PC.printf(__TIME__);
walter76 1:75827d765e34 96
Charles David Young 28:c81d00ec28a3 97 GPS.baud(9600); // set the baud-rate of the serial port dedicated to the GPS
walter76 0:6d1742703713 98
Charles David Young 28:c81d00ec28a3 99 CS1 = 1; // presets CS of MAX7219
Charles David Young 28:c81d00ec28a3 100 CS2 = 1; // preset CS of 74HC595
walter76 1:75827d765e34 101
Charles David Young 28:c81d00ec28a3 102 DigitsDisplay.Display_6D_write(0x543210);
Charles David Young 28:c81d00ec28a3 103 DigitsDisplay.Display_2D_write(0);
walter76 0:6d1742703713 104
Charles David Young 28:c81d00ec28a3 105 // RTC is supposed to be loose time at power down (no backup battery)
Charles David Young 28:c81d00ec28a3 106 // An initialization is performed anyway
Charles David Young 28:c81d00ec28a3 107 set_time(0); // Set time
charlesdavidyoung 24:db7494389c03 108
Charles David Young 28:c81d00ec28a3 109 PWM.period_ms(3); // set the PWM period
Charles David Young 28:c81d00ec28a3 110 PWM.write(0.8); // set the PWM duty-cycle
walter76 1:75827d765e34 111
Charles David Young 28:c81d00ec28a3 112 Beep(); // initial beep
walter76 1:75827d765e34 113
Charles David Young 28:c81d00ec28a3 114 // set the 1 sec ticker to periodically call the Update() routine
Charles David Young 28:c81d00ec28a3 115 // NOTE: this is also the 1-sec time base for counters. A better approach
Charles David Young 28:c81d00ec28a3 116 // would replace the ticker with an interrupt from the RTC (to be implemented)
Charles David Young 53:04999d536e92 117 SecTenth_Beat.attach_us(&UpdateIO, TickerPeriod);
Charles David Young 28:c81d00ec28a3 118 //RTC::attach(&Update, RTC::Second);
Charles David Young 28:c81d00ec28a3 119 //RTC::detach(RTC::Second);
walter76 1:75827d765e34 120
Charles David Young 60:6ae1a2390600 121 TRIG1.rise(&Count1_up);
Charles David Young 60:6ae1a2390600 122 TRIG2.rise(&Count2_up);
Charles David Young 60:6ae1a2390600 123
Charles David Young 28:c81d00ec28a3 124 // main loop does nothing as all activities are interrupt driven
Charles David Young 28:c81d00ec28a3 125 while(1)
Charles David Young 28:c81d00ec28a3 126 {
Charles David Young 28:c81d00ec28a3 127 // dance (or drink a beer)
Charles David Young 28:c81d00ec28a3 128 }
walter76 0:6d1742703713 129 }
walter76 0:6d1742703713 130
walter76 0:6d1742703713 131
walter76 1:75827d765e34 132 //-------- END OF MAIN --------------
walter76 0:6d1742703713 133 //==============================================================================
walter76 0:6d1742703713 134
walter76 1:75827d765e34 135 // Definition of routines
walter76 1:75827d765e34 136
walter76 1:75827d765e34 137 //---------------------------------------------------------------------------
walter76 1:75827d765e34 138 // Update values to be displayed
Charles David Young 10:f48cc6be5ae8 139 void logToPC()
Charles David Young 10:f48cc6be5ae8 140 {
Charles David Young 10:f48cc6be5ae8 141 PC.printf("\nADC: %.02f", ADC_val);
Charles David Young 10:f48cc6be5ae8 142 PC.printf(Stopped ? " stopped" : " started");
Charles David Young 10:f48cc6be5ae8 143 // Timestamp to PC (debug)
Charles David Young 10:f48cc6be5ae8 144 seconds = time(NULL); // get current time
Charles David Young 10:f48cc6be5ae8 145 strftime(Text, 50, "%H:%M:%S", localtime(&seconds));
Charles David Young 10:f48cc6be5ae8 146 PC.printf(" RTC: %s, CNT1: %7d CNT2: %7d",Text, Count1, Count2);
charlesdavidyoung 24:db7494389c03 147 PC.printf(" wheel %f", direction);
Charles David Young 10:f48cc6be5ae8 148 }
walter76 1:75827d765e34 149
Charles David Young 53:04999d536e92 150 void UpdateIO()
Charles David Young 53:04999d536e92 151 {
Charles David Young 53:04999d536e92 152 if (++TickerPeriodCount >= TickerPeriodsPerSecond)
Charles David Young 53:04999d536e92 153 {
Charles David Young 53:04999d536e92 154 TickerPeriodCount = 0;
Charles David Young 53:04999d536e92 155 UpdateOutput();
Charles David Young 53:04999d536e92 156 }
Charles David Young 53:04999d536e92 157 UpdateInput();
Charles David Young 53:04999d536e92 158 }
Charles David Young 53:04999d536e92 159
Charles David Young 53:04999d536e92 160 void UpdateOutput()
charlesdavidyoung 18:ef5678ab1889 161 {
Charles David Young 49:a67f2a3d228a 162 // Capture the counts early so they will be more accurate
Charles David Young 49:a67f2a3d228a 163 uint32_t Count1Save = Count1;
Charles David Young 49:a67f2a3d228a 164 uint32_t Count2Save = Count2;
Charles David Young 50:19ab5315e2b4 165 Count1 = 0;
Charles David Young 50:19ab5315e2b4 166 Count2 = 0;
Charles David Young 49:a67f2a3d228a 167
Charles David Young 49:a67f2a3d228a 168 if(Stopped)
Charles David Young 49:a67f2a3d228a 169 {
Charles David Young 49:a67f2a3d228a 170 // disable interrupts on TRIG1 and TRIG2
Charles David Young 49:a67f2a3d228a 171 TRIG1.rise(NULL);
Charles David Young 49:a67f2a3d228a 172 TRIG2.rise(NULL);
Charles David Young 49:a67f2a3d228a 173 }
Charles David Young 49:a67f2a3d228a 174
Charles David Young 28:c81d00ec28a3 175 // This must be called periodically to update the LEDs
Charles David Young 28:c81d00ec28a3 176 ModeSwitch.UpdateOutput();
charlesdavidyoung 24:db7494389c03 177
Charles David Young 38:1642320d83a0 178 switch (currentModeToDisplay) {
Charles David Young 34:10550b327e3d 179 case CNT1:
Charles David Young 49:a67f2a3d228a 180 DigitsDisplay.Display_6D_write(Count1Save);
Charles David Young 41:08bf3ea5eba4 181 DigitsDisplay.Display_2D_Blank();
Charles David Young 34:10550b327e3d 182 break;
Charles David Young 34:10550b327e3d 183 case CNT2:
Charles David Young 49:a67f2a3d228a 184 DigitsDisplay.Display_6D_write(Count2Save);
Charles David Young 41:08bf3ea5eba4 185 DigitsDisplay.Display_2D_Blank();
Charles David Young 34:10550b327e3d 186 break;
Charles David Young 34:10550b327e3d 187 case PROSPECT:
Charles David Young 49:a67f2a3d228a 188 if (Count1Save)
Charles David Young 49:a67f2a3d228a 189 DigitsDisplay.Display_6D_write(Count1Save);
Charles David Young 44:a26ca542ae5e 190 else
Charles David Young 49:a67f2a3d228a 191 DigitsDisplay.Display_6D_write(Count2Save);
Charles David Young 41:08bf3ea5eba4 192 DigitsDisplay.Display_2D_Blank();
Charles David Young 34:10550b327e3d 193 break;
Charles David Young 34:10550b327e3d 194 case NULL1:
Charles David Young 34:10550b327e3d 195 DigitsDisplay.Display_6D_write(0);
Charles David Young 41:08bf3ea5eba4 196 DigitsDisplay.Display_2D_Blank();
Charles David Young 34:10550b327e3d 197 break;
Charles David Young 37:6f7bb913e08b 198 case NULL2:
Charles David Young 34:10550b327e3d 199 DigitsDisplay.Display_6D_write(0);
Charles David Young 41:08bf3ea5eba4 200 DigitsDisplay.Display_2D_Blank();
Charles David Young 34:10550b327e3d 201 break;
Charles David Young 38:1642320d83a0 202 case VOLTS:
Charles David Young 34:10550b327e3d 203 DigitsDisplay.Display_6D_write(0);
Charles David Young 41:08bf3ea5eba4 204 DigitsDisplay.Display_2D_Blank();
Charles David Young 34:10550b327e3d 205 break;
Charles David Young 38:1642320d83a0 206 case VOLUME:
Charles David Young 34:10550b327e3d 207 case DIM:
Charles David Young 34:10550b327e3d 208 default:
Charles David Young 34:10550b327e3d 209 break;
Charles David Young 34:10550b327e3d 210 }
Charles David Young 16:b2e77eb76ab4 211 }
Charles David Young 16:b2e77eb76ab4 212
Charles David Young 16:b2e77eb76ab4 213 void UpdateInput()
charlesdavidyoung 24:db7494389c03 214 {
charlesdavidyoung 24:db7494389c03 215 // This must be called periodically to monitor switch input
Charles David Young 38:1642320d83a0 216 direction = ModeSwitch.UpdateInput();
Charles David Young 34:10550b327e3d 217 currentMode = ModeSwitch.GetPosition();
Charles David Young 34:10550b327e3d 218
Charles David Young 34:10550b327e3d 219 switch (currentMode) {
Charles David Young 34:10550b327e3d 220 case CNT1:
Charles David Young 34:10550b327e3d 221 case CNT2:
Charles David Young 44:a26ca542ae5e 222 currentModeToDisplay = currentMode;
Charles David Young 44:a26ca542ae5e 223
Charles David Young 44:a26ca542ae5e 224 if ( (direction > 0)
Charles David Young 44:a26ca542ae5e 225 && (TickerCorrection < TickerCorrectionMax))
Charles David Young 44:a26ca542ae5e 226 {
Charles David Young 44:a26ca542ae5e 227 TickerCorrection++;
Charles David Young 46:c7ce8fccb712 228 Sec_Beat.attach_us(&UpdateOutput, 1000000 + 1000*TickerCorrection);
Charles David Young 51:6b916f91f4d9 229 DigitsDisplay.Display_2D_write(TickerCorrection);
Charles David Young 44:a26ca542ae5e 230 }
Charles David Young 44:a26ca542ae5e 231 else
Charles David Young 44:a26ca542ae5e 232 if ( (direction < 0)
Charles David Young 44:a26ca542ae5e 233 && (TickerCorrection > TickerCorrectionMin))
Charles David Young 44:a26ca542ae5e 234 {
Charles David Young 44:a26ca542ae5e 235 TickerCorrection--;
Charles David Young 46:c7ce8fccb712 236 Sec_Beat.attach_us(&UpdateOutput, 1000000 + 1000*TickerCorrection);
Charles David Young 51:6b916f91f4d9 237 DigitsDisplay.Display_2D_write(TickerCorrection);
Charles David Young 44:a26ca542ae5e 238 }
Charles David Young 44:a26ca542ae5e 239 break;
Charles David Young 34:10550b327e3d 240 case PROSPECT:
Charles David Young 34:10550b327e3d 241 case VOLTS:
Charles David Young 38:1642320d83a0 242 currentModeToDisplay = currentMode;
Charles David Young 34:10550b327e3d 243 break;
Charles David Young 34:10550b327e3d 244 case NULL1:
Charles David Young 37:6f7bb913e08b 245 case NULL2:
Charles David Young 34:10550b327e3d 246 break;
Charles David Young 38:1642320d83a0 247 case VOLUME:
Charles David Young 39:dee91966b45c 248 if ( (direction > 0)
Charles David Young 39:dee91966b45c 249 && (volume < maxVolume))
Charles David Young 39:dee91966b45c 250 volume++;
Charles David Young 39:dee91966b45c 251 else
Charles David Young 39:dee91966b45c 252 if ( (direction < 0)
Charles David Young 39:dee91966b45c 253 && (volume > 0))
Charles David Young 39:dee91966b45c 254 volume--;
Charles David Young 39:dee91966b45c 255
Charles David Young 38:1642320d83a0 256 DigitsDisplay.Display_2D_write(volume);
Charles David Young 34:10550b327e3d 257 break;
Charles David Young 34:10550b327e3d 258 case DIM:
Charles David Young 39:dee91966b45c 259 if (direction > 0)
Charles David Young 39:dee91966b45c 260 DigitsDisplay.Display_brightness_up();
Charles David Young 39:dee91966b45c 261 else
Charles David Young 39:dee91966b45c 262 if (direction < 0)
Charles David Young 39:dee91966b45c 263 DigitsDisplay.Display_brightness_down();
Charles David Young 39:dee91966b45c 264
Charles David Young 38:1642320d83a0 265 DigitsDisplay.Display_2D_write(DigitsDisplay.GetBrightness());
Charles David Young 34:10550b327e3d 266 break;
Charles David Young 34:10550b327e3d 267 default:
Charles David Young 34:10550b327e3d 268 break;
charlesdavidyoung 24:db7494389c03 269 }
Charles David Young 34:10550b327e3d 270
Charles David Young 53:04999d536e92 271 ADC_val = KEYB.read(); // read voltage from keyboard
Charles David Young 53:04999d536e92 272 if ( (ADC_val<0.1) // START/STOP pushbutton pressed
Charles David Young 53:04999d536e92 273 && (!StartStopPressed))
Charles David Young 53:04999d536e92 274 {
Charles David Young 53:04999d536e92 275 StartStopPressed = true;
Charles David Young 59:f96a503bd228 276 if (Stopped)
Charles David Young 59:f96a503bd228 277 {
Charles David Young 59:f96a503bd228 278 // Enable interrupts on rising edge of digital inputs TRIG1 & TRIG2
Charles David Young 59:f96a503bd228 279 TRIG1.rise(&Count1_up);
Charles David Young 59:f96a503bd228 280 TRIG2.rise(&Count2_up);
Charles David Young 59:f96a503bd228 281 }
Charles David Young 53:04999d536e92 282 Stopped=!Stopped; // toggle status
Charles David Young 53:04999d536e92 283 }
Charles David Young 53:04999d536e92 284 else
Charles David Young 53:04999d536e92 285 StartStopPressed = false;
charlesdavidyoung 5:4f90b458dbdf 286
Charles David Young 53:04999d536e92 287 if((ADC_val>0.6)&&(ADC_val<0.7)) // CLEAR pushbutton pressed
Charles David Young 53:04999d536e92 288 {
Charles David Young 53:04999d536e92 289 Count1 = 0; // clear counters
Charles David Young 53:04999d536e92 290 Count2 = 0;
Charles David Young 53:04999d536e92 291 }
Charles David Young 57:f4215ca747e5 292 //logToPC();
Charles David Young 16:b2e77eb76ab4 293 return;
Charles David Young 16:b2e77eb76ab4 294 }
walter76 1:75827d765e34 295
walter76 0:6d1742703713 296 //---------------------------------------------------------------------------
walter76 1:75827d765e34 297 // Increment CNT1 every time a rising edge is detected on TRIG1 (interrupt)
walter76 1:75827d765e34 298
walter76 1:75827d765e34 299 void Count1_up(void)
walter76 1:75827d765e34 300 {
Charles David Young 33:35e3ab4d5ba7 301 //Beep();
Charles David Young 28:c81d00ec28a3 302 Count1++;
Charles David Young 28:c81d00ec28a3 303 return;
walter76 1:75827d765e34 304 }
walter76 1:75827d765e34 305
walter76 1:75827d765e34 306 //---------------------------------------------------------------------------
walter76 1:75827d765e34 307 // Increment CNT1 every time a rising edge is detected on TRIG2 (interrupt)
walter76 1:75827d765e34 308
walter76 1:75827d765e34 309 void Count2_up(void)
walter76 1:75827d765e34 310 {
Charles David Young 33:35e3ab4d5ba7 311 //Beep();
Charles David Young 28:c81d00ec28a3 312 Count2++;
Charles David Young 28:c81d00ec28a3 313 return;
walter76 1:75827d765e34 314 }
walter76 1:75827d765e34 315
walter76 1:75827d765e34 316
walter76 1:75827d765e34 317 //---------------------------------------------------------------------------
walter76 1:75827d765e34 318 //Generates a short beep via BUZZ
walter76 1:75827d765e34 319
walter76 1:75827d765e34 320 void Beep(void)
walter76 1:75827d765e34 321 {
Charles David Young 28:c81d00ec28a3 322 BUZZ = 1; // turn-on the buzzer
Charles David Young 33:35e3ab4d5ba7 323 wait_us(100); // wait
Charles David Young 28:c81d00ec28a3 324 BUZZ = 0; // turn-off the buzzer
Charles David Young 28:c81d00ec28a3 325 return;
walter76 0:6d1742703713 326 }
walter76 0:6d1742703713 327
walter76 1:75827d765e34 328 //-------- END OF FILE --------------
walter76 1:75827d765e34 329 //==============================================================================