/*- Flashent: Parameterlist Example
 *
 *  Copyright (C) 1995 MCT Paul & Scherer Berlin.
 *  This source is in the public domain.
 */

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <target.h>
#include <sys/nofloat.h>

#include "flash.h"

#ifndef ROM
    #define ROM ROM_BASE
#endif
#define PBLOCK  	(fword *)(ROM_BASE + 32 * 1024)

#define dimof(v) 	(sizeof(v) / sizeof(*(v)))
#define	NULLPOINTER	((struct parameter *)-1L)
#define	NULLWORD        ((fword)-1L)

/*- Parameter structure.
 */

struct parameter{
    struct parameter *next;
    char data[76];
};

/*- Last parameter pointer cache & search funtion.
 */

static struct parameter *last_parameter_pointer = NULLPOINTER;

static struct parameter *
init_last_parameter_pointer(fword *pblock){
    for(last_parameter_pointer = last_parameter_pointer == NULLPOINTER
        ? (struct parameter *)pblock
        : last_parameter_pointer;
        last_parameter_pointer->next != NULLPOINTER;
        last_parameter_pointer = last_parameter_pointer->next
    );
    return last_parameter_pointer;
}

/*- Print parameter buffer.
 */

static void
print_parameter_list(fword *pblock){
    struct parameter *p;

    for(p = (struct parameter *)pblock; p != NULLPOINTER; p = p->next){
        if(*p->data != (char)NULLWORD){
            printf("%-*.*s\n", dimof(p->data), dimof(p->data), p->data);
        }
    }
}

/*- Insert new record into parameter buffer.
 */

static void
insert_parameter(fword *pblock, char *buf){
    struct parameter *p;

    if(last_parameter_pointer == NULLPOINTER){
        init_last_parameter_pointer(pblock);
    }
    if(last_parameter_pointer
     < (struct parameter *)((char *)pblock
        + flash_block_size - sizeof(struct parameter))
    ){
        p = last_parameter_pointer + 1;
        if( flash_write(&last_parameter_pointer->next, &p, sizeof(p)) < 0
         || flash_write(&last_parameter_pointer->data, buf, (strlen(buf)
            + sizeof(fword)) / sizeof(fword) * sizeof(fword)) < 0
        ){
            printf("Write error @ 0x%p\n", p);
        }else{
            last_parameter_pointer = p;
        }
    }else{
        puts("Parameter buffer is full - erase first with 'e'.");
    }
}

/*- This is where the action is.
 */

void
dumpmemory(unsigned char *address, long length){
    long n;

    for(n = 0; n < length; n++){
        if(!(n % 16)){
            printf("%#08lx:  ", (long)(address + n));
        }
        printf("%02x ", address[n]);
        switch(n % 16){
            case 7: putchar(' '); /* down */
            case 3: case 11: putchar(' '); break;
            case 15: puts(""); break;
        }
    }
    puts("");
}

static void
action(fword *pblock){
    char buf[dimof(last_parameter_pointer->data)];

    puts(">>> Usage <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    puts("Empty lines will print the buffer so far");
    puts("New lines are inserted at the end");
    puts("Lines constisting only of a 'q' will terminate");
    puts("Lines constisting only of a 'e' will erase");
    puts("Lines constisting only of a 'd' will dump the whole block");
    puts("");
    while(1){
        printf("Talk to me! > ");
        fgets(buf, dimof(buf), stdin);
        if(strrchr(buf, '\n')){
            *strrchr(buf, '\n') = 0;
        }
        if(buf[0] == 'q' && !buf[1]){
            return;
        }
        if(buf[0] == 'e' && !buf[1]){
            puts("Erasing parameter block");
            flash_block_erase((void *)pblock);
            last_parameter_pointer = NULLPOINTER;
            continue;
        }
        if(buf[0] == 'd' && !buf[1]){
            dumpmemory(pblock, flash_block_size);
        }
        if(!buf[0]){
            print_parameter_list(pblock);
        }else{
            printf("Inserting: \"%s\"\n", buf);
            insert_parameter(pblock, buf);
        }
    }
}

/*- Main.
 */

int
main(int argc, char **argv){

    puts("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
    puts("==============================================================================");
    puts(" Flash memory parameter list demo\n");
    puts("==============================================================================");
    puts("");

    /*- Initialize flash packet. */
    if(flash_identify(PBLOCK) < 0){
        puts("Error: Cannot identify flash chips. Trying anyway.");
    }
    flash_write(0, 0, 0);
    puts(">>> Flash chip information <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    printf("Manufacturer: %s\n", flash_manufacturer());
    printf("Chipname:     %s\n", flash_name());
    puts("");

    while (1){
        action(PBLOCK);
    }
}
