예제 #1
0
int main(void) {
    chip_startup_routine();

    configure_can_reads();
    statep = DSM_Init();
    set_state_machine_configs();

	while (1) {
		if (!RingBuffer_IsEmpty(&CAN_rx_buffer)) {
			CCAN_MSG_OBJ_T temp_msg;
			RingBuffer_Pop(&CAN_rx_buffer, &temp_msg);
			Board_UART_Print("Received Message ID: 0x");
			itoa(temp_msg.mode_id, str, 16);
			Board_UART_Println(str);
		}	
        
        read_input_requests(inputp);
        // MODE_REQUEST mode_request = get_mode_request(inputp);

        DI_ERROR step_error;
        // step_error = DSM_Step(inputp, statep, outputp, mode_request, msTicks);
        handle_error(step_error);

        demo_process_UART_commands(statep, uart_rx_buf, UART_RX_BUFFER_SIZE, msg_obj);

        check_CAN_error();
	}

    return 0;
}
예제 #2
0
/* UCOM interrupt EP_IN and EP_OUT endpoints handler */
static ErrorCode_t UCOM_int_hdlr(USBD_HANDLE_T hUsb, void *data, uint32_t event)
{
	switch (event) {
	case USB_EVT_IN:
		/* USB_EVT_IN occurs when HW completes sending IN packet. So clear the
		    busy flag for main loop to queue next packet.
		 */
		g_usb.usbTxFlags &= ~UCOM_TX_BUSY;
		if (RingBuffer_GetCount(&usb_txrb) >= 1) {
			g_usb.usbTxFlags |= UCOM_TX_BUSY;
			RingBuffer_Pop(&usb_txrb, g_usb.usbTx_buff);
			USBD_API->hw->WriteEP(g_usb.hUsb, HID_EP_IN, g_usb.usbTx_buff, AVAM_P_COUNT);
		}
		break;
	case USB_EVT_OUT:
		g_usb.usbRx_count = USBD_API->hw->ReadEP(hUsb, HID_EP_OUT, g_usb.usbRx_buff);
#ifdef DEBUG_VERBOSE
		if (RingBuffer_GetCount(&usb_rxrb) == RX_BUF_CNT) {
			debug32("E:(%d-%x %x %x %x) usb_rxrb overflow evt out\n", g_usb.usbRx_count,
					g_usb.usbRx_buff[0],
					g_usb.usbRx_buff[1],
					g_usb.usbRx_buff[2],
					g_usb.usbRx_buff[3]);
		}
#endif

		if (g_usb.usbRx_count >= AVAM_P_COUNT) {
			RingBuffer_Insert(&usb_rxrb, g_usb.usbRx_buff);
			g_usb.usbRx_count -= AVAM_P_COUNT;
		}

		if (g_usb.usbRxFlags & UCOM_RX_BUF_QUEUED) {
			g_usb.usbRxFlags &= ~UCOM_RX_BUF_QUEUED;
			if (g_usb.usbRx_count != 0)
				g_usb.usbRxFlags |= UCOM_RX_BUF_FULL;
		}
		break;
	case USB_EVT_OUT_NAK:
		/* queue free buffer for RX */
		if ((g_usb.usbRxFlags & (UCOM_RX_BUF_FULL | UCOM_RX_BUF_QUEUED)) == 0) {
			g_usb.usbRx_count = USBD_API->hw->ReadReqEP(hUsb, HID_EP_OUT, g_usb.usbRx_buff, UCOM_RX_BUF_SZ);
#ifdef DEBUG_VERBOSE
			if (RingBuffer_GetCount(&usb_rxrb) == RX_BUF_CNT)
				debug32("E: usb_rxrb overflow evt nak\n");
#endif
			if (g_usb.usbRx_count >= AVAM_P_COUNT) {
				RingBuffer_Insert(&usb_rxrb, g_usb.usbRx_buff);
				g_usb.usbRx_count -= AVAM_P_COUNT;
			}
			g_usb.usbRxFlags |= UCOM_RX_BUF_QUEUED;
		}
		break;
	default:
		break;
	}

	return LPC_OK;
}
예제 #3
0
/* Read data from usb */
uint32_t UCOM_Read(uint8_t *pBuf)
{
	uint16_t cnt = 0;

	cnt = RingBuffer_Pop(&usb_rxrb, (uint8_t *) pBuf);
	g_usb.usbRxFlags &= ~UCOM_RX_BUF_FULL;

	return cnt;
}
예제 #4
0
/* UART transmit-only interrupt handler for ring buffers */
void Chip_UART_TXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB)
{
	uint8_t ch;

	/* Fill FIFO until full or until TX ring buffer is empty */
	while ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) != 0 &&
		   RingBuffer_Pop(pRB, &ch)) {
		Chip_UART_SendByte(pUART, ch);
	}
}
예제 #5
0
/* UART transmit-only interrupt handler for ring buffers */
void Chip_UARTN_TXIntHandlerRB(LPC_USARTN_T *pUART, RINGBUFF_T *pRB)
{
    uint8_t ch;

    /* Fill FIFO until full or until TX ring buffer is empty */
    while (((Chip_UARTN_GetStatus(pUART) & UARTN_STAT_TXRDY) != 0) &&
            RingBuffer_Pop(pRB, &ch)) {
        Chip_UARTN_SendByte(pUART, ch);
    }
}
예제 #6
0
/* Send data to usb */
uint32_t UCOM_Write(uint8_t *pBuf)
{
	uint32_t ret = 0;

	RingBuffer_Insert(&usb_txrb, pBuf);

	if (g_usb.usbTxFlags & UCOM_TX_CONNECTED) {
		if (!(g_usb.usbTxFlags & UCOM_TX_BUSY) && RingBuffer_GetCount(&usb_txrb)) {
			g_usb.usbTxFlags |= UCOM_TX_BUSY;
			RingBuffer_Pop(&usb_txrb, g_usb.usbTx_buff);
			ret = USBD_API->hw->WriteEP(g_usb.hUsb, HID_EP_IN, g_usb.usbTx_buff, AVAM_P_COUNT);
		}
	}

	return ret;
}
예제 #7
0
/**
 * Run0 function for the gas mq2 device.
 *
 * @note this function should be called periodically by higherlevel routines
 * @param p_gas gas_mq2 device
 * @return	status_ok if succeeded (otherwise check status.h for details).
 */
status_t GAS_MQ2_Run0(gas_mq2_t *p_gas)
{
	status_t status = status_ok;
	uint8_t newsamples;
	uint8_t i;
	/* first check if there are new samples in the adc ringbuffer */
	newsamples = RingBuffer_GetCount(p_gas->p_adc->p_ringbuffer[p_gas->adcchannel]);
	/* if there are new samples */
	if(newsamples) /* if not zero */
	{
		for(i = 0; i < newsamples; i++)
		{
			/* pop latest sample */
			RingBuffer_Pop(p_gas->p_adc->p_ringbuffer[p_gas->adcchannel], &p_gas->latestresult);
			/* check for treshold */
			if(p_gas->latestresult > p_gas->alarmtreshold)
			{
				/* then increment the alarmcounter */
				p_gas->alarmcounter++;
			}
		}
	}
	return status;
}
예제 #8
0
int main(void)
{

	//---------------
	// Initialize SysTick Timer to generate millisecond count
	if (Board_SysTick_Init()) {
		// Unrecoverable Error. Hang.
		while(1);
	}

	//---------------
	// Initialize GPIO and LED as output
	Board_LEDs_Init();
	Board_LED_On(LED0);
	Board_LED_On(LED1);
	Board_LED_On(LED2);
	Board_LED_On(LED3);

	//Initialize I2C
	Board_I2C_Init();

	//---------------
	// Initialize UART Communication
	Board_UART_Init(UART_BAUD_RATE);
	Board_UART_Println("Started up");

	//---------------
	// Initialize CAN  and CAN Ring Buffer

	RingBuffer_Init(&can_rx_buffer, _rx_buffer, sizeof(CCAN_MSG_OBJ_T), BUFFER_SIZE);
	RingBuffer_Flush(&can_rx_buffer);

	Board_CAN_Init(CCAN_BAUD_RATE, CAN_rx, CAN_tx, CAN_error);

	// For your convenience.
	// typedef struct CCAN_MSG_OBJ {
	// 	uint32_t  mode_id;
	// 	uint32_t  mask;
	// 	uint8_t   data[8];
	// 	uint8_t   dlc;
	// 	uint8_t   msgobj;
	// } CCAN_MSG_OBJ_T;

	/* [Tutorial] How do filters work?

		Incoming ID & Mask == Mode_ID for msgobj to accept message

		Incoming ID : 0xabc
		Mask: 		  0xF0F &
		            -----------
		              0xa0c

		mode_id == 0xa0c for msgobj to accept message

	*/

	//Set mask to only accept messages from Driver Interface
	msg_obj.msgobj = 1;
	msg_obj.mode_id = DI_PACKET__id;
	msg_obj.mask = 0x555;
	LPC_CCAN_API->config_rxmsgobj(&msg_obj);

	can_error_flag = false;
	can_error_info = 0;
	
	lastPrint = msTicks;	

	PDM_STATUS_T pdm_status;
	
	int tmp;
	bool lv_i2c = true, cs_i2c = true, mux_i2c = true;

	//Board_I2C_Reset(I2C_GG_CONTINUOUS, i2c_tx_buffer);

	//Open I2C Channel 0
	i2c_tx_buffer[0] = I2C_MUX_CHANNEL_0;
	tmp = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_MUX_SLAVE_ADDRESS, i2c_tx_buffer, 1);
	Board_UART_Print("Opened Channel 0: ");
	Board_UART_PrintNum(tmp, 10, true);

	//Set Gas Gauge 0 to continuous data collection
	i2c_tx_buffer[0] = I2C_GG_CTRL_REG;
	i2c_tx_buffer[1] = I2C_GG_CONTINUOUS;
	tmp = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_GG_SLAVE_ADDRESS, i2c_tx_buffer, 2);
	Board_UART_Print("Set I2C0 to continuous data collection: ");
	Board_UART_PrintNum(tmp, 10, true);

	//Open I2C Channel 1
	i2c_tx_buffer[0] = I2C_MUX_CHANNEL_1;
	tmp = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_MUX_SLAVE_ADDRESS, i2c_tx_buffer, 1);
	Board_UART_Print("Opened Channel 1: ");
	Board_UART_PrintNum(tmp, 10, true);

	//Set Gas Gauge 1 to continuous data collection
	i2c_tx_buffer[0] = I2C_GG_CTRL_REG;
	i2c_tx_buffer[1] = I2C_GG_CONTINUOUS;
	tmp = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_GG_SLAVE_ADDRESS, i2c_tx_buffer, 2);
	Board_UART_Print("Set I2C1 to continuous data collection: ");
	Board_UART_PrintNum(tmp, 10, true);

	

	while (1) {
		
		//Set PDM status based on CAN messages from Driver Interface
		if (!RingBuffer_IsEmpty(&can_rx_buffer)) {					
			CCAN_MSG_OBJ_T temp_msg;
			RingBuffer_Pop(&can_rx_buffer, &temp_msg);
			//Test for DI OFF or SHUTDOWN IMPENDING message
			if((temp_msg.data[3] << 8 | temp_msg.data[2]) == ____DI_PACKET__DRIVE_STATUS__SHUTDOWN_IMPENDING ||	
					(temp_msg.data[3] << 8 | temp_msg.data[2]) == ____DI_PACKET__DRIVE_STATUS__OFF) {	
				if(pdm_status.pdm_on) {							
					pdm_status.pdm_on = false;
					Board_LED_Off(LED0);
					Board_I2C_Reset(I2C_GG_SLEEP, i2c_tx_buffer);
				}
			}
			else {
				if(!(pdm_status.pdm_on)) {
					pdm_status.pdm_on = true;
					Board_LED_On(LED0);
					Board_I2C_Reset(I2C_GG_CONTINUOUS, i2c_tx_buffer);
				}
			}
		}
		

		//Reset gas gauge 0 if it has been diconnected and then reconnected to power
		i2c_tx_buffer[0] = I2C_MUX_CHANNEL_0;
		tmp = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_MUX_SLAVE_ADDRESS, i2c_tx_buffer, 1);	//Open I2C Channel 0
		tmp = Chip_I2C_MasterCmdRead(DEFAULT_I2C, I2C_GG_SLAVE_ADDRESS, I2C_GG_CTRL_REG, i2c_rx_buffer, 1);	
		Board_UART_PrintNum(i2c_rx_buffer[0],16,true);
		if((uint16_t)i2c_rx_buffer[0] == I2C_GG_DEFAULT) {					//Test for default values in control register
			if(pdm_status.pdm_on) {
				Board_I2C_Reset(I2C_GG_CONTINUOUS, i2c_tx_buffer);
			}
			else {
				Board_I2C_Reset(I2C_GG_SLEEP, i2c_tx_buffer);
			}
			//Send a heartbeat with a com error
			Board_CAN_SendHeartbeat(&pdm_status, &msg_obj, true);
		}

			
		//Reset gas gauge 1 if it has been diconnected and then reconnected to power	
		i2c_tx_buffer[0] = I2C_MUX_CHANNEL_1;
		tmp = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_MUX_SLAVE_ADDRESS, i2c_tx_buffer, 1);	//Open 12C Channel 1
		tmp = Chip_I2C_MasterCmdRead(DEFAULT_I2C, I2C_GG_SLAVE_ADDRESS, I2C_MUX_CHANNEL_0, i2c_rx_buffer, 1);
		Board_UART_PrintNum(i2c_rx_buffer[0],16,true);
		if((uint16_t)i2c_rx_buffer[0] == I2C_GG_DEFAULT) {					//Test for default values in control register
			if(pdm_status.pdm_on) {
				Board_I2C_Reset(I2C_GG_CONTINUOUS, i2c_tx_buffer);
			}
			else {
				Board_I2C_Reset(I2C_GG_SLEEP, i2c_tx_buffer);
			}
			//Send a heartbeat with a com error
			Board_CAN_SendHeartbeat(&pdm_status, &msg_obj, true);
		}


		/* Update PDM and Debug LED code */

		//Attempt to open I2C Channel 0
		i2c_tx_buffer[0] = I2C_MUX_CHANNEL_0;
		mux_i2c = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_MUX_SLAVE_ADDRESS, i2c_tx_buffer, 1);	
		//Attempt to update Critical Systems PDM Struct
		cs_i2c = Board_PDM_Status_Update(&pdm_status, i2c_rx_buffer, true);			
		//Attempt to open I2C Channel 1
		i2c_tx_buffer[0] = I2C_MUX_CHANNEL_1;
		mux_i2c = Chip_I2C_MasterSend(DEFAULT_I2C, I2C_MUX_SLAVE_ADDRESS, i2c_tx_buffer, 1);	
		//Attempt to update Low Voltage PDM struct
		lv_i2c = Board_PDM_Status_Update(&pdm_status, i2c_rx_buffer, false);			
		//Run debug logic and update state
		Board_PDM_Status_Debug(&pdm_status, mux_i2c, cs_i2c, lv_i2c);

		if(msTicks - lastPrint > FREQ_THRESHOLD){				// 10 times per second
			lastPrint = msTicks;				// Store the current time, to allow the process to be done in another 1/10 seconds
			
			Board_CAN_SendHeartbeat(&pdm_status, &msg_obj, false);
		}
	}
}
예제 #9
0
파일: main.c 프로젝트: MITEVT/can_validator
int main(void)
{

	//---------------
	// Initialize UART Communication
	Board_UART_Init(UART_BAUD_RATE);
	Board_UART_Println("Started up");

	//---------------
	// Initialize SysTick Timer to generate millisecond count
	if (Board_SysTick_Init()) {
		Board_UART_Println("Failed to Initialize SysTick. ");
		// Unrecoverable Error. Hang.
		while(1);
	}

	//---------------
	// Initialize GPIO and LED as output
	Board_LEDs_Init();
	Board_LED_On(LED0);

	//---------------
	// Initialize CAN  and CAN Ring Buffer

	RingBuffer_Init(&can_rx_buffer, _rx_buffer, sizeof(CCAN_MSG_OBJ_T), BUFFER_SIZE);
	RingBuffer_Flush(&can_rx_buffer);

	Board_CAN_Init(CCAN_BAUD_RATE, CAN_rx, CAN_tx, CAN_error);

	// For your convenience.
	// typedef struct CCAN_MSG_OBJ {
	// 	uint32_t  mode_id;
	// 	uint32_t  mask;
	// 	uint8_t   data[8];
	// 	uint8_t   dlc;
	// 	uint8_t   msgobj;
	// } CCAN_MSG_OBJ_T;

	msg_obj.msgobj = 1;
	msg_obj.mode_id = 0x000;
	msg_obj.mask = 0x000;
	LPC_CCAN_API->config_rxmsgobj(&msg_obj);

	can_error_flag = false;
	can_error_info = 0;

	uint8_t status_led_state = 1;
	uint32_t status_led_time = msTicks;

	while (1) {
		if (!RingBuffer_IsEmpty(&can_rx_buffer)) {
			Board_LED_On(LED3);
			CCAN_MSG_OBJ_T temp_msg;
			RingBuffer_Pop(&can_rx_buffer, &temp_msg);
			Board_UART_PrintNum(temp_msg.mode_id, 16, false);
			Board_UART_Print("\t");
			Board_UART_PrintNum(temp_msg.dlc, 10, false);

			int i = 0;
			for (i = 0; i < temp_msg.dlc; i++) {
				Board_UART_Print("\t");
				Board_UART_PrintNum(temp_msg.data[i], 16, false);
			}

			Board_UART_Println("");
			Board_LED_Off(LED3);
		}	

		if (can_error_flag) {
			can_error_flag = false;
			Board_UART_Print("CAN Error: 0b");
			Board_UART_PrintNum(can_error_info, 2, true);
		}

		if (msTicks - status_led_time > STATUS_LED_PERIOD) {
			status_led_time = msTicks;
			status_led_state = 1 - status_led_state;
			Board_LED_Set(LED0, status_led_state);
		}
	}
}
예제 #10
0
int main(void) {
	if (Board_SysTick_Init()) {
		while(1);
	}

	Board_LEDs_Init();
	Board_LED_On(LED0);
	Board_ADC_Init();

	uint16_t tps_data = 0;
	int16_t tps_error = 0;

	Board_UART_Init(9600);

	DEBUG_Print("Started up\n\r");

	RingBuffer_Init(&rx_buffer, _rx_buffer, sizeof(CCAN_MSG_OBJ_T), 8);
	RingBuffer_Flush(&rx_buffer);

	Board_CAN_Init(TEST_CCAN_BAUD_RATE, CAN_rx, CAN_tx, CAN_error);

	msg_obj.msgobj = 1;
	msg_obj.mode_id = 0x301;
	msg_obj.mask = 0x000;
	LPC_CCAN_API->config_rxmsgobj(&msg_obj);

	can_error_flag = false;
	can_error_info = 0;
	
	bool send = false;
	while (1) {
		
		Board_TPS_ADC_Read(&tps_data);		
	
//		itoa(tps_data,tx_buffer_str,10);
//		DEBUG_Print("TPS_DATA:");
//		DEBUG_Print(tx_buffer_str);
//		DEBUG_Print("\r\n");

		if (!RingBuffer_IsEmpty(&rx_buffer)) {
			CCAN_MSG_OBJ_T temp_msg;
			RingBuffer_Pop(&rx_buffer, &temp_msg);
			DEBUG_Print("Received Message ID: 0x");
			itoa(temp_msg.mode_id, str, 16);
			DEBUG_Print(str);
			DEBUG_Print("\r\n");
		}
		
		if (can_error_flag) {
			can_error_flag = false;
			DEBUG_Print("CAN Error: 0b");
			itoa(can_error_info, str, 2);
			DEBUG_Print(str);
			DEBUG_Print("\r\n");
		}
		
		if (send) {
			DEBUG_Print("Sending CAN with ID: 0x301\r\n");
			msg_obj.msgobj = 2;
			msg_obj.mode_id = 0x301;
			msg_obj.dlc = 4;
			msg_obj.data[0] = tps_data>>2;
			msg_obj.data[1] = (uint8_t) 0x00;
			msg_obj.data[2] = (uint8_t) tps_error;
			LPC_CCAN_API->can_transmit(&msg_obj);
			Board_UART_PrintNum(msg_obj.data[0],10,true);
			Board_UART_PrintNum(msg_obj.data[1],10,true);
			Board_UART_PrintNum(msg_obj.data[2],10,true);
		}

		uint8_t count;
		count = Chip_UART_Read(LPC_USART, uart_rx_buf, UART_RX_BUFFER_SIZE);
		if (count != 0) {
			switch (uart_rx_buf[0]) {
				case 'a':
					send = true;
					break;
				case 'z':
					send = false;
					break;
				case 'r':
					DEBUG_Print("Sending CAN with ID: 0x301\r\n");
					msg_obj.msgobj = 2;
					msg_obj.mode_id = 0x301;
					msg_obj.dlc = 2;
					msg_obj.data[0] = tps_data;
					msg_obj.data[1] = tps_error;
					LPC_CCAN_API->can_transmit(&msg_obj);
					Board_UART_PrintNum(msg_obj.data[0],10,true);
					Board_UART_PrintNum(msg_obj.data[1],10,true);
					break;
				
				default:
					DEBUG_Print("Invalid Command\r\n");
					break;
			}
		}
	}
}
예제 #11
0
/**
 * @details Where all the magic happens
 * @return Shouldn't return
 */
int main(void) {

	Init_Core();
	Init_SM();
	Init_Board();
	Init_Globals();
	Init_CAN();
	Init_Timers();

	// ------------------------------------------------
	// Begin

	DEBUG_Print("Started Up\r\n");

	while(1) {

		uint8_t count;
		if ((count = Chip_UART_Read(LPC_USART, Rx_Buf, UART_RX_BUF_SIZE)) != 0) {
			switch (Rx_Buf[0]) {
				case 'a': // Print out Brusa Mains Info
					DEBUG_Print("Actual Mains Voltage: ");
					itoa(brusa_actual_1.mains_mVolts, str, 10);
					DEBUG_Print(str);
					DEBUG_Print("\r\n");

					DEBUG_Print("Mains type: ");
					itoa(brusa_actual_1.mains_cAmps, str, 10);
					DEBUG_Print(str);
					DEBUG_Print("\r\n");

					DEBUG_Print("Temp: ");
					itoa((brusa_temp.power_temp / 10) - 40 , str, 10);
					DEBUG_Print(str);
					DEBUG_Print("\r\n");

					DEBUG_Print("Temp: 0x");
					itoa(brusa_temp.power_temp , str, 16);
					DEBUG_Print(str);
					DEBUG_Print("\r\n");
					break;
				case 'b': // Print out Actual Brusa Output
					DEBUG_Print("Actual Out Voltage: ");
					itoa(brusa_actual_1.output_mVolts, str, 10);
					DEBUG_Println(str);

					DEBUG_Print("Actual Out Current: ");
					itoa(brusa_actual_1.output_cAmps, str, 10);
					DEBUG_Println(str);
					break;
				case 'f': // Print out Pack State
					itoa(pack_state.pack_min_mVolts, str, 10);
					DEBUG_Print("Pack Min Voltage: ");
					DEBUG_Print(str);
					DEBUG_Print("\r\n");
					itoa(pack_state.pack_max_mVolts, str, 10);
					DEBUG_Print("Pack Max Voltage: ");
					DEBUG_Print(str);
					DEBUG_Print("\r\n");

					break;
				case 'y': // Print out Module Balance State
					itoa(PackManager_GetExtModId(0), str, 16);
					DEBUG_Print("Mod 0x");
					DEBUG_Print(str);
					itoa(PackManager_GetExtBal(0), str, 2);
					DEBUG_Print(": 0b");
					DEBUG_Println(str);
					itoa(PackManager_GetExtModId(1), str, 16);
					DEBUG_Print("Mod 0x");
					DEBUG_Print(str);
					itoa(PackManager_GetExtBal(1), str, 2);
					DEBUG_Print(": 0b");
					DEBUG_Println(str);
					break;
				case 'e': 
					itoa(brusa_error,str, 2);
					DEBUG_Println(str);
					break;
				case 'm': // Print out charge mode and brusa error
					DEBUG_Print("Charge Mode: ");
					itoa(Charge_GetMode(), str, 10);
					DEBUG_Println(str);
					DEBUG_Print("Error Messages: ");
					itoa((uint64_t)brusa_error, str, 2);
					DEBUG_Println(str);
					break;
				default:
					DEBUG_Print("Unknown Command\r\n");
			}
		}

		//-----------------------------
		// Detect Input Changes (Default to IDLE)

		MODE_INPUT_T inp = INP_IDLE;
		if (!Board_Switch_Read()) {
			inp = INP_CHRG;
		} else {
			inp = INP_IDLE;
		}

		//-----------------------------
		// Update pack_state
		pack_state.contactors_closed = Board_Contactors_Closed();
		pack_state.msTicks = msTicks;
		pack_state.brusa_error = brusa_error;
		pack_state.pack_cAmps_in = brusa_actual_1.output_cAmps;

		//-----------------------------
		// SSM Step
		ERROR_T result = SSM_Step(&pack_state, inp, &out_state);
		if (result != ERROR_NONE) {
			_error(result, true, false);
		}

		//-----------------------------
		// Check if SSM has Changed State
		// Currently only changes Poll Frequency
		// [TODO] Set a status LED!!
		if (SSM_GetMode() != mode) {
			mode = SSM_GetMode();
			switch (SSM_GetMode()) {
				case IDLE:
					Chip_TIMER_SetMatch(LPC_TIMER32_1, 0, Hertz2Ticks(BCM_POLL_IDLE_FREQ));
					Chip_TIMER_Reset(LPC_TIMER32_1); // Otherwise shit gets F****D
					break;
				case CHARGING:
					Chip_TIMER_SetMatch(LPC_TIMER32_1, 0, Hertz2Ticks(BCM_POLL_CHARGING_FREQ));
					Chip_TIMER_Reset(LPC_TIMER32_1);
					break;
				case DRAINING:
					Chip_TIMER_SetMatch(LPC_TIMER32_1, 0, Hertz2Ticks(BCM_POLL_DRAINING_FREQ));
					Chip_TIMER_Reset(LPC_TIMER32_1);
					break;
			}
		}

		//-----------------------------
		// Carry out out_state
		if (out_state.close_contactors && !Board_Contactors_Closed()) {
			Board_Close_Contactors(true);
		} else if (!out_state.close_contactors && Board_Contactors_Closed()) {
			Board_Close_Contactors(false);
		}

		if (out_state.brusa_output) {
			brusa_control.clear_error = out_state.brusa_clear_latch;
			brusa_control.output_mVolts = out_state.brusa_mVolts;
			brusa_control.output_cAmps = out_state.brusa_cAmps;
			Chip_TIMER_Enable(LPC_TIMER32_0);
		} else {
			brusa_control.output_mVolts = 0;
			brusa_control.output_cAmps = 0;
			Chip_TIMER_Disable(LPC_TIMER32_0);
		}

		//-----------------------------
		// Retrieve available brusa messages
		int8_t tmp = MCP2515_GetFullReceiveBuffer();
		int8_t res = 0;
		if (tmp == 2) {
			MCP2515_ReadBuffer(&mcp_msg_obj, 0);
			res = Brusa_Decode(&brusa_messages, &mcp_msg_obj);
			if (res == -1) {
				DEBUG_Println("Brusa Decode Error");
				res = 0;
			}
			MCP2515_ReadBuffer(&mcp_msg_obj, 1);
			res = Brusa_Decode(&brusa_messages, &mcp_msg_obj);
		} else if (tmp == 0) { // Receive Buffer 0 Full
			MCP2515_ReadBuffer(&mcp_msg_obj, tmp);
			res = Brusa_Decode(&brusa_messages, &mcp_msg_obj);
		} else if (tmp == 1) { //Receive buffer 1 full
			MCP2515_ReadBuffer(&mcp_msg_obj, tmp);
			res = Brusa_Decode(&brusa_messages, &mcp_msg_obj);
		} 

		if (res == -1) {
			DEBUG_Println("Brusa Decode Error");
			res = 0;
		}

		//-----------------------------
		// Send brusa message if its time
		if (brusa_message_send) {
			brusa_message_send = false;
			Brusa_MakeCTL(&brusa_control, &mcp_msg_obj);
			MCP2515_LoadBuffer(0, &mcp_msg_obj);
			MCP2515_SendBuffer(0);
		}
		
		//-----------------------------
		// Check for and decode A123 Messages
		if (!RingBuffer_IsEmpty(&rx_buffer)) {

			CCAN_MSG_OBJ_T temp_msg;
			RingBuffer_Pop(&rx_buffer, &temp_msg);
			res = PackManager_Update(&temp_msg);

			if (new_std_msg_sent) {
				PackManager_Commit(&pack_state);
				new_std_msg_sent = false;
			}
			
		}

		if (res == -1) {
			DEBUG_Println("A123 Decode Error");
		}

		//-----------------------------
		// Timed output
		if (msTicks - last_debug_message > TIMED_MESSAGE_DELAY) {
			message_count++;
			last_debug_message = msTicks;
			switch (message_count % 7) {
				case 0:
					if (out_state.balance) {
						itoa(mbb_cmd.balance_target_mVolts, str, 10);
						DEBUG_Print("Balancing to: ");
						DEBUG_Println(str);
					} else {
						DEBUG_Println("Not balancing");
					}
					
					break;
				case 1:
					itoa(brusa_control.output_mVolts, str, 10);
					DEBUG_Print("Brusa out V: ");
					DEBUG_Println(str);
					break;
				case 2:
					itoa(brusa_control.output_cAmps, str, 10);
					DEBUG_Print("Brusa out C: ");
					DEBUG_Println(str);
					break;
				case 3:
					DEBUG_Print("Actual Out Voltage: ");
					itoa(brusa_actual_1.output_mVolts, str, 10);
					DEBUG_Println(str);
					break;
				case 4:
					DEBUG_Print("Actual Out Current: ");
					itoa(brusa_actual_1.output_cAmps, str, 10);
					DEBUG_Println(str);
					break;
				case 5:
					DEBUG_Print("Mode: ");
					DEBUG_Println((SSM_GetMode() == CHARGING) ? "Chrg":"Idle");
					break;
				case 6:
					DEBUG_Print("Brusa Output: ");
					itoa(out_state.brusa_output, str, 2);
					DEBUG_Println(str);

					DEBUG_Print("\r\n");
					break;

			}
		}
	}

	return 0;
}