Go Down

Topic: Using templates in a library (SOLVED) (Read 1 time) previous topic - next topic

DigitalJohnson

#5
Dec 03, 2012, 06:24 pm Last Edit: Dec 03, 2012, 06:35 pm by DigitalJohnson Reason: 1
@tuxduino

:D Thank you very much! It finally works. As for the double cast, I'm not sure. Copied it from EEPROMWriteAnything. You've been a big help. If there's anything I can do for you...

Thanks again,
DigitalJohnson

PS. I'll share for anyone that can use it.

External Memory library

ExMem.h
Code: [Select]

#ifndef EXMEM_H
#define EXMEM_H

#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

#include <inttypes.h>
#include <avr/io.h>

class exmem
{
    public:
    exmem();
    void enable(uint8_t addressWidth = 16,
    uint16_t lowerLimit = 0x0000,
    uint8_t upperSectorWaitState = 0x00,
    uint8_t lowerSectorWaitState = 0x00);
    void disable(void);
    template <class TYPE> uint16_t write(bool sector, uint16_t address, const TYPE &data);
    template <class TYPE> uint16_t read(bool sector, uint16_t address, TYPE &store);
};


extern exmem ExMem;

static uint16_t upperSectorOffset = 0x0000;
static uint16_t upperLimit = 0xFFFF;
static uint16_t upperSize = 0xDE00;
static uint16_t lowerSize = 0xDE00;

exmem::exmem()
{
}

void exmem::enable(uint8_t addressWidth, uint16_t upperSectorBoundry,
uint8_t upperSectorWaitState, uint8_t lowerSectorWaitState)
{
    switch (addressWidth)
    {
        XMCRB &= 0xF8;
        case 8:
        upperLimit = 0x00FF;
        XMCRB = 0x07;
        break;
        case 10:
        upperLimit = 0x03FF;
        XMCRB = 0x06;
        break;
        case 11:
        upperLimit = 0x07FF;
        XMCRB = 0x05;
        break;
        case 12:
        upperLimit = 0x0FFF;
        XMCRB = 0x04;
        break;
        case 13:
        upperLimit = 0x1FFF;
        XMCRB = 0x03;
        break;
        case 14:
        upperLimit = 0x3FFF;
        XMCRB = 0x02;
        break;
        case 15:
        upperLimit = 0x7FFF;
        XMCRB = 0x01;
        break;
        default:
        upperLimit = 0xFFFF;
        break;
    }
    uint16_t boundry;
    if (addressWidth < 15)
    {
        boundry = 0x0000;
    }
    else if (addressWidth < 16)
    {
        boundry = constrain(upperSectorBoundry, 0x0000, 0x6000);
    }
    else
    {
        boundry = upperSectorBoundry;
    }
    XMCRA &= 0x8F;
    switch (boundry)
    {
        case 0x4000:
        upperSectorOffset = 0x1E00;
        XMCRA |= 0x20;
        break;
        case 0x6000:
        upperSectorOffset = 0x3E00;
        XMCRA |= 0x30;
        break;
        case 0x8000:
        upperSectorOffset = 0x5E00;
        XMCRA |= 0x40;
        break;
        case 0xA000:
        upperSectorOffset = 0x7E00;
        XMCRA |= 0x50;
        break;
        case 0xC000:
        upperSectorOffset = 0x9E00;
        XMCRA |= 0x60;
        break;
        case 0xE000:
        upperSectorOffset = 0xBE00;
        XMCRA |= 0x70;
        break;
        default:
        upperSectorOffset = 0x0000;
        break;
    }
    if (0 < upperSectorOffset)
    {
        lowerSize = upperSectorOffset;
        upperSize = ((1 + upperLimit) - (0x2200 + upperSectorOffset));
    }
    else
    {
        lowerSize = upperSize = ((1 + upperLimit) - 0x2200);
    }
    switch (upperSectorWaitState)
    {
        XMCRA &= 0xF3;
        case 1:
        XMCRA |= 0x04;
        break;
        case 2:
        XMCRA |= 0x08;
        break;
        case 3:
        XMCRA |= 0x0C;
        break;
        default:
        break;
    }
    switch (lowerSectorWaitState)
    {
       
        XMCRA &= 0xFC;
        case 1:
        XMCRA |= 0x01;
        break;
        case 2:
        XMCRA |= 0x02;
        break;
        case 3:
        XMCRA |= 0x03;
        break;
        default:
        break;
    }
    XMCRA |= 0x80;
}

void exmem::disable(void)
{
    XMCRA &= 0x7F;
}

template <class TYPE>
uint16_t exmem::write(bool sector, uint16_t address, const TYPE &data)
{
    uint8_t *pExtMemory = reinterpret_cast <uint8_t *> (0x2200);
    const uint8_t *pData = (const uint8_t *)(const void *)&data;
    uint16_t i;
    i = 0;
    if (sector)
    {
        if (address >= upperSize)
        {
            return i;
        }
    }
    else
    {
        if (address >= lowerSize)
        {
            return i;
        }
    }
    for (; i < sizeof(data); i++)
    {
        if (sector)
        {
            uint8_t *pMemory;
            pMemory = (uint8_t *)(pExtMemory + upperSectorOffset + address++);
            *pMemory = (uint8_t)(*pData++);
        }
        else
        {
            uint8_t *pMemory;
            pMemory = (uint8_t *)(pExtMemory + address++);
            *pMemory = (uint8_t)(*pData++);
        }
    }
    return i;
}

template <class TYPE>
uint16_t exmem::read(bool sector, uint16_t address, TYPE &store)
{
    uint8_t *pExtMemory = reinterpret_cast <uint8_t *> (0x2200);
    uint8_t *pStore = (uint8_t *)(void *)&store;
    uint16_t i;
    i = 0;
    if (sector)
    {
        if (address >= upperSize)
        {
            return i;
        }
    }
    else
    {
        if (address >= lowerSize)
        {
            return i;
        }
    }
    for (; i < sizeof(store); i++)
    {
        if (sector)
        {
            uint8_t *pMemory = (pExtMemory + upperSectorOffset + address++);
            *pStore++ = (uint8_t)(*pMemory);
        }
        else
        {
            uint8_t *pMemory = (pExtMemory + address++);
            *pStore++ = (uint8_t)(*pMemory);
        }
    }
    return i;
}

exmem ExMem = exmem();

#endif
DigitalJohnson

DigitalJohnson

After I get all the comments back in I'll post it on google code. Enjoy.

DJ
DigitalJohnson

tuxduino


DigitalJohnson

I've found a small bug. If I pass data type char* to the write function, say char *c1 = "hello world", it will return with a value of 2, meaning it wrote 2 bytes. Then I pass the read function a variable of char*, say char *c2, and read from the same address written to. It also returns with 2, meaning it read 2 bytes. But when I use Serial.print(c2), It prints "hello world" as it should. Why is it returning a value of 2 when it clearly is more. Float returns 4, as do double, long long returns 8, and uint8_t = 1 and uint16_t = 2, all as expected. So what's with char*?

Can anyone shed some light on this?

DJ
DigitalJohnson

PaulS

Quote
it will return with a value of 2, meaning it wrote 2 bytes.

The value 2 means that a pointer is 2 bytes. It has NOTHING to do with the amount of data pointed to.

To verify that, create an array of ints, and pass that, via a pointer, to the class. The array can have 27 elements in it, and you will still get a 2 back.

Go Up