static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA) { if (Channel[timer] < 0) *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer else { if (SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive) digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated } Channel[timer]++; // increment to the next channel if (SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks; if (SERVO(timer,Channel[timer]).Pin.isActive) // check if activated digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high } else { // finished all channels so wait for the refresh period to expire before starting over if ( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed *OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL); else *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel } }
uint8_t Servo::attach(int pin, int minimum, int maximum) { if (servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); servo_pin[servoIndex] = pin; servo_ticks[servoIndex] = usToTicks(DEFAULT_PULSE_WIDTH); servo_active_mask |= (1<<servoIndex); min_ticks = usToTicks(minimum); max_ticks = usToTicks(maximum); if (!(SIM_SCGC6 & SIM_SCGC6_PDB)) { SIM_SCGC6 |= SIM_SCGC6_PDB; // TODO: use bitband for atomic bitset PDB0_MOD = 0xFFFF; PDB0_CNT = 0; PDB0_IDLY = 0; PDB0_SC = PDB_CONFIG; // TODO: maybe this should be a higher priority than most // other interrupts (init all to some default?) PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; } NVIC_ENABLE_IRQ(IRQ_PDB); } return servoIndex; }
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel) { // clear interrupt tc->TC_CHANNEL[channel].TC_SR; if (Channel[timer] < 0) tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // channel set to -1 indicated that refresh interval completed so reset the timer else if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive) extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated Channel[timer]++; // increment to the next channel if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer,Channel[timer]).ticks; if (SERVO(timer,Channel[timer]).Pin.isActive) // check if activated extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // its an active channel so pulse it high } else { // finished all channels so wait for the refresh period to expire before starting over tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV < usToTicks(REFRESH_INTERVAL) - 4 ? (unsigned int)usToTicks(REFRESH_INTERVAL) // allow a few ticks to ensure the next OCR1A not missed : tc->TC_CHANNEL[channel].TC_CV + 4; // at least REFRESH_INTERVAL has elapsed Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel } }
static mp_obj_t servo_obj_angle(int n_args, const mp_obj_t *args) { pyb_servo_obj_t *self = args[0]; if (n_args == 1) { // get float angle = map_uint_to_float(servo_ticks[self->servo_id], usToTicks(self->min_usecs), usToTicks(self->max_usecs), 0.0, 180.0); return mp_obj_new_float(angle); } // Set float angle = mp_obj_get_float(args[1]); if (angle < 0.0F) { angle = 0.0F; } if (angle > 180.0F) { angle = 180.0F; } servo_ticks[self->servo_id] = map_float_to_uint(angle, 0.0F, 180.0F, usToTicks(self->min_usecs), usToTicks(self->max_usecs)); return mp_const_none; }
Servo::Servo() { if (ServoCount < MAX_SERVOS) { /// TODO: Really, we need to search through servos[] for the first one /// that is not being used, rather than always use ServoCount as the /// index. What happens if you create 24 servos, then destroy one /// and create another. Right now that would fail, even though you /// weren't actively using 24 servos. this->servoIndex = ServoCount++; // assign a servo index to this instance servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default to neutral position } else this->servoIndex = INVALID_SERVO ; // too many servos }
void Servo::writeMicroseconds(int value) { // calculate and store the values for the given channel byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { if( value < SERVO_MIN() ) // ensure pulse width is valid value = SERVO_MIN(); else if( value > SERVO_MAX() ) value = SERVO_MAX(); value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 servos[channel].ticks = value; // this is atomic on a 16bit uC, no need to disable Interrupts } }
static mp_obj_t servo_obj_usecs(int n_args, const mp_obj_t *args) { pyb_servo_obj_t *self = args[0]; uint usecs; if (n_args == 1) { // get return MP_OBJ_NEW_SMALL_INT(ticksToUs(servo_ticks[self->servo_id])); } // Set usecs = mp_obj_get_int(args[1]); if (self->min_usecs < self->max_usecs) { usecs = clamp(usecs, self->min_usecs, self->max_usecs); } else { usecs = clamp(usecs, self->max_usecs, self->min_usecs); } servo_ticks[self->servo_id] = usToTicks(usecs); return mp_const_none; }
void Servo::writeMicroseconds(int value) { // calculate and store the values for the given channel byte channel = this->servoIndex; if (channel < MAX_SERVOS) { // ensure channel is valid if (value < SERVO_MIN()) // ensure pulse width is valid value = SERVO_MIN(); else if (value > SERVO_MAX()) value = SERVO_MAX(); value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 uint8_t oldSREG = SREG; cli(); servos[channel].ticks = value; SREG = oldSREG; } }
void Servo_writeMicroseconds(byte servoIndex, int value) { if( (servoIndex < MAX_SERVOS) ) // ensure channel is valid { if( value < SERVO_MIN() ) // ensure pulse width is valid value = SERVO_MIN(); else if( value > SERVO_MAX() ) value = SERVO_MAX(); value = value - SERVO_TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 uint8_t oldSREG = SREG; cli(); servos[servoIndex].ticks = value; SREG = oldSREG; } }
void Servo::writeMicroseconds(int value) { // calculate and store the values for the given channel byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { if( value < SERVO_MIN() ) // ensure pulse width is valid value = SERVO_MIN(); else if( value > SERVO_MAX() ) value = SERVO_MAX(); value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 CCTL0 = 0; // disable interrupt to avoid race condition servos[channel].ticks = value; CCTL0 = CCIE; } }
//************************************************************************ void Servo::writeMicroseconds(int value) { // calculate and store the values for the given channel byte channel = this->servoIndex; if ( (channel >= 0) && (channel < MAX_SERVOS) ) // ensure channel is valid { if ( value < SERVO_MIN() ) // ensure pulse width is valid value = SERVO_MIN(); else if ( value > SERVO_MAX() ) value = SERVO_MAX(); value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead unsigned int status; status = disableInterrupts(); servos[channel].ticks = value; restoreInterrupts(status); } }
/* write(value, speed) - Just like write but at reduced speed. value - Target position for the servo. Identical use as value of the function write. speed - Speed at which to move the servo. speed=0 - Full speed, identical to write speed=1 - Minimum speed speed=255 - Maximum speed */ void Servo::write(float value, uint8_t speed) { // This fuction is a copy of write and writeMicroseconds but value will be saved // in target instead of in ticks in the servo structure and speed will be save // there too. //double degrees = value; if (speed) { if (value < MIN_PULSE_WIDTH) { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) // updated to use constrain instead of if, pva value = value * 10;//make the value tem times bigger, must after the if() detection or if() will fail value = constrain(value, 0, 1800); value = map(value, 0, 1800, SERVO_MIN(), SERVO_MAX()); } // calculate and store the values for the given channel byte channel = this->servoIndex; if( (channel >= 0) && (channel < MAX_SERVOS) ) { // ensure channel is valid // updated to use constrain instead of if, pva //value = constrain(value, SERVO_MIN(), SERVO_MAX()); //Serial.println(value,DEC); //value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 // Set speed and direction uint8_t oldSREG = SREG; cli(); servos[channel].target = value; servos[channel].speed = speed; SREG = oldSREG; } } else { write (value); } }
static void initISR(timer16_Sequence_t timer) { if( timer == _timer1){ if( SRV_TAUxEN == 0 ){ #ifdef WORKAROUND_READ_MODIFY_WRITE SBI2( SRV_SFR2_PERx, SRV_SFR2_BIT_TAUxEN ); /* supplies input clock */ #else SRV_TAUxEN = 1U; /* supplies input clock */ #endif SRV_TPSx = TIMER_CLOCK; } #ifdef WORKAROUND_READ_MODIFY_WRITE /* Set INTTM04 low priority */ SBI( SRV_SFR_PR1xx, SRV_SFR_BIT_TMPR1xx ); SBI( SRV_SFR_PR0xx, SRV_SFR_BIT_TMPR0xx ); /* Mask channel 04 interrupt */ CBI( SRV_SFR_MKxx, SRV_SFR_BIT_TMMKxx ); /* enable INTTM04 interrupt */ CBI( SRV_SFR_IFxx, SRV_SFR_BIT_TMIFxx ); /* clear INTTM04 interrupt flag */ #else /* Set INTTM04 low priority */ SRV_TMPR1xx = 1U; SRV_TMPR0xx = 1U; /* Mask channel 04 interrupt */ SRV_TMMKxx = 0U; /* enable INTTM04 interrupt */ SRV_TMIFxx = 0U; /* clear INTTM04 interrupt flag */ #endif /* Channel 0 used as interval timer */ SRV_TMRxx = 0x8000U; SRV_TDRxx = (unsigned int)usToTicks(REFRESH_INTERVAL); SRV_TSx |= SRV_CHx; /* operation is enabled (start trigger is generated) */ delay(1); Channel[timer] = -1; handle_interrupts(_timer1); /* TDR0x setting */ } }
void Servo::writeMicroseconds(int value) { // calculate and store the values for the given channel byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { if( value < SERVO_MIN() ) // ensure pulse width is valid value = SERVO_MIN(); else if( value > SERVO_MAX() ) value = SERVO_MAX(); value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 #if defined(REL_GR_KURUMI) servos[channel].ticks = value; #else noInterrupts(); servos[channel].ticks = value; interrupts(); #endif } }
void init_servo(void) { // for servo SIM_SCGC6 |= SIM_SCGC6_PDB; // TODO: use bitband for atomic read-mod-write pinMode(12, OUTPUT); PDB0_MOD = 0xFFFF; PDB0_CNT = 0; PDB0_IDLY = 0; PDB0_SC = PDB_CONFIG; NVIC_ENABLE_IRQ(IRQ_PDB); // TODO: maybe this should be a higher priority than most // other interrupts (init all to some default?) PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; //servo_active_mask = 9; servo_active_mask = 8; //servo_pin[0] = 12; //servo_ticks[0] = usToTicks(600); servo_pin[3] = 11; servo_ticks[3] = usToTicks(2100); //pinMode(12, OUTPUT); pinMode(11, OUTPUT); }
mp_obj_t pyb_Servo(void) { uint16_t mask; pyb_servo_obj_t *self = m_new_obj(pyb_servo_obj_t); self->base.type = &servo_obj_type; self->min_usecs = MIN_PULSE_WIDTH; self->max_usecs = MAX_PULSE_WIDTH; /* Find an unallocated servo id */ self->servo_id = 0; for (mask=1; mask < (1<<MAX_SERVOS); mask <<= 1) { if (!(servo_allocated_mask & mask)) { servo_allocated_mask |= mask; servo_active_mask &= ~mask; servo_ticks[self->servo_id] = usToTicks(DEFAULT_PULSE_WIDTH); return self; } self->servo_id++; } m_del_obj(pyb_servo_obj_t, self); mp_raise_ValueError("No available servo ids"); return mp_const_none; }
// Value is a float, in us. and represents the on-time for this servo pin // Pin is the pin number being changed int32_t SoftPWMServoServoWrite(uint32_t Pin, float Value) { SoftPWMServoRawWrite(Pin, usToTicks(Value), SOFTPWMSERVO_SERVO); return SOFTPWMSERVO_OK; }
void hwTimerCallback( void ) { int i, j; int logicState = 1; int logicStateLen = 0; bool repeatCode = false; /* stop the HW TIMER */ RTC_REG_WRITE(FRC1_CTRL_ADDRESS, DIVDED_BY_16 | TM_EDGE_INT); //Set GPIO0 to LOW gpio_output_set(0, BIT0, BIT0, 0); /* load the HW TIMER for next IR message frame */ uint32 ticks = usToTicks(70000); RTC_REG_WRITE(FRC1_LOAD_ADDRESS, ticks); /* derive the raw IR message frame */ for( i = 0 ; i < ( edgeIndex - 1 ) ; i++) { /* find number of bits in current interval */ logicStateLen = ( intervalArr[i] / minInterval ); for( j = 0 ; j < logicStateLen ; j++) { rawIrMsg[ rawIrMsgLen ] = logicState; rawIrMsgLen++; } /* toggle state */ logicState ^= 1; #if 0 os_printf( "\r\nDuration of interval %d: %d us\r\n", i, intervalArr[i] ); #endif } #if 1 /* print the received raw IR message frame */ os_printf( "\r\nRAW IR CODE: "); for ( i = 0 ; i < rawIrMsgLen ; i++ ) { os_printf( "%d", rawIrMsg[i] ); } #endif /********************************************** * DECODE NEC MESSAGE FRAME! * - every message frame contains 32 coded bits **********************************************/ /* set index to the beginning of the coded bits */ /* the message frame starts with a burst of 16 logic 1's, skip them all */ i = 0 ; while ( rawIrMsg[i] == 1 ) i++; /* the message frame continues with a burst of 8 logic 0's, skip them all */ j = 0; while (rawIrMsg[i] == 0) { i++; j++; } /* if the number of zeros is 4, then ignore the current message frame since * it corresponds to a "REPEATED CODE". */ if ( j <= 4 ) { #if 1 os_printf( "\r\nREPEATED CODE"); #endif repeatCode = true; } /* decode raw message only if it is not a repeat code */ if (repeatCode == false) { /* at this point 'i' contains the index of the beginning of the encoded bits */ /* decode raw message * - [1][0][0][0] represents a '1' * - [1][0] represents a '0' */ irCmd = 0; for (j = 0; j < 32; j++) { if (rawIrMsg[i + 2] == 0) { /* it is a '1', so left shift a '1' */ irCmd = (irCmd << 1) | 1; /* move to the beginning of the next encoded bit * (increment i until next 1 in raw message frame) */ do {i++;} while ( rawIrMsg[i] == 0 ); } else { /* it is a '0', so left shift a '0' */ irCmd = irCmd << 1; /* move to the beginning of the next encoded bit */ i += 2; } } #if 1 /* print the received IR cmd */ os_printf("\r\nIR CMD: %x", irCmd); #endif } /********************************************** * END - DECODE NEC MESSAGE FRAME! * - every message frame contains 32 coded bits **********************************************/ /* reset index */ edgeIndex = 0; #if 1 os_printf("\r\nEnd of IR message frame\r\n"); #endif return; }
// initialize the custom stuff that goes beyond esp-link void user_init() { // Initialize the GPIO subsystem. gpio_init(); /* ====================================== */ /* UART */ /* ====================================== */ // Initialize UART0 and UART1 /* NOTE: UART1 and I2S share same GPIO. Cannot use simultaneously. */ uart_init( BIT_RATE_115200, BIT_RATE_115200 ); // uart0_sendStr( "\nUART0 - USED TO PROGRAM THE MODULE\n" ); os_printf("\n===================\nUART1 - DEBUG OUPUT\n===================\n"); /* NOTE: PWM CANNOT BE USED SIMULTANEOUSLY WITH HW TIMER */ #if 0 /* ====================================== */ /* PWM */ /* ====================================== */ uint32 pwm_period = 1000; uint32 pwm_duty[PWM_CHANNEL] = {0}; uint32 io_info[][3] = { {PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM}, {PWM_1_OUT_IO_MUX,PWM_1_OUT_IO_FUNC,PWM_1_OUT_IO_NUM}, }; /* PIN FUNCTION INIT FOR PWM OUTPUT */ pwm_init(pwm_period, pwm_duty, PWM_CHANNEL, io_info); /* set pwm_duty cycle */ pwm_set_duty (14185, 0); pwm_set_duty (22222, 1); // todo: explain why 22222 is the highest possible value /* start PWM */ pwm_start(); // NOTE: PWM causes spikes in other GPIOs #endif /* ====================================== */ /* GPIO INTERRPUT */ /* ====================================== */ /* Set GPIO12 in GPIO mode */ PIN_FUNC_SELECT( PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12 ); /* Set GPIO12 as input */ GPIO_DIS_OUTPUT( GPIO_ID_PIN(12) ); /* Disable all GPIO interrupts */ ETS_GPIO_INTR_DISABLE(); /* Set a GPIO callback function */ ETS_GPIO_INTR_ATTACH( gpioCallback, NULL ); /* Configure the type of edge */ gpio_pin_intr_state_set( GPIO_ID_PIN(12), GPIO_PIN_INTR_ANYEDGE ); ETS_GPIO_INTR_ENABLE(); /* ====================================== */ /* SOFTWARE TIMER */ /* ====================================== */ // Set GPIO0 to output mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0); //Set GPIO0 low gpio_output_set(0, RELAY_PIN, RELAY_PIN, 0); /* disarm timer */ os_timer_disarm((ETSTimer*)&some_timer); /* set callback */ os_timer_setfn((ETSTimer*)&some_timer, (os_timer_func_t *) softwareTimerCallback, NULL); /* arm the timer -> os_timer_arm(<pointer>, <period in ms>, <fire periodically>) */ os_timer_arm((ETSTimer*)&some_timer, 10, 1); /* ====================================== */ /* OS TASK */ /* ====================================== */ /* setup OS task */ // system_os_task(user_procTask, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen); /* send a message to OS task (fire task) */ // system_os_post(user_procTaskPrio, 0, 0 ); /* ====================================== */ /* HARDWARE TIMER */ /* ====================================== */ /* The hardware timer is used to indicate when a complete IR message frame should have * arrived in order to process the received data and calculate the IR command. * * It is configured in "one-shot" mode. It is started when the beginning of an * IR message frame is detected and stopped after the complete message frame has been read. * This means that the duration of the HW timer should be longer than the duration of * the longest message frame. In the NEC IR tranmission protocol all message frames have * a duration of approximately 67.5ms. */ /* load the HW TIMER */ uint32 ticks = usToTicks(70000); // 70ms RTC_REG_WRITE(FRC1_LOAD_ADDRESS, ticks); /* register callback function */ ETS_FRC_TIMER1_INTR_ATTACH( hwTimerCallback, NULL ); /* enable interrupts */ TM1_EDGE_INT_ENABLE(); ETS_FRC1_INTR_ENABLE(); /* don't start timer yet */ /* the timer is started inside the GPIO INT callback */ /* ====================================== */ /* UDP SERVER */ /* ====================================== */ /* usage: echo <data> | nc -wl -u <ip address> <port> * example: echo "foo" | nc -w1 -u 192.168.1.187 7777 */ /* allocate space for server */ pUdpServer = (struct espconn *) os_zalloc(sizeof(struct espconn)); /* clear allocated memory */ ets_memset(pUdpServer, 0, sizeof(struct espconn)); /* create the server */ espconn_create(pUdpServer); /* set the type of server */ pUdpServer->type = ESPCONN_UDP; /* allocate memory for UDP settings */ pUdpServer->proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp)); /* set the port that the server will be listening to */ pUdpServer->proto.udp->local_port = 7777; /* register the callback */ espconn_regist_recvcb(pUdpServer, udpServerRxCb); /* start listening */ if (espconn_create(pUdpServer)) { while (1) { os_printf("Error creating a UDP server\n"); } } /* ====================================== */ /* WIFI */ /* ====================================== */ wifi_set_opmode(STATION_MODE); wifi_station_get_config_default(&stconf); // os_strncpy((char*) stconf.ssid, "TP-LINK_2.4GHz_FC2E51", 32); // os_strncpy((char*) stconf.password, "tonytony", 64); os_strncpy((char*) stconf.ssid, "WLAN-PUB", 32); os_strncpy((char*) stconf.password, "", 64); // os_strncpy((char*) stconf.ssid, "MAD air", 32); // os_strncpy((char*) stconf.password, "glioninlog", 64); stconf.bssid_set = 0; wifi_station_set_config(&stconf); // /* ====================================== */ // /* WS2812 LED STRIP */ // /* ====================================== */ // // /* NOTE: UART1 and I2S share same GPIO. Cannot use simultaneously. */ // ws2812_init(); // // /* G R B */ // uint8_t ledout[] = { // 0xff, 0x00, 0x00, //4th //// 0xff, 0x00, 0x00, //3rd //// 0x00, 0xff, 0x00, //2nd //// 0x00, 0x00, 0xff, //1st // }; // //#if 0 // os_printf("\r\nB R G: %x %x %x\r\n", ledout[0], ledout[1],ledout[2]); //#endif // // ws2812_push( ledout, sizeof( ledout ) ); /* ====================================== */ /* TCP CONNECTION */ /* ====================================== */ /* allocate space for server */ pTcpConn = (struct espconn *) os_zalloc(sizeof(struct espconn)); /* clear allocated memory */ ets_memset(pTcpConn, 0, sizeof(struct espconn)); /* set the type of connection */ pTcpConn->type = ESPCONN_TCP; /* set state to NONE */ pTcpConn->state = ESPCONN_NONE; /* allocate memory for TCP settings */ pTcpConn->proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp)); /* set the port that the connection will be listening to */ pTcpConn->proto.tcp->local_port = espconn_port(); /* set the remote port and IP address */ pTcpConn->proto.tcp->remote_port = 80; os_memcpy(pTcpConn->proto.tcp->remote_ip, server_ip_address, sizeof(server_ip_address)); /* register callbacks */ espconn_regist_connectcb(pTcpConn, tcpConnCb); espconn_regist_reconcb(pTcpConn, tcpReconnCb); /* disarm timer */ os_timer_disarm((ETSTimer*)&wifi_setup_timer); /* set callback */ os_timer_setfn((ETSTimer*)&wifi_setup_timer, (os_timer_func_t *) wifiConnectTimerCb, NULL); /* arm the timer -> os_timer_arm(<pointer>, <period in ms>, <fire periodically>) */ os_timer_arm((ETSTimer*)&wifi_setup_timer, 5000, 1); return; }