//*****************************************************************************
//
// CANdriver.c - Driver for the Peripheral Device Controller (CAN) on the Stellaris
//         development board.
//
// Copyright (c) 2005-2008 Luminary Micro, Inc.  All rights reserved.
// 
// Software License Agreement
// 
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
// 
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws.  All rights are reserved.  You may not combine
// this software with "viral" open-source software in order to form a larger
// program.  Any use in violation of the foregoing restrictions may subject
// the user to criminal sanctions under applicable laws, as well as to civil
// liability for the breach of the terms and conditions of this license.
// 
// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 3416 of the Stellaris Peripheral Driver Library.
//
//*****************************************************************************



#include <common.h>
#include <can.h>
#include <CANdriver.h>
#include <string.h>

//Interni promenne--------------------------------------------------------------
tCANMsgObject g_MsgObjectStatus;	// This holds the information for the data send message object that is used to send commands and to send command responses.
tCANMsgObject g_MsgObjectSettings;	// This holds the information for the data receive message object that is used to receive commands.
tCANMsgObject g_MsgObjectData;		// This holds the information for the data send message object that is used to send commands and to send command responses.
tCANMsgObject g_MsgObjectReset;
tCANMsgObject g_MsgObjectStatusReq; 

static unsigned long const g_ulVersion = CURRENT_VERSION;	                // constant that holds the firmware version for this application.
unsigned char *g_ucSettings;
unsigned char *g_ucData;

//Deklarace funkci--------------------------------------------------------------
void CANConfigureNetwork();		                                        // Nastaveni objektu, ktery bude prijimat vsechny zpravy na CAN sbernici


//Struktura pro konfiguraci CAN kontroleru / rychlost--------------------------
tCANBitClkParms CANBitClkSettings[] =
{
    {16,8,4,8}, // CANBAUD_125K
    {16,8,4,4},  // CANBAUD_250K
    {16,8,4,2},  // CANBAUD_500K
    {16,8,4,1}   // CANBAUD_1M
};

//*****************************************************************************
//Iniciailizace CAN kontroleru-------------------------------------------------
void CANInitialize(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);                                // Konfigurace pinu pro CAN_0
    GPIOPinTypeCAN(GPIO_PORTB_BASE, CAN_PINS);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);		                        // Povoleni CAN kontroleru
   
    CANInit(CAN0_BASE);			                                        // Restartovani stavu vsech objektu zprav a stavu CAN modulu do defin.stavu
    CANBitTimingSet(CAN0_BASE, &CANBitClkSettings[CANBAUD_1M]);                 // Nastaveni rychlosti
    CANEnable(CAN0_BASE);		                                        // Nastaveni vychoziho stavu pro CAN0 / stav INIT
    CANIntEnable(CAN0_BASE, CAN_INT_MASTER|CAN_INT_ERROR|CAN_INT_STATUS);	// Povoleni preruseni od CAN kontroleru    
 
    //CANIntRegister(INT_CAN0,&CANIntHandler);
    IntEnable(INT_CAN0);		                                        // Povoleni preruseni pro CAN  / NVIC
    IntMasterEnable();			                                        // Povoleni preruseni procesoru

    CANConfigureNetwork();		                                        // Nastaveni objektu, ktery bude prijimat vsechny zpravy na CAN sbernici
}


//*****************************************************************************
//
// This function handles incoming commands.
//
//*****************************************************************************
void CAN_ProcessCmd(void)
{

}


//*****************************************************************************
//
// The CAN controller interrupt handler.
//
// /return None.
//
//*****************************************************************************
void CANIntHandler(void)
{
    unsigned long ulStatus;

    //
    // Find the cause of the interrupt, if it is a status interrupt then just
    // acknowledge the interrupt by reading the status register.
    //
    ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);

    switch(ulStatus)
    {

        case CAN_MSGOBJ_SETTINGS:
        {
            CANMessageGet(CAN0_BASE, CAN_MSGOBJ_SETTINGS, &g_MsgObjectSettings, true);
            request.flag.can_message_settings_received = 1;
            break;
        }
        case CAN_MSGOBJ_STATUS_REQ:
        {
            CANMessageGet(CAN0_BASE, CAN_MSGOBJ_STATUS_REQ, &g_MsgObjectStatusReq, true);
            request.flag.can_message_status_req_received = 1;
            // TODO DO something with settings data
            break;
        }
        case CAN_MSGOBJ_STATUS:
        {
            request.flag.can_message_status_send = 0;  // Clear the data transmit pending flag.
            break;
        }

        case CAN_MSGOBJ_DATA:   // The data transmit message object has been sent successfully.
        {
            request.flag.can_message_data_send = 0;    // Clear the data transmit pending flag.
            break;
        }
        case CAN_MSGOBJ_RESET_REQ:    // Do reset!
        {
            request.flag.can_message_status_req_received = 1;
            // SysCtlReset();          
            break;
        }
        // This was a status interrupt so read the current status to
        // clear the interrupt and return.
        default:
        {
            CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
            return;
        }
    }

    //
    // Acknowledge the CAN controller interrupt has been handled.
    //
    CANIntClear(CAN0_BASE, ulStatus);
}


//*****************************************************************************
//
//! Send a CAN message.
//!
//! \param data specifies the pointer to data to send.
//!
//! This function will perform the SSI transfers required to write a register
//! in the CAN.
//!
//! This function is contained in <tt>CANdriver.c</tt>, with <tt>CANdriver.h</tt>
//! containing the API definition for use by applications.
//!
//! \return None.
//
//*****************************************************************************
void CANSendMessage(char const *data)
{
  unsigned char count = strlen(data);  
  while(count>0)
  {
    g_MsgObjectData.ulMsgLen = ( count > 8 ? 8 : count) ;      // The length of the message, which should only be 8 bytes.
    g_MsgObjectData.pucMsgData = (unsigned char*)data;  
    CANMessageSet(CAN0_BASE, CAN_MSGOBJ_DATA, &g_MsgObjectData, MSG_OBJ_TYPE_TX);
    count-=g_MsgObjectData.ulMsgLen;
  }
  while ((CANStatusGet(CAN0_BASE, CAN_STS_CONTROL) & CAN_STATUS_TXOK) !=  CAN_STATUS_TXOK); //puvodne CAN1_BASE
}

//*****************************************************************************
//
// Configure CAN message objects for the application.
//
// This function configures the message objects used by this application.
// The following four message objects used by this application:
// MSGOBJ_ID_BUTTON, MSGOBJ_ID_LED, MSGOBJ_ID_DATA_TX, and MSGOBJ_ID_DATA_RX.
//
// /return None.
//
//*****************************************************************************
void CANConfigureNetwork(void)
{
//*****************************************************************************
// RX CAN MESSAGES
//*****************************************************************************

    // This is the message object used to receive requests
    g_MsgObjectStatusReq.ulMsgID = CAN_MSGOBJ_STATUS_REQ;
    g_MsgObjectStatusReq.ulMsgIDMask = CAN_MSGOBJ_STATUS_REQ;
    g_MsgObjectStatusReq.ulFlags = MSG_OBJ_RX_INT_ENABLE;  // This enables interrupts for transmitted messages.
    g_MsgObjectStatusReq.ulMsgLen = 0; // Set the length of the message
    CANMessageSet(CAN0_BASE, CAN_MSGOBJ_STATUS, &g_MsgObjectStatusReq, MSG_OBJ_TYPE_RX_REMOTE);

    // This message object will receive updates for the system settings
    g_MsgObjectSettings.ulMsgID = CAN_MSGOBJ_SETTINGS;
    g_MsgObjectSettings.ulMsgIDMask = CAN_MSGOBJ_SETTINGS;
    g_MsgObjectSettings.ulFlags = MSG_OBJ_RX_INT_ENABLE;
    g_MsgObjectSettings.ulMsgLen = 8;      // The length of the message, which should only be 8 bytes.
    g_MsgObjectSettings.pucMsgData = (unsigned char*)&g_ucSettings;
    CANMessageSet(CAN0_BASE, CAN_MSGOBJ_SETTINGS, &g_MsgObjectSettings, MSG_OBJ_TYPE_RX);
   
    // This message object will receive reset request
    g_MsgObjectReset.ulMsgID = CAN_MSGOBJ_RESET_REQ;
    g_MsgObjectReset.ulMsgIDMask = CAN_MSGOBJ_RESET_REQ;
    g_MsgObjectReset.ulFlags = MSG_OBJ_RX_INT_ENABLE;
    g_MsgObjectReset.ulMsgLen = 1;      // The length of the message, which should only be 1 device address bytes.
    CANMessageSet(CAN0_BASE, CAN_MSGOBJ_RESET_REQ, &g_MsgObjectReset, MSG_OBJ_TYPE_RX);

//*****************************************************************************
// TX CAN MESSAGES
//*****************************************************************************
    
    // This is the message object used to send status as a FW version
    g_MsgObjectStatus.ulMsgID = CAN_MSGOBJ_STATUS;
    g_MsgObjectStatus.ulFlags = MSG_OBJ_TX_INT_ENABLE;  // This enables interrupts for transmitted messages.
    g_MsgObjectStatus.ulMsgLen = 4; // Set the length of the message, which should only be two bytes and the
    g_MsgObjectStatus.pucMsgData = (unsigned char*)&g_ulVersion;      // data is always firmware version
    CANMessageSet(CAN0_BASE, CAN_MSGOBJ_STATUS, &g_MsgObjectStatus, MSG_OBJ_TYPE_TX); // Send as a IsAlive status message after the power on

    // This message object will send data
    g_MsgObjectData.ulMsgID = CAN_MSGOBJ_DATA;
    g_MsgObjectData.ulFlags = MSG_OBJ_TX_INT_ENABLE;    // This enables interrupts for transmitted messages.
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
