/* * Demonstrate Nut/OS delay timer. * * The delay function will not release the CPU, keeping all other threads * blocked. It is a good choice for very short delays, where context * switching is undesirable or would take too long. Use it sparingly and * for short delays only. */ static void DelayDemo(void) { uint32_t req; uint32_t act; for (req = 1024UL; req <= 8UL * 1024UL * 1024UL; req *= 2) { printf("Delaying %lu us, ", req); act = NutGetMillis(); NutMicroDelay(req); act = NutGetMillis() - act; printf("delayed %lu ms\n", act); } }
/* * Demonstrate Nut/OS sleep timer. * * This often used function serves two purposes: Delaying the current * thread and releasing the CPU. * * This demo will run endlessly. */ static void SleepDemo(void) { uint32_t req = 1; uint32_t act; for (;;) { printf("Sleeping %lu ms, ", req); act = NutGetMillis(); NutSleep(req); act = NutGetMillis() - act; printf("slept %lu ms\n", act); req *= 2; } }
/* * Demonstrate Nut/OS periodic timer. * * Periodic timers will call the callback function and then restart * the timer automatically. They must be explicitly stopped, if no * longer needed. */ static void PeriodicDemo(int s) { HANDLE t; HANDLE e = NULL; int i; uint32_t ms; printf("Start %d s periodic timer\n", s); t = NutTimerStart(s * 1000UL, TimerCallback, &e, 0); for (i = 0; i < 5; i++) { ms = NutGetMillis(); printf(" Waiting..."); NutEventWait(&e, NUT_WAIT_INFINITE); ms = NutGetMillis() - ms; printf("elapsed after %lu ms\n", ms); } puts(" Stop periodic timer"); NutTimerStop(t); }
/* * Calculate round trip time. */ void NutTcpCalcRtt(TCPSOCKET * sock) { uint16_t delta; if (sock->so_retran_time == 0) return; delta = (uint16_t) NutGetMillis() - (sock->so_retran_time & ~1); /* According to RFC793 (or STD007), page 41, we use 0.8 for ALPHA and 2.0 for BETA. */ sock->so_rtto = min (TCP_RTTO_MAX, max(TCP_RTTO_MIN, (delta * 4 + sock->so_rtto * 8) / 10)); //@@@printf ("[%04X] new retran timeout: %u, delta: %u\n", (u_short) sock, sock->so_rtto, delta); }
/*! * \brief Probe the I2C bus for a specified slave address * (STM32V2 implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_probe function pointer. This may happen even if no * slave device had been attached to the bus and thus without any * previous call to NUTI2C_BUS::bus_init. However, in that case * NUTI2C_BUS::bus_configure will have been called. * * */ static int I2cBusProbe(NUTI2C_BUS *bus, int sla) { STM32_I2CCB *icb; I2C_TypeDef *i2c; uint32_t isr, tmo; if ((bus->bus_flags & I2C_BF_INITIALIZED) == 0) { int res; res = I2cBusInit(bus); if (res) return res; } icb = (STM32_I2CCB *) bus->bus_icb; i2c = (I2C_TypeDef*) icb->icb_base; i2c->ISR = 0; i2c->CR2 = I2C_CR2_AUTOEND | 0*I2C_CR2_NBYTES| I2C_CR2_STOP | I2C_CR2_START| 0*I2C_CR2_ADD10 | 0* I2C_CR2_RD_WRN |sla<<1; tmo = NutGetMillis() + (20000/(bus->bus_rate)) + 2; while(!(i2c->ISR & I2C_ISR_STOPF)) { /* Break loop if bus is stuck*/ if (NutGetMillis() > tmo) { i2c->ICR |= (I2C_ICR_ARLOCF | I2C_ICR_STOPCF | I2C_ICR_NACKCF ); return -1; } } isr = i2c->ISR; if (isr & I2C_ICR_NACKCF ) { return -1; } return 0; }
/*! * \brief Initiate TCP segment transmission. * * Check the TCP socket status and send any segment waiting * for transmission. * * The function will not return until the data has been stored in the * network device hardware for transmission. If the device is not ready * for transmitting a new packet, the calling thread will be suspended * until the device becomes ready again. * * If the target host is connected through an Ethernet network and if * the hardware address of that host is currently unknown, an ARP * request is sent out and the function will block until a response * is received or an ARP timeout occurs. * * Segments containing data or SYN and FIN flags are added to a special * queue for unacknowledged segments and will be retransmitted by the * TCP timer thread, if not acknowledged by the remote within a specific * time. The state machine will remove these segments from the queue * as soon as they are acknowledged. * * \note This function is mainly used by the TCP state machine. * Applications typically do not call this function but * use NutTcpSend(), which is part of the TCP socket interface. * * \param sock Socket descriptor. This pointer must have been retrieved * by calling NutTcpCreateSocket(). * \param data Pointer to TCP segment contents. * \param size TCP segment length. * * \return 0 on success, -1 otherwise. Returning 0 does not imply that * the data has been successfully delivered, because flow control * and retransmission is still handled in the background. */ int NutTcpOutput(TCPSOCKET * sock, CONST u_char * data, u_short size) { NETBUF *nb; NETBUF *nb_clone = 0; TCPHDR *th; u_short csum; u_char hlen; /* * Check if anything to send at all. */ if (size == 0 && (sock->so_tx_flags & (SO_SYN | SO_FIN | SO_FORCE)) == 0) return 0; /* * Build TCP header. Add room for MAXSEG option if this is a * SYN segment. */ hlen = sizeof(TCPHDR); if (sock->so_tx_flags & SO_SYN) hlen += 4; if ((nb = NutNetBufAlloc(0, NBAF_TRANSPORT, hlen)) == 0) { sock->so_last_error = ENOBUFS; return -1; } th = (TCPHDR *) nb->nb_tp.vp; th->th_sport = sock->so_local_port; th->th_dport = sock->so_remote_port; th->th_x2 = 0; th->th_off = hlen >> 2; sock->so_tx_flags &= ~SO_FORCE; /* * Process ACK flag. */ th->th_seq = htonl(sock->so_tx_nxt); if (sock->so_tx_flags & SO_ACK) { th->th_flags = TH_ACK; sock->so_tx_flags &= ~SO_ACK; th->th_ack = htonl(sock->so_rx_nxt); } else { th->th_flags = 0; th->th_ack = 0; } /* * Any SYN is sent first. Add options too. We rely on the caller * not to send a SYN segment with data, because this may break * some old stacks. */ if (sock->so_tx_flags & SO_SYN) { u_char *cp; u_short n_mss = htons(sock->so_mss); th->th_flags |= TH_SYN; sock->so_tx_flags &= ~SO_SYN; sock->so_tx_nxt++; cp = (u_char *) (th + 1); *cp++ = TCPOPT_MAXSEG; *cp++ = TCPOLEN_MAXSEG; *cp++ = *(u_char *)&n_mss; *cp = *((u_char *)(&n_mss) + 1); } /* * Next preference is sending data. Set PUSH flag. */ else if (size) { if ((nb = NutNetBufAlloc(nb, NBAF_APPLICATION, size)) == 0) { sock->so_last_error = ENOBUFS; return -1; } memcpy(nb->nb_ap.vp, (void *)data, size); sock->so_tx_nxt += size; th->th_flags |= TH_PUSH; } /* * If all data sent, transmit any waiting FIN. */ else if (sock->so_tx_flags & SO_FIN) { th->th_flags |= TH_FIN; sock->so_tx_flags &= ~SO_FIN; sock->so_tx_nxt++; //@@@printf ("[%04X]TcpOutput: sending FIN\n", (u_short) sock); } /* * We close our receiver window, if it is * below the maximum segment size. */ if (sock->so_rx_win < sock->so_mss) th->th_win = 0; else th->th_win = htons(sock->so_rx_win); th->th_sum = 0; th->th_urp = 0; /* * Calculate TCP checksum. */ csum = NutIpPseudoChkSumPartial(sock->so_local_addr, sock->so_remote_addr, IPPROTO_TCP, htons(nb->nb_tp.sz + nb->nb_ap.sz)); csum = NutIpChkSumPartial(csum, th, nb->nb_tp.sz); th->th_sum = NutIpChkSum(csum, nb->nb_ap.vp, nb->nb_ap.sz); #ifdef NUTDEBUG if (__tcp_trf) NutDumpTcpHeader(__tcp_trs, "OUT", sock, nb); #endif /* * To avoid a race condition in tcp state machine, the segment is first * appended to the transmission que, and then sent to the network. */ /* * Append the segment to our transmission queue. */ //@@@printf ("[%04X]TcpOutput: size: %u, flags: %u\n", (u_short) sock, size, th->th_flags); if (size || ((th->th_flags & (TH_FIN | TH_SYN)))) { //@@@printf ("[%04X]TcpOutput: appending nb to queue\n", (u_short) sock); NETBUF *nbp; nb->nb_next = 0; if ((nbp = sock->so_tx_nbq) == 0) { sock->so_tx_nbq = nb; /* * First entry, so initialize our retransmission timer. * It is also set at various places in the state machine, * but here is the best central point to do it. We may * carefully check later, if we can remove some in the * state machine. */ sock->so_retran_time = (u_short) NutGetMillis() | 1; } else { while (nbp->nb_next) nbp = nbp->nb_next; nbp->nb_next = nb; } if (sock->so_rtt_seq == 0) sock->so_rtt_seq = ntohl (th->th_seq); nb_clone = NutNetBufClone (nb); } else nb_clone = nb; /* * IP output might fail because of routing, ARP or network device * problems or because the system ran out of memory. */ if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, nb_clone)) return -1; NutNetBufFree (nb_clone); return 0; }