void sleepSeconds(uint32_t seconds) { unsigned long i; i = milliseconds; i += seconds * 1000; stay_asleep = true; HWREG(NVIC_SYS_CTRL) |= NVIC_SYS_CTRL_SLEEPDEEP; while ( stay_asleep && (milliseconds < i) ) { MAP_IntMasterDisable(); // Set PRIMASK so CPU wakes on IRQ but ISRs don't execute until PRIMASK is cleared SysTickMode_DeepSleepCoarse(); CPUwfi_safe(); // Handle low-power SysTick triggers without using the default SysTickIntHandler if (HWREG(NVIC_INT_CTRL) & NVIC_INT_CTRL_PENDSTSET) { milliseconds += 1000; HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR; } else { milliseconds += (DEEPSLEEP_CPU - HWREG(NVIC_ST_CURRENT)) / (DEEPSLEEP_CPU / 1000); } // Restore SysTick to normal parameters in preparation for full-speed ISR execution SysTickMode_Run(); MAP_IntMasterEnable(); // Clearing PRIMASK allows pending ISRs to run } HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP); stay_asleep = false; }
int main() { MAP_IntVTableBaseSet((unsigned long) &g_pfnVectors[0]); MAP_IntEnable(FAULT_SYSTICK); MAP_IntMasterEnable(); PRCMCC3200MCUInit(); cc3200_leds_init(); /* Console UART init. */ MAP_PRCMPeripheralClkEnable(CONSOLE_UART_PERIPH, PRCM_RUN_MODE_CLK); MAP_PinTypeUART(PIN_55, PIN_MODE_3); /* PIN_55 -> UART0_TX */ MAP_PinTypeUART(PIN_57, PIN_MODE_3); /* PIN_57 -> UART0_RX */ MAP_UARTConfigSetExpClk( CONSOLE_UART, MAP_PRCMPeripheralClockGet(CONSOLE_UART_PERIPH), CONSOLE_BAUD_RATE, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); MAP_UARTFIFODisable(CONSOLE_UART); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); VStartSimpleLinkSpawnTask(8); osi_TaskCreate(v7_task, (const signed char *) "v7", V7_STACK_SIZE + 256, NULL, 3, NULL); osi_TaskCreate(blinkenlights_task, (const signed char *) "blink", 256, NULL, 9, NULL); osi_start(); return 0; }
//***************************************************************************** // // Change the value of a variable atomically. // // \param pulVal points to the index whose value is to be modified. // \param ulDelta is the number of bytes to increment the index by. // \param ulSize is the size of the buffer the index refers to. // // This function is used to increment a read or write buffer index that may be // written in various different contexts. It ensures that the read/modify/write // sequence is not interrupted and, hence, guards against corruption of the // variable. The new value is adjusted for buffer wrap. // // \return None. // //***************************************************************************** static void UpdateIndexAtomic(volatile unsigned long *pulVal, unsigned long ulDelta, unsigned long ulSize) { tBoolean bIntsOff; // // Turn interrupts off temporarily. // bIntsOff = MAP_IntMasterDisable(); // // Update the variable value. // *pulVal += ulDelta; // // Correct for wrap. We use a loop here since we don't want to use a // modulus operation with interrupts off but we don't want to fail in // case ulDelta is greater than ulSize (which is extremely unlikely but...) // while(*pulVal >= ulSize) { *pulVal -= ulSize; } // // Restore the interrupt state // if(!bIntsOff) { MAP_IntMasterEnable(); } }
//***************************************************************************** //! Board Initialization & Configuration //***************************************************************************** static void bootmgr_board_init(void) { // set the vector table base MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // enable processor interrupts MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); // mandatory MCU initialization PRCMCC3200MCUInit(); mperror_bootloader_check_reset_cause(); #if MICROPY_HW_ANTENNA_DIVERSITY // configure the antenna selection pins antenna_init0(); #endif // enable the data hashing engine CRYPTOHASH_Init(); // init the system led and the system switch mperror_init0(); // clear the safe boot flag, since we can't trust its content after reset PRCMClearSafeBootRequest(); }
void timerInit() { #ifdef TARGET_IS_BLIZZARD_RB1 // // Run at system clock at 80MHz // MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ| SYSCTL_OSC_MAIN); #else // // Run at system clock at 120MHz // MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ|SYSCTL_OSC_MAIN|SYSCTL_USE_PLL|SYSCTL_CFG_VCO_480), F_CPU); #endif // // SysTick is used for delay() and delayMicroseconds() // MAP_SysTickPeriodSet(F_CPU / SYSTICKHZ); MAP_SysTickEnable(); MAP_IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY); MAP_SysTickIntEnable(); MAP_IntMasterEnable(); // PIOSC is used during Deep Sleep mode for wakeup MAP_SysCtlPIOSCCalibrate(SYSCTL_PIOSC_CAL_FACT); // Factory-supplied calibration used }
//***************************************************************************** // //! Board Initialization & Configuration //! //! \param None //! //! \return None // //***************************************************************************** static void BoardInit(void) { // // Set vector table base // #ifndef USE_TIRTOS // // Set vector table base // #if defined(ccs) || defined(gcc) MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); #endif #if defined(ewarm) MAP_IntVTableBaseSet((unsigned long)&__vector_table); #endif #endif // // Enable Processor // MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); }
//***************************************************************************** //! Board Initialization & Configuration //***************************************************************************** static void bootmgr_board_init(void) { // set the vector table base MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // enable processor interrupts MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); // mandatory MCU initialization PRCMCC3200MCUInit(); // clear all the special bits, since we can't trust their content after reset // except for the WDT reset one!! PRCMClearSpecialBit(PRCM_SAFE_BOOT_BIT); PRCMClearSpecialBit(PRCM_FIRST_BOOT_BIT); // check the reset after clearing the special bits mperror_bootloader_check_reset_cause(); #if MICROPY_HW_ANTENNA_DIVERSITY // configure the antenna selection pins antenna_init0(); #endif // enable the data hashing engine CRYPTOHASH_Init(); // init the system led and the system switch mperror_init0(); }
//***************************************************************************** // //! Board Initialization & Configuration //! //! \param None //! //! \return None // //***************************************************************************** static void BoardInit(void) { /* In case of TI-RTOS vector table is initialize by OS itself */ #ifndef USE_TIRTOS // // Set vector table base // #if defined(ccs) MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); #endif //ccs #if defined(ewarm) MAP_IntVTableBaseSet((unsigned long)&__vector_table); #endif //ewarm #endif //USE_TIRTOS // // Enable Processor // MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); }
int platform_init() { // Set the clocking to run from PLL #if defined( FORLM3S9B92 ) || defined( FORLM3S9D92 ) MAP_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); #else MAP_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ); #endif // Setup PIO pios_init(); // Setup SSIs spis_init(); // Setup UARTs uarts_init(); // Setup timers timers_init(); // Setup PWMs pwms_init(); #ifdef BUILD_ADC // Setup ADCs adcs_init(); #endif #ifdef BUILD_CAN // Setup CANs cans_init(); #endif // Setup system timer cmn_systimer_set_base_freq( MAP_SysCtlClockGet() ); cmn_systimer_set_interrupt_freq( SYSTICKHZ ); // Setup ethernet (TCP/IP) eth_init(); // Common platform initialization code cmn_platform_init(); // Virtual timers // If the ethernet controller is used the timer is already initialized, so skip this sequence #if VTMR_NUM_TIMERS > 0 && !defined( BUILD_UIP ) // Configure SysTick for a periodic interrupt. MAP_SysTickPeriodSet( MAP_SysCtlClockGet() / SYSTICKHZ ); MAP_SysTickEnable(); MAP_SysTickIntEnable(); MAP_IntMasterEnable(); #endif // All done return PLATFORM_OK; }
/** * This function is used to unlock access to critical sections when lwipopt.h * defines SYS_LIGHTWEIGHT_PROT. It enables interrupts if the value of the lev * parameter indicates that they were enabled when the matching call to * sys_arch_protect() was made. * * @param lev is the interrupt level when the matching protect function was * called */ void sys_arch_unprotect(sys_prot_t lev) { /* Only turn interrupts back on if they were originally on when the matching sys_arch_protect() call was made. */ if(!(lev & 1)) { MAP_IntMasterEnable(); } }
static void BoardInit(void) { MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); }
//***************************************************************************** // //! Board Initialization & Configuration //! //! \param None //! //! \return None // //***************************************************************************** static void BoardInit(void) { // Set vector table base MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // Enable Processor MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); }
void initBoard() { #ifndef USE_TIRTOS #if defined(ccs) || defined(gcc) MAP_IntVTableBaseSet((unsigned long) &g_pfnVectors[0]); #endif #if defined(ewarm) MAP_IntVTableBaseSet((unsigned long)&__vector_table); #endif #endif MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); PinMuxConfig(); GPIO_IF_LedConfigure(LED1); GPIO_IF_LedOff(MCU_RED_LED_GPIO); InitTerm(); ClearTerm(); UART_PRINT("Blink - Parse for IoT sample application\r\n"); UART_PRINT("----------------------------------------\r\n"); UART_PRINT("\r\n"); UART_PRINT("[Blink] Board init\r\n"); // start the spawn task short status = VStartSimpleLinkSpawnTask(SPAWN_TASK_PRIORITY); if (status < 0) { UART_PRINT("[Blink] Spawn task failed\r\n"); ERR_PRINT(status); LOOP_FOREVER(); } // initialize the I2C bus status = I2C_IF_Open(I2C_MASTER_MODE_FST); if (status < 0) { UART_PRINT("[Blink] I2C opening error\r\n"); ERR_PRINT(status); LOOP_FOREVER(); } UART_PRINT("[Blink] Device : TI SimpleLink CC3200\r\n"); #ifdef USE_TIRTOS UART_PRINT("[Blink] Operating system : TI-RTOS\r\n"); #endif #ifdef USE_FREERTOS UART_PRINT("[Blink] Operating system : FreeRTOS\r\n"); #endif #ifndef SL_PLATFORM_MULTI_THREADED UART_PRINT("[Blink] Operating system : None\r\n"); #endif }
int main() { #ifndef USE_TIRTOS MAP_IntVTableBaseSet((unsigned long) &g_pfnVectors[0]); #endif MAP_IntEnable(FAULT_SYSTICK); MAP_IntMasterEnable(); PRCMCC3200MCUInit(); /* Console UART init. */ MAP_PRCMPeripheralClkEnable(CONSOLE_UART_PERIPH, PRCM_RUN_MODE_CLK); MAP_PinTypeUART(PIN_55, PIN_MODE_3); /* PIN_55 -> UART0_TX */ MAP_PinTypeUART(PIN_57, PIN_MODE_3); /* PIN_57 -> UART0_RX */ MAP_UARTConfigSetExpClk( CONSOLE_UART, MAP_PRCMPeripheralClockGet(CONSOLE_UART_PERIPH), CONSOLE_BAUD_RATE, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); MAP_UARTFIFOLevelSet(CONSOLE_UART, UART_FIFO_TX1_8, UART_FIFO_RX4_8); MAP_UARTFIFOEnable(CONSOLE_UART); setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); cs_log_set_level(LL_INFO); cs_log_set_file(stdout); LOG(LL_INFO, ("Hello, world!")); MAP_PinTypeI2C(PIN_01, PIN_MODE_1); /* SDA */ MAP_PinTypeI2C(PIN_02, PIN_MODE_1); /* SCL */ I2C_IF_Open(I2C_MASTER_MODE_FST); /* Set up the red LED. Note that amber and green cannot be used as they share * pins with I2C. */ MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK); MAP_PinTypeGPIO(PIN_64, PIN_MODE_0, false); MAP_GPIODirModeSet(GPIOA1_BASE, 0x2, GPIO_DIR_MODE_OUT); GPIO_IF_LedConfigure(LED1); GPIO_IF_LedOn(MCU_RED_LED_GPIO); if (VStartSimpleLinkSpawnTask(8) != 0) { LOG(LL_ERROR, ("Failed to create SL task")); } if (!mg_start_task(MG_TASK_PRIORITY, MG_TASK_STACK_SIZE, mg_init)) { LOG(LL_ERROR, ("Failed to create MG task")); } osi_start(); return 0; }
void SysPlatformConfig(void) /********************************************************************************/ { #if defined(COMPLIER_CCS) MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); #elif defined(COMPLIER_EARM) MAP_IntVTableBaseSet((unsigned long)&__vector_table); #endif /* Enable Processor */ MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); }
void HardwareSerial::end() { unsigned long ulInt = MAP_IntMasterDisable(); flushAll(); /* If interrupts were enabled when we turned them off, * turn them back on again. */ if(!ulInt) { MAP_IntMasterEnable(); } MAP_UARTIntDisable(UART_BASE, UART_INT_RT | UART_INT_TX); MAP_UARTIntUnregister(UART_BASE); }
//***************************************************************************** // //! Board Initialization & Configuration //! //! \param None //! //! \return None // //***************************************************************************** static void BoardInit(void) { /* In case of TI-RTOS vector table is initialize by OS itself */ // // Set vector table base // MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // // Enable Processor // MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); }
static void BoardInit() { MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); UDMAInit(); MAP_PRCMPeripheralClkEnable(PRCM_UARTA0, PRCM_RUN_MODE_CLK); MAP_PinTypeUART(PIN_55, PIN_MODE_3); MAP_PinTypeUART(PIN_57, PIN_MODE_3); InitTerm(); }
void suspend(void) { stay_asleep = true; HWREG(NVIC_SYS_CTRL) |= NVIC_SYS_CTRL_SLEEPDEEP; while(stay_asleep) { MAP_IntMasterDisable(); // Set PRIMASK so CPU wakes on IRQ but ISRs don't execute until PRIMASK is cleared MAP_SysTickDisable(); // Halt SysTick during suspend mode - millis will no longer increment CPUwfi_safe(); MAP_SysTickEnable(); // Re-enable SysTick before ISRs start (in case ISR uses millis/micros) MAP_IntMasterEnable(); // Clearing PRIMASK allows pending ISRs to run } HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP); }
void systick_init() { // // Configure SysTick for a periodic interrupt. // MAP_SysTickPeriodSet(MAP_SysCtlClockGet() / SYSTICKHZ); MAP_SysTickEnable(); MAP_SysTickIntEnable(); //MAP_IntEnable(INT_GPIOA); MAP_IntEnable(INT_GPIOE); MAP_IntMasterEnable(); MAP_SysCtlPeripheralClockGating(false); MAP_GPIOIntTypeSet(GPIO_PORTE_BASE, ENC_INT, GPIO_FALLING_EDGE); MAP_GPIOPinIntClear(GPIO_PORTE_BASE, ENC_INT); MAP_GPIOPinIntEnable(GPIO_PORTE_BASE, ENC_INT); UARTprintf("int enabled\n"); }
//***************************************************************************** // //! Empties the ring buffer. //! //! \param ptRingBuf is the ring buffer object to empty. //! //! Discards all data from the ring buffer. //! //! \return None. // //***************************************************************************** void RingBufFlush(tRingBufObject *ptRingBuf) { tBoolean bIntsOff; // // Check the arguments. // ASSERT(ptRingBuf != NULL); // // Set the Read/Write pointers to be the same. Do this with interrupts // disabled to prevent the possibility of corruption of the read index. // bIntsOff = MAP_IntMasterDisable(); ptRingBuf->ulReadIndex = ptRingBuf->ulWriteIndex; if(!bIntsOff) { MAP_IntMasterEnable(); } }
/** * This function will initial LPC40xx board. */ void rt_hw_board_init() { MAP_IntMasterDisable(); IntRegister(FAULT_HARD, HardFault_Handler); IntRegister(FAULT_PENDSV, PendSV_Handler); IntRegister(FAULT_SYSTICK, SysTick_Handler); // // Enable lazy stacking for interrupt handlers. This allows floating-point // instructions to be used within interrupt handlers, but at the expense of // extra stack usage. // MAP_FPULazyStackingEnable(); // // Set the clocking to run directly from the external crystal/oscillator. // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the // crystal on your board. // SysClock = MAP_SysCtlClockFreqSet( (SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), SYS_CLOCK_DEFAULT); MAP_SysTickDisable(); MAP_SysTickPeriodSet(SysClock/ RT_TICK_PER_SECOND - 1); MAP_SysTickIntEnable(); MAP_SysTickEnable(); /* set pend exception priority */ //IntPrioritySet(FAULT_PENDSV, (1 << 5) - 1); /*init uart device*/ rt_hw_uart_init(); //redirect RTT stdio to CONSOLE device rt_console_set_device(RT_CONSOLE_DEVICE_NAME); // // Enable interrupts to the processor. // MAP_IntMasterEnable(); }
//***************************************************************************** //! Board Initialization & Configuration //***************************************************************************** static void bootmgr_board_init(void) { // Set vector table base MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // Enable Processor Interrupts MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); // Mandatory MCU Initialization PRCMCC3200MCUInit(); mperror_bootloader_check_reset_cause(); // Enable the Data Hashing Engine HASH_Init(); // Init the system led and the system switch mperror_init0(); // clear the safe boot flag, since we can't trust its content after reset PRCMClearSafeBootRequest(); }
int main(void) { IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); MAP_PRCMPeripheralClkEnable(PRCM_GPIOA0, PRCM_RUN_MODE_CLK); MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK); MAP_PRCMPeripheralClkEnable(PRCM_GPIOA2, PRCM_RUN_MODE_CLK); MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK); MAP_IntMasterEnable(); PRCMCC3200MCUInit(); MAP_SysTickIntEnable(); MAP_SysTickPeriodSet(F_CPU / 1000); MAP_SysTickEnable(); setup(); for (;;) { loop(); if (serialEventRun) serialEventRun(); } }
//***************************************************************************** //! Board Initialization & Configuration //***************************************************************************** static void bootmgr_board_init(void) { // Set vector table base MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); // Enable Processor Interrupts MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); // Mandatory MCU Initialization PRCMCC3200MCUInit(); pybwdt_check_reset_cause(); // Enable the Data Hashing Engine HASH_Init(); // Init the system led and the system switch mperror_init0(); // clear the safe boot request, since we should not trust // the register's state after reset mperror_clear_safe_boot(); }
int main() { MAP_IntVTableBaseSet((unsigned long)vectors); MAP_IntMasterEnable(); MAP_IntEnable(FAULT_SYSTICK); PRCMCC3200MCUInit(); #ifdef UART_LOG MAP_PRCMPeripheralClkEnable(PRCM_UART_TERM, PRCM_RUN_MODE_CLK); MAP_PinTypeUART(PIN_TERM_TX, PIN_TERM_TX_MODE); MAP_PinTypeUART(PIN_TERM_RX, PIN_TERM_RX_MODE); MAP_UARTConfigSetExpClk(UART_TERM, MAP_PRCMPeripheralClockGet(PRCM_UART_TERM), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE)); #endif MonitorLoop(); asm(" BKPT"); while ( 1 ); return 0; }
//***************************************************************************** // //! initDriver //! //! @param None //! //! @return none //! //! @brief The function initializes a CC3000 device and triggers it to start //! operation // //***************************************************************************** int initDriver(void) { // Init GPIO's pio_init(); // Init Spi init_spi(); // Enable processor interrupts MAP_IntMasterEnable(); // WLAN On API Implementation wlan_init( CC3000_UsynchCallback, sendWLFWPatch, sendDriverPatch, sendBootLoaderPatch, ReadWlanInterruptPin, WlanInterruptEnable, WlanInterruptDisable, WriteWlanPin); // Trigger a WLAN device wlan_start(0); // Turn on the LED 1 (RED) to indicate that we are active and initiated WLAN successfully turnLedOn(1); // Mask out all non-required events from CC3000 wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE|HCI_EVNT_WLAN_UNSOL_INIT |HCI_EVNT_WLAN_ASYNC_PING_REPORT); DispatcherUARTConfigure(SysCtlClockGet()); SysCtlDelay(1000000); // Generate teh event to CLI: send a version string { char cc3000IP[50]; char *ccPtr; unsigned short ccLen; DispatcherUartSendPacket((unsigned char*)pucUARTExampleAppString, sizeof(pucUARTExampleAppString)); ccPtr = &cc3000IP[0]; ccLen = itoa(PALTFORM_VERSION, ccPtr); ccPtr += ccLen; *ccPtr++ = '.'; ccLen = itoa(APPLICATION_VERSION, ccPtr); ccPtr += ccLen; *ccPtr++ = '.'; ccLen = itoa(SPI_VERSION_NUMBER, ccPtr); ccPtr += ccLen; *ccPtr++ = '.'; ccLen = itoa(DRIVER_VERSION_NUMBER, ccPtr); ccPtr += ccLen; *ccPtr++ = '\f'; *ccPtr++ = '\r'; *ccPtr++ = '\0'; DispatcherUartSendPacket((unsigned char*)cc3000IP, strlen(cc3000IP)); } ucStopSmartConfig = 0; // Configure SysTick to occur X times per second, to use as a time // reference. Enable SysTick to generate interrupts. InitSysTick(); return(0); }
int main() { // // Enable lazy stacking for interrupt handlers. This allows floating-point // instructions to be used within interrupt handlers, but at the expense of // extra stack usage. // MAP_FPUEnable(); MAP_FPULazyStackingEnable(); // // Set the clocking to run from the PLL at 50MHZ, change to SYSCTL_SYSDIV_2_5 for 80MHz if neeeded // MAP_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); MAP_IntMasterDisable(); // // Initialize the SW2 button // MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // // Unlock PF0 so we can change it to a GPIO input // Once we have enabled (unlocked) the commit register then re-lock it // to prevent further changes. PF0 is muxed with NMI thus a special case. // HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01; HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0; MAP_GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_0); MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA , GPIO_PIN_TYPE_STD_WPU); // // Initialize the communication layer with a default UART setting // AbstractComm * comm = NULL; AbstractComm * uart_comm = new UARTComm(); purpinsComm communication(uart_comm); // // Initialize the robot object // purpinsRobot purpins; // // Initialize the EEPROM // purpinsSettings settings; // // Initialize the MPU6050-based IMU // mpudata_t mpu; //unsigned long sample_rate = 10 ; //mpu9150_init(0, sample_rate, 0); memset(&mpu, 0, sizeof(mpudata_t)); // // Get the current processor clock frequency. // ulClockMS = MAP_SysCtlClockGet() / (3 * 1000); //unsigned long loop_delay = (1000 / sample_rate) - 2; // // Configure SysTick to occur 1000 times per second // MAP_SysTickPeriodSet(MAP_SysCtlClockGet() / SYSTICKS_PER_SECOND); MAP_SysTickIntEnable(); MAP_SysTickEnable(); MAP_IntMasterEnable(); // // Load the settings from EEPROM // // Load the robot's ID settings.get(PP_SETTING_ID, &id, sizeof(uint32_t)); // Load the motors' PID gains settings.get(PP_SETTING_LEFT_PID, purpins.leftPIDGains(), sizeof(PIDGains)); settings.get(PP_SETTING_RIGHT_PID, purpins.rightPIDGains(), sizeof(PIDGains)); // Load the communication type uint32_t comm_type; settings.get(PP_SETTING_COMM_TYPE, &comm_type, sizeof(uint32_t)); // Holding SW2 at startup forces USB Comm if(comm_type != PP_COMM_TYPE_USB && MAP_GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_0) == 1) { if(comm_type == PP_COMM_TYPE_CC3000) { comm = new WiFiComm(); // Load network and server settings settings.get(PP_SETTING_NETWORK_DATA, (static_cast<WiFiComm*>(comm))->network(), sizeof(Network)); settings.get(PP_SETTING_SERVER_DATA, (static_cast<WiFiComm*>(comm))->server(), sizeof(Server)); // Set WiFiComm as the underlying communication layer communication.setCommLayer(comm); } else if(comm_type == PP_COMM_TYPE_ESP8266) { // TODO } else if(comm_type == PP_COMM_TYPE_XBEE) { // TODO } } // // Communication variables and stuff // uint8_t sensors_pack[SENSORS_PACK_SIZE]; bool send_pack = false; unsigned long sensor_streaming_millis = 0; unsigned long last_millis = millis(); uint8_t data[SERIAL_BUFFER_SIZE]; size_t data_size; uint8_t action; // // Main loop, just managing communications // while(1) { // // Check for a new action // action = communication.getMsg(data, data_size); // If we got an action... if(action > 0) { // Process it!!! if(action == PP_ACTION_GET_VERSION) { uint8_t version = VERSION; communication.sendMsg(PP_ACTION_GET_VERSION, (void*)(&version), 1); } else if(action == PP_ACTION_DRIVE) { RobotSpeed speed; memcpy(&speed, data, sizeof(speed)); purpins.setSpeed(&speed); communication.sendAck(PP_ACTION_DRIVE); } else if(action == PP_ACTION_DRIVE_MOTORS) { MotorSpeeds motor_speeds; memcpy(&motor_speeds, data, sizeof(motor_speeds)); purpins.setMotorSpeeds(&motor_speeds); communication.sendAck(PP_ACTION_DRIVE_MOTORS); } else if(action == PP_ACTION_DRIVE_PWM) { MotorPWMs motor_pwms; memcpy(&motor_pwms, data, sizeof(motor_pwms)); purpins.setPWM(&motor_pwms); communication.sendAck(PP_ACTION_DRIVE_PWM); } else if(action == PP_ACTION_GET_ODOMETRY) { Pose odometry; purpins.getOdometry(&odometry); communication.sendMsg(PP_ACTION_GET_ODOMETRY, (void*)(&odometry), sizeof(odometry)); } else if(action == PP_ACTION_GET_MOTOR_SPEEDS) { MotorSpeeds speed; purpins.getMotorSpeeds(&speed); communication.sendMsg(PP_ACTION_GET_MOTOR_SPEEDS, (void*)(&speed), sizeof(speed)); } else if(action == PP_ACTION_GET_ENCODER_PULSES) { EncoderPulses encoder_pulses; purpins.getEncoderTicks(&encoder_pulses); communication.sendMsg(PP_ACTION_GET_ENCODER_PULSES, (void*)(&encoder_pulses), sizeof(encoder_pulses)); } else if(action == PP_ACTION_GET_IMU) { IMU imu_data; imu_data.orientation_x = mpu.fusedQuat[0]; imu_data.orientation_y = mpu.fusedQuat[1]; imu_data.orientation_z = mpu.fusedQuat[2]; imu_data.orientation_w = mpu.fusedQuat[4]; imu_data.linear_acceleration_x = mpu.calibratedAccel[0]; imu_data.linear_acceleration_y = mpu.calibratedAccel[1]; imu_data.linear_acceleration_z = mpu.calibratedAccel[2]; imu_data.angular_velocity_x = mpu.calibratedMag[0]; imu_data.angular_velocity_y = mpu.calibratedMag[1]; imu_data.angular_velocity_z = mpu.calibratedMag[2]; communication.sendMsg(PP_ACTION_GET_IMU, (void*)(&imu_data), sizeof(imu_data)); } else if(action == PP_ACTION_GET_IR_SENSORS) { // TODO: Add the IR sensors } else if(action == PP_ACTION_GET_GAS_SENSOR) { // TODO: Add the gas sensor } else if(action == PP_ACTION_SET_SENSORS_PACK) { bool ok = true; memset(sensors_pack, 0, SENSORS_PACK_SIZE); if(data_size > SENSORS_PACK_SIZE) { communication.error(PP_ERROR_BUFFER_SIZE); ok = false; break; } for(unsigned int i=0 ; i<data_size ; i++) { if(data[i] < PP_ACTION_GET_ODOMETRY || data[i] > PP_ACTION_GET_GAS_SENSOR) { communication.error(PP_ERROR_SENSOR_UNKNOWN); ok = false; break; } } if(ok) { memcpy(sensors_pack, data, data_size); communication.sendAck(PP_ACTION_SET_SENSORS_PACK); } } else if(action == PP_ACTION_GET_SENSORS_PACK) { send_pack = true; } else if(action == PP_ACTION_SET_SENSOR_STREAMING) { float sensor_streaming_frequency; memcpy(&sensor_streaming_frequency, data, sizeof(sensor_streaming_frequency)); sensor_streaming_millis = 1/sensor_streaming_frequency * 1000; communication.sendAck(PP_ACTION_SET_SENSOR_STREAMING); } else if(action == PP_ACTION_SET_GLOBAL_POSE) { Pose pose; memcpy(&pose, data, sizeof(pose)); purpins.setGlobalPose(&pose); communication.sendAck(PP_ACTION_SET_GLOBAL_POSE); } else if(action == PP_ACTION_SET_NEIGHBORS_POSES) { // TODO: Finish this } else if(action == PP_ACTION_SET_ID) { memcpy(&id, data, sizeof(id)); settings.save(PP_SETTING_ID, data, sizeof(uint32_t)); communication.sendAck(PP_ACTION_SET_ID); } else if(action == PP_ACTION_GET_ID) { communication.sendMsg(PP_ACTION_GET_ID, (void*)(&id), sizeof(id)); } else if(action == PP_ACTION_SET_PID_GAINS) { memcpy(purpins.leftPIDGains(), data, sizeof(PIDGains)); memcpy(purpins.rightPIDGains(), data+sizeof(PIDGains), sizeof(PIDGains)); settings.save(PP_SETTING_LEFT_PID, data, sizeof(PIDGains)); settings.save(PP_SETTING_RIGHT_PID, data+sizeof(PIDGains), sizeof(PIDGains)); communication.sendAck(PP_ACTION_SET_PID_GAINS); } else if(action == PP_ACTION_GET_PID_GAINS) { memcpy(data, purpins.leftPIDGains(), sizeof(PIDGains)); memcpy(data+sizeof(PIDGains), purpins.rightPIDGains(), sizeof(PIDGains)); communication.sendMsg(PP_ACTION_GET_ID, (void*)(data), 2*sizeof(PIDGains)); } else if(action == PP_ACTION_SET_SERVER_DATA) { settings.save(PP_SETTING_SERVER_DATA, data, sizeof(Server)); communication.sendAck(PP_ACTION_SET_SERVER_DATA); } else if(action == PP_ACTION_GET_SERVER_DATA) { settings.get(PP_SETTING_SERVER_DATA, data, sizeof(Server)); communication.sendMsg(PP_ACTION_GET_SERVER_DATA, (void*)(data), sizeof(Server)); } else if(action == PP_ACTION_SET_NETWORK_DATA) { settings.save(PP_SETTING_NETWORK_DATA, data, sizeof(Network)); communication.sendAck(PP_ACTION_SET_NETWORK_DATA); } else if(action == PP_ACTION_GET_NETWORK_DATA) { settings.get(PP_SETTING_NETWORK_DATA, data, sizeof(Network)); communication.sendMsg(PP_ACTION_GET_NETWORK_DATA, (void*)(data), sizeof(Network)); } else if(action == PP_ACTION_SET_COMM_TYPE) { memcpy(&comm_type, data, sizeof(comm_type)); if(comm_type != communication.type()) { if(comm_type == PP_COMM_TYPE_USB) { communication.setCommLayer(uart_comm); if(comm != NULL) delete comm; } if(comm_type == PP_COMM_TYPE_CC3000) { if(comm != NULL) delete comm; comm = new WiFiComm(); // Load network and server settings settings.get(PP_SETTING_NETWORK_DATA, (static_cast<WiFiComm*>(comm))->network(), sizeof(Network)); settings.get(PP_SETTING_SERVER_DATA, (static_cast<WiFiComm*>(comm))->server(), sizeof(Server)); // Set WiFiComm as the underlying communication layer communication.setCommLayer(comm); } else if(comm_type == PP_COMM_TYPE_ESP8266) { // TODO } else if(comm_type == PP_COMM_TYPE_XBEE) { // TODO } else { communication.error(PP_ERROR_COMM_UNKNOWN); } communication.sendAck(PP_ACTION_SET_COMM_TYPE); } } } // if(action > 0) // // Manage sensor streaming // unsigned long current_millis = millis(); if(send_pack || (sensor_streaming_millis > 0 && (current_millis - last_millis) >= sensor_streaming_millis)) { size_t size = 0; for(int i=0 ; i<SENSORS_PACK_SIZE ; i++) { if(sensors_pack[i] == 0) break; if(sensors_pack[i] == PP_ACTION_GET_ODOMETRY) { Pose odometry; purpins.getOdometry(&odometry); memcpy(data+size, &odometry, sizeof(odometry)); size += sizeof(odometry); } else if(sensors_pack[i] == PP_ACTION_GET_MOTOR_SPEEDS) { MotorSpeeds speed; purpins.getMotorSpeeds(&speed); memcpy(data+size, &speed, sizeof(speed)); size += sizeof(speed); } else if(sensors_pack[i] == PP_ACTION_GET_ENCODER_PULSES) { EncoderPulses encoder_pulses; purpins.getEncoderTicks(&encoder_pulses); memcpy(data+size, &encoder_pulses, sizeof(encoder_pulses)); size += sizeof(encoder_pulses); } else if(sensors_pack[i] == PP_ACTION_GET_IMU) { IMU imu_data; imu_data.orientation_x = mpu.fusedQuat[0]; imu_data.orientation_y = mpu.fusedQuat[1]; imu_data.orientation_z = mpu.fusedQuat[2]; imu_data.orientation_w = mpu.fusedQuat[4]; imu_data.linear_acceleration_x = mpu.calibratedAccel[0]; imu_data.linear_acceleration_y = mpu.calibratedAccel[1]; imu_data.linear_acceleration_z = mpu.calibratedAccel[2]; imu_data.angular_velocity_x = mpu.calibratedMag[0]; imu_data.angular_velocity_y = mpu.calibratedMag[1]; imu_data.angular_velocity_z = mpu.calibratedMag[2]; memcpy(data+size, &imu_data, sizeof(imu_data)); size += sizeof(imu_data); } else if(sensors_pack[i] == PP_ACTION_GET_IR_SENSORS) { // TODO: Add the IR sensors } else if(sensors_pack[i] == PP_ACTION_GET_GAS_SENSOR) { // TODO: Add the gas sensor } } communication.sendMsg(PP_ACTION_GET_SENSORS_PACK, (void*)(data), size); last_millis = current_millis; send_pack = false; } // if(send_pack ... } // while(1) return 0; }
int main(void) { int delay; float fTemperature, fPressure, fAltitude, fK_Altitude, fAltitude_sum,fK_Altitude_sum; int count,i; // static float f_meas[VAR_COUNT], fAlt_Mean, fAlt_Var; unsigned short sw1_count, sw2_count; unsigned char sw1_was_cleared = 0, sw2_was_cleared = 0; // Set the clocking to run directly from the external crystal/oscillator. MAP_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | WRFL_XTAL); //init ports and peripherals PlatformInit(); Nokia5110_Init(); Nokia5110_Clear(); Nokia5110_DrawFullImage(gears_logo); for(delay=0; delay<1000000; delay=delay+1); Nokia5110_Clear(); Nokia5110_SetCursor(3, 1); Nokia5110_OutString("WRFL"); Nokia5110_SetCursor(1, 2); Nokia5110_OutString("Prototype"); Nokia5110_SetCursor(2, 4); Nokia5110_OutString("VER 0.1"); Nokia5110_SetCursor(0, 5); Nokia5110_OutString("NightMecanic"); for(delay=0; delay<1000000; delay=delay+1); Nokia5110_Clear(); // // Enable interrupts to the processor. // MAP_IntMasterEnable(); // // Initialize I2C1 peripheral. // I2CMInit(&g_sI2CInst, BMP180_I2C_BASE, BMP180_I2C_INT, 0xff, 0xff, MAP_SysCtlClockGet()); // // Initialize the BMP180 // BMP180Init(&g_sBMP180Inst, &g_sI2CInst, BMP180_I2C_ADDRESS, BMP180AppCallback, &g_sBMP180Inst); // // Wait for initialization callback to indicate reset request is complete. // while(g_vui8DataFlag == 0) { // // Wait for I2C Transactions to complete. // } // // Reset the data ready flag // g_vui8DataFlag = 0; //set oversampling to 8x g_sBMP180Inst.ui8Mode = 0xC0; //Initialize the Kalman filter Kalman_Init(&Alt_KState, 0.0f, 1.0f, ALT_KALMAN_R, ALT_KALMAN_Q); // // Enable the system ticks at 10 hz. // MAP_SysTickPeriodSet(MAP_SysCtlClockGet() / (40 * 3)); MAP_SysTickIntEnable(); MAP_SysTickEnable(); Nokia5110_SetCursor(0, 0); Nokia5110_OutString("SW1:"); Nokia5110_SetCursor(0, 2); Nokia5110_OutString("SW2:"); //config done count = 0; // // Begin the data collection and printing. Loop Forever. // while(1) { // SW1 if (sw_state & SW1){ if (sw1_was_cleared){ sw1_was_cleared = 0; sw1_count++; Nokia5110_SetCursor(5, 0); Nokia5110_OutUDec(sw1_count); } }else sw1_was_cleared = 1; //SW2 if (sw_state & SW2){ if (sw2_was_cleared){ sw2_was_cleared = 0; sw2_count++; Nokia5110_SetCursor(5, 2); Nokia5110_OutUDec(sw2_count); } }else sw2_was_cleared = 1; // handle BMP180 data (display average every 50 samples) if (g_vui8DataFlag ){ // // Reset the data ready flag. // g_vui8DataFlag = 0; // // Get a local copy of the latest temperature data in float format. // BMP180DataTemperatureGetFloat(&g_sBMP180Inst, &fTemperature); // // Print temperature with three digits of decimal precision. // //Nokia5110_SetCursor(0, 0); //Nokia5110_OutString("Temp:"); //Nokia5110_OutFloatp3(fTemperature); // // Get a local copy of the latest air pressure data in float format. // BMP180DataPressureGetFloat(&g_sBMP180Inst, &fPressure); // // Print Pressure with three digits of decimal precision. // //Nokia5110_SetCursor(0, 1); // Nokia5110_OutString("Pres:"); //Nokia5110_SetCursor(0, 2); //display in hPa //Nokia5110_OutFloatp3((fPressure / 100.0f)); // // Calculate the altitude. // //fAltitude = 44330.0f * (1.0f - powf(fPressure / 101325.0f, // 1.0f / 5.255f)); //corrected: fAltitude = 44330.0f * (1.0f - powf(fPressure / LOC_ALT_P0, 1.0f / 5.255f)); // Kalman filtered altitude Kalman_Update (&Alt_KState, fAltitude); fK_Altitude = Alt_KState.X; fAltitude_sum += fAltitude; fK_Altitude_sum += fK_Altitude; count++; if (count>=50){ Nokia5110_SetCursor(0, 3); Nokia5110_OutString("Alt:"); Nokia5110_OutFloatp3(fAltitude_sum/50.0); Nokia5110_SetCursor(0, 5); Nokia5110_OutString("KAlt:"); Nokia5110_OutFloatp3(fK_Altitude_sum/50.0); fAltitude_sum = 0; fK_Altitude_sum = 0; count = 0; } /* //calculate variance f_meas[count]=fK_Altitude; count++; if (count>=VAR_COUNT){ fAlt_Mean = 0.0f; fAlt_Var = 0.0f; // calculate mean for(i=0; i<VAR_COUNT; i++){ fAlt_Mean = fAlt_Mean +f_meas[i]; } fAlt_Mean = fAlt_Mean/((float) VAR_COUNT); // Calculate Var for(i=0; i<VAR_COUNT; i++){ fAlt_Var = fAlt_Var + powf((f_meas[i] - fAlt_Mean),2.0f); } fAlt_Var = fAlt_Var/((float) VAR_COUNT); // // Print altitude with three digits of decimal precision. // Nokia5110_SetCursor(0, 4); Nokia5110_OutString("Var:"); Nokia5110_OutFloatp3(fAlt_Var); count = 0; } */ // // Delay to keep printing speed reasonable. About 100msec. // //MAP_SysCtlDelay(MAP_SysCtlClockGet() / (10 * 3)); } }//while end }
void main(void) { static struct uip_eth_addr eth_addr; uip_ipaddr_t ipaddr; cpu_init(); uart_init(); printf("Welcome\n"); spi_init(); enc28j60_comm_init(); printf("Welcome\n"); enc_init(mac_addr); // // Configure SysTick for a periodic interrupt. // MAP_SysTickPeriodSet(MAP_SysCtlClockGet() / SYSTICKHZ); MAP_SysTickEnable(); MAP_SysTickIntEnable(); //MAP_IntEnable(INT_GPIOA); MAP_IntEnable(INT_GPIOE); MAP_IntMasterEnable(); MAP_SysCtlPeripheralClockGating(false); printf("int enabled\n"); MAP_GPIOIntTypeSet(GPIO_PORTE_BASE, ENC_INT, GPIO_FALLING_EDGE); MAP_GPIOPinIntClear(GPIO_PORTE_BASE, ENC_INT); MAP_GPIOPinIntEnable(GPIO_PORTE_BASE, ENC_INT); uip_init(); eth_addr.addr[0] = mac_addr[0]; eth_addr.addr[1] = mac_addr[1]; eth_addr.addr[2] = mac_addr[2]; eth_addr.addr[3] = mac_addr[3]; eth_addr.addr[4] = mac_addr[4]; eth_addr.addr[5] = mac_addr[5]; uip_setethaddr(eth_addr); #define DEFAULT_IPADDR0 10 #define DEFAULT_IPADDR1 0 #define DEFAULT_IPADDR2 0 #define DEFAULT_IPADDR3 201 #define DEFAULT_NETMASK0 255 #define DEFAULT_NETMASK1 255 #define DEFAULT_NETMASK2 255 #define DEFAULT_NETMASK3 0 #undef STATIC_IP #ifdef STATIC_IP uip_ipaddr(ipaddr, DEFAULT_IPADDR0, DEFAULT_IPADDR1, DEFAULT_IPADDR2, DEFAULT_IPADDR3); uip_sethostaddr(ipaddr); printf("IP: %d.%d.%d.%d\n", DEFAULT_IPADDR0, DEFAULT_IPADDR1, DEFAULT_IPADDR2, DEFAULT_IPADDR3); uip_ipaddr(ipaddr, DEFAULT_NETMASK0, DEFAULT_NETMASK1, DEFAULT_NETMASK2, DEFAULT_NETMASK3); uip_setnetmask(ipaddr); #else uip_ipaddr(ipaddr, 0, 0, 0, 0); uip_sethostaddr(ipaddr); printf("Waiting for IP address...\n"); uip_ipaddr(ipaddr, 0, 0, 0, 0); uip_setnetmask(ipaddr); #endif httpd_init(); #ifndef STATIC_IP dhcpc_init(mac_addr, 6); dhcpc_request(); #endif long lPeriodicTimer, lARPTimer; lPeriodicTimer = lARPTimer = 0; int i; // = MAP_GPIOPinRead(GPIO_PORTA_BASE, ENC_INT) & ENC_INT; while(true) { //MAP_IntDisable(INT_UART0); MAP_SysCtlSleep(); //MAP_IntEnable(INT_UART0); //i = MAP_GPIOPinRead(GPIO_PORTA_BASE, ENC_INT) & ENC_INT; /*while(i != 0 && g_ulFlags == 0) { i = MAP_GPIOPinRead(GPIO_PORTA_BASE, ENC_INT) & ENC_INT; }*/ if( HWREGBITW(&g_ulFlags, FLAG_ENC_INT) == 1 ) { HWREGBITW(&g_ulFlags, FLAG_ENC_INT) = 0; enc_action(); } if(HWREGBITW(&g_ulFlags, FLAG_SYSTICK) == 1) { HWREGBITW(&g_ulFlags, FLAG_SYSTICK) = 0; lPeriodicTimer += SYSTICKMS; lARPTimer += SYSTICKMS; //printf("%d %d\n", lPeriodicTimer, lARPTimer); } if( lPeriodicTimer > UIP_PERIODIC_TIMER_MS ) { lPeriodicTimer = 0; int l; for(l = 0; l < UIP_CONNS; l++) { uip_periodic(l); // // If the above function invocation resulted in data that // should be sent out on the network, the global variable // uip_len is set to a value > 0. // if(uip_len > 0) { uip_arp_out(); enc_send_packet(uip_buf, uip_len); uip_len = 0; } } for(l = 0; l < UIP_UDP_CONNS; l++) { uip_udp_periodic(l); if( uip_len > 0) { uip_arp_out(); enc_send_packet(uip_buf, uip_len); uip_len = 0; } } } if( lARPTimer > UIP_ARP_TIMER_MS) { lARPTimer = 0; uip_arp_timer(); } } }