/*! * \brief Configure the I2C bus controller (GPIO TWI implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_conf function pointer. Most implementations will * also call this function during initialization to set the * default configuration. * * Right now only the bus clock rate is configurable. */ static int TwiBusConf(NUTI2C_BUS *bus) { GPIO_TWICB *icb; long rate; /* Check parameters. */ NUTASSERT(bus != NULL); NUTASSERT(bus->bus_icb != NULL); icb = (GPIO_TWICB *) bus->bus_icb; /* Get requested rate or use the default. */ rate = bus->bus_rate; if (rate == 0) { rate = 100000L; } if (rate > 400000) { /* Speed out of range */ return -1; } icb->delay_unit = 250000/rate; if (icb->delay_unit == 0) icb->delay_unit = 1; return 0; }
/*! * \brief Transfer data on the SPI bus. * * A device must have been selected by calling GpioSpi0Select(). * * \param node Specifies the SPI bus node. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined * byte values are transmitted. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming * data is discarded. * \param xlen Number of bytes to transfer. * * \return Always 0. */ int GpioSpiBus0Transfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen) { GSPIREG *gspi; /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_stat != NULL); gspi = (GSPIREG *)node->node_stat; /* We use dedicated static routines for each mode in the hope that ** this improves the compiler's optimization for the inner loop. */ switch (node->node_mode & SPI_MODE_3) { case SPI_MODE_0: SpiMode0Transfer(gspi, txbuf, rxbuf, xlen); break; case SPI_MODE_1: SpiMode1Transfer(gspi, txbuf, rxbuf, xlen); break; case SPI_MODE_2: SpiMode2Transfer(gspi, txbuf, rxbuf, xlen); break; case SPI_MODE_3: SpiMode3Transfer(gspi, txbuf, rxbuf, xlen); break; } return 0; }
/*! * \brief Transfer data on the SPI bus in polling mode. * * A device must have been selected by calling At91SpiSelect(). * * \param node Specifies the SPI bus node. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined * byte values are transmitted. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming * data is discarded. * \param xlen Number of bytes to transfer. * * \return Always 0. */ int At91SpiBusPollTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen) { uint8_t b = 0xff; uint8_t *txp = (uint8_t *) txbuf; uint8_t *rxp = (uint8_t *) rxbuf; uintptr_t base; /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); NUTASSERT(node->node_bus->bus_base != 0); base = node->node_bus->bus_base; while (xlen--) { if (txp) { b = *txp++; } /* Transmission starts by writing the transmit data. */ outr(base + SPI_TDR_OFF, b); /* Wait for receiver data register full. */ while((inr(base + SPI_SR_OFF) & SPI_RDRF) == 0); /* Read incoming data. */ b = (uint8_t)inr(base + SPI_RDR_OFF); if (rxp) { *rxp++ = b; } } return 0; }
/*! * \brief File system specific functions. * * \param dev Identifies the file system device that receives the * control function. * \param req Requested control function. May be set to one of the * following constants: * - FS_FILE_SEEK * - FS_VOL_MOUNT, conf points to an FSCP_VOL_MOUNT structure. * - FS_VOL_UNMOUNT, conf should be a NULL pointer. * \param conf Points to a buffer that contains any data required for * the given control function or receives data from that * function. * * \return 0 on success, -1 otherwise. */ static int RawFsIOCtl(NUTDEVICE * dev, int req, void *conf) { int rc = -1; switch (req) { case FS_FILE_SEEK: NUTASSERT(conf != NULL); RawFsFileSeek((NUTFILE *) ((IOCTL_ARG3 *) conf)->arg1, /* */ (long *) ((IOCTL_ARG3 *) conf)->arg2, /* */ (int) ((IOCTL_ARG3 *) conf)->arg3); break; case FS_VOL_MOUNT: { /* Mount a volume. */ FSCP_VOL_MOUNT *par = (FSCP_VOL_MOUNT *) conf; NUTASSERT(par != NULL); NUTASSERT(dev != NULL); rc = RawFsMount(dev, par->fscp_bmnt, par->fscp_part_type); if (rc) { /* Release resources on failures. */ RawFsUnmount(dev); } } break; case FS_VOL_UNMOUNT: /* Unmount a volume. */ NUTASSERT(dev != NULL); rc = RawFsUnmount(dev); break; } return rc; }
/*! \brief Select a device on the first SPI bus. * * Locks and activates the bus for the specified node. * * \param node Specifies the SPI bus node. * \param tmo Timeout in milliseconds. To disable timeout, set this * parameter to NUT_WAIT_INFINITE. * * \return 0 on success. In case of an error, -1 is returned and the bus * is not locked. */ int NplSpiBusSelect(NUTSPINODE * node, uint32_t tmo) { int rc; /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); /* Allocate the bus. */ rc = NutEventWait(&node->node_bus->bus_mutex, tmo); if (rc) { errno = EIO; } else { /* If the mode update bit is set, then update our shadow registers. */ if (node->node_mode & SPI_MODE_UPDATE) { NplSpiSetup(node); } /* Finally activate the node's chip select. */ rc = NplSpiChipSelect(node->node_cs, 0); if (rc) { /* Release the bus in case of an error. */ NutEventPost(&node->node_bus->bus_mutex); } } return rc; }
/*! * \brief Retrieve the size of a previously opened file. * * This function is called by the low level size routine of the C runtime * library, using the _NUTDEVICE::dev_size entry. * * \param nfp Pointer to a \ref _NUTFILE structure, obtained by a * previous call to RawFsFileOpen(). * * \return Size of the file. */ static long RawFsFileSize(NUTFILE * nfp) { RAWVOLUME *vol; NUTASSERT(nfp != NULL); NUTASSERT(nfp->nf_dev != NULL); vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb; return vol->vol_sect_cnt * vol->vol_sect_len; }
/*! * \brief Transfer data on the SPI bus using double buffered PDC. * * A device must have been selected by calling At91SpiSelect(). * * \todo Not yet done. Given up after SAM7SE SDRAM problems. * Currently working fine on SAM7X platform * \todo Is this working asynchronously? Old comments mentioned that * the transfer might be still active when function returns. * * \param node Specifies the SPI bus node. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined * byte values are transmitted. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming * data is discarded. * \param xlen Number of bytes to transfer. * * \return Always 0. */ int At91SpiBusDblBufTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen) { uintptr_t base; uint32_t cr; uint32_t ir = 0; #if defined(SPIBUS0_DOUBLE_BUFFER_HEURISTIC) || defined(SPIBUS1_DOUBLE_BUFFER_HEURISTIC) if (xlen < SPI_DOUBLE_BUFFER_MIN_TRANSFER_SIZE) { return At91SpiBusPollTransfer(node, txbuf, rxbuf, xlen); } #endif /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); NUTASSERT(node->node_bus->bus_base != 0); base = node->node_bus->bus_base; outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS); if (xlen) { /* Set first transmit pointer and counter. */ if (txbuf) { outr(base + PERIPH_TPR_OFF, (uint32_t)txbuf); } else { outr(base + PERIPH_TPR_OFF, (uint32_t)rxbuf); } cr = PDC_TXTEN; outr(base + PERIPH_TCR_OFF, xlen); /* Set first receive pointer and counter. */ if (rxbuf) { outr(base + PERIPH_RPR_OFF, (uint32_t)rxbuf); outr(base + PERIPH_RCR_OFF, xlen); cr |= PDC_RXTEN; ir = SPI_RXBUFF; } else { cr |= PDC_RXTDIS; ir = SPI_TXBUFE; outr(base + PERIPH_RPR_OFF, 0); outr(base + PERIPH_RCR_OFF, 0); } outr(base + PERIPH_TNPR_OFF, 0); outr(base + PERIPH_TNCR_OFF, 0); outr(base + PERIPH_RNPR_OFF, 0); outr(base + PERIPH_RNCR_OFF, 0); outr(base + SPI_IDR_OFF, (unsigned int) - 1); outr(base + SPI_IER_OFF, ir); outr(base + PERIPH_PTCR_OFF, cr); NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE); outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS); } return 0; }
/*! * \brief Update SPI shadow registers. * * \param node Specifies the SPI bus node. * * \return Always 0. */ int At91SpiSetup(NUTSPINODE * node) { uint32_t clk; uint32_t clkdiv; AT91SPIREG *spireg; NUTASSERT(node != NULL); NUTASSERT(node->node_stat != NULL); NUTASSERT(node->node_bus != NULL); NUTASSERT(node->node_bus->bus_base != 0); spireg = node->node_stat; spireg->at91spi_mr &= ~(SPI_MODFDIS | SPI_LLB); if ((node->node_mode & SPI_MODE_FAULT) == 0) { spireg->at91spi_mr |= SPI_MODFDIS; } if (node->node_mode & SPI_MODE_LOOPBACK) { spireg->at91spi_mr |= SPI_LLB; } spireg->at91spi_csr &= ~(SPI_BITS | SPI_CPOL | SPI_NCPHA | SPI_CSAAT | SPI_SCBR); if (node->node_bits) { spireg->at91spi_csr |= ((uint32_t)(node->node_bits - 8) << SPI_BITS_LSB) & SPI_BITS; } if (node->node_mode & SPI_MODE_CPOL) { spireg->at91spi_csr |= SPI_CPOL; } if ((node->node_mode & SPI_MODE_CPHA) == 0) { spireg->at91spi_csr |= SPI_NCPHA; } if (node->node_mode & SPI_MODE_CSKEEP) { spireg->at91spi_csr |= SPI_CSAAT; } /* Query peripheral clock. */ clk = NutClockGet(NUT_HWCLK_PERIPHERAL); /* Calculate the SPI clock divider. Avoid rounding errors. */ clkdiv = (clk + node->node_rate - 1) / node->node_rate; /* The divider value minimum is 1. */ if (clkdiv < 1) { clkdiv++; } /* The divider value maximum is 255. */ else if (clkdiv > 255) { clkdiv = 255; } spireg->at91spi_csr |= clkdiv << SPI_SCBR_LSB; /* Update interface parameters. */ node->node_rate = clk / clkdiv; node->node_mode &= ~SPI_MODE_UPDATE; return 0; }
/*! * \brief Transfer data on the SPI bus using single buffered interrupt mode. * * A device must have been selected by calling At91SpiSelect(). * * \param node Specifies the SPI bus node. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined * byte values are transmitted. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming * data is discarded. * \param xlen Number of bytes to transfer. * * \return Always 0. */ static int Stm32SpiBusTransfer(NUTSPINODE * node, const void *txbuf, void *rxbuf, int xlen) { SPI_TypeDef* base; // DMA_Channel_TypeDef* channel_rx,*channel_tx; /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); NUTASSERT(node->node_bus->bus_base != 0); base = (SPI_TypeDef*)node->node_bus->bus_base; /* if(base == SPI1_BASE){ channel_rx=DMA1_Channel2; channel_tx=DMA1_Channel3; }else if(base == SPI2_BASE){ channel_rx=DMA1_Channel4; channel_tx=DMA1_Channel5; }else if(base == SPI3_BASE){ channel_rx=DMA2_Channel1; channel_tx=DMA2_Channel2; };*/ // DMA_Setup(channel_rx,(void*)rxbuf,(void*)(&(base->DR)),xlen,DMA_DIR_PeripheralSRC|DMA_MemoryDataSize_Byte|DMA_PeripheralDataSize_Byte|DMA_Priority_VeryHigh|DMA_IT_TC);//rx // DMA_Setup(channel_tx,(void*)txbuf,(void*)(&(base->DR)),xlen,DMA_DIR_PeripheralDST|DMA_MemoryDataSize_Byte|DMA_PeripheralDataSize_Byte|DMA_Priority_VeryHigh|DMA_IT_TC);//tx // DMA_Enable(channel_rx);DMA_Enable(channel_tx); // DMA_Register_Interrupt(channel_rx,&SPI_QUE); Stm32SpiEnable(base); unsigned char * tx = (unsigned char*)txbuf; unsigned char * rx = (unsigned char*)rxbuf; while( xlen-- > 0){ unsigned char b = tx ? (* tx ++) : 0xff; base->DR = b; /* wait until receive buffer no longer empty */ while ( ( base->SR & SPI_SR_RXNE ) == 0 ) { } b = base->DR; if( rx ) { * rx ++ = b; } } // NutEventWait(&SPI_QUE,0); Stm32SpiDisable(base); return 0; }
/*! * \brief Write data to a file. * * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous * call to RawFsFileOpen(). * \param buffer Pointer to the data to be written. If zero, then the * output buffer will be flushed. * \param len Number of bytes to write. * * \return The number of bytes written. A return value of -1 indicates an * error. */ int RawFsFileWrite(NUTFILE * nfp, CONST void *buffer, int len) { int rc; int step; uint8_t *buf; RAWFILE *fcb; RAWVOLUME *vol; NUTASSERT(nfp != NULL); /* Flush file if buffer is a NULL pointer. */ if (buffer == NULL || len == 0) { return RawFsFileFlush(nfp); } /* Sanity check. */ NUTASSERT(nfp->nf_fcb != NULL); NUTASSERT(nfp->nf_dev != NULL); NUTASSERT(nfp->nf_dev->dev_dcb != NULL); fcb = (RAWFILE *) nfp->nf_fcb; vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb; /* * Write the data. */ buf = (uint8_t *) buffer; for (rc = 0, step = 0; rc < len; rc += step) { /* Did we reach the end of a sector? */ if (fcb->f_sect_pos >= vol->vol_sect_len) { /* Yes, move to the next sector. */ fcb->f_sect_num++; fcb->f_sect_pos -= vol->vol_sect_len; } /* Load the sector we want to write to. */ if (RawFsSectorLoad(nfp->nf_dev, fcb->f_sect_num)) { rc = -1; break; } /* The number of bytes we write to this sector. */ step = (int) (vol->vol_sect_len - fcb->f_sect_pos); if (step > len - rc) { step = len - rc; } /* Copy data to this sector. */ memcpy(&vol->vol_sect_buf[fcb->f_sect_pos], &buf[rc], step); vol->vol_sect_dirty = 1; /* Advance file pointers. */ fcb->f_pos += step; fcb->f_sect_pos += step; } return rc; }
/*! * \brief Save Nut/OS configuration in non-volatile memory. * * Since Nut/OS version 4.7.5, this routine is no longer called automatically * during system initialization. Thus, if NutLoadConfig() fails, then the * non-volatile memory remains invalid and NutLoadConfig() will again fail * during the next system start. * * \return 0 if OK, -1 on failures. */ int NutSaveConfig(void) { /* Sanity checks. */ NUTASSERT(sizeof(CONFOS) <= 255); NUTASSERT(strlen(confos.hostname) <= MAX_HOSTNAME_LEN); /* Update the magic part. */ confos.size = sizeof(CONFOS); memcpy(confos.magic, CONFOS_EE_MAGIC, sizeof(CONFOS_EE_MAGIC) - 1); return NutNvMemSave(CONFOS_EE_OFFSET, &confos, sizeof(CONFOS)); }
/*! \brief Deselect a device on the first SPI bus. * * Deactivates the chip select and unlocks the bus. * * \param node Specifies the SPI bus node. * * \return Always 0. */ int NplSpiBusDeselect(NUTSPINODE * node) { /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); /* Deactivate the node's chip select. */ NplSpiChipSelect(node->node_cs, 1); /* Release the bus. */ NutEventPost(&node->node_bus->bus_mutex); return 0; }
/*! \brief Deselect a device on the SPI bus. * * Deactivates the chip select and unlocks the bus. * * \param node Specifies the SPI bus node. * * \return Always 0. */ int GpioSpiBus0Deselect(NUTSPINODE * node) { /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); /* Deactivate the node's chip select. */ GpioSpi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0); /* Release the bus. */ NutEventPost(&node->node_bus->bus_mutex); return 0; }
/*! \brief Deselect a device on the SPI bus. * * Deactivates the chip select and unlocks the bus. * * \param node Specifies the SPI bus node. * * \return Always 0. */ static int Stm32SpiBusDeselect(NUTSPINODE * node) { /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); NutSpiBusWait(node, NUT_WAIT_INFINITE); /* Deactivate the node's chip select. */ Stm32SpiChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0); /* Release the bus. */ NutEventPostAsync(&node->node_bus->bus_mutex); return 0; }
/*! * \brief Return the length of a file. * * \param fd Descriptor of a previously opened file, device or * connected socket. * * \return Filelength in bytes or -1 in case of an error. */ long _filelength(int fd) { NUTFILE *fp = (NUTFILE *) ((uintptr_t) fd); NUTDEVICE *dev; long l; NUTASSERT(fp != NULL); dev = fp->nf_dev; if (dev == 0) { NUTVIRTUALDEVICE *vdv = (NUTVIRTUALDEVICE *) fp; if (vdv->vdv_ioctl && vdv->vdv_ioctl(vdv, IOCTL_GETFILESIZE, &l) == 0) return l; else { errno = EBADF; return -1; } } if (dev->dev_size == 0) { errno = EBADF; return -1; } return (*dev->dev_size) (fp); }
/*! * \brief Initialize an SPI bus node. * * This routine is called for each SPI node, which is registered via * NutRegisterSpiDevice(). * * \param node Specifies the SPI bus node. * * \return 0 on success or -1 if there is no valid chip select. */ int NplSpiBusNodeInit(NUTSPINODE * node) { int rc; /* Sanity check. */ NUTASSERT(node != NULL); NUTASSERT(node->node_bus != NULL); /* Try to deactivate the node's chip select. */ rc = NplSpiChipSelect(node->node_cs, 1); if (rc == 0) { NplSpiSetup(node); } return rc; }
/*! * \brief Transfer data on the SPI bus in polling mode. * * A device must have been selected by calling NplSpiSelect(). * * \param node Specifies the SPI bus node. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined * byte values are transmitted. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming * data is discarded. * \param xlen Number of bytes to transfer. * * \return Always 0. */ int NplSpiBusPollTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen) { uint8_t rxc; uint8_t txc = 0xFF; uint8_t *txp = (uint8_t *) txbuf; uint8_t *rxp = (uint8_t *) rxbuf; /* Sanity check. */ NUTASSERT(node != NULL); while (xlen--) { if (txp) { txc = *txp++; } /* Transmission starts by writing the transmit data. */ outb(NPL_MMCDR, txc); /* Wait for receiver data register full. */ while ((inb(NPL_SLR) & NPL_MMCREADY) == 0); /* Read incoming data. */ rxc = inb(NPL_MMCDR); if (rxp) { *rxp++ = rxc; } } return 0; }
/*! * \brief Update SPI shadow registers. * * \param node Specifies the SPI bus node. * * \return Always 0. */ static int NplSpiSetup(NUTSPINODE * node) { #if defined(NUT_PLL_NPLCLK1) uint32_t clk; uint32_t clkdiv; NUTASSERT(node != NULL); /* Query the PLL number routed to Clock B. */ clk = Cy2239xGetPll(NUT_PLL_NPLCLK1); /* Get the frequency of this PLL. */ clk = Cy2239xPllGetFreq((int)clk, 7); /* Calculate the required divider value. */ clkdiv = (clk + NPL_MMC_CLOCK - 10) / NPL_MMC_CLOCK; /* * Not sure about the Cy-routines. The DIVSEL bit specifies which * divider is used, which is indirectly connected to S2, which is * high by default. For now set both dividers. */ if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 1, (int)clkdiv)) { return -1; } if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 0, (int)clkdiv)) { return -1; } /* Update interface parameters. */ node->node_rate = clk / clkdiv; node->node_mode &= ~SPI_MODE_UPDATE; #endif return 0; }
/*! * \brief Insert a new timer in the global timer list. * * Applications should not call this function. * * \param tn Pointer to the timer structure to insert. * * \todo Make this local function static. */ void NutTimerInsert(NUTTIMERINFO * tn) { NUTTIMERINFO *tnp; NUTASSERT(tn != NULL); tn->tn_prev = NULL; for (tnp = nutTimerList; tnp; tnp = tnp->tn_next) { if (tn->tn_ticks_left < tnp->tn_ticks_left) { tnp->tn_ticks_left -= tn->tn_ticks_left; break; } tn->tn_ticks_left -= tnp->tn_ticks_left; tn->tn_prev = tnp; } tn->tn_next = tnp; if (tn->tn_next) { tn->tn_next->tn_prev = tn; } if (tn->tn_prev) { tn->tn_prev->tn_next = tn; } else { nutTimerList = tn; } }
/*! * \brief Stop a specified timer. * * Only periodic timers need to be stopped. One-shot timers * are automatically stopped by the timer management after * ther first timer interval. Anyway, long running one-shot * timers may be stopped to release the occupied memory. * * \param handle Identifies the timer to be stopped. This handle must * have been created by calling NutTimerStart() or * NutTimerStartTicks(). */ void NutTimerStop(HANDLE handle) { NUTTIMERINFO *tn = (NUTTIMERINFO *)handle; NUTASSERT(tn != NULL); #ifdef NUTDEBUG if (__os_trf) fprintf(__os_trs, " TIM %p NutTimerStop\n", handle); #endif /* Disable periodic operation and callback. */ tn->tn_ticks = 0; tn->tn_callback = NULL; /* If not already elapsed, expire the timer. */ if (tn->tn_ticks_left) { if (tn->tn_prev) { tn->tn_prev->tn_next = tn->tn_next; } else { nutTimerList = tn->tn_next; } if (tn->tn_next) { tn->tn_next->tn_prev = tn->tn_prev; tn->tn_next->tn_ticks_left += tn->tn_ticks_left; } tn->tn_ticks_left = 0; NutTimerInsert(tn); } }
int _seek(int fd, long offset, int origin) { NUTFILE *fp = (NUTFILE *) ((uintptr_t) fd); NUTDEVICE *dev; IOCTL_ARG3 conf; NUTASSERT(fp != NULL); conf.arg1 = (void*) fp; conf.arg2 = (void*) &offset; conf.arg3 = (void*) origin; dev = fp->nf_dev; if (dev != 0) { if ((*dev->dev_ioctl) (dev, FS_FILE_SEEK, &conf)) { return 0; } else { errno = EINVAL; return -1; } } else { errno = EINVAL; return -1; } }
/*! * \brief Load Nut/OS configuration from non-volatile memory. * * This routine is automatically called during system initialization. * It tries to read the OS configuration structure \ref CONFOS from * non-volatile memory, starting at /ref CONFOS_EE_OFFSET. * * The routine may fail, if * - non-volatile memory is not supported, * - non-volatile memory contains invalid data, * - the configuration structure has changed. * * \return 0 if OK, -1 on failures, in which case the hostname will * be set to \ref CONFOS_VIRGIN_HOSTNAME. */ int NutLoadConfig(void) { /* Sanity check. */ NUTASSERT(sizeof(CONFOS) <= 255); if (NutNvMemLoad(CONFOS_EE_OFFSET, &confos, sizeof(CONFOS)) == 0 /* If loaded... */ && confos.size == sizeof(CONFOS) /* ...check magic size and cookie. */ && memcmp(confos.magic, CONFOS_EE_MAGIC, sizeof(CONFOS_EE_MAGIC) - 1) == 0) { return 0; } /* No valid configuration, set virgin hostname. */ NUTASSERT(sizeof(confos.hostname) > strlen(CONFOS_VIRGIN_HOSTNAME)); strcpy(confos.hostname, CONFOS_VIRGIN_HOSTNAME); return -1; }
/*! * \brief Move file pointer to a specified position. * * Moving beyond the current file size is not supported. * * \param nfp File descriptor. * \param pos Requested file position. * \param whence Positioning directive. * * \return 0 on success, -1 otherwise. In the latter case the position * is unspecified. */ static int RawFsFileSeek(NUTFILE * nfp, long *pos, int whence) { int rc = 0; long npos; RAWFILE *fcb; NUTASSERT(nfp != NULL); NUTASSERT(nfp->nf_fcb != NULL); fcb = nfp->nf_fcb; NUTASSERT(pos != NULL); npos = *pos; switch (whence) { case SEEK_CUR: /* Relative to current position. */ npos += fcb->f_pos; break; case SEEK_END: /* Relative to file end. */ npos += RawFsFileSize(nfp); break; } /* Make sure that we are within limits. */ if (npos < 0 || npos > RawFsFileSize(nfp)) { errno = EINVAL; rc = -1; } else { RAWVOLUME *vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb; NUTASSERT(nfp != NULL); NUTASSERT(nfp != NULL); vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb; *pos = npos; fcb->f_pos = npos; fcb->f_sect_num = 0; while (npos >= (long)vol->vol_sect_len) { fcb->f_sect_num++; npos -= vol->vol_sect_len; } fcb->f_sect_pos = npos; } return rc; }
/*! * \brief Reentrant variant of RawFsFileOpen(). */ static NUTFILE *RawFsApiFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc) { NUTFILE *rc; RAWVOLUME *vol; NUTASSERT(dev != NULL); vol = (RAWVOLUME *) dev->dev_dcb; NUTASSERT(vol != NULL); /* Lock filesystem access. */ NutEventWait(&vol->vol_fsmutex, 0); /* Call worker routine. */ rc = RawFsFileOpen(dev, path, mode, acc); /* Release filesystem lock. */ NutEventPost(&vol->vol_fsmutex); return rc; }
/*! * \brief Load sector. * * \param dev Specifies the file system device. * \param sect Sector to load. * * \return 0 on success, -1 on failures. */ static int RawFsSectorLoad(NUTDEVICE * dev, uint32_t sect) { int rc = -1; RAWVOLUME *vol; NUTASSERT(dev != NULL); vol = (RAWVOLUME *) dev->dev_dcb; /* Gain mutex access. */ NUTASSERT(vol != NULL); NutEventWait(&vol->vol_iomutex, 0); /* Nothing to do if sector is already loaded. */ if (vol->vol_sect_num == sect) { rc = 0; } /* Make sure that the sector buffer is clean. */ else if (RawFsSectorFlush(dev) == 0) { NUTFILE *blkmnt = dev->dev_icb; NUTDEVICE *blkdev = blkmnt->nf_dev; BLKPAR_SEEK pars; blkmnt = dev->dev_icb; NUTASSERT(blkmnt != NULL); blkdev = blkmnt->nf_dev; NUTASSERT(blkdev != NULL); /* Set the block device's sector position. */ pars.par_nfp = blkmnt; pars.par_blknum = sect; if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_SEEK, &pars) == 0) { /* Read a single block from the device. */ if ((*blkdev->dev_read) (blkmnt, vol->vol_sect_buf, 1) == 1) { vol->vol_sect_num = sect; rc = 0; } } } /* Release mutex access. */ NutEventPostAsync(&vol->vol_iomutex); return rc; }
/*! * \brief Reentrant variant of RawFsFileRead(). */ static int RawFsApiFileRead(NUTFILE * nfp, void *buffer, int size) { int rc; RAWVOLUME *vol; NUTASSERT(nfp != NULL); NUTASSERT(nfp->nf_dev != NULL); vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb; NUTASSERT(vol != NULL); /* Lock filesystem access. */ NutEventWait(&vol->vol_fsmutex, 0); /* Call worker routine. */ rc = RawFsFileRead(nfp, buffer, size); /* Release filesystem lock. */ NutEventPost(&vol->vol_fsmutex); return rc; }
/*! * \brief Write a character to a stream. * * \param c Character to write. * \param stream Pointer to a previously opened stream. * * \return The character written or EOF to indicate an error. * * \warning The function will not check, if the stream pointer points * to a valid stream. */ int fputc(int c, FILE * stream) { char ch = (char) c; NUTASSERT(stream != NULL); if (_write(stream->iob_fd, &ch, 1) != 1) c = EOF; return c; }
/*! * \brief I2C bus transfer (STM I2C implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_tran function pointer. */ static int I2cBusTran(NUTI2C_SLAVE *slave, NUTI2C_MSG *msg) { NUTI2C_BUS *bus; STM32_I2CCB *icb; I2C_TypeDef *i2c; uint32_t cr2; int rc = 0; bus = slave->slave_bus; NUTASSERT(bus != NULL); NUTASSERT(bus->bus_icb != NULL); icb = (STM32_I2CCB *) bus->bus_icb; icb->icb_msg = msg; icb->errors = 0; i2c = (I2C_TypeDef *) icb->icb_base; cr2 = i2c->CR2; cr2 &= 0xf8000000; /* Clean out */ cr2 |= slave->slave_address << 1; msg->msg_widx = 0; msg->msg_ridx = 0; /* are there bytes to write? */ if (msg->msg_wlen) { i2c->CR1 |= I2C_CR1_TXIE | I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_NACKIE; if (msg->msg_wlen > 0xff) cr2 |= I2C_CR2_NBYTES | I2C_CR2_RELOAD; else cr2 |= msg->msg_wlen << 16; } else if (msg->msg_rsiz) { i2c->CR1 |= I2C_CR1_RXIE | I2C_CR1_STOPIE | I2C_CR1_NACKIE; if (msg->msg_rsiz > 0xff) cr2 |= I2C_CR2_RD_WRN | I2C_CR2_NBYTES | I2C_CR2_RELOAD; else cr2 |= I2C_CR2_RD_WRN | msg->msg_rsiz << 16; } i2c->CR2 = cr2 | I2C_CR2_START; rc = NutEventWait(&icb->icb_queue, slave->slave_timeout); if ((icb->errors) || (rc)) msg->msg_ridx = -1; return msg->msg_ridx; }
/*! * \brief Read data from a file. * * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous * call to RawFsFileOpen(). * \param buffer Pointer to the data buffer to fill. * \param size Maximum number of bytes to read. * * \return The number of bytes actually read. A return value of -1 indicates * an error. */ int RawFsFileRead(NUTFILE * nfp, void *buffer, int size) { int rc; int step; uint8_t *buf; RAWVOLUME *vol; RAWFILE *fcb; /* Ignore input flush. */ if (buffer == NULL || size == 0) { return 0; } NUTASSERT(nfp != NULL); NUTASSERT(nfp->nf_dev != NULL); fcb = nfp->nf_fcb; NUTASSERT(fcb != NULL); vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb; NUTASSERT(vol != NULL); buf = (uint8_t *) buffer; for (rc = 0, step = 0; rc < size; rc += step) { /* Did we reach the end of a sector? */ if (fcb->f_sect_pos >= vol->vol_sect_len) { /* Yes, move to the next sector. */ fcb->f_sect_num++; fcb->f_sect_pos -= vol->vol_sect_len; } /* Make sure that the required sector is loaded. */ if (RawFsSectorLoad(nfp->nf_dev, fcb->f_sect_num)) { rc = -1; break; } step = (int) (vol->vol_sect_len - fcb->f_sect_pos); if (step > size - rc) { step = size - rc; } memcpy(&buf[rc], &vol->vol_sect_buf[fcb->f_sect_pos], step); fcb->f_pos += step; fcb->f_sect_pos += step; } return rc; }
/*! * \brief Mimic initialization without actually registering the device. * * This is a little bit tricky. If we want to use the existing DataFlash * routines for accessing the system configuration, they must be * properly initialized. This is normally done by calling NutRegister... * in the application. However, the system configuration must be know * before entering any application code. * */ static int SpiAt45dConfigDevice(void) { #if !defined(DEV_SPIBUS) return -1; #else /* DEV_SPIBUS */ if (devSysConf == NULL) { NUTSPINODE *node; NUTDEVICE *dev; #if NUT_CONFIG_AT45D == 0 dev = &devSpiAt45d0; #elif NUT_CONFIG_AT45D == 1 dev = &devSpiAt45d1; #elif NUT_CONFIG_AT45D == 2 dev = &devSpiAt45d2; #elif NUT_CONFIG_AT45D == 3 dev = &devSpiAt45d3; #else return -1; #endif node = (NUTSPINODE *) dev->dev_icb; NUTASSERT(node != NULL); if (node->node_bus == NULL) { NUTSPIBUS *bus; bus = &DEV_SPIBUS; node->node_bus = bus; } #ifdef NUT_CONFIG_AT45D_CS node->node_cs = NUT_CONFIG_AT45D_CS; #endif NUTASSERT(node->node_bus->bus_initnode != NULL); if ((*node->node_bus->bus_initnode) (node)) { return -1; } NutEventPost(&node->node_bus->bus_mutex); if (SpiAt45dInit(dev)) { return -1; } devSysConf = dev; } return 0; #endif /* DEV_SPIBUS */ }