Basic Mid-Level control for the rebuilt MorphGI control unit, using PWM to communicate with the low level controllers.

Dependencies:   ros_lib_kinetic

LLComms.cpp

Committer:
dofydoink
Date:
2021-06-24
Revision:
42:5a5ad23a4bb1
Parent:
39:e69a6fa12977

File content as of revision 42:5a5ad23a4bb1:

// LLComms.cpp

#include "LLComms.h"

LLComms::LLComms() : 
    queue(32 * EVENTS_EVENT_SIZE), //32 //8 * EVENTS_EVENT_SIZE
    spi_0(PC_12, PC_11, PC_10),
//    spi_1(PF_9, PF_8, PF_7),
//    spi_2(PB_15, PC_2, PB_13),
    // These interrupt pins have to be declared AFTER SPI declaration. No Clue Why.
    pinGate0(PF_11),
    pinGate1(PG_14),
    pinGate2(PF_15),
    //pinGate3(PF_12),
    pinReset(PD_2)
{ // Constructor

    spi_0.format(16,2);
    spi_0.frequency(LOW_LEVEL_SPI_FREQUENCY);
//    spi_1.format(16,2);
//    spi_1.frequency(LOW_LEVEL_SPI_FREQUENCY);


    PinName LLPins[N_CHANNELS] = {PD_15, PE_10, PD_14};//, PD_11};//, PE_7, PB_1, PB_12, PD_13, PB_5};
    
    for (short int i=0; i<N_CHANNELS; i++) {
        isDataReady[i] = 0;
        cs_LL[i] = new DigitalOut(LLPins[i]);
        //cs_ADC[i] = new DigitalOut(ADCPins[i]);
    }
    
    // Initialise relevant variables
    for(short int i=0; i<N_CHANNELS; i++) {
        // All chip selects in off state
        *cs_LL[i] = 1;
        //*cs_ADC[i] = 1;
        // Initialise pressures/positions
        pressureSensor_uint[i] = 0.0;
        pressureSensor_bar[i] = -1.0;
        positionSensor_uint[i] = 0.0;
        positionSensor_mm[i] = -1.0;
    }
    pinReset = 1; // Initialise reset pin to not reset the controllers.
    wait(0.25);
    pinReset=0; // Reset controllers to be safe
    wait(0.25);
    pinReset = 1; // Ready to go

//    pinReset.mode(PullUp); // Initialise reset pin to not reset the controllers.
//    wait(0.25);
//    pinReset.write(0); // Reset controllers to be safe
//    wait(0.25);
//    pinReset.mode(PullUp); // Ready to go
//    wait(0.25);
    
    // Set up rise interrupts MIGHT NOT NEED TO BE POINTERS
    pinGate0.rise(callback(this,&LLComms::rise0));
    pinGate1.rise(callback(this,&LLComms::rise1));
    pinGate2.rise(callback(this,&LLComms::rise2));
    //pinGate3.rise(callback(this,&LLComms::rise3));

    // Set up fall interrupts MIGHT NOT NEED TO BE POINTERS
    pinGate0.fall(callback(this,&LLComms::fall0));
    pinGate1.fall(callback(this,&LLComms::fall1));
    pinGate2.fall(callback(this,&LLComms::fall2));
    //pinGate3.fall(callback(this,&LLComms::fall3));

}

//LLComms::~LLComms(void) { } // Destructor
unsigned int LLComms::formatMessage(short int type, double dblValue, double dblMaxValue) {
    // Convert to a 9-bit number
    int intValue = (int) ((dblValue/dblMaxValue)*511);
    intValue = intValue & 0x1FF; // Ensure number is 9-bit
    // Initialize message with value
    unsigned int intMsg = intValue;
    // Calculate checksum (the decimal sum of the position data)
    int intCheckSum = 0, intTempVar = intValue;
    while( intTempVar>0 ) {
        intCheckSum += intTempVar%10;
        intTempVar = floor(intTempVar/10.0);
    }
    // Add checksum to message
    intMsg = intMsg<<5;
    intMsg = intMsg | intCheckSum;
    // Add type bit (0 == position, 1 == velocity)
    intMsg = intMsg<<1;
    intMsg = intMsg | (int)type; // CAST AS BOOL
    // Calculate decimal parity check for the whole message
    unsigned int count = 0, b = 1;  
    for(short int i=0; i<32; i++) {
        if( intMsg & (b << i) ) count++;
    }
    // Add parity bit to message (0 == Odd, 1 == Even)
    // Parity selected in this way to prevent 0x0000 from passing checks
    bool boolParity = !(bool)(count%2);
    intMsg = intMsg<<1;
    intMsg = intMsg | (int)boolParity;
    return intMsg;
}

bool LLComms::CheckMessage(int msg) {
    // Find message parity
    short int count = 0;
    for(short int i=0; i<32; i++) {
        if( msg>>1 & (1<<i) ) count++;
    }
    int intParity = !(count%2);
    // Find message CheckSum    
    int intChkSum = 0;
    int intTempVar = msg>>7;
    while(intTempVar > 0) {
        intChkSum += intTempVar%10;
        intTempVar = int(intTempVar/10);
    }
    // Check if parity and CheckSum match
    bool isParityCorrect = (intParity == (msg&0x1));
    bool isChkSumCorrect = (intChkSum == ((msg>>2)&0x1F));
    bool isCheckPassed = (isParityCorrect && isChkSumCorrect);
    return isCheckPassed;
}

bool LLComms::PerformMasterSPI(SPI *spi, unsigned int outboundMsgs[], unsigned int inboundMsgsData[]) {
    unsigned int dummyMsg = 0x5555;
    bool isSuccess = true;
    unsigned int inboundMsg, typeBit;
    AnalogIn ain(PA_4); // Random analogue pin
    for(short int i=0; i<3; i++) { // Loop 3 times for 3 SPI messages
        ain.read_u16(); // Read analogue pin to cause a delay
        ain.read_u16();
        if(i==0) {
            inboundMsg = spi->write(outboundMsgs[0]);
        } else if(i==1) {
            inboundMsg = spi->write(outboundMsgs[1]);
        } else {
            inboundMsg = spi->write(dummyMsg);
        }
        //rawMsg[i] = inboundMsg;
        if((unsigned int)inboundMsg != dummyMsg) { // Message is not dummy which is only used for reply
            typeBit = inboundMsg>>1 & 0x1;
            inboundMsgsData[typeBit] = inboundMsg>>7 & 0x1FF;
            if( !CheckMessage(inboundMsg) ) {
                isSuccess = false;
            }
        }
    }
    return isSuccess;
}

void LLComms::SendReceiveData(int channel) {
    mutChannel[channel].lock(); // Lock mutex for specific Channel
    
    // Construct messages
    unsigned int intPositionMsg = formatMessage(0,demandPosition_mm[channel],MAX_ACTUATOR_LIMIT_MM);
    unsigned int intVelocityMsg = formatMessage(1,demandSpeed_mmps[channel],MAX_SPEED_MMPS);
    //unsigned int rawMsg[3];
    *cs_LL[channel] = 0; // Select relevant chip
    unsigned int outboundMsgs[2] = { intPositionMsg , intVelocityMsg };
    unsigned int inboundMsgsData[2] = { 0 };
    bool isSPIsuccess = false;
    if( channel < 3 ) {
        isSPIsuccess = PerformMasterSPI(&spi_0,outboundMsgs,inboundMsgsData);
    } //else {
//        isSPIsuccess = PerformMasterSPI(&spi_1,outboundMsgs,inboundMsgsData,rawMsg);
//    }
//    else if( channel < 7 ) {
//        isSPIsuccess = PerformMasterSPI(&spi_1,outboundMsgs,inboundMsgsData);
//    } else {
//        isSPIsuccess = PerformMasterSPI(&spi_2,outboundMsgs,inboundMsgsData);
//    }
    *cs_LL[channel] = 1; // Deselect chip
    if( isSPIsuccess ) {
        isDataReady[channel] = 0; // Data no longer ready, i.e. we now require new data
        positionSensor_uint[channel] = inboundMsgsData[0];
        positionSensor_mm[channel] = ((double)inboundMsgsData[0]/511) * (double)MAX_ACTUATOR_LENGTH_MM;
        positionSensor_mm[channel] = min( max(positionSensor_mm[channel],0.0) , (double)MAX_ACTUATOR_LENGTH_MM );
        pressureSensor_uint[channel] = inboundMsgsData[1];
        pressureSensor_bar[channel] = ((double)inboundMsgsData[1]/511) * (double)MAX_PRESSURE_LIMIT;
        pressureSensor_bar[channel] = min( max(pressureSensor_bar[channel],0.0) , (double)MAX_PRESSURE_LIMIT );
    } else { // Data is STILL ready and will be resent at the next pin interrupt
        printf("SPI failed: %d. Resending.\n\r",channel);
    }
    
    mutChannel[channel].unlock();//unlock mutex for specific channel
    
 //   if(channel ==3){
//        printf("%x\t%x\t%x\r\n",rawMsg[0], rawMsg[1], rawMsg[2] );
//    }

//    printf("%d, ", channel);
//    if(channel == 3){
//        printf("\r\n");
//    }
}

// Common rise handler function 
void LLComms::common_rise_handler(int channel) {
    //printf("%d %d common_rise_handler\n\r",channel,isDataReady[channel]);
    //countervar++;
    if (isDataReady[channel]) { // Check if data is ready for transmission
        ThreadID[channel] = queue.call(this,&LLComms::SendReceiveData,channel); // Schedule transmission
    }
}

// Common fall handler functions
void LLComms::common_fall_handler(int channel) {
    queue.cancel(ThreadID[channel]); // Cancel relevant queued event
}

// Stub rise functions
void LLComms::rise0(void) { common_rise_handler(0); }
void LLComms::rise1(void) { common_rise_handler(1); }
void LLComms::rise2(void) { common_rise_handler(2); }
//void LLComms::rise3(void) { common_rise_handler(3); }

// Stub fall functions
void LLComms::fall0(void) { common_fall_handler(0); }
void LLComms::fall1(void) { common_fall_handler(1); }
void LLComms::fall2(void) { common_fall_handler(2); }
//void LLComms::fall3(void) { common_fall_handler(3); }