Callum and Adel's changes on 12/02/19

Dependencies:   Crypto

main.cpp

Committer:
CallumAlder
Date:
2019-03-18
Revision:
29:c96439a60184
Parent:
28:4f02ac845e5d
Child:
30:fbae0e5f200d

File content as of revision 29:c96439a60184:

#include "SHA256.h"
#include "mbed.h"
// #include <iostream>
// #include "rtos.h"

/*TODO:
Change
Indx
newCmd
MAXCMDLENGTH
move the global variables to a class because we arent paeasents
*/

//Photointerrupter input pins
#define I1pin D3
#define I2pin D6
#define I3pin D5

//Incremental encoder input pins
#define CHApin   D12
#define CHBpin   D11

//Motor Drive output pins   //Mask in output byte
#define L1Lpin D1           //0x01
#define L1Hpin A3           //0x02
#define L2Lpin D0           //0x04
#define L2Hpin A6          //0x08
#define L3Lpin D10           //0x10
#define L3Hpin D2          //0x20

#define PWMpin D9

//Motor current sense
#define MCSPpin   A1
#define MCSNpin   A0

//Mapping from sequential drive states to motor phase outputs
/*
State   L1  L2  L3
0       H   -   L
1       -   H   L
2       L   H   -
3       L   -   H
4       -   L   H
5       H   L   -
6       -   -   -
7       -   -   -
*/

//Status LED
DigitalOut led1(LED1);

//Photointerrupter inputs
InterruptIn I1(I1pin);
InterruptIn I2(I2pin);
InterruptIn I3(I3pin);

//Motor Drive outputs
DigitalOut L1L(L1Lpin);
DigitalOut L1H(L1Hpin);
DigitalOut L2L(L2Lpin);
DigitalOut L2H(L2Hpin);
DigitalOut L3L(L3Lpin);
DigitalOut L3H(L3Hpin);

PwmOut pwmCtrl(PWMpin);

//Drive state to output table
const int8_t driveTable[] = {0x12,0x18,0x09,0x21,0x24,0x06,0x00,0x00};

//Mapping from interrupter inputs to sequential rotor states. 0x00 and 0x07 are not valid
const int8_t stateMap[] = {0x07,0x05,0x03,0x04,0x01,0x00,0x02,0x07};
//const int8_t stateMap[] = {0x07,0x01,0x03,0x02,0x05,0x00,0x04,0x07}; //Alternative if phase order of input or drive is reversed

//Phase lead to make motor spin
const int8_t lead = 2;  //2 for forwards, -2 for backwards


class Comm /*: public T_*/{

public:

    Thread t_comm_out;
    Thread t_motor_ctrl;
    // Thread *p_motor_ctrl;

    bool _RUN;

    RawSerial pc;
    // Queue<void, 8> inCharQ;  // Input Character Queue


    static const char MsgChar[11];

    uint8_t MAXCMDLENGTH;

    volatile uint8_t cmdIndx;
    volatile uint8_t inCharQIdx;

    volatile uint32_t motorPower; // motor toque
    volatile float targetVel;
    volatile float targetRot;

    enum msgType {motorState, posIn, velIn, posOut, velOut,

        hashRate, keyAdded, nonceMatch,

        torque, rotations,

        error};

    typedef struct {
        msgType type;
        uint32_t message;
    } msg;

    Mail<msg, 32> mailStack;

    void serialISR(){
        if (pc.readable()) {
            char newChar = pc.getc();
            // inCharQ.put((void*)newChar); // void* = pointer to an unknown type that cannot be dereferenced

            if (inCharQIdx == (MAXCMDLENGTH)) {
                inCharQ[MAXCMDLENGTH] = '\0'; // force the string to have an end character
                putMessage(error, 1);
                inCharQIdx = 0; // reset buffer index
                // pc.putc('\r'); // carriage return moves to the start of the line
                // for (int i = 0; i < MAXCMDLENGTH; ++i)
                // {
                //     inCharQ[i] = ' ';
                //     pc.putc(' ');
                // }

                // pc.putc('\r'); // carriage return moves to the start of the line
            }
            else{
                if(newChar != '\r'){                //While the command is not over,
                    inCharQ[inCharQIdx] = newChar;      //save input character and
                    inCharQIdx++;                      //advance index
                    pc.putc(newChar);
                }
                else{
                    inCharQ[inCharQIdx] = '\0';         //When the command is finally over,
                    strncpy(newCmd, inCharQ, MAXCMDLENGTH); // Will copy 18 characters from inCharQ to newCmd
                    cmdParser();                    //parse the command for decoding.
                    for (int i = 0; i < MAXCMDLENGTH; ++i) // reset buffer
                        inCharQ[i] = ' ';
                    inCharQIdx = 0; // reset index
                }
            }
        }


    }

    /*void commInFn() {
        // if (_RUN)

        while (_RUN) {
            osEvent newEvent = inCharQ.get();
            uint8_t newChar = (uint8_t)(newEvent.value.p); // size_t to type cast the 64bit pointer properly
            pc.putc(newChar);
            if(cmdIndx >= MAXCMDLENGTH){            //Make sure there is no overflow in comand.
                cmdIndx = 0;
                putMessage(error, 1);
            }
            else{
                if(newChar != '\r'){                //While the command is not over,
                    newCmd[cmdIndx] = newChar;      //save input character and
                    cmdIndx++;                      //advance index
                }
                else{
                    newCmd[cmdIndx] = '\0';         //When the command is finally over,
                    cmdIndx = 0;                    //reset index and
                    cmdParser();                    //parse the command for decoding.
                }
            }
        }
    }*/

    void returnCursor() {
        pc.putc('>');
        for (int i = 0; i < inCharQIdx; ++i) // reset cursor position
            pc.putc(inCharQ[i]);
        // for (int i = inCharQIdx; i < MAXCMDLENGTH; ++i) // fill remaining with blanks
        //         pc.putc(' ');
        // pc.putc('<');
    }

    void cmdParser(){
        switch(newCmd[0]) {
            case 'K': //(MsgChar[keyAdded])://
                newKey_mutex.lock();                        //Ensure there is no deadlock
                sscanf(newCmd, "K%x", &newKey);             //Find desired the Key code
                putMessage(keyAdded, newKey);           //Print it out
                newKey_mutex.unlock();
                break;
            case 'V': //(MsgChar[velIn])://
                sscanf(newCmd, "V%f", &targetVel);          //Find desired the target velocity
                putMessage(velIn, targetVel);      //Print it out
                break;
            case 'R': //(MsgChar[posIn])://
                sscanf(newCmd, "R%f", &targetRot);          //Find desired target rotation
                putMessage(posIn, targetRot);      //Print it out
                break;
            case 'T': //(MsgChar[torque])://
                sscanf(newCmd, "T%d", &motorPower);         //Find desired target torque
                putMessage(torque, motorPower);         //Print it out
                break;
            default: break;
        }
    }

    //~~~~~Decode messages to print on serial port~~~~~
    void commOutFn() {
        while (_RUN) {
            osEvent newEvent = mailStack.get();
            msg *pMessage = (msg *) newEvent.value.p;

            //Case switch to choose serial output based on incoming message
            switch (pMessage->type) {
                case motorState:
                    pc.printf("The motor is currently in state %x\n\r", pMessage->message);
                    break;
                case hashRate:
                    pc.printf("\r>%s< Mining: %.4u Hash/s\r", inCharQ, (uint32_t) pMessage->message);
                    returnCursor();
                    break;
                case nonceMatch:
                    pc.printf("\r>%s< Nonce found: %x\r", inCharQ, pMessage->message);
                    returnCursor();
                    break;
                case keyAdded:
                    pc.printf("New Key Added:\t0x%016x\n\r", pMessage->message);
                    break;
                case torque:
                    pc.printf("Motor Torque set to:\t%d\n\r", pMessage->message);
                    break;
                case velIn:
                    pc.printf("Target Velocity set to:\t%.2f\n\r", targetVel);
                    break;
                case velOut:
                    pc.printf("Current Velocity:\t%.2f\n\r", \
                            (float) ((int32_t) pMessage->message / 6));
                    break;
                case posIn:
                    pc.printf("Target Rotation set to:\t%.2f\n\r", \
                            (float) ((int32_t) pMessage->message / 6));
                    break;
                case posOut:
                    pc.printf("Current Position:\t%.2f\n\r", \
                            (float) ((int32_t) pMessage->message / 6));
                    break;
                case error:
                    pc.printf("\r>%s< Debugging position:%x\n\r", inCharQ, pMessage->message);
                    for (int i = 0; i < MAXCMDLENGTH; ++i) // reset buffer
                        inCharQ[i] = ' ';
                    break;
                default:
                    pc.printf("Unknown Error. Message: %x\n\r", pMessage->message);
                    break;
            }
            mailStack.free(pMessage);
        }
    }

    // attach_us -> runs funtion every 100ms 
    void motorCtrlFn() {
        Ticker motorCtrlTicker;
        motorCtrlTicker.attach_us(callback(this,&Comm::motorCtrlTick), 1e5);
        while (1) {
            t_motor_ctrl.signal_wait((int32_t)0x1);
            pc.printf("B4115"); 
        }
    }

    void motorCtrlTick(){
        t_motor_ctrl.signal_set(0x1);
    }


    //TODO: stop function, maybe use parent de-constructor
    //void stop_comm{}

    // public:

    volatile uint64_t newKey;   // hash key
    Mutex newKey_mutex;         // Restrict access to prevent deadlock.

    Comm() :  pc(SERIAL_TX, SERIAL_RX),
              t_comm_out(osPriorityAboveNormal, 1024),
              t_motor_ctrl(osPriorityAboveNormal, 1024)
    { // inherit from the RawSerial constructor

        pc.printf("%s\n\r", "Welcome" );
        MAXCMDLENGTH = 18;

        // reset buffer
        // MbedOS prints 'Embedded Systems are fun and do awesome things!'
        // if you print a null terminator
        pc.putc('>');
        for (int i = 0; i < MAXCMDLENGTH; ++i) {
            inCharQ[i] = '.';
            pc.putc('.');
        }
        pc.putc('<');
        pc.putc('\r');

        inCharQ[MAXCMDLENGTH] = '\0';
        strncpy(newCmd, inCharQ, MAXCMDLENGTH);

        cmdIndx = 0;

        inCharQIdx = 0;
        // inCharQIdx = MAXCMDLENGTH-1;



        pc.attach(callback(this, &Comm::serialISR));

        // Thread t_comm_in(osPriorityAboveNormal, 1024);
        // Thread t_comm_out(osPriorityAboveNormal, 1024);
        // Thread t_motor_ctrl(osPriorityAboveNormal, 1024);

        motorPower = 300;
        targetVel = 45.0;
        targetRot = 459.0;



        /*MsgChar = {'m', 'R', 'V', 'r', 'v',

                  'h', 'K', 'n',

                  'T', 'r',

                  'e'};*/
    }


    void putMessage(msgType type, uint32_t message){
        msg *p_msg = mailStack.alloc();
        p_msg->type = type;
        p_msg->message = message;
        mailStack.put(p_msg);
    }

    void start_comm(){
        _RUN = true;


        // reset buffer
        // MbedOS prints 'Embedded Systems are fun and do awesome things!'
        // if you print a null terminator
        pc.putc('>');
        for (int i = 0; i < MAXCMDLENGTH; ++i) {
            inCharQ[i] = '.';
            pc.putc('.');
        }
        pc.putc('<');
        pc.putc('\r');

        inCharQ[MAXCMDLENGTH] = '\0';
        strncpy(newCmd, inCharQ, MAXCMDLENGTH);

        // returnCursor();

        // t_comm_in.start(callback(this, &Comm::commInFn));
        // this::thread::wait()
        // wait(1.0);
        t_comm_out.start(callback(this, &Comm::commOutFn));
        t_motor_ctrl.start(callback(this, &Comm::motorCtrlFn));


    }

    char newCmd[];  // because unallocated must be defined at the bottom of the class
    char inCharQ[];
};



class Motor{


protected:
    int8_t orState;    //Rotot offset at motor state 0
    int8_t currentState;    //Rotot offset at motor state 0
    int8_t stateList[6];    //Rotot offset at motor state 0
    //Run the motor synchronisation
    
    int8_t* params[2];

    float dutyC; // 1 = 100%
    float mtrPeriod; // motor period
    int stateCount;

public:

    Motor(){

        orState = motorHome();;    //Rotot offset at motor state 0
        currentState = readRotorState();;    //Rotot offset at motor state 0
        stateList[6];    //Rotot offset at motor state 0

        motorOut((currentState-orState+lead+6)%6); // We push it digitally

        dutyC = 0.8;
        mtrPeriod = 2e-3; // motor period
        pwmCtrl.pulsewidth(mtrPeriod*dutyC);

        params[0] = &currentState;
        params[1] = &orState;

        I1.fall(callback(this, &Motor::stateUpdate));
        I2.fall(callback(this, &Motor::stateUpdate));
        I3.fall(callback(this, &Motor::stateUpdate));
        I1.rise(callback(this, &Motor::stateUpdate));
        I2.rise(callback(this, &Motor::stateUpdate));
        I3.rise(callback(this, &Motor::stateUpdate));

        pwmCtrl.period(mtrPeriod);
        pwmCtrl.pulsewidth(mtrPeriod*dutyC);
        
        stateCount = 0;

    }


        //Set a given drive state
    void motorOut(int8_t driveState){

        //Lookup the output byte from the drive state.
        int8_t driveOut = driveTable[driveState & 0x07];

        //Turn off first
        if (~driveOut & 0x01) L1L = 0;
        if (~driveOut & 0x02) L1H = 1;
        if (~driveOut & 0x04) L2L = 0;
        if (~driveOut & 0x08) L2H = 1;
        if (~driveOut & 0x10) L3L = 0;
        if (~driveOut & 0x20) L3H = 1;

        //Then turn on
        if (driveOut & 0x01) L1L = 1;
        if (driveOut & 0x02) L1H = 0;
        if (driveOut & 0x04) L2L = 1;
        if (driveOut & 0x08) L2H = 0;
        if (driveOut & 0x10) L3L = 1;
        if (driveOut & 0x20) L3H = 0;
    }

    //Convert photointerrupter inputs to a rotor state
    inline int8_t readRotorState(){
        return stateMap[I1 + 2*I2 + 4*I3];
    }

    //Basic synchronisation routine
    int8_t motorHome() {
        //Put the motor in drive state 0 and wait for it to stabilise
        motorOut(0);
        wait(2.0);

        //Get the rotor state
        return readRotorState();
    }


    void stateUpdate() { // () { // **params
        *params[0] = readRotorState();
        int8_t currentState = *params[0];
        int8_t offset = *params[1];

        motorOut((currentState - offset + lead + 6) % 6);
        
        if (stateCount<6){
            stateList[stateCount] = currentState;
            stateCount++;
        }
        else {
            //pc.printf("states");
            //for(int i = 0; i < 6; ++i)
            //pc.printf("%02i,", stateList[i]);
            //pc.printf("\n\r");
            stateCount = 0;
        }
        
        
    }

};



//Main
int main() {

    // std::ios::sync_with_stdio(false);
    Comm comm_plz;

    // comm_plz.pc.printf("%s\n", "do i work bruh" ); // using printf of class is calm
    SHA256 Miner;

    Motor motor;

    uint8_t sequence[] = {0x45,0x6D,0x62,0x65,0x64,0x64,0x65,0x64,
                          0x20,0x53,0x79,0x73,0x74,0x65,0x6D,0x73,
                          0x20,0x61,0x72,0x65,0x20,0x66,0x75,0x6E,
                          0x20,0x61,0x6E,0x64,0x20,0x64,0x6F,0x20,
                          0x61,0x77,0x65,0x73,0x6F,0x6D,0x65,0x20,
                          0x74,0x68,0x69,0x6E,0x67,0x73,0x21,0x20,
                          0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                          0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    uint64_t* key = (uint64_t*)((int)sequence + 48);
    uint64_t* nonce = (uint64_t*)((int)sequence + 56);
    uint8_t hash[32];
    uint32_t length64 = 64;
    uint32_t hashCounter = 0;
    Timer timer;

    comm_plz.start_comm();

    // Motor States

    // pc.printf("Rotor origin: %x\n\r",orState);
    // orState is subtracted from future rotor state inputs to align rotor and motor states
    // intState = readRotorState();
    //if (intState != intStateOld) {
    //     pc.printf("old:%d \t new:%d \t next:%d \n\r",intStateOld, intState, (intState-orState+lead+6)%6);
    //     intStateOld = intState;
    //     motorOut((intState-orState+lead+6)%6); //+6 to make sure the remainder is positive
    // }

    // Keep the program running indefinitely
    timer.start();          // start timer
    
    while (1) {
        // pc.printf("Current:%d \t Next:%d \n\r", currentState, (currentState-orState+lead+6)%6);
        comm_plz.newKey_mutex.lock();
        *key = comm_plz.newKey;
        comm_plz.newKey_mutex.unlock();
        Miner.computeHash(hash, sequence, length64);
        hashCounter++;
        if ((hash[0]==0) && (hash[1]==0)){
            comm_plz.putMessage((Comm::msgType)7, *nonce);
        }

        // Try a new nonce
        (*nonce)++;

        // Per Second i.e. when greater or equal to 1
        if (timer.read() >= 1){
            comm_plz.putMessage((Comm::msgType)5, hashCounter);
            //pc.printf("HashRate = %02u \n\r",hashCounter);
            hashCounter=0;
            timer.reset();
        }
    }
}