Sonder Design Team / Mbed 2 deprecated BlackBoard_Firmware_Fast_read_not_test

Dependencies:   Memory25L16_fast USBDevice mbed

Fork of BlackBoard_Firmware_MVP by Sonder Design Team

BB_Basic.cpp

Committer:
ThomasSonderDesign
Date:
2017-02-14
Revision:
8:3577b060d7af
Parent:
7:b30c411a6d36
Child:
9:7c0f42f090e8

File content as of revision 8:3577b060d7af:

/******************************************************************************
 * S O N D E R
 * Copyright 2016 (C) Sonder Design Pty Ltd - All Rights Reserved
 * Unauthorised copying of this file, via any medium is strictly prohibited
 * Proprietary and confidential
 *****************************************************************************/
/*
This is the first implementation of a functional firmware. It allows the user to change the Display layout and type. Improvements for later
versions will include usb keyboard support
*/
#include "mbed.h"
#include "USBHID.h"
#include "Memory.h"
#include "VKCodes.h"

/******************************************************************************
 * Definitiontions
 */
//Constants for black board

DigitalOut cs_mem(P0_2);        //Set up memory's Chip Select pin
DigitalOut cs_epd(P1_23);       //Set up epd's Chip Select pin
DigitalOut TconEn(P0_5);        //Tcon Enable pin, open drain must invert
DigitalOut start(P0_14);
DigitalIn TCbusy(P0_4);           //Tcon busy line

DigitalOut myled(P0_9);
DigitalOut SRclk(P0_15);        //Shift register clk signal
DigitalOut SRlat (P1_22);       //Shift register output latch
DigitalOut SRds(P1_14);         //Shiftreg data pin

DigitalIn E(P1_13);             //Definne row row A input pin
DigitalIn D(P0_7);              //Definne row row B input pin
DigitalIn C(P1_28);             //Definne row row C input pin
DigitalIn B(P1_31);             //Definne row row D input pin
DigitalIn A(P1_29);             //Definne row row E input pin

DigitalIn modC(P0_11);          //Definne row mod C input pin
DigitalIn modB(P0_12);          //Definne row mod B input pin
DigitalIn modA(P0_13);          //Definne row mod A input pin

Serial pc (P0_19,P0_18);        //Setup a real serial port
Memory mem(P0_2);               //Create a new memory manager with chip select on P0_2

USBHID hid(64, 8,0x1234,0x3241); //Create a HID conection with and 64 byte input and 8 byte output report, PID0x1234 VID 3241

volatile int *PIN39IOREG = (int *)0x4004403C;
int reportLength = 64;              //The length of the report recieved

//Codes to send to the pc
int readyAndWaiting []= {2,0x25,0,0,0,0,0,0};
int busy []= {2,0x50,0,0,0,0,0,0};
int readyForComand []= {2,0x75,0,0,0,0,0,0};


int GlobalAddress = 0;              //The last adress written to plus one
int lastErasedBlock =0;             //The Adress of the last erases block
int currentName = 0;                //The position in the nameList of the curret layout
char nameList[16][5];                  //A list of all the Layouts in memory, each name is 5 bytes long

//Locations in memory were the 16 layouts can be stored
const int slots [] = {0,0x20000, 0x40000,0x60000, 0x80000, 0xa0000, 0xc0000, 0xe0000, 0x100000, 0x120000,0x140000,0x160000,0x180000, 0x1a0000,0x1e0000};
bool erasedSlots[]= {true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false};

int keybuffer[10][2];   //A buffer for storing key presses (mod key plus key)

int scanCode [5][14]= { //This 2D array maps key scan codes to letter codes
    {VK_OEM_3, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, VK_OEM_MINUS, VK_OEM_PLUS, VK_BACK},
    {VK_TAB, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P},
    {KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, VK_OEM_1},
    {KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, VK_LSHIFT,VK_CONTROL,VK_LMENU},
    {VK_F1, VK_F2,VK_F3,VK_F4, VK_SPACE, VK_TAB, VK_BACK, VK_RSHIFT,VK_LWIN,VK_RMENU}
};


/******************************************************************************
 * Set up Functions
 */
char check(int depth)      //Check availible memory
{
    char c;
    char *ptr = new char;
    //pc.printf("stack at %p, heap at %p\n", &c, ptr);
    //pc.printf("sh,%i,%i\n", &c, ptr);
    pc.printf("mem size = %p\n", &c-ptr);
    //if (depth <= 0) return;
    //    check(depth-1);
    free(ptr);
    return 1;
}

/**
 * Set up the memory SPI
 */
SPI setupSPI()
{
    SPI my_spi(P0_9,P0_8,P0_10);    // mosi, miso, sclk
    //cs_mem = 1;                         // Chip must be deselected
    my_spi.format(8,3);             // Setup the spi for 8 bit data, low steady state clock,
    my_spi.frequency(1000000);      // second edge capture, with a 1MHz clock rate, Will work up to 20MHz
    return my_spi;
}


/**
 * Setup USB HID, usefull for later not used in this iterarion
 */
/*USBHID setupUSB()
{
    USBHID hid(64, 8,0x1234,0x3241); //Create a HID conection with and 64 byte input and 8 byte output report, PID0x1234 VID 3241
    return hid;
}*/


/******************************************************************************
 * USB Functions
 */

/**
 * checks the usb recive buffer, if it contains data it is coppired to USBDataBuffer and returns 1
 * if the empty return -1;
 */
int readUSB(int USBDataBuffer[])
{
    HID_REPORT recv_report;
    if(hid.readNB(&recv_report)) {                      //Check if there is a received report
        //printf("\n");
        for(int i = 0; i<recv_report.length; i++) {     //Store the report in a locat array
            //printf(" %x", recv_report.data[i]);
            USBDataBuffer[i] = recv_report.data[i];
        }
        return 1;
    } else {
        return -1;
    }
}


/**
 * usbSend, send an eight byte report over usb
 */
void sendUSB(int usbReport[])
{
    //pc.printf("\nS: %x",usbReport[1]);
    HID_REPORT send_report;
    send_report.length = 8;

    send_report.data[0] = usbReport[0];
    send_report.data[1] = usbReport[1]; //comand byte
    send_report.data[2] = usbReport[2];
    send_report.data[3] = usbReport[3];
    send_report.data[4] = usbReport[4];
    send_report.data[5] = usbReport[5];
    send_report.data[6] = usbReport[6];
    send_report.data[7] = usbReport[7];
    hid.send(&send_report);
}




/******************************************************************************
 * Keyboard  Functions
 */

/**
 * keyScan(int keyBuffer[][]). Sacns the keyboard matrix and stores any keypresses in the 2D keyBuffer
 * If a key press was detected it returns the most recent key press, otherwise it returns 0
 */
int keyScan()
{
    //Initialise and set Up code
    int counter=0;      //Keubuffer index counter
    int rowNum = 0;
    int code =0;        //the return value, the last key pushed

    /*Clear the keybuffer*/
    for(int i = 0; i<10; i++) {
        keybuffer[i][0]=0;
        keybuffer[i][1]=0;
    }

    int noCols = 16;  //number of bits to be shifted
    int t = 1000;  //wait time in uS. This is the period in us of the shift register clock
    SRclk=0;
    SRlat = 0;
    SRds =1;    //Set first bit high


    for (int col = 0; col<noCols; col++) {    //Loop through one shifit reg
        SRclk = 1;      //clock in current bit      //        __       __
        wait_us(t/2);                               //SRclk__|  |_..._|  |_
        SRds = 0;       //set dext bit low          //      ___
        wait_us(t/2);                               //SRds |   |___..._____
        SRclk=0;                                    //          _         _
        SRlat = 1;      //latch all data out        //SRlat____| |_...___| |_
        wait_us(t/2);                               //
        SRlat=0;

        /*
        Check if a button has been pressed by scaning the rows
        Generates a unique code depending on which button has been pressed
        The code is looked up in the scanCode Array
        */
        if(A>0) {
            //pc.printf("A\n");
            rowNum = 0;
            code = scanCode[rowNum][col];
            keybuffer[counter][1]= code;
            counter++;
        }
        if(B>0) {
            //pc.printf("B\n");
            rowNum = 1;
            code = scanCode[rowNum][col];
            keybuffer[counter][1]= code;
            counter++;
        }
        if(C>0) {
            //pc.printf("C\n");
            rowNum = 2;
            code = scanCode[rowNum][col];
            keybuffer[counter][1]= code;
            counter++;
        }
        if(D>0) {
            //pc.printf("D\n");
            rowNum = 3;
            code = scanCode[rowNum][col];
            keybuffer[counter][1]= code;
            counter++;
        }
        if(E>0) {
            //pc.printf("E\n");
            rowNum = 4;
            code = scanCode[rowNum][col];
            keybuffer[counter][1]= code;
            counter++;
        }

        /*Scan the mod keys and assign them to the mod column of key buffer in the from zero up*/
        if(col>0) {
            counter=0;

            if(modC>0) {
                rowNum = 0;
                code = scanCode[rowNum][col];
                keybuffer[counter][0]= code;
            }
            if(modB>0) {
                rowNum = 0;
                code = scanCode[rowNum][col];
                keybuffer[counter][0]= code;
            }
            if(modA>0) {
                rowNum = 0;
                code = scanCode[rowNum][col];
                keybuffer[counter][0]= code;
            }
        }
    }
    return code;
}


/**
 * int sendKey(int mod, int key). Sends a keypress to the pc over usb
 */
void sendKey(int mod, int key)
{
    int temp[]= {0x01,mod,key,0,0,0,0,0};
    sendUSB(temp);
}

/**
 * keyCheck(), scanss the keys and sends the keypress to the pc over usb
 */
void keyCheck(){
    //pc.printf("KeyCheck\n");
    if (keyScan()>0) {                  //check if keyScan returned key presss
            pc.printf("\nKey scan|n");
            int countpos =0;
            while(keybuffer[countpos][1]>0) {   //While there are keypresses in the buffer
                pc.printf("%i",keybuffer[countpos][1]);
                pc.printf(" ");
                sendKey(keybuffer[countpos][0],keybuffer[countpos][1]);//Send key press
                countpos++;
                myled=0;
            }
        }
}

/******************************************************************************
 * Memory control funtions
 */


/**
 * Writes the contense of USBDataBuffer to memoryBuffer, starting at bufferIndex
 * returns the index of the last written byte+1;
 */
int appendBuffer(int USBDataBuffer[], char memoryBuffer[], int bufferIndex)
{
    //printf("\n");
    int posIndex=0;
    for(int i = 0; i < 64; i++) {
            
        memoryBuffer[bufferIndex+i]=USBDataBuffer[i];
        posIndex++;
    }
    return (bufferIndex+posIndex);
}

/**
 *Sends the ready and waiting signall and loops untill data is recieved.
 *Recieved data is stored in the USBDataBuffer
 */
void waitForData(int USBDataBuffer[])
{
    sendUSB(readyAndWaiting);
    while (readUSB(USBDataBuffer)<1) {
        sendUSB(readyAndWaiting);
    }
}


/**
 * receives 64 packets over usb and stores them in memooryBuffer. When memory Buffer is full it is
 * written to memory at address. This is repeated 336 times to write a whole image to memory.
 * returns the next availible adsress;
 */
int writeImage(SPI my_spi,int Address)
{
    Timer t;
    t.start();          //Start the timer
    pc.printf("\nAddress: %i\n", Address);
    int USBDataBuffer [64];             //Creat a buffer for recived data
    char memoryBuffer [bufferSize];     //Create a memory buffer, to be sent to flash
    int bufferIndex = 0;                //points to the next available possition in memory
    int startAddress = Address;
    while (Address<startAddress+86272) {
        //waitForData(USBDataBuffer);         //Waits untill data is recieved on usb, puts it in USBDataBuffer
        while(bufferIndex<bufferSize) {
            waitForData(USBDataBuffer);
                bufferIndex=appendBuffer(USBDataBuffer, memoryBuffer, bufferIndex);     //Appends USBDataBuffer onto memoryBuffer
        }
        bufferIndex=0;          

        //Checks if the block has been erased. only virgin bytes can be written to, so if a block has not been errased it is write
        //protected. this erases a block before writung to it if nessisary.
        int currentSlot = Address/0x20000;
        if (erasedSlots[currentSlot]) {
            Address = mem.writeData(my_spi, memoryBuffer, Address, bufferSize);
        } else {
            pc.printf("\nCan not write to unerased slot.");
            Address = mem.writeData(my_spi, memoryBuffer, Address, bufferSize);
        }        
    }
    pc.printf("\n pinnished writing");
    t.stop();
    pc.printf("\nwrite image %i", t.read_ms());
    t.reset();
    return Address;
}

/**
 * Writes a single memorybuffer to memory
 * receives 64 packets over usb and stores them in memooryBuffer. When memory Buffer is full it is
 * written to memory at address.
 * returns the next availible adsress;
 */
int writeFrame(SPI my_spi,int Address)
{
    int USBDataBuffer [64];             //Creat a buffer for recived data
    char memoryBuffer [bufferSize];     //Create a memory buffer, to be sent to flash
    int bufferIndex = 0;                //points to the next available possition in memory
    Timer t;
    t.start();          //Start the timer

    waitForData(USBDataBuffer);         //Waits untill data is recieved on usb, puts it in USBDataBuffer
    t.stop();

    while(bufferIndex<bufferSize) {
        bufferIndex=appendBuffer(USBDataBuffer, memoryBuffer, bufferIndex);     //Appends USBDataBuffer onto memoryBuffer
        t.start();
        waitForData(USBDataBuffer);
        t.stop();
    }

    //Checks if the block has been erased. only virgin bytes can be written to, so if a block has not been errased it is write
    //protected. this erases a block before writung to it if nessisary.
    int currentSlot = Address/0x20000;
    pc.printf("\nCurrent slot: %i", currentSlot);
    if (erasedSlots[currentSlot]) {
        pc.printf("\nNE");
        Address = mem.writeData(my_spi, memoryBuffer, Address, bufferSize);
    } else {
        pc.printf("\nCan not write to unerased slot.");
    }
    //t.stop();
    pc.printf("\nWait1  Wate2-4 %i", t.read_ms());
    t.reset();
    return Address;
}


/**
 * Sends a report containing a the name of the layout stored at a given slot
 */
void getLayoutName(int slot)
{
    int temp [] = {0x31,slot,nameList[slot][0],nameList[slot][1],nameList[slot][2],nameList[slot][3],nameList[slot][4],0};
    sendUSB(temp);
    pc.printf("\nSlot %d = %c%c%c%c%c",slot, nameList[slot][0],nameList[slot][1],nameList[slot][2],nameList[slot][3],nameList[slot][4]);
}


/**
 * Sends three reports containing the list of layout names stored in memory.
 */
void getNameList()
{
    for(int slot =0; slot< 16; slot++) {
        getLayoutName(slot);
        }
}

/**
 * Sends the name of the Current layout
 */
void getCurrentLayout()
{
    getLayoutName(currentName);
}

/**
 * Writes the name of a given layout to the top memory address in its reserved block
 * name[] is a 5 bytes char array with the most significant byte at name[0]
 */
void nameBlock(SPI my_spi, char name[], int slot)
{
    //char temp[]= {name};
    mem.writeData(my_spi, name, slots[slot]+0x1ff00, 5);
}

/**
 * Reads memory to find the names of the layouts stored. puts the names into nameList
 */
void populateNameList(SPI my_spi)
{
    for(int slot=0; slot<16; slot++) {
        char name[5];
        mem.readData(my_spi, name, slots[slot]+0x1FF00, 5); //Read five bytes from the end of a slot into the name array
        for( int i = 0; i<5; i++) {
            nameList[slot][i]=name[i];
        }
    }
}

/**
 * Prepares the memory for a new Layout, writes the layout's name, and erases the blocks
 */
void prepImage(SPI my_spi, int slot, char name[])
{
    pc.printf("\nSlot: %i", slots[slot]);
    mem.blockErase(my_spi, slots[slot]);           //erase the bottom block of the slot
    mem.blockErase(my_spi, slots[slot]+0x10000);   //erase the top block of the slot
    pc.printf("\nWorking");
    nameBlock(my_spi, name,  slots[slot]/*+0x1FFF9*/); //Write the name of the layout to memory
    erasedSlots[slot]=true;                        //Mark the erased slot as true
    populateNameList(my_spi);
}


/******************************************************************************
 * Display control funtions
 */

/*###### EPD Set Up ######*/
//Sets up the EPD  spi pins
SPI setupEPD()
{
    pc.printf("\nEpd setup");
    /////Setup the spi link with the EDP////
    SPI epd_spi(P0_21, P1_21, P1_20);    //SPI setup: mosi, miso, sclk
    // Setup the spi for 8 bit data, high steady state clock,
    // second edge capture, with a 5MHz clock rate
    epd_spi.format(8,3);
    epd_spi.frequency(5000000);
    return epd_spi;
}


/*###### EPD Write ######*/
//Update the whole display with data from memory, starting at the 
int EPD_Write(SPI mem_spi, int address)
{
    pc.printf("\nAddress: %i", address);
    //Setup the SPIs
    SPI epd_spi = setupEPD();       //Creat a new SPI object to comunicate with the EPD

    //Create local variables
    int lineLengh = 60;            //the length of the display in bytes
    int imageLength = 1440;
    char sixtyBytes[lineLengh];        //Create a line buffer
    
    //int line = 0;               //counter to keep track of the current line
    //int frameLine = 0;          //counter to keep track of the line in the current frame
    

    //led=!led;
    
    //Begin SPI comunication
    cs_epd=1;           //EPD chip deselected
    TconEn =1;          //Tcon ON set High
    wait_ms(120);       //delay 120ms
    cs_epd=0;           //Select the Tcon chip
    wait_ms(1);         //delay 1ms
    //Write Header
    epd_spi.write(0x06);
    epd_spi.write(0xa0);
    wait_ms(120);   //delay 120ms

    //loop throug 1440 lines
    for(int j=0; j<imageLength; j++) {
        //pc.printf("\n");
        mem.readData(mem_spi, sixtyBytes, address, lineLengh);    //Read the line, putt them in buffer return the next address to read from
        for(int i =0; i<lineLengh; i++) {             //Read one byte from the buffer
            epd_spi.write(sixtyBytes[i]);      //and write it to the display
            //pc.printf("%i%i%i%i%i%i%i%i",sixtyBytes[i]>>7&&1,sixtyBytes[i]>>6&&1,sixtyBytes[i]>>5&&1,sixtyBytes[i]>>4&&1,sixtyBytes[i]>>3&&1,sixtyBytes[i]>>2&&1,sixtyBytes[i]>>1&&1,sixtyBytes[i]&&1);
            address++;
            //byteCounter++;
        }
        
        epd_spi.write(00);      //Write a 0 at the end of each line
        if(j%100==0){
            keyCheck();
            }
        //wait_us(10000);
    }
    wait_us(1000);
    DigitalOut sclk(P0_13);   //serial clk
    sclk = 0;
    cs_epd=1;       //Deselct the chip
    Timer t;
    t.start();          //Start the timer
     while(TCbusy)
    {
        keyCheck();
        //wait_ms
        }
        t.stop();
    TconEn=0;       //Deassert Tcon ON
    cs_epd=0;       //Deassert chip select

    printf("\ntime = %i ", t.read_ms());
    t.reset();
    return 1;
}

/*###### EPD Write ######*/
//Update the whole display with data from a reserved slot
int EPD_Swap(SPI mem_spi, int slot)
{
    return EPD_Write(mem_spi, slots[slot]);
}
/*******************************************************
 * Main Function
 */
int main()
{
    Timer t;

    int USBDataBuffer[64];
    SPI my_spi = setupSPI();        //Creates an SPI object to comunicate with the external memory
    populateNameList(my_spi);       //Reads the names  of layouts stored in external memory into RAM

    while(1) {
        //pc.printf("Loop");

        sendUSB(readyForComand);
        keyCheck();        

        sendUSB(readyForComand);
        if (readUSB(USBDataBuffer)>0) {
            pc.printf("\nSwitch %i",USBDataBuffer[1]);
            char temp[] = {USBDataBuffer[3],USBDataBuffer[4],USBDataBuffer[5],USBDataBuffer[6],USBDataBuffer[7]};
            switch(USBDataBuffer[1]) {
                case 0x10:          //If the recieved data is a write instruction
                    GlobalAddress = writeFrame(my_spi, USBDataBuffer[2]*65536+USBDataBuffer[3]*256+USBDataBuffer[4]);       //Write the following data to the memory at 24 bit address usbDatabuffer[2-4]
                    break;
                case 0x11:
                    pc.printf("\nPrep write");
                    prepImage(my_spi, USBDataBuffer[2], temp);//Prepare a slot in memory for an image
                    break;
                case 0x12:
                    pc.printf("\nImage write");
                    writeImage(my_spi, USBDataBuffer[2]*65536+USBDataBuffer[3]*256+USBDataBuffer[4]);//Write the next 86400 bytes of data to the memory starting at 24 bit address usbDatabuffer[2-4]
                    break;
                case 0x20:          //If the recieved comand is a read instruction
                    //mem.readData(my_spi, memoryBuffer, USBDataBuffer[2], USBDataBuffer[3]);//read(spi, destination[], address, length)
                    //pc.printf(" \n---EPD UPDATE--- %i",USBDataBuffer[2]*65536+USBDataBuffer[3]*256+USBDataBuffer[4]);
                    EPD_Write(my_spi, USBDataBuffer[2]*65536+USBDataBuffer[3]*256+USBDataBuffer[4]);
                    break;
                case 0x21:          //If the recieved comand is a swap instruction
                    EPD_Swap(my_spi, USBDataBuffer[2]);
                    break;    
                case 0x30:          //If the recieved comand is a request for the cutrrent name
                    populateNameList(my_spi);
                    getNameList();
                    break;
                case 0x35:          //If the recieved comand is a request for all the names 
                    getCurrentLayout();
                    break;
                default:
                    pc.printf("\nfail! [%x %x %x %x %x %x %x %x]",USBDataBuffer[0],USBDataBuffer[1],USBDataBuffer[2],USBDataBuffer[3],USBDataBuffer[4],USBDataBuffer[5],USBDataBuffer[6],USBDataBuffer[7]);
            }
        }

        //pc.printf("\n%d", t.read_us());
        t.reset();
    }
}