DAT290 / kod / Network_protocol / CAN_interface.c
CAN_interface.c
Raw
/*
 * HOW TO USE THIS PROTOCOL
 *
 * 1. Run CAN_init with true if it is the central unit, otherwise false
 * 
 * 2. Register message handlers through registerMessageHandler. ACKs are handled internally
 * except for REQUEST_INIT (in which case, there is no ACK)
 * 
 * 3. If this is an auxiliary unit, run CAN_auxRequestInit to request to start communication
 * with the central unit. If this is the central unit, run CAN_centralSetInit in the message
 * handler for REQUEST_INIT
 * 
 * 4. When initialization is done, auxInit will be set as true and normal communication can 
 * begin by using CAN_send()
 * 
*/
#include "misc.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "GPIO.h"
#include "USART_dump.h"
#include "CAN_interface.h"
#include "CAN_messageTypes.h"
#include "RNG.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define	CAN1_IRQ_VECTOR		(0x2001C000+0x90)
#define __CAN_IRQ_PRIORITY		2

#define PRIME_ONE 1664525
#define PRIME_TWO 1013904223

#define MAX_NUMBER_OF_MESSAGE_TYPES 16
#define MAX_NUMBER_OF_AUX_UNITS 32

static bool centralUnit;
static bool auxInit;
static uint16_t localAuxId;
// stores all passwords for all aux units
static uint16_t auxPasswords [MAX_NUMBER_OF_AUX_UNITS][2];
static bool auxAvailable [MAX_NUMBER_OF_AUX_UNITS];
static void (*messagesHandlers[MAX_NUMBER_OF_MESSAGE_TYPES])(Message*);

CanRxMsg RxMessage;
CanTxMsg TxMsessage;


//helper function, converts 1 byte to 0x## 
void charToHex (char* hex, char number){
    char* index = "0123456789ABCDEF";
    hex[0] = index[(number & 0xF0) >> 4];
    hex[1] = index[(number & 0xF)];
}

//debug function, dumps the content of a received message
void dump_CanRxMsg(CanRxMsg* msg){
    char value [20];
    itoa(msg -> StdId, value, 10);
    DUMP("Standard ID of frame:");
    DUMP(value);
    itoa(msg -> ExtId, value, 10);
    DUMP("Extended ID of frame:");
    DUMP(value);
    itoa(msg -> RTR, value, 10);
    DUMP("Type of frame:");
    DUMP(value);
    itoa(msg -> IDE, value, 10);
    DUMP("Identifier type of frame:");
    DUMP(value);
    itoa(msg -> DLC, value, 10);
    DUMP("Length of data:");
    DUMP(value);
    DUMP("Data:");
    char data [16];
    char temp[2];
    for(int i = 0; i < (msg -> DLC); i++){
    charToHex(temp, (char) (msg -> Data[i]));
        data[2*i] = temp[0];
        data[2*i + 1] = temp[1];
    }
    data[2*(msg -> DLC)] = '\0';
    DUMP(data);
    DUMP("");
}

//creates an 11-bit id from struct
uint32_t ConstructId(ID* id){
    uint32_t intId = 0;
    intId = ((id -> alarm) <<10) | ((id -> direction) << 9) | ((id -> msgType) << 5) | id -> auxId;
    return intId;
}

//parsing 11-bit id to struct
void DeconstructId(uint32_t id, ID* result){
    result -> alarm = (id & (1<<10))>>10;
    result -> direction = (id & (1<<9))>>9;
    result -> msgType = (id & (0b1111<<5))>>5;
    result -> auxId = id & 0b11111;
}

//decoupling from STM32 library into struct
void deconstructMessage(CanRxMsg* rxMsg, Message* msg){
    ID newId;
    DeconstructId(rxMsg -> StdId, &newId);
    msg -> id = newId;
    memcpy(msg -> data, rxMsg -> Data + 2, rxMsg -> DLC - 2);
}

//genereates a single password from seed
uint16_t generatePassword(uint16_t seed){
    unsigned int intPassword;
    intPassword = PRIME_ONE * seed + PRIME_TWO;
    uint16_t password = intPassword;
    return password;
}

//generates a password pair for the current exchange of frames and stores them in auxPasswords
void generatePasswordPair(uint16_t seed, uint16_t auxId){
    if(auxId >= MAX_NUMBER_OF_AUX_UNITS) {
        if(debug){
            DUMP("generatePasswordPair: auxId too big");
        }
        return;
    }
    auxPasswords[auxId][0] = generatePassword(seed);
    auxPasswords[auxId][1] = generatePassword(generatePassword(seed));
}

// returns 1 if its correct, 2 if its the last pass, can be an error or a replay attack, 0 if its completely incorrect
char validatePackage(uint16_t auxId, uint16_t receivedPass, uint16_t msgType){
    uint16_t testPass;
    //contains no passwords
    if(msgType == REQUEST_INIT || msgType == AUXILIARY_INIT){
        return 1;
    }
    if(msgType != ACK){
		testPass = generatePassword(auxPasswords[auxId][SECOND_PASS]);
    }else{
        testPass = auxPasswords[auxId][SECOND_PASS];
    }
    
    if(debug){
        char str[10];
        itoa(testPass, str,10);
        DUMP("testPass:");
        DUMP(str);
        itoa(receivedPass, str,10);
        DUMP("receivedPass:");
        DUMP(str);
        DUMP("");
    }

    // the pass is the same as last time, could either happen because of a replay attack or because an ack did not get through
    if(auxPasswords[auxId][OLD] == receivedPass){
        return 2;
    }else if(testPass == receivedPass){
        // the pass matches the expected pass and the package is validated. new exchange has begun and new passwords are generated
        if(msgType != ACK){
            generatePasswordPair(auxPasswords[auxId][LASTPASS], auxId);
        }
        return 1;
    }else{
        // the pass does not match, something went wrong
        return 0;
    }
}

void REQUEST_INIT_callback(Message* msg){
    
}

bool CAN_sendRaw(uint32_t id, uint8_t* data, uint32_t dataLength){
    if(dataLength > 8) {
        return false;
    } 
    CanTxMsg msg;
    msg.StdId = id & 0x7FF;
    msg.DLC = dataLength;
    memcpy(msg.Data, data, dataLength);
    msg.RTR = CAN_RTR_DATA;
    msg.IDE = CAN_ID_STD;
    return CAN_Transmit(CAN1, &msg);
}

//aux unit wants to be recongnized by the central unit -> sends request to central unit 
bool CAN_auxRequestInit(uint8_t auxType){
    if (centralUnit) return false;
    uint32_t initID = (0b0 << 10) | (0b1 << 9) | ((REQUEST_INIT & 0b1111) << 5); 
    uint8_t initData[8];
    initData[0] = auxType;
    uint32_t tempId = RNG_getRandomNumber();
    memcpy(initData + 1, &tempId, 4);
    return CAN_sendRaw(initID, initData, 5);
}

//central unit gives an auxId and passes the associated tempId -> generates a password pair and opens a connection with an aux unit
bool CAN_centralSetInit(uint16_t auxId, uint32_t tempId){
    if(!centralUnit) return false;
    uint32_t initID = (0b0 << 10) | (0b0 << 9) | ((AUXILIARY_INIT & 0b1111) << 5 | (auxId & 0b11111)); 
    uint16_t pass0 = (uint16_t) RNG_getRandomNumber();
    generatePasswordPair(pass0, auxId);
    uint8_t initData[8];
    memcpy(initData, &pass0, 2);
    memcpy(initData + 2, &tempId, 4);
    return CAN_sendRaw(initID, initData, 6);
} 

//inits this instance of the network layer
bool CAN_init(bool isCentralUnit) {
    // clear messagesHandlers
    auxInit = false;
    localAuxId = 0;
    for (int i = 0; i < sizeof(messagesHandlers) / sizeof(uint8_t*); ++i) {
        messagesHandlers[i] = 0;
    }
    centralUnit = isCentralUnit;
	for(int i = 0; i < MAX_NUMBER_OF_AUX_UNITS; i++){
        auxAvailable[i] = true;
        auxPasswords[i][0] = 0;
        auxPasswords[i][1] = 0;
    }
    RNG_init();
    if (!can_init()) {
        return false;
    }
    return true;
}

//sends a CAN-message with the given inputs.
bool CAN_send(uint16_t auxId, uint8_t msgType, uint8_t* data, uint32_t dataLength) {
    //data check, verify that input is valid
    if(dataLength > 6) {
        return false;
    } else if(auxId >= MAX_NUMBER_OF_AUX_UNITS){
        return false;
	} else if(msgType >= MAX_NUMBER_OF_MESSAGE_TYPES){
        return false;
    } else if(auxAvailable[auxId]==false){
        return false;
	}
	

    uint16_t pass;
    //new interaction started, generate new password pair and prevent more messages from being sent. else, get the ACK password
    if(msgType != ACK) {
        generatePasswordPair(auxPasswords[auxId][LASTPASS], auxId);
        pass = auxPasswords[auxId][FIRST_PASS];
        auxAvailable[auxId] = false;
    } else{
        pass = auxPasswords[auxId][SECOND_PASS]; 
    }

    if(debug){
        char str[10];
        itoa(pass, str,10);
        DUMP("pass:");
        DUMP(str);
    }
    
    ID header;
    if (msgType == ALARM) {
        header.alarm = 1;
        header.msgType = ALARM;
    } else {
        header.alarm = 0;
        header.msgType = msgType;
    }
    header.auxId = auxId;
    header.direction = !centralUnit;
    
    CanTxMsg msg;
    msg.StdId = ConstructId(&header);
    msg.DLC = dataLength + 2;
    memcpy(msg.Data + 2, data, dataLength);
    memcpy(msg.Data, &pass, 2);
    msg.RTR = CAN_RTR_DATA;
    msg.IDE = CAN_ID_STD;
    return CAN_Transmit(CAN1, &msg);
}

//exposed to top layer to set callback functions based on msgType
bool CAN_registerMessageHandler(uint8_t msgType, void (*callback)(Message*)) {
    if (msgType == ALARM) {
        messagesHandlers[MAX_NUMBER_OF_MESSAGE_TYPES - 1] = callback;
    }

    // Check for invalid message type.
    if (msgType >= MAX_NUMBER_OF_MESSAGE_TYPES) {
        return false;
    }

    messagesHandlers[msgType] = callback;
    return true;
}

//is only called with a message which has been validated, runs callback function corresponding to msgType.
bool onValidMessageReceived(Message* msg) {
    
	//return ACK msg if non ACK received, else free up communication with other pier.
    if(msg -> id.msgType != ACK){
        CAN_send(msg -> id.auxId, ACK, 0, 0);
    } else{
        auxAvailable[msg -> id.auxId] = true;
    }
    void(*callback)(Message*);
    
    //set the callback funciton
    callback = messagesHandlers[msg -> id.msgType];
    
    // No handler
    if (callback == 0) {
        return false;
    }
    
    callback(msg);
    return true;
}

//parses message to internal struct and validates if it's authentic. If a message is authed, it calls upon the corresponding callback funciton
void can_irq_handler(void)
{
    CanRxMsg rxMsg;
    Message msg;
    uint16_t msgPass;
    if(CAN_MessagePending(CAN1, CAN_FIFO0)) {
		CAN_Receive(CAN1, CAN_FIFO0, &rxMsg);
        if(debug){
            DUMP("frame received:");
            dump_CanRxMsg(&rxMsg);
        }
        deconstructMessage(&rxMsg, &msg);
        
        
        //uint16_t msgPass = *((uint16_t*) rxMsg.Data);             <<<<<TEST THIS LINE, IT SHOULD WORK
		msgPass = rxMsg.Data[0] | rxMsg.Data[1] << 8;
        if(msg.id.msgType == REQUEST_INIT){
            messagesHandlers[REQUEST_INIT](&msg);
            return;
        } else if(msg.id.msgType == AUXILIARY_INIT){
            //checking that it isn't central unit or already initialized
            if(auxInit || centralUnit) {
                return;
            }
            auxInit = true;
            localAuxId = msg.id.auxId;
            generatePasswordPair(msgPass, localAuxId);
            onValidMessageReceived(&msg);
            return;
        } 
        //drop the packet if it doesn't match localAuxId
        if(!centralUnit && (localAuxId != msg.id.auxId)){
            if(debug){
                DUMP("frame dropped: not trageted for this unit");
            }
            return;
        }
        
        //normal frame handling
        if(validatePackage(msg.id.auxId, msgPass , msg.id.msgType) != 0){
            onValidMessageReceived(&msg);
        } else if(debug){
            DUMP("frame dropped: non-valid message received");
        }
    }
}

//initializes CAN
bool can_init()
{
	CAN_InitTypeDef CAN_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	// Connect CAN pins to AF9. See more below
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_CAN1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_CAN1);  

	// Configure CAN RX and TX pins
	// See page 41 of MD407 reference manual
	// Connect CAN1 pins to AF
    // PB9 - CAN1 TX
    // PB8 - CAN1 RX
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_CAN1);  	
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_CAN1);  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);	

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;	
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);	

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;	
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = __CAN_IRQ_PRIORITY;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	 
	/* CAN register init */
	CAN_DeInit(CAN1);

	/* CAN filter init */
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
	
	/* CAN cell init */
	CAN_InitStructure.CAN_TTCM = DISABLE; // time-triggered communication mode = DISABLED
    CAN_InitStructure.CAN_ABOM = DISABLE; // automatic bus-off management mode = DISABLED
    CAN_InitStructure.CAN_AWUM = DISABLE; // automatic wake-up mode = DISABLED
    CAN_InitStructure.CAN_NART = DISABLE; // non-automatic retransmission mode = DISABLED
    CAN_InitStructure.CAN_RFLM = DISABLE; // receive FIFO locked mode = DISABLED
    CAN_InitStructure.CAN_TXFP = DISABLE; // transmit FIFO priority = DISABLED
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; // normal CAN mode

	/* CAN Baudrate = 1 MBps (CAN clocked at 30 MHz) */
	CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_4tq;
	CAN_InitStructure.CAN_Prescaler = 7;
	
	uint8_t can_init_status = CAN_Init(CAN1, &CAN_InitStructure);
	
	*((void (**)(void) ) CAN1_IRQ_VECTOR ) = can_irq_handler;
	// We need the following function because it's not equivalent to what NVIC_Init does with respect
	// to IRQ priority. Which seems bananas to me...
    NVIC_SetPriority( CAN1_RX0_IRQn, __CAN_IRQ_PRIORITY);
	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
	
	return can_init_status;
}