Пример #1
0
byte EEPROM_24XX1025::readByte(void) {
  // Reads a byte from the current position and returns it

  if (eeprom_pos != curpos) {
    // If the EEPROM internal position counter has (or might have) changed,
    // do a "full" read, where we sent the 16-byte address.
    I2c16.read((uint8_t)(devaddr | ((BLOCKNUM(curpos)) << 2)), TO_PAGEADDR(curpos), 1U);
    eeprom_pos = curpos;
  }
  else {
    // If we know that the internal counter is correct, don't send the address, but
    // rely on the EEPROM logic to return the "next" byte properly. This saves
    // overhead and time.
    I2c16.read((uint8_t)(devaddr | ((BLOCKNUM(curpos)) << 2)), 1U);
  }

  curpos++;
  eeprom_pos++;
  if (eeprom_pos == 65536) {
    // Seems to wrap here. The datasheet could be read as if this were 17-bit, but I don't think it is.
    eeprom_pos = 0;
  }
  if (curpos >= DEVICE_SIZE) {
    // Wrap around if we overflow the device capacity.
    curpos %= DEVICE_SIZE;
    eeprom_pos = 0xffffffff;
  }

  return I2c16.receive(); // Returns 0 if no bytes are queued
}
Пример #2
0
// Private method
uint8_t EEPROM_24XX1025::writeChunk(uint32_t fulladdr, const void *data, uint8_t bytesToWrite) {
  // Used to turn 1-128 byte writes into full page writes (i.e. turn them into proper single-page writes)
  if (bytesToWrite == 0 || bytesToWrite > 128 || fulladdr >= DEVICE_SIZE)
    return 0;

  if (fulladdr + bytesToWrite > DEVICE_SIZE)
    bytesToWrite = DEVICE_SIZE - fulladdr;

  // Calculate the 16-bit address, and the page number of the first and second (if applicable)
  // blocks we're going to write to.
  uint32_t pageaddr = TO_PAGEADDR(fulladdr);
  uint8_t firstBlock = BLOCKNUM(fulladdr);
  uint8_t secondBlock = BLOCKNUM(fulladdr + bytesToWrite - 1);

  // These page numbers are *relative to the block number*, i.e. firstPage = 0 may mean at byte 0 or byte 65536
  // depending on firstBlock above. Same goes for secondPage/secondBlock of course.
  uint16_t firstPage = pageaddr / 128; // pageaddr is already relative to block!
  uint16_t secondPage = (TO_PAGEADDR(pageaddr + bytesToWrite - 1))/128;

  if (firstPage == secondPage && firstBlock == secondBlock) {
    // Data doesn't "cross the border" between pages. Easy!
    return writeSinglePage(fulladdr, data, bytesToWrite);
  }
  else {
    // The data spans two pages, e.g. begins at address 120 and is 12 bytes long, which would make it go
    // past the edge of this page (addresses 0 - 127) and onto the next.
    // We need to split this write manually.

    uint8_t bytesInFirstPage = ((firstPage + 1) * 128) - pageaddr;
    uint8_t bytesInSecondPage = bytesToWrite - bytesInFirstPage;

    uint8_t ret = 0;

    // Write the data that belongs to the first page
    if ((ret = writeSinglePage(TO_FULLADDR(firstBlock, pageaddr), data, bytesInFirstPage))
      != bytesInFirstPage)
    {
      return ret;
    }

    // Write the data that belongs to the second page
    if ((ret = writeSinglePage(TO_FULLADDR(secondBlock, secondPage * 128), (const void*)((byte *)data + bytesInFirstPage), bytesInSecondPage))
      != bytesInSecondPage)
    {
      return bytesInFirstPage + ret;
    }
  }

  return bytesToWrite;
}
Пример #3
0
/*
 * write operation on the wing
 */
int
dtfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
	off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
{
	struct puffs_node *pn = opc;
	struct dtfs_file *df = DTFS_CTOF(opc);
	uint8_t *src, *dest;
	size_t copylen;

	if (pn->pn_va.va_type != VREG)
		return EISDIR;

	if (ioflag & PUFFS_IO_APPEND)
		offset = pn->pn_va.va_size;

	if (*resid + offset > pn->pn_va.va_size)
		dtfs_setsize(pn, *resid + offset);

	src = buf;
	while (*resid > 0) {
		int i;
		copylen = MIN(*resid, BLOCKLEFT(offset, DTFS_BLOCKSIZE));
		i = BLOCKNUM(offset, DTFS_BLOCKSHIFT);
		dest = df->df_blocks[i]
		    + BLOCKOFF(offset, DTFS_BLOCKSIZE);
		memcpy(dest, src, copylen);
		offset += copylen;
		dest += copylen;
		*resid -= copylen;
	}

	dtfs_updatetimes(pn, 0, 1, 1);

	return 0;
}
Пример #4
0
/*
 * Read operation, used both for VOP_READ and VOP_GETPAGES
 */
int
dtfs_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
	off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
{
	struct puffs_node *pn = opc;
	struct dtfs_file *df = DTFS_CTOF(opc);
	quad_t xfer, origxfer;
	uint8_t *src, *dest;
	size_t copylen;

	if (pn->pn_va.va_type != VREG)
		return EISDIR;

	xfer = MIN(*resid, df->df_datalen - offset);
	if (xfer < 0)
		return EINVAL;

	dest = buf;
	origxfer = xfer;
	while (xfer > 0) {
		copylen = MIN(xfer, BLOCKLEFT(offset, DTFS_BLOCKSIZE));
		src = df->df_blocks[BLOCKNUM(offset, DTFS_BLOCKSHIFT)]
		    + BLOCKOFF(offset, DTFS_BLOCKSIZE);
		memcpy(dest, src, copylen);
		offset += copylen;
		dest += copylen;
		xfer -= copylen;
	}
	*resid -= origxfer;

	dtfs_updatetimes(pn, 1, 0, 0);

	return 0;
}
Пример #5
0
//dealloc inode
int deallocInode(int inum)
{
	int i,j;
	inode_t inode;
	dir_t dirBlock;
	//Get to start of inode 
	lseek(fdImage,BYOFF_INODE(inum),SEEK_SET);
	//Read the inode
	read(fdImage, &inode, sizeof(inode_t));

	if(inode.type==MFS_DIRECTORY)//if directory
	{
		//should be empty except for the two default entries . ..
		assert(inode.blockPtrs[0]!=-1);//has to have at least one block
		
		for(i=0; i<14; i++)
		{
			if(inode.blockPtrs[i]!=-1)//valid blockPtr
			{
				//Go to that block
				lseek(fdImage, inode.blockPtrs[i], SEEK_SET);
				read(fdImage, &dirBlock, sizeof(dir_t));
				//Check all entries in the directory block
				for(j=0; j<NUM_DIR_ENTS; j++)
				{
					if( (dirBlock.dirEnt[j].inum != -1) && !(i==0 && j<2) )//valid directory entry which is not one of the first two
						return -1;//could not deallocate Inode
				}
			}
		}
		//empty directory
	}
	//Either empty directory or simple file
	inode.type=MFS_UNUSED;//mark it unused
	//update as unused inode
	lseek(fdImage,BYOFF_INODE(inum),SEEK_SET);
	write(fdImage, &inode, sizeof(inode_t));
	//dealloc all its data blocks
	for(i=0; i<14; i++)
	{
		if(inode.blockPtrs[i]!=-1)//valid ptr
			deallocDataBlock(BLOCKNUM(inode.blockPtrs[i]));
	}

	//update superblock inode count
	super.ninodes--;
	lseek(fdImage, BYOFF_SUPER, SEEK_SET);
	write(fdImage, &super, sizeof(superblock_t));

	return 0;

}
Пример #6
0
// Private method
uint8_t EEPROM_24XX1025::readChunk(uint32_t fulladdr, const void *data, uint8_t bytesToRead) {
  if (bytesToRead == 0 || fulladdr >= DEVICE_SIZE)
    return 0;
  if (fulladdr + bytesToRead > DEVICE_SIZE)
    bytesToRead = DEVICE_SIZE - fulladdr;

  uint8_t err = 0;
  if (fulladdr < 65536 && fulladdr + bytesToRead > 65536) {
    // This read crosses the "block boundary" and cannot be sequentially read
    // by the EEPROM itself

    // Read part 1 (from the first block)
    err = I2c16.read(devaddr, fulladdr /* always 16-bit */, 65536 - fulladdr, (byte *)data);
    if (err) {
      eeprom_pos = 0xffffffff;
      return 0;
    }

    // Read part 2 (from the second block)
    err = I2c16.read(devaddr | (1 << 2), 0, bytesToRead - (65536 - fulladdr), (byte *)data + (uint16_t)((65536 - fulladdr)));
    if (err) {
      eeprom_pos = 0xffffffff;
      curpos += (65536 - fulladdr); // move the cursor forward the amount we read successfully
      if (curpos >= DEVICE_SIZE)
        curpos %= DEVICE_SIZE;
      return (uint8_t)(65536 - fulladdr); // num bytes read previously
    }
    else {
      eeprom_pos = TO_FULLADDR(1, bytesToRead - (65536 - fulladdr));
      curpos += bytesToRead;
      if (curpos >= DEVICE_SIZE)
        curpos %= DEVICE_SIZE;
      return bytesToRead;
    }
  }
  else {
    // Doesn't cross the block border, so we can do this in one read
    uint8_t block = BLOCKNUM(fulladdr);
    err = I2c16.read(devaddr | (block << 2), TO_PAGEADDR(fulladdr), bytesToRead, (byte *)data);
    if (err) {
      eeprom_pos = 0xffffffff;
      return 0;
    }
    else {
      eeprom_pos += bytesToRead;
      curpos += bytesToRead;
      if (curpos >= DEVICE_SIZE)
        curpos %= DEVICE_SIZE;
      return bytesToRead;
    }
  }
}
Пример #7
0
// Private method
uint8_t EEPROM_24XX1025::writeSinglePage(uint32_t fulladdr, const void *data, uint8_t bytesToWrite) {
  // Writes 1 - 128 bytes, but only *within a single page*. Never crosses a page/block border.
  // Enforcing this is up to the caller.
  if (bytesToWrite == 0 | bytesToWrite > 128)
    return 0;

  uint8_t ret = I2c16.write(devaddr | ((BLOCKNUM(fulladdr)) << 2), TO_PAGEADDR(fulladdr), (byte *)data, bytesToWrite);
  if (ret != 0) {
    // We can't be sure what the internal counter is now, since it looks like the write failed.
    eeprom_pos = 0xffffffff;
    return 0;
  }
  else {
    // Try to keep track of the internal counter
    eeprom_pos += bytesToWrite;
    curpos += bytesToWrite;
    if (curpos >= DEVICE_SIZE)
      curpos %= DEVICE_SIZE;
  }

  // Wait for the EEPROM to finish this write. To do so, we use acknowledge polling,
  // a technique described in the datasheet. We sent a START condition and the device address
  // byte, and see if the device acknowledges (pulls SDA low) or not. Loop until it does.
  uint32_t start = micros();
  while (I2c16.acknowledgePoll(devaddr | ((BLOCKNUM(fulladdr)) << 2)) == 0) {
    delayMicroseconds(20);
  }
  uint32_t end = micros();

  if (end - start < 500) {
    // This write took less than 500 us (typical is 3-4 ms). This most likely means
    // that the device is write protected, as it will acknowledge new commands at once
    // when write protect is active.
    Serial.println("WARNING: EEPROM appears to be write protected!");
    return 0;
  }

  return bytesToWrite;
}
Пример #8
0
boolean EEPROM_24XX1025::writeByte(byte data) {
  // Writes a byte to the EEPROM.
  // WARNING: writing a single byte still uses a full page write,
  // so writing 128 sequential bytes instead of 1 page write
  // will use 128 times as many of the chip's limited lifetime writes!!
  // In otherwords: ONLY USE THIS if you *really* only need to write ONE byte.
  // Even for just *TWO* bytes, write([pos,] data, bytesToWrite) is "twice as good"!
  // In short: writeBlock for 128 bytes will use 1 page "life" each on 1 or 2 pages.
  // writeByte 128 times will use 128 page "lives", spread over 1 or 2 pages.

  // Find which block the byte is in, based on the full (17-bit) address.
  // We can only supply 16 bits to the EEPROM, plus a separate "block select" bit.
  uint8_t block = BLOCKNUM(curpos);

  uint8_t ret = I2c16.write((uint8_t)(devaddr | (block << 2)), TO_PAGEADDR(curpos), data);
  if (ret != 0) {
    // Looks like something failed. Reset the EEPROM counter "copy", since we're no longer
    // sure what it ACTUALLY is.
    eeprom_pos = 0xffffffff;
    return false;
  }

  curpos++;
  eeprom_pos = curpos; // We changed the internal counter when we wrote the address just above.
  if (curpos >= DEVICE_SIZE) {
    // Wrap around if we overflow the device capacity.
    curpos %= DEVICE_SIZE;
    eeprom_pos = 0xffffffff; // Not sure what the internal counter does. It PROBABLY resets to 0, but...
  }

  // Wait for the EEPROM to finish this write. To do so, we use acknowledge polling,
  // a technique described in the datasheet. We sent a START condition and the device address
  // byte, and see if the device acknowledges (pulls SDA low) or not. Loop until it does.
  uint32_t start = micros();
  while (I2c16.acknowledgePoll(devaddr | (block << 2)) == 0) {
    delayMicroseconds(20);
  }
  uint32_t end = micros();

  if (end - start < 500) {
    // This write took less than 500 us (typical is 3-4 ms). This most likely means
    // that the device is write protected, as it will acknowledge new commands at once
    // when write protect is active.
    Serial.println("WARNING: EEPROM appears to be write protected!");
    return 0;
  }

  return true; // success
}
Пример #9
0
static void
gcmarkregion(void *start, void *end)
{
#define STACK 128
	void *startstk[STACK];
	void *endstk[STACK];
	char *low = (char *)g.heaplow;
	char *high = (char *)g.heaphigh - sizeof (char *);
	int tos = 1;

	startstk[0] = start;
	endstk[0] = end;

	while (tos-- > 0)
	{
#ifdef PTRMASK
		char *st = (char *)(((uLong)startstk[tos]) & PTRMASK);
		char *e = (char *)(((uLong)endstk[tos] - sizeof (char *)) & PTRMASK);
#else
		char *st = (char *)startstk[tos];
		char *e = (char *)endstk[tos] - sizeof (char *);
#endif
		char *s;

		for (s = st; s <= e; s += PTRBUMP)
		{
			char *p = *(char **)s;
			int num;
			struct pageinfo *pi;
			void *pp;
			size_t bb;
			boolean big = FALSE;

			if (p < low || p > high)
				continue;

			pi = GETPAGEINFO(p);
			num = PAGENUM(pi);

			if (num >= MAXPAGES)/* bogus block? */
				continue;

			while (!GETBIT(g.ourpages, num) && num >= 0)
			{
				num--;
				pi = (struct pageinfo *)((char *)pi - BYTESPERPAGE);
				big = TRUE;
			}

			if (num < 0)		/* bogus block? */
				continue;

			if (pi->blocksize == 0)	/* hit in free block */
			{
				/* pi->history |= 1; */		/* flag the hit */
				continue;
			}

			if (pi->blocksize == -1)	/* big block */
			{
				pp = (char *)pi + sizeof (struct pageinfo);

				if (g.skipinterior && pp != p)
					continue;

				if (pi->refbits[0])	/* already marked and walked */
					continue;

				pi->refbits[0] = 1;
				bb = pi->count * BYTESPERPAGE - sizeof (struct pageinfo);
				FPRINTF((stdout, "gcmarkregion: st=%p e=%p s=%p"
						" p=%p pp=%p bb=%d\n",
						st, e, s, p, pp, bb));
			}
			else if (big)		/* bogus block */
				continue;
			else				/* regular block */
			{
				num = BLOCKNUM(pi, p);

				/* if the last byte of this block is outside a page, it is
				   bogus */
				if (num >= pi->numblocks)
				{
					/* pi->history |= 1; */		/* flag the hit */
					continue;
				}

				bb = pi->blocksize;
				pp = (char *)pi + num * bb + sizeof (struct pageinfo);

				if (g.skipinterior && pp != p)
					continue;

				if (GETBIT(pi->refbits, num))
								/* already marked and walked */
					continue;

				SETBIT(pi->refbits, num);
			}

			if ((char *)pp < low || (char *)pp > high)
				crash("gcmarkregion(): block pointer pp not in heap");

			if ((char *)pp + bb < low || (char *)pp + bb > (char *)g.heaphigh)
				crash("gcmarkregion(): end of block pointer pp not in heap");

			if (tos >= STACK)
				gcmarkregion(pp, pp + bb);
			else
			{
				startstk[tos] = pp;
				endstk[tos] = pp + bb;
				tos++;
			}
		}
	}
}