/*! * \brief Create a new system timer. * * Applications should not call this function. * * \param ticks Specifies the timer interval in system ticks. * \param callback Identifies the function to be called on each * timer interval. * \param arg The argument passed to the callback function. * \param flags If set to TM_ONESHOT, the timer will be stopped * after the first interval. Set to 0 for periodic * timers. * * \return Timer handle if successfull, 0 otherwise. The handle * may be used to release the timer by calling TimerStop. * * \todo Make this local function static or directly integrate it into * NutTimerStartTicks(). */ NUTTIMERINFO * NutTimerCreate(uint32_t ticks, void (*callback) (HANDLE, void *), void *arg, uint8_t flags) { NUTTIMERINFO *tn; tn = NutHeapAlloc(sizeof(NUTTIMERINFO)); if (tn) { tn->tn_ticks_left = ticks + NutGetTickCount() - nut_ticks_resume; /* * Periodic timers will reload the tick counter on each timer * intervall. */ if (flags & TM_ONESHOT) { tn->tn_ticks = 0; } else { tn->tn_ticks = ticks; } /* Set callback and callback argument. */ tn->tn_callback = callback; tn->tn_arg = arg; } #ifdef NUTDEBUG if (__os_trf) fprintf(__os_trs, " TIM %p NutTimerCreate\n", tn); #endif return tn; }
/*! * \brief Return the milliseconds counter value. * * This function returns the value of a counter, which is incremented * every system timer tick. During system start, the counter is cleared * to zero and will overflow with the 32 bit tick counter (4294967296). * With the default 1024 ticks/s this will happen after 49.71 days. * The resolution is also given by the system ticks. * * \note There is intentionally no provision to modify the seconds counter. * Callers can rely on a continuous update and use this value for * system tick independend timeout calculations. * Depending on * * \return Value of the seconds counter. */ uint32_t NutGetMillis(void) { // carefully stay within 32 bit values uint32_t ticks = NutGetTickCount(); uint32_t seconds = ticks / NutGetTickClock(); ticks -= seconds * NutGetTickClock(); return seconds * 1000 + (ticks * 1000 ) / NutGetTickClock(); }
THREAD(DiscoveryResponder, arg) { UDPSOCKET *sock; DISCOVERY_TELE *dist; u_long raddr; u_short rport; int len; /* Insist on allocating a datagram buffer. */ while ((dist = malloc(sizeof(DISCOVERY_TELE))) == NULL) { NutSleep(1000); } /* Insist on creating a socket. */ while ((sock = NutUdpCreateSocket(disopt.disopt_port)) == NULL) { NutSleep(1000); } /* Nut/Net doesn't provide UDP datagram buffering by default. */ { u_short max_ms = sizeof(DISCOVERY_TELE) * 3; NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms)); } /* Create a pseudo random telegram identifier. */ memcpy(&xid, &confnet.cdn_mac[2], sizeof(xid)); xid += NutGetTickCount(); /* Optionally send initial announce datagram. */ if (disopt.disopt_flags & DISF_INITAL_ANN) { /* Variable sleep avoids broadcast storms in large installations. */ NutSleep(500 + (xid & 0x7FF)); if ((len = NutDiscoveryAnnTele(dist)) > 0) { NutUdpSendTo(sock, INADDR_BROADCAST, disopt.disopt_port, dist, len); } } /* Handle discovery telegrams in an endless loop. */ for (;;) { len = NutUdpReceiveFrom(sock, &raddr, &rport, dist, sizeof(DISCOVERY_TELE), 0); /* Updates may be filtered by an IP mask. */ if ((raddr & disopt.disopt_ipmask) == raddr && len > 0 && discovery_callback) { if ((len = discovery_callback(raddr, rport, dist, len)) > 0) { /* Broadcast response if destination is unreachable. */ if ((raddr & confnet.cdn_ip_mask) != (confnet.cdn_ip_addr & confnet.cdn_ip_mask)) { raddr = INADDR_BROADCAST; } NutUdpSendTo(sock, raddr, disopt.disopt_port, dist, len); } } /* Avoid system blocking by datagram storms. */ NutSleep(100); } }
/*! * \brief Process elapsed timers. * * This routine is called during context switch processing. * Applications should not use this function. */ void NutTimerProcessElapsed(void) { NUTTIMERINFO *tn; uint32_t ticks; uint32_t ticks_new; // calculate ticks since last call ticks = NutGetTickCount(); ticks_new = ticks - nut_ticks_resume; nut_ticks_resume = ticks; // process timers while (nutTimerList && ticks_new){ tn = nutTimerList; // subtract time if (ticks_new < tn->tn_ticks_left) { tn->tn_ticks_left -= ticks_new; ticks_new = 0; } else { ticks_new -= tn->tn_ticks_left; tn->tn_ticks_left = 0; } // elapsed if (tn->tn_ticks_left == 0){ // callback if (tn->tn_callback) { (*tn->tn_callback) (tn, (void *) tn->tn_arg); } // remove from list nutTimerList = nutTimerList->tn_next; if (nutTimerList) { nutTimerList->tn_prev = NULL; } if ((tn->tn_ticks_left = tn->tn_ticks) == 0) { #ifdef NUTDEBUG if (__os_trf) fprintf(__os_trs, " TIM %p free NutTimerProcessElapsed\n", tn); #endif NutHeapFree(tn); } else { // re-insert #ifdef NUTDEBUG if (__os_trf) fprintf(__os_trs, " TIM %p reinsert NutTimerProcessElapsed\n", tn); #endif NutTimerInsert(tn); } } } }
void NutTimerInit(void) { #ifdef __NUT_EMULATION__ gettimeofday( &timeStart, NULL ); #else NutRegisterTimer(NutTimerIntr); NutEnableTimerIrq(); //Not Used /* Remember the CPU clock for which the loop counter is valid. */ //Not Used nut_delay_loops_clk = NutGetCpuClock(); #if !defined(NUT_DELAYLOOPS) #ifndef NUT_TICK_FREQ #define NUT_TICK_FREQ 1000UL #endif { /* Wait for the next tick. */ uint32_t cnt = NutGetTickCount(); while (cnt == NutGetTickCount()); /* Wait for the next tick, counting loops. */ cnt = NutGetTickCount(); while (cnt == NutGetTickCount()) { nut_delay_loops++; } /* * The loop above needs more cycles than the actual delay loop. * Apply the correction found by trial and error. Works acceptable * with GCC for Ethernut 1 and 3. */ #if defined(__AVR__) nut_delay_loops *= 103UL; nut_delay_loops /= 26UL; #else //nut_delay_loops *= 137UL; //nut_delay_loops /= 25UL; //nut_delay_loops *= 190UL; //nut_delay_loops /= 25UL; nut_delay_loops *= 185UL; nut_delay_loops /= 24UL; #endif } #endif #endif }
/* * \brief Default discovery datagram handler. * * \param ip Sender's IP address. * \param port Sender's UDP port. * \param dtel Pointer to the UDP telegram buffer. * \param len UDP telegram size. */ static int NutDiscoveryHandler(u_long ip, u_short port, DISCOVERY_TELE * dist, int len) { int rc = -1; /* Check minimum datagram length. */ if (len >= sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom)) { if (dist->dist_type == DIST_REQUEST) { /* Respond to requests. */ rc = NutDiscoveryAnnTele(dist); } else if (dist->dist_type == DIST_APPLY /* Apply telegram. */ && dist->dist_xid == xid /* Check exchange ID. */ && dist->dist_ver >= DISCOVERY_VERSION) { /* Minimum version required. */ xid += NutGetTickCount(); /* Store configuration. */ rc = NutDiscoveryAppConf(dist); } } return rc; }
/*! * \brief Return the seconds counter value. * * This function returns the value of a counter, which is incremented * every second. During system start, the counter is cleared to zero. * * \note There is intentionally no provision to modify the seconds counter. * Callers can rely on a continuous update and use this value for * system tick independend timeout calculations. Applications, * which want to use this counter for date and time functions, * should use an offset value. * * \return Value of the seconds counter. */ uint32_t NutGetSeconds(void) { return NutGetTickCount() / NutGetTickClock(); }