/** * sleepRtc * * Put panStamp into Power-down state during "time". * This function uses Timer 2 connected to an external 32.768KHz crystal * in order to exit (interrupt) from the power-down state * * 'time' Sleeping time: * RTC_250MS = 250 ms * RTC_500MS = 500 ms * RTC_1S = 1 s * RTC_2S = 2 s * RTC_8S = 8 s */ void AVRRTC::sleepRtc(unsigned char time) { // Power-down panStamp set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_enable(); setup_rtc(time); delayMicroseconds(10); // Disable ADC ADCSRA &= ~(1 << ADEN); // Unpower functions //PRR = 0xFF; -> temporary for testing // Enter sleep mode sleep_mode(); // ZZZZZZZZ... // Wake-up!! wakeUp(); }
static void serial_puts(char *str) { again: cli(); if (output.printing) { sleep_enable(); sei(); sleep_cpu(); sleep_disable(); goto again; } sei(); output.str = str; output.printing = 1; serial_interrupt_dre_enable(); }
void CHandler::run(void) { switch (state) { case SLEEP: cc1101->powerdown(); //PSU_BYPASS(); //TPS62730 in Bypass mode lowest Iq psuBypass.setEnable(); WatchdogInit(txinterval); //BIT_SET_LO(PORTD, 5); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_mode(); //====================================================================== // SLEEP //====================================================================== sleep_disable(); //BIT_SET_HI(PORTD, 5); wdt_disable(); // enable WDT in reset mode wdt_enable(WDTO_2S); wdt_reset(); psuBypass.setDisable(); //PSU_2V1(); // Use 2.1 V for transmission to keep current down cc1101->wakeUp(); state = TRANSMIT; break; case TRANSMIT: txSeqNr++; if (txSeqNr >= 900) { //900 TX PACKETS IN AN HOUR txSeqNr = 0; tag.lifecnt++; } tag.count = txSeqNr; //====================================================================== // TRANSMIT //====================================================================== wdt_reset(); // If transmit does not finish in 500ms a System reset is issued. cc1101->transmit((u08*) &tag, sizeof(TAG::sRfTag), eCC1100_TX_TYPE_CCA); wdt_disable(); state = SLEEP; break; } }
void yackpower(byte n) /*! @brief Manages the power saving mode This is called in yackbeat intervals with either a TRUE or FALSE as parameter. Whenever the parameter is TRUE a beat counter is advanced until the timeout level is reached. When timeout is reached, the chip shuts down and will only wake up again when issued a level change interrupt on either of the input pins. When the parameter is FALSE, the counter is reset. @param n TRUE: OK to sleep, FALSE: Can not sleep now */ { static uint32_t shdntimer=0; if (n) // True = we could go to sleep { if(shdntimer++ == YACKSECS(PSTIME)) { shdntimer=0; // So we do not go to sleep right after waking up.. set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_bod_disable(); sleep_enable(); sei(); sleep_cpu(); cli(); // There is no technical reason to CLI here but it avoids hitting the ISR every time // the paddles are touched. If the remaining code needs the interrupts this is OK to remove. } } else // Passed parameter is FALSE { shdntimer=0; } }
int main(void) { display__init(); rts__init(); rts__set(1); usart0__rate__set(USART0__BAUD_RATE); usart0__tx__enabled__set(1); // FILE usart_out = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE); // stdout = &usart_out; onewire__bus__init(); // sleeping set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); display__init(); sei(); #if !defined(__AVR_ARCH__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-noreturn" #endif for(;;) { main__thread__run(); } #if !defined(__AVR_ARCH__) #pragma clang diagnostic pop #endif #if !defined(__AVR_ARCH__) #pragma clang diagnostic push #pragma ide diagnostic ignored "OCDFAInspection" #endif return 0; #if !defined(__AVR_ARCH__) #pragma clang diagnostic pop #endif return 0; }
void hwPowerDown(const uint8_t wdto) { // Let serial prints finish (debug, log etc) #ifndef MY_DISABLED_SERIAL MY_SERIALDEVICE.flush(); #endif // disable ADC for power saving ADCSRA &= ~(1 << ADEN); // save WDT settings const uint8_t WDTsave = WDTCSR; if (wdto != WDTO_SLEEP_FOREVER) { wdt_enable(wdto); // enable WDT interrupt before system reset WDTCSR |= (1 << WDCE) | (1 << WDIE); } else { // if sleeping forever, disable WDT wdt_disable(); } set_sleep_mode(SLEEP_MODE_PWR_DOWN); cli(); sleep_enable(); #if defined(__AVR_ATmega328P__) sleep_bod_disable(); #endif // Enable interrupts & sleep until WDT or ext. interrupt sei(); // Directly sleep CPU, to prevent race conditions! // Ref: chapter 7.7 of ATMega328P datasheet sleep_cpu(); sleep_disable(); // restore previous WDT settings cli(); wdt_reset(); // enable WDT changes WDTCSR |= (1 << WDCE) | (1 << WDE); // restore saved WDT settings WDTCSR = WDTsave; sei(); // enable ADC ADCSRA |= (1 << ADEN); }
void Sleep(byte interval) { noInterrupts (); // timed sequence below MCUSR = 0; // reset various flags WDTCSR |= 0b00011000; // see docs, set WDCE, WDE WDTCSR = 0b01000000 | interval; // set WDIE, and appropriate delay wdt_reset(); byte adcsra_save = ADCSRA; ADCSRA = 0; // disable ADC set_sleep_mode (SLEEP_MODE_PWR_DOWN); // sleep mode is set here sleep_enable(); interrupts (); sleep_cpu (); // now goes to Sleep and waits for the interrupt ADCSRA = adcsra_save; // stop power reduction(Enable ADC) }
void setSleep(void) { //dbg << ','; // some debug //_delay_ms(10); // delay is necessary to get it printed on the console before device sleeps //_delay_ms(100); // some power savings by switching off some CPU functionality ADCSRA = 0; // disable ADC backupPwrRegs(); // save content of power reduction register and set it to all off sleep_enable(); // enable sleep offBrownOut(); // turn off brown out detection sleep_cpu(); // goto sleep // sleeping now // -------------------------------------------------------------------------------------------------------------------- // wakeup will be here sleep_disable(); // first thing after waking from sleep, disable sleep... recoverPwrRegs(); // recover the power reduction register settings //dbg << '.'; // some debug }
//#START_FUNCTION_HEADER////////////////////////////////////////////////////// //# //# Description: Puts the unit into sleep while enabling proper interrupts to //# exit sleep mode. In normal mode, we want to sleep in between //# data ready aquisitions to maximize power. When no motion is present, //# we only want to be woken up by BLE or movement again, not data //# ready. //# //# Parameters: still --> true = disable acc data interrupts //# false = enable acc data interrupts //# //# Returns: Nothing //# //#//END_FUNCTION_HEADER//////////////////////////////////////////////////////// void sleep_handler(bool still) { got_slp_wake = false; got_data_acc = false; got_int_ble = false; factory_sleep = false; set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); cli(); sleep_bod_disable(); enable_int(PCIE0); enable_int(PCIE1); still ? disable_int(PCIE2) : enable_int(PCIE2); //if we want to sleep in between data reads AND when no motion occurs clear_acc_ints(); sei(); sleep_cpu(); sleep_disable(); enable_int(PCIE2); }
// Put the System to sleep when the power button is pressed, or the mode times out void sleepNow() { attachInterrupt(wakePin-2,wakeNow,RISING); set_sleep_mode(SLEEP_MODE_IDLE); //PWR_DOWN); sleep_enable(); power_adc_disable(); power_spi_disable(); power_timer0_disable(); power_timer1_disable(); power_timer2_disable(); power_twi_disable(); attachInterrupt(wakePin-2,wakeNow,RISING); // Attach our wakeup interrupt sleep_mode(); // Goodnight // Once we get here, it has woken up! sleep_disable(); power_all_enable(); attachInterrupt(wakePin-2,nop,RISING); // Debounce reset button input -- throw away any pending interrupts (detachInterrupt leaves them pending) delay(250); // Debounce reset button input -- wait for button unpress }
int main(void) { OSCCAL=eeprom_read_byte(0x00); // Настройка генератора. PRR=0x0b; // выключаем лишние устройства. DDRB=0b00000111; // настраиваем порт в PORTB=0b00000000; // сбрасываем в ноль DDRA= 0b10011000; // настраиваем порт А PORTA=0b00010000; // выключаем приемопередатчик DIDR0=0b00000110; // отключаем цифровые входы от компаратора // сторожевой таймер WDTCSR=0x18; // настраиваем сторожевой таймер WDTCSR=0x29; // сторожевой таймер сброс через 8 секунд. // настройка переменных flag=0; set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); id_yd=0; while (1) { ClsBit(PORTA,pwr_up); // выключаем приемник flag=0; delay_ms(20); ACSR=0b00011011; // включаем компаратор. delay_ms(10); sei(); // разрешаем прерывания while(!flag) sleep_cpu(); //ждем удара и усыпляем контролер // удар произошел передаем данные // cli(); // запрещаем прерывания. SetBit(PORTA,pwr_up); // включаем приемник delay_ms(10); // задержка 10 ms. LoadConf(); // загружаем конфигурацию. // передаем пакет. PutChar(0xe7); PutChar(adr); PutChar(id_yd); ce0; // активизируем передачу delay_ms(9); // делаем выдержку по времени 1 ms. wdr(); // сбрасываем сторожевой таймер. } }
int main(void) { initialize(); trt_uart_init(); /* Print a statement to the serial communication terminal when the system is reset. */ stdout = stdin = stderr = &uart_str; fprintf(stdout,"TinyRealTime: 2/9/09\n\r"); /* Sets up the kernel data structures. * The parameter is the desired starck size of the idle task. * For a null idle task, a stack size of 80 should be sufficient. */ trtInitKernel(80); /* Creates semaphores with identifer semnumber and initial values initval. */ trtCreateSemaphore(SEM_RX_ISR_SIGNAL, 0); trtCreateSemaphore(SEM_STRING_DONE , 0); trtCreateSemaphore(SEM_S , 1); trtCreateSemaphore(SEM_P , 1); trtCreateSemaphore(SEM_I , 1); trtCreateSemaphore(SEM_D , 1); /* Identifies the three functions to the kernel as threads. * The parameters specify pointers to the functions, the * desired stack size, the initial release time, the initial deadline time, * and an abitrary data input structure */ trtCreateTask(serialTask , 200, SECONDS2TICKS(0.1), SECONDS2TICKS(0.2 ), &(args[0])); trtCreateTask(motorTask , 200, SECONDS2TICKS(0.3), SECONDS2TICKS(0.32), &(args[1])); /* Choose our preferred sleep mode */ set_sleep_mode(SLEEP_MODE_IDLE); /* Set sleep enable (SE) bit */ sleep_enable(); /* Sleep the CPU when a task isn't running. */ while (1) { sleep_cpu(); } }
void os_sleep_cpu(void *user_data, SleepCheck sleep_check) { do { cli(); if (sleep_check(user_data)) { if (_inhibit_deep_sleep) set_sleep_mode(SLEEP_MODE_IDLE); else set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_enable(); sei(); sleep_cpu(); sleep_disable(); } sei(); } while (sleep_check(user_data)); }
void naiboard_sleep(void) { if (naiboard_state.usb_vendor_enabled) // If we're not connected we won't go to sleep. return; // We're only using the IDLE sleep level because USB doesn't work below that. // Not much power saving though... SLEEP.CTRL = SLEEP_SMODE_IDLE_gc; sysclk_disable_peripheral_clock(&RTC); //printf_P(PSTR("sleep\n")); WDT_Disable(); sleep_enable(); cpu_sleep(); // Waking up sleep_disable(); WDT_Enable(); sysclk_enable_peripheral_clock(&RTC); //printf_P(PSTR("wake\n")); }
/** * sleepWd * * Put panStamp into Power-down state during "time". * This function uses the internal watchdog timer in order to exit (interrupt) * from the power-down state * * 'time' Sleeping time: * WDTO_15MS = 15 ms * WDTO_30MS = 30 ms * WDTO_60MS = 60 ms * WDTO_120MS = 120 ms * WDTO_250MS = 250 ms * WDTO_500MS = 500 ms * WDTO_1S = 1 s * WDTO_2S = 2 s * WDTO_4S = 4 s * WDTO_8S = 8 s */ void AVRRTC::sleepWd(unsigned char time) { // Power-down panStamp set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); setup_watchdog(time); delayMicroseconds(10); // Disable ADC ADCSRA &= ~(1 << ADEN); // Unpower functions PRR = 0xFF; //power_all_disable(); //clock_prescale_set(clock_div_8); // Enter sleep mode sleep_mode(); // ZZZZZZZZ... // Wake-up!! wakeUp(); }
void loop() { Serial.print("sleepy "); Serial.print(++counter); Serial.print(" wdtFired="); Serial.println(wdtFired); wdtFired = 0; digitalWrite(LED_PIN, HIGH); // set the LED on delay(250); digitalWrite(LED_PIN, LOW); // set the LED on Serial.print("sleeping... "); delay(20); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here sleep_enable(); sleep_mode(); // System sleeps here sleep_disable(); // System continues execution here when watchdog timed out Serial.println("awake"); delay(8000); }
unsigned int getADC(unsigned char input) { ADMUX = (input & 15) | _BV(REFS0); // AVcc reference + external cap. ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0) | _BV(ADIE) | _BV(ADEN); sei(); if (1) { ADCSRA |= 1<<ADSC; while(ADCSRA & 1<<ADSC) {} } else { SREG |= _BV(SREG_I); set_sleep_mode(SLEEP_MODE_ADC); sleep_enable(); sleep_mode(); } return ADCW; // unsigned int result = ADCL | ADCH << 8; // return result; }
int main(void) { // set for 1 MHz clock CPU_PRESCALE(4); // set all pins as inputs with pullup resistors #if defined(PORTA) DDRF = 0; PORTF = 0xFF; #endif DDRB = 0; PORTB = 0xFF; DDRC = 0; PORTC = 0xFF; DDRD = 0; PORTD = 0xFF; #if defined(PORTE) DDRE = 0; PORTE = 0xFF; #endif #if defined(PORTF) DDRF = 0; PORTF = 0xFF; #endif // initialize USB usb_init(); // do nothing (USB code handles reboot message) while (1) { _delay_ms(1); // put the CPU into low power idle mode set_sleep_mode(SLEEP_MODE_IDLE); cli(); sleep_enable(); sei(); sleep_cpu(); sleep_disable(); } }
static void shine_leds(uint16_t dur, uint8_t cur_vals[]) { for (TCNT1 = 0; TCNT1 < dur; /*nothing*/) { for (uint8_t t = 0; t < BIT_SCHED_LEN; t++) { for (uint8_t i = 0; i < NUM_LEDS; i++) { uint8_t tmp_port = ALL_GND_PULL_OFF, tmp_ddr = ALL_INPUT; if (lookup_on_off(cur_vals[i], t)) { turn_led_on(&tmp_ddr, &tmp_port, i); } DDRA = tmp_ddr; PORTA = tmp_port; } DDRA = ALL_INPUT; PORTA = ALL_POS_PULL_ON; DDRB = ALL_INPUT; PORTB = ALL_POS_PULL_ON; if (go_to_sleep) { _delay_ms(2000); cli(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); // don't wake up via mode button GIMSK &= ~_BV(PCIE0); sei(); sleep_cpu(); sleep_disable(); GIMSK |= _BV(PCIE0); _delay_ms(1000); go_to_sleep = 0; } if (next_animation || TCNT1 > dur) break; } if (next_animation) break; } }
void switchOff(void){ //u8g_SleepOn(&u8g); //u8g_SleepOn(&u8g); u8g_FirstPage(&u8g); do { } while (u8g_NextPage(&u8g)); EIMSK = (1 << INT1) | (1 << INT0); EICRA = (1 << ISC11) | (1 << ISC10) | (1 << ISC01) | (1 << ISC00); sei(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_mode(); //_delay_ms(100); sleep_disable(); EIMSK = 0x00; // Detach interrupt after waken up. EICRA = 0x00; //u8g_SleepOff(&u8g); _delay_ms(500); }
void power_save() { /* Enter power saving mode. SLEEP_MODE_IDLE is the least saving * mode, but it's the only one that will keep the UART running. * In addition, we need timer0 to keep track of time, timer 1 * to drive the buzzer and timer2 to keep pwm output at its rest * voltage. */ set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); power_adc_disable(); power_spi_disable(); power_twi_disable(); pin_write(LED_PIN, LOW); sleep_mode(); // Go to sleep pin_write(LED_PIN, HIGH); sleep_disable(); // Resume after wake up power_all_enable(); }
// -------------------------------------------------------------------------- //wiselib::WiselibApplication<Os, ExampleApplication> example_app; // -------------------------------------------------------------------------- int main() { init(); #if defined(USBCON) USBDevice.attach(); #endif ExampleApplication Example; ::Serial.begin(9600); for(;;) { if ( serialEventRun ) serialEventRun(); while(true) { cli(); if(wiselib::ArduinoTask::tasks_.empty()) { // #if ARDUINO_ALLOW_SLEEP sleep_enable(); sei(); sleep_cpu(); sleep_disable(); // #endif sei(); delay(10); } else { sei(); break; } } wiselib::ArduinoTask t = wiselib::ArduinoTask::tasks_.front(); wiselib::ArduinoTask::tasks_.pop(); t.callback_(t.userdata_); delay(10); } return 0; }
//#START_FUNCTION_HEADER////////////////////////////////////////////////////// //# //# Description: //# Puts the sensor into factory mode. This mode //# is essentially an ultra deep sleep mode that is only brought out //# of sleep by one specific interrupt generated by the BLE unit. //# //# Parameters: None //# //# Returns: Nothing //# //#//END_FUNCTION_HEADER//////////////////////////////////////////////////////// void set_factory_mode() { got_slp_wake = false; got_data_acc = false; got_int_ble = false; factory_sleep = true; enable_int(PCIE0); disable_int(PCIE1); disable_int(PCIE2); acc1.MMA8452Standby(); acc2.MMA8452Standby(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); cli(); sleep_bod_disable(); sei(); sleep_cpu(); sleep_disable(); clear_acc_ints(); }
int main(void) { // PB0 is connected to a LED DDRB |= (1 << PB0); // Disable all internal systems during power down mode PRR = (1 << PRTIM1) | (1 << PRTIM0) | (1 << PRUSI) | (1 << PRADC); sei(); while (1) { GIMSK |= (1 << INT0); // This needs to be before the sleep instruction // Sleep in power down mode. Before we sleep we enable the INT0 interrupt. set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_cpu(); // If we have been woken up 4 times then it is time to do 'work' // Flash the led three times for (uint8_t i = 0; i < 3; i++) { PORTB |= (1 << PB0); _delay_ms(50); PORTB &= ~(1 << PB0); _delay_ms(50); } // Wait while the line goes up again while ((PINB & (1 << PB2)) == 0) { // Wait } } return 0; }
/* Accesses the global variables - leftSleepingTimeMs (contains the remaining sleeping time in ms - sleepingActive (information if sleeping mode should be active The sleep mode is switched ON inside this function. With the IDLE sleeping mode the timer 0 continues to run. During each timer 0 overflow interrupt (always after 27ms) the controller wakes up and the global variable leftSleepingTime is decreased inside the ISR. As long the leftSleepingTime is > 0 this functions continues to enter the sleeping mode. */ void sleepDeeplyMs() { set_sleep_mode(SLEEP_MODE_IDLE); /* disable interrupts */ cli(); sleepingActive = TRUE; while(leftSleepingTimeMs > 33) { /* the variable leftSleepingTimeMs is now decremented each 33ms in the timer0 overflow interrupt -> see interrupt.c for details */ sleep_enable(); /* enable interrupts */ sei(); sleep_cpu(); sleep_disable(); } sleepingActive = FALSE; sei(); }
void GeogramONE::goToSleep() { delay(200); //need delay because GSM module is shutting down. 1000 works uint8_t pcicrReg = PCICR; //backup the current Pin Change Interrupt register PCICR = 0; // disable all pin change interrupts. Need to do this because of NewSoftSerial pinMode(9,INPUT); //shut off NewSoftSerial Tx pin digitalWrite(9,LOW); //set to high impedance digitalWrite(8,LOW); // set NewSoftSerial Rx pin to high impedance set_sleep_mode (SLEEP_MODE_PWR_DOWN); sleep_enable(); MCUCR = _BV (BODS) | _BV (BODSE); MCUCR = _BV (BODS); sleep_cpu (); /*********ATMEGA is sleeping at this point***************/ sleep_disable(); pinMode(9,OUTPUT); //restore NewSoftSerial settings digitalWrite(9,HIGH); digitalWrite(8,HIGH); PCICR = pcicrReg; //restore Pin Change Interrupt register }
void sleep_init(void) { ACSR |= _BV(ACD); // disable the analog comparator ADCSRA &= ~_BV(ADEN); // disable ADC set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); //turn off the brown-out detector. //must have an ATtiny45 or ATtiny85 rev C or later for software to be able to disable the BOD. //current while sleeping will be <0.5uA if BOD is disabled, <25uA if not. cli(); /* mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE); //turn off the brown-out detector mcucr2 = mcucr1 & ~_BV(BODSE); MCUCR = mcucr1; MCUCR = mcucr2; */ sei(); //ensure interrupts enabled so we can wake up again sleep_cpu(); //go to sleep cli(); //wake up here, disable interrupts sleep_disable(); sei(); //enable interrupts again (but INT0 is disabled from above) }
static int protothreadWaitForTrigger(struct pt *pt) { PT_BEGIN(pt); while(1) { PT_WAIT_UNTIL(pt, (state == STATE_SWITCH_ON) || (state == STATE_RESPAWN)); if (tsBtnPressed == 0) { sleep_enable(); sei(); sleep_cpu(); sleep_disable(); } else { if (state == STATE_SWITCH_ON && millis() - tsBtnPressed > 2000) { state = STATE_WAKE_UP; } if (state == STATE_RESPAWN) { state = STATE_EXPLODE; } } } PT_END(pt); }
void WDTSleep::sleep(uint16_t seconds) { // Start WDT cli(); WDTCSR = _BV(WDCE) | _BV(WDE); // Enable WDT WDTCSR = _BV(WDIE) | _BV(WDP3) | _BV(WDP0); // Set WDT timeout to 8 secs sei(); // Sleep... sleepIntervals = seconds >> 3; while(sleepIntervals) { set_sleep_mode (SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_cpu (); // cancel sleep as a precaution sleep_disable(); } // Stop WDT wdt_disable(); }
int main(void) { initSPI(); initNRF24L01(); //initUSART(); //Init LEDs and flash once to show script running LED_DDR|=(1 << LED_RED)|(1 << LED_GREEN); // set LED pins for output LED_DDR2|=(1 << LED_BLUE); // set blue LED pin for output flashLED(); //Flash to show initiated initADC(); ADCSRA |= (1<<ADSC); // Start conversion - didn't do earlier as not all bits set //Reduce power power_timer0_disable(); power_timer1_disable(); power_timer2_disable(); power_twi_disable(); //Sleep modes set_sleep_mode(SLEEP_MODE_ADC); sleep_enable(); sleep_bod_disable(); sleep_cpu(); sleep_mode(); //Power down nrf24 // Mainloop - use asm to stop empty infinite loop being optimised out. while(1) { asm(""); } return 0; }