// Program FL_EE.C, Sourceboost C, PIC16F887, ICD2
//
// Illustrates how to write to and read from flash EEPROM memory.  Note
// that this is 14-bits wide.
//
// The program is simplified to log data by repeatedly calling a stub make_meas
// which generates four words and saving these to flash EEPROM beginning at
// location 0x1000.  Each of these four words is displayed on the serial LCD
// using a 'M' (meas) delimiter.
//
// These four word blocks of data are sequentially written to EEPROM by reading
// a 16 word block, inserting the four word block and then programming the 16
// word block.
//
// The program memory is then displayed by reading four word blocks. Note that
// the delimiter 'D' is used to indicate the "dump" code is being executed.
//
// copyright, Peter H. Anderson, Baltimore, MD, July, '09

#include <system.h>
#include <icd2.h>
#include <string.h>
#include <stdio.h>

#pragma DATA 0x2007, 0x28e4
#pragma DATA 0x2008, 0x3eff
#pragma CLOCK_FREQ 4000000

#define NEGATIVE 1
#define POSITIVE 0

#define TRUE !0
#define FALSE 0

//#define DEBUG

typedef unsigned char byte;

void log_data(void);
void dump_data(void);

void make_meas(int *data, byte num_words);

void write_flash_eeprom(int write_address, int *data, byte num_words);
void read_flash_eeprom(int read_address, int *data, byte num_words);

void print_str(char *s);
void print_ch(char ch);

void print_ints(int *d, byte num, char ch);
void asynch_setup(void);

void main(void)
{
    asynch_setup();
    while(1)
    {
        log_data();
        dump_data();
    }
}

void log_data(void)
{
    byte n;
    int data[16];

    int write_address = 0x1000;

    for (n=0; n<25; n++)   // 100 words
    {
        make_meas(data, 4);
        write_flash_eeprom(write_address, data, 4);
        write_address += 4;
    }
}

void dump_data(void)
{
    byte m, n;
    int data[16], read_address = 0x1000;

    for (n=0; n<25; n++)
    {
        read_flash_eeprom(read_address, data, 4);
        print_ints(data, 4, 'D');
        read_address += 4;
    }
}

void write_flash_eeprom(int write_address, int *data, byte num_bytes)
{
    int base_address, save_buffer[16];
    byte n, offset;

    base_address = write_address & 0xfff0;	// zero the least signif 4 bits
    offset = write_address & 0x000f;

    eecon1.EEPGD = 1;	// flash data

    read_flash_eeprom(base_address, save_buffer, 16);	// fetch what is in the 16 byte block
    // print_ints(save_buffer, 16, 'W');
    // now insert the new data
    for (n=0; n<num_bytes; n++)
    {
        save_buffer[n+offset] = data[n];
    }

    eeadrh = (byte) (base_address >> 8);
    eeadr = (byte) (base_address & 0xff);

    for (n=0; n<16; n++)
    {
        eedath = save_buffer[n] >> 8;
        eedata = save_buffer[n] & 0xff;
        eecon1.EEPGD = 1;
        eecon1.WREN = 1;

        // disable interrupts
        eecon2 = 0x55;
        eecon2 = 0xaa;
        eecon1.WR = 1;
        asm
        {
           NOP
           NOP
        }

        eecon1.WREN = 0;
        // okay to enable ints
        ++eeadr;
    }
}

void read_flash_eeprom(int read_address, int *data, byte num_words)
{
    byte n, h, l;

    for (n=0; n<num_words; n++)
    {

        eeadrh = (byte) (read_address >> 8);
        eeadr = (byte) (read_address & 0xff);

        eecon1.EEPGD = 1;	// flash data
        eecon1.RD = 1;
        asm
        {
           NOP
           NOP
           NOP
           NOP
           NOP
           NOP
        }

        h = eedath;  l = eedata;
        data[n] = (((int) h) << 8) | l;
        ++read_address;
    }
}

void make_meas(int *data, byte num_words)
{
    static byte m = 0;
    byte n;

    for (n=0; n<num_words; n++)
    {
        data[n] = m * 100 + 4 * n;
    }
    ++m;
    m = (m==20) ? 0 : m;
    print_ints(data, 4, 'M');
    delay_s(2);
}

void asynch_setup(void)
{   // for UART, see Manual pages beginning at page 151
    trisc.7 = 1;
    trisc.6 = 1;    // TX
    rcsta.SPEN = 1; // enable serial port
    txsta.TXEN = 1; // enable transmitter
    txsta.SYNC = 0; // asynchronous
    txsta.BRGH = 1;

    spbrg = 25; // 9600 baud at 4.0 MHz
}

void print_ints(int *d, byte num, char ch)
{
    byte i, j;
    char s[20];

    strcpy(s, "?f");
    print_str(s);

    for (i=0; i<num; i++)
    {
        sprintf(s, "%u", d[i]);
        print_str(s);
        print_ch(ch); // distictive delimiter

        if (((i % 4) == 0) && (i!=0))
        {
            strcpy(s, "?n");
            print_str(s);
        }
    }
    delay_s(1);
}

void print_str(char *s)
{
    while(*s != '\0')
    {
        txreg = *s;
        while(txsta.TRMT == 0)
        {
        }
        ++s;
    }
}


void print_ch(char ch)
{
    txreg = ch;
    while(txsta.TRMT == 0)
    {
    }
}