unsigned long micros() { unsigned long m; // uint8_t oldSREG = SREG, t; uint8_t t = 0; istate_t state = __get_interrupt_state(); __disable_interrupt(); // cli(); m = timer0_overflow_count; // t = TCNT0; #warning what is this tcnt0 doing? #ifdef TIFR0 if ((TIFR0 & _BV(TOV0)) && (t < 255)) m++; #else // if ((TIFR & _BV(TOV0)) && (t < 255)) // m++; #endif // SREG = oldSREG; __set_interrupt_state(state); return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); }
unsigned char CircularBufferRead(CircularBuffer * pCircularBuffer, unsigned char * readValue) { ISTATE state = __get_interrupt_state(); __disable_interrupt(); unsigned char isEmpty = CircularBufferIsEmpty(pCircularBuffer); // Verify that there is data to read. if (!isEmpty) { // Read current value at current read pointer position. *(readValue) = *(pCircularBuffer->pRead); // Manipulate pointers. // Compare the current ptr offset position to the buffer start. if (pCircularBuffer->pRead < pCircularBuffer->pBufferEnd) { // If the pointer address is less than the buffer start address + size of // the buffer, increment the pointer. pCircularBuffer->pRead = pCircularBuffer->pRead + 1; } else { // If the pointer reaches the end, set it back to the beginning. pCircularBuffer->pRead = pCircularBuffer->pBuffer; } } __set_interrupt_state(state); return isEmpty; }
unsigned char CircularBufferWrite(CircularBuffer * pCircularBuffer, unsigned char value) { ISTATE state = __get_interrupt_state(); __disable_interrupt(); unsigned char isFull = CircularBufferIsFull(pCircularBuffer); // Verify that there is free space available to write data. if (!isFull) { // Write value at current write pointer position. *(pCircularBuffer->pWrite) = value; // Manipulate pointers. // Compare the current ptr offset position to the buffer start. if (pCircularBuffer->pWrite < pCircularBuffer->pBufferEnd) { // If the pointer address is less than the buffer start address + size of // the buffer, increment the pointer. pCircularBuffer->pWrite = pCircularBuffer->pWrite + 1; } else { // If the pointer reaches the end, set it back to the beginning. pCircularBuffer->pWrite = pCircularBuffer->pBuffer; } } __set_interrupt_state(state); return isFull; }
/**************************************************************************//** * @brief Register an interrupt handler to the specified GPIO pin(s). * This function will register a general ISR to the GPIO port * and then assign the ISR specified by \e pfnIntHandler to the * given pins. * * @param ui32Base The GPIO port. Can be one of the following: * \li \b IO_PIN_PORT_1 * \li \b IO_PIN_PORT_2 * @param ui8Pins The bit-packed representation of the pin(s) * @param pfnIntHandler A pointer to the interrupt handling function * * @return None ******************************************************************************/ void ioPinIntRegister(uint32_t ui32Base, uint8_t ui8Pins, void (*pfnIntHandler)(void)) { uint_fast8_t ui8Cnt; uint16_t ui16IntState; // // Critical section // ui16IntState = __get_interrupt_state(); __disable_interrupt(); if(pfnIntHandler) { // // Update HasIsr variables and clear interrupt flags // switch(ui32Base) { case IO_PIN_PORT_1: ioPort1PinHasIsr |= ui8Pins; P1IFG &= (~ui8Pins); break; case IO_PIN_PORT_2: ioPort2PinHasIsr |= ui8Pins; P2IFG &= (~ui8Pins); break; } } // // Go through pins // for(ui8Cnt = 0; ui8Cnt < 8; ui8Cnt++) { if(ui8Pins & (1 << ui8Cnt)) { // // Place function to offset in the correct lookup table // switch(ui32Base) { case IO_PIN_PORT_1: ioPort1IsrTable[ui8Cnt] = pfnIntHandler; break; case IO_PIN_PORT_2: ioPort2IsrTable[ui8Cnt] = pfnIntHandler; break; default: break; } } } // // End critical section // __set_interrupt_state(ui16IntState); }
// zapis do pamieci pod adres (mem_ptr + 2), w segmencie ograniczonym przez // segment_end // zwraca: 1 - nastapilo kasowanie pamieci; 0 - kasowanie nie nastapilo int save_to_memory(unsigned int int_to_save, unsigned int **mem_ptr, unsigned int segment_start, unsigned int segment_end) { int retval = 0; unsigned short wdog_state; *mem_ptr += 1; if(*mem_ptr > (unsigned int*)segment_end) { retval = 1; clear_memory((unsigned int*)segment_start);//kasuj pamiec *mem_ptr = (unsigned int*)segment_start; } wdog_state = WDTCTL; // zachowaj stan watchdoga WDTCTL = WDTPW + WDTCNTCL; // zresetuj watchdoga WDTCTL = WDTPW + WDTHOLD; // wylacz watch-doga istate_t state = __get_interrupt_state(); __disable_interrupt(); FCTL3 = FWKEY; // wyczysc LOCK FCTL1 = FWKEY + WRT; // wlacz zapis **mem_ptr = int_to_save; // zapis FCTL1 = FWKEY; // wylacz zapis FCTL3 = FWKEY + LOCK; // ustaw LOCK if ((WATCHDOG_ON) && !(wdog_state & WDTHOLD)) WDTCTL = WDTPW; // wlacz watchdoga __set_interrupt_state(state); return retval; }
/******************************************************************************* * @fn timerAIntConnect * * @brief Connect function to timer interrupt * * input parameters * * @param isr - pointer to function * * output parameters * * @return none */ void timerAIntConnect(ISR_FUNC_PTR isr) { uint16_t ui16IntState; ui16IntState = __get_interrupt_state(); __disable_interrupt(); fptr = isr; //HAL_INT_UNLOCK(key); /*HAL replace*/ __set_interrupt_state(ui16IntState); }
void uDelay(uint32 Delay) { FuncIN(UDELAY); __istate_t s = __get_interrupt_state(); __disable_interrupt(); Wait(Delay); __set_interrupt_state(s); FuncOUT(UDELAY); }
// czeka us_num mikrosekund (min 31 dla ACLK) inline void delay_us(int us_num) { istate_t istate; TACCR0 = (int)ceil((double)(us_num * TIMER_FQ) / 1000000); TAR = 0; TACTL |= MC_1; // wlacza timer. przerwania timera musza byc wl. istate = __get_interrupt_state(); // zachowanie stanu przerwan globalnych do { _BIS_SR(LPM0_bits + GIE); // zasnij w oczekiwaniu na timer A __disable_interrupt(); // zablokuj na czas sprawdzenia warunku while } while (TACTL & MC_1); // dopiero gdy timer A jest wylaczony, // wiemy ze nastapilo przerwanie timera A. __set_interrupt_state(istate); // przywrocenie poprzedniego stanu przerwan }
unsigned long millis() { unsigned long m; istate_t state = __get_interrupt_state(); __disable_interrupt(); // uint8_t oldSREG = SREG; // disable interrupts while we read timer0_millis or we might get an // inconsistent value (e.g. in the middle of a write to timer0_millis) // cli(); m = timer0_millis; __set_interrupt_state(state); // SREG = oldSREG; return m; }
/****************************************************************************** * @fn HalOTAInvRC * * @brief Invalidate the active image so that the boot code will instantiate * the DL image on the next reset. * * @param None. * * @return None. */ void HalOTAInvRC(void) { // Save interrupt and watchdog settings. istate_t ist = __get_interrupt_state(); uint8 wdt = WDTCTL & 0xFF; WDTCTL = WDTPW + WDTHOLD; // Stop watchdog per data sheet. __disable_interrupt(); // Stop interrupts to insure sequential writes in time. FCTL3 = FWKEY; // Clear Lock bit. FCTL1 = FWKEY + WRT; // Set WRT bit for write operation *((uint16 *)LO_ROM_BEG) = 0x0000; FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCK; // Set LOCK bit WDTCTL = WDTPW + wdt; // Restore watchdog setting. __set_interrupt_state(ist); // Restore interrupts setting. }
// czyszczenie segmentu wskazanego przez mem_ptr void clear_memory(unsigned int *mem_ptr) { unsigned short wdog_state; istate_t state = __get_interrupt_state(); __disable_interrupt(); wdog_state = WDTCTL; // zachowaj stan watchdoga WDTCTL = WDTPW + WDTCNTCL; // zresetuj watchdoga WDTCTL = WDTPW + WDTHOLD; // wylacz watch-doga //flash. 514 kHz < SMCLK < 952 kHz FCTL2 = FWKEY +FSSEL1+FN0; // ustawienie zegarow SMLCK/2 FCTL3 = FWKEY; // wyczysc LOCK FCTL1 = FWKEY + ERASE; // wlacz kasowanie *mem_ptr = 0; // kasowanie segmentu FCTL1 = FWKEY; // wylacz zapis FCTL3 = FWKEY + LOCK; // ustaw LOCK if ((WATCHDOG_ON) && !(wdog_state & WDTHOLD)) WDTCTL = WDTPW; // wlacz watchdoga __set_interrupt_state(state); }
/****************************************************************************** * @fn HalOTARead * * @brief Read from the storage medium according to image type. * * @param oset - Offset into the monolithic image. * @param pBuf - Pointer to the buffer in which to copy the bytes read. * @param len - Number of bytes to read. * @param type - Which image: HAL_OTA_RC or HAL_OTA_DL. * * @return None. */ void HalOTARead(uint32 oset, uint8 *pBuf, uint16 len, image_t type) { if (HAL_OTA_DL == type) { HalXNVRead(oset, pBuf, len); } else { istate_t ss = __get_interrupt_state(); __disable_interrupt(); if ((oset + LO_ROM_BEG) > LO_ROM_END) // Read from active image in high flash. { oset = HI_ROM_BEG + oset - (LO_ROM_END - LO_ROM_BEG + 1); } else // Read from active image in low flash. { uint8 *ptr = (uint8 *)((uint16)oset + LO_ROM_BEG); while (len) { // If a read crosses from low to high flash, break and fall into high flash read loop. if (ptr > (uint8 *)LO_ROM_END) { oset = HI_ROM_BEG; break; } *pBuf++ = *ptr++; len--; } } while (len--) { *pBuf++ = __data20_read_char(oset++); } __set_interrupt_state(ss); } }
/**************************************************************************//** * @brief Unregister an interrupt handler to the specified GPIO pin(s). * * @param ui32Base The GPIO port. Can be one of the following: * \li \b IO_PIN_PORT_1 * \li \b IO_PIN_PORT_2 * @param ui8Pins The bit-packed representation of the pin(s) * * @return None ******************************************************************************/ void ioPinIntUnregister(uint32_t ui32Base, uint8_t ui8Pins) { // // Critical section // uint16_t ui16IntState = __get_interrupt_state(); __disable_interrupt(); // // Register null function to pins // Doing this is not necessary, but is less confusing during debug. If not // cleared, the pins' interrupt vector tables may be non-null even when // no custom ISR is actually registered. It is the ioPortXPinHasIsr vars // that are used to decide whether a custom interrupt is registered or not. // ioPinIntRegister(ui32Base, ui8Pins, 0); // // Clear "pin has isr" variables // switch(ui32Base) { case IO_PIN_PORT_1: ioPort1PinHasIsr &= ~ui8Pins; break; case IO_PIN_PORT_2: ioPort2PinHasIsr &= ~ui8Pins; break; } // // End critical section // __set_interrupt_state(ui16IntState); }
//*----------------------------------------------------------------------------- //* Nazwa funkcji : komunikcja_RSwin //* Interpretacja i wykonanie rozkazów wysy³anych z programu RS-win //*----------------------------------------------------------------------------- void komunikcja_RSwin(char *ptr1, char *ptr2, unsigned int *ptr3) { //Zmienne lokalne ---------------------------------------------------------- unsigned long adres =0;; //----------------Koniec zmiennych lokalnych ------------------------------- //Zmienne tymczasowe ------------------------------------------------------- int tmp =0; //----------------Koniec zmiennych tymczasowych ---------------------------- //Zapis do dowolnego segmentu ---------------------------------------------- if ((ptr1[0]==0xAD)& (ptr1[1]==0x05)) { //Zapis programu zrodlowego adres = ptr1[4]+(ptr1[5]*0x100); if (ptr1[3]==0x70) { unsigned int Save = __get_interrupt_state(); __disable_interrupt(); if (adres==0) { //CleanFlash((int)AT91C_IFLASH_MEM->FlashProgram+FlashProgramOfset,0,sizeof(gProg)); CleanFlash((char*)&AT91C_IFLASH_MEM->FlashProgram+FlashProgramOfset,sizeof(gProg)); } at91flashWrite((int)AT91C_IFLASH_MEM->FlashProgram+FlashProgramOfset,adres,ptr1+7,ptr1[6]); __set_interrupt_state(Save); __enable_interrupt(); //Potwierdzenie ptr2[0]=0xAC; ptr2[1]=0x02; *ptr3=2; ptr2[2]=CheckSum(ptr2, ptr3); /* memory_read=(char*)&gProg+adres; for (char i=0; i<ptr1[6]; i++) { *memory_read=*(ptr1+7+i); memory_read++; } */ //przepisz program z flash do ram char *memory_read_prog; memory_read_prog=(char*)(AT91C_IFLASH_MEM->FlashProgram+FlashProgramOfset); char *SourRam= (char*)&gProg; int tProgramTabSize=ProgramTabSize; for (int k = 0 ; k <= tProgramTabSize ; k++) { SourRam[k]=memory_read_prog[k]; } } if (ptr1[3]==0x10) { char *memory_read; memory_read=(char*)&gProg+adres; for (char i=0; i<ptr1[6]; i++) { *memory_read=*(ptr1+7+i); memory_read++; } //Potwierdzenie ptr2[0]=0xAC; ptr2[1]=0x02; *ptr3=2; ptr2[2]=CheckSum(ptr2, ptr3); } }//-----------Koniec zapisu do dowolnego segmentu -------------------------- //Odczyt z dowolnego segmentu ---------------------------------------------- if ((ptr1[0]==0xAD)& (ptr1[1]==0x03)) { //Odczyt programu zrodlowego if ((ptr1[2]==0x00) & (ptr1[3]==0x10) /*& (ptr1[4]!=0x40)*/) { tmp = 2; ptr2[0] =0xAC; ptr2[1] =0x04; //*ptr3=2; adres = ptr1[4]+(ptr1[5]*0x100); char *memory_read; //memory_read=(char*)(AT91C_IFLASH_MEM->FlashProgram+FlashProgramReserveOfset); memory_read=(char*)&gProg; for (int k = 0 ; k <= (ptr1[6]-1) ; k++) { tmp++; ptr2[2+k] =memory_read[adres+k]; } *ptr3=tmp; ptr2[tmp]=CheckSum(ptr2, ptr3); } //tmp if ((ptr1[2]==0x00) & (ptr1[3]>0x70) & (ptr1[3]<0xC0) /*& (ptr1[4]!=0x40)*/) { tmp = 2; ptr2[0] =0xAC; ptr2[1] =0x04; //*ptr3=2; adres = ptr1[4]+(ptr1[5]*0x100); for (int k = 0 ; k <= (ptr1[6]-1) ; k++) { ptr2[2+k] = pProg[adres+k]; tmp++; } *ptr3=tmp; ptr2[tmp]=CheckSum(ptr2, ptr3); } //kon tmp }//------------------Koniec odczytu z dowolnego segmentu-------------------- //Odczyt z segmentu 0 ------------------------------------------------------ if ((ptr1[0]==0xAC)& (ptr1[1]==0x03) & (ptr1[2]!=0x14) & (ptr1[2]!=0x80) ) { //odczyt zmiennych dwustanwych if ( (ptr1[2]+(ptr1[3]*0x100)>= 0xC000) && (ptr1[2]+(ptr1[3]*0x100)<= 0xC7FF) ) { ptr2[0] =0xAC; ptr2[1] =0x04; tmp = 2; for (int k = 0; k <= ptr1[4]-1; k++) { adres = (ptr1[2]+(ptr1[3]*0x100)-0xC000 +k); ptr2[2+k] = BinVarToMaster(&adres); tmp++; } }//Koniec odczytu zmiennych dwustanowych //Odczyt zmiennych analogowych if ( (ptr1[2]+(ptr1[3]*0x100)>= 0xC800) && (ptr1[2]+(ptr1[3]*0x100)<= 0xDFFF) ) { ptr2[0] =0xAC; ptr2[1] =0x04; tmp = 2; for (int k = 0; k <= ptr1[4]-1; k=k+4) { adres = ((ptr1[2]+(ptr1[3]*0x100)-0xC800)/4) +(k/4); Convers_DW_B.DWvar = AnaVarToMaster(&adres); // zmiana kolejnoœci dla nowego RSWINa /* ptr2[k+2] =Convers_DW_B.Bvar[3]; ptr2[k+3] =Convers_DW_B.Bvar[2]; ptr2[k+4] =Convers_DW_B.Bvar[0]; ptr2[k+5] =Convers_DW_B.Bvar[1]; */ ptr2[k+2] =Convers_DW_B.Bvar[0]; ptr2[k+3] =Convers_DW_B.Bvar[1]; ptr2[k+4] =Convers_DW_B.Bvar[2]; ptr2[k+5] =Convers_DW_B.Bvar[3]; tmp=tmp+4; } }//Koniec odczytu zmiennych analogowych *ptr3=tmp; ptr2[tmp]=CheckSum(ptr2, ptr3); }//-------------------Koniec odczytu z segmentu 0--------------------------- //Zapis do segmentu 0------------------------------------------------------- if ((ptr1[0]==0xAC)& (ptr1[1]==0x05)) { //Zapis zmiennych dwustanowych if ( (ptr1[2]+(ptr1[3]*0x100)>= 0xC000) && (ptr1[2]+(ptr1[3]*0x100)<= 0xC7FF)) { for (int k = 0; k <= ptr1[4]-1; k++) { adres = (ptr1[2]+(ptr1[3]*0x100)-0xC000+k); MasterToBinVar(&adres, &ptr1[5]); //Konwersja z formatu Master i zapis } }//Koniec zapisu zmiennych dwustanowch //Zapis zmiennej analogowej if ( (ptr1[2]+(ptr1[3]*0x100)>= 0xC800) && (ptr1[2]+(ptr1[3]*0x100)<= 0xDFFF)) { for (int k = 0; k <= ptr1[4]-1; k=k+4) { /* // zmiana kolejnoœci dla nowego RSWINa Convers_DW_B.Bvar[3] = ptr1[5+(k)+0]; Convers_DW_B.Bvar[2] = ptr1[5+(k)+1]; Convers_DW_B.Bvar[0] = ptr1[5+(k)+2]; Convers_DW_B.Bvar[1] = ptr1[5+(k)+3]; */ Convers_DW_B.Bvar[0] = ptr1[5+(k)+0]; Convers_DW_B.Bvar[1] = ptr1[5+(k)+1]; Convers_DW_B.Bvar[2] = ptr1[5+(k)+2]; Convers_DW_B.Bvar[3] = ptr1[5+(k)+3]; adres= (((ptr1[2]+(ptr1[3]*0x100)-0xC800))/4)+(k/4); MasterToAnaVar(&adres, &Convers_DW_B.DWvar); } //koniec petli k }//Koniec zapisu zmiennych analogowych //Potwierdzenie ptr2[0]=0xAC; ptr2[1]=0x02; *ptr3=2; //koniec potwoerdzenia ptr2[2]=CheckSum(ptr2, ptr3); //suma kontrolna }//------------------Koniec zapisu do segmentu 0--------------------------- //!!! Standardowe pytania -------------------------------------------------- //Przepisz program uzytkowy z Ram do flash if ( (ptr1[0]==0xAC) && (ptr1[1]==0x06) && (ptr1[2]==0x4E) ) { ptr2[0]=0xAC; ptr2[1]=0x02; *ptr3=2; ptr2[2]=CheckSum(ptr2, ptr3); RamToFlash(); ProgramChangeExecute(&gProg); } //Ustaw pu³apkê if ( (ptr1[0]==0xAA)&& (ptr1[1]==0xAA)&& (ptr1[2]==0x01) ) { Trap.Row=ptr1[3]; Trap.Col=ptr1[4]; Trap.Enable=1; Trap.Activ=0; Trap.Change=1; //Potwierdzenie ptr2[0]=0xAB; ptr2[1]=0xAB; *ptr3=2; ptr2[2]=CheckSum(ptr2, ptr3); //suma kontrolna //koniec potwoerdzenia }//koniec "Ustaw pu³apkê" //Usuñ pu³apki if ( (ptr1[0]==0xAA)&& (ptr1[1]==0xAA)&& (ptr1[2]==0x02) ) { Trap.Enable=0; Trap.Row=0; Trap.Col=0; Trap.Activ=0; //Potwierdzenie ptr2[0]=0xAB; ptr2[1]=0xAB; *ptr3=2; ptr2[2]=CheckSum(ptr2, ptr3); //suma kontrolna //koniec potwoerdzenia }//koniec "Ustaw pu³apkê" //Odczytaj stany "Output" procedur (ptr1[3]-startowy rz¹d procedur, ptr1[4]-ilosc rzedow do odczytu if ( (ptr1[0]==0xAA)&& (ptr1[1]==0xAA)&& (ptr1[2]==0x03) ) { ptr2[0] =0xAC; ptr2[1] =0x04; tmp = 2; for (int Row = ptr1[3] ; Row<ptr1[3]+ptr1[4] ; Row++) { for (int Col = 0 ; Col<MaxPrcInLine ; Col++) { ptr2[tmp++] =gProg.Line[Row].Proc[Col].Out>>8; ptr2[tmp++] =gProg.Line[Row].Proc[Col].Out & 0xFF; } } *ptr3=tmp; ptr2[tmp]=CheckSum(ptr2, ptr3); }//koniec "Ustaw pu³apkê"
/**************************************************************************//** * @brief This function returns a bitmask of keys pushed. * * @note If keys are handled using polling (\b BSP_KEY_MODE_POLL), the * returned bitmask will never contain a combination of multiple key * bitmasks, for example, (\b BSP_KEY_LEFT |\b BSP_KEY_UP). * Furthermore, in this case argument \e ui8ReadMask is ignored. * * @param ui8ReadMask is a bitmask of keys to read. Read keys are cleared * and new key presses can be registered. Use * \b BSP_KEY_ALL to read status of all keys. * * @return Returns bitmask of pushed keys ******************************************************************************/ uint8_t bspKeyPushed(uint8_t ui8ReadMask) { if(ui8BspKeyMode == BSP_KEY_MODE_POLL) { // // Polling mode. // #ifdef __MSP430F5438A__ // // Get key state bitmask // uint_fast8_t ui8Pins = ((~BSP_KEY_IN) & BSP_KEY_ALL); // // Return the first key pressed // if(ui8Pins & BSP_KEY_SELECT) { BSP_KEY_DEBOUNCE(BSP_KEY_IN & BSP_KEY_SELECT); return (BSP_KEY_SELECT); } else if(ui8Pins & BSP_KEY_LEFT) { BSP_KEY_DEBOUNCE(BSP_KEY_IN & BSP_KEY_LEFT); return (BSP_KEY_LEFT); } else if(ui8Pins & BSP_KEY_RIGHT) { BSP_KEY_DEBOUNCE(BSP_KEY_IN & BSP_KEY_RIGHT); return (BSP_KEY_RIGHT); } else if(ui8Pins & BSP_KEY_UP) { BSP_KEY_DEBOUNCE(BSP_KEY_IN & BSP_KEY_UP); return (BSP_KEY_UP); } else if(ui8Pins & BSP_KEY_DOWN) { BSP_KEY_DEBOUNCE(BSP_KEY_IN & BSP_KEY_DOWN); return (BSP_KEY_DOWN); } #elif defined (__MSP430F5529__) // // Check if the key is pressed // if((~BSP_KEY_1_IN) & BSP_KEY_1) { BSP_KEY_DEBOUNCE(BSP_KEY_1_IN & BSP_KEY_1); return (BSP_KEY_SELECT); } else if((~BSP_KEY_2_IN) & BSP_KEY_2) { BSP_KEY_DEBOUNCE(BSP_KEY_2_IN & BSP_KEY_2); return (BSP_KEY_UP); } #endif // // No keys pressed // return (0); } #ifndef BSP_KEY_NO_ISR else { uint_fast8_t ui8Bm = 0; // // Disable global interrupts // uint16_t ui16IntState = __get_interrupt_state(); __disable_interrupt(); // // Critical section // ui8Bm = bspKeysPressed; bspKeysPressed &= ~ui8ReadMask; // // Re-enable interrupt if initially enabled, and return key bitmask // __set_interrupt_state(ui16IntState); return (ui8Bm); } #else else { // // If we get here, something is configured wrong (ISR mode chosen _and_ // BSP_KEY_NO_ISR defined) // return (0);