/* * 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; }