/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 * Description.
 * =======================================================================
 *  applicationStart() is the entry point for user applications.  This
 *  This function will be called after the kernel has started and the
 *  TCP/IP stack has loaded.  applicationTcpDown() is called periodically
 *  after the kernel has started while the system is waiting for the
 *  TCP/IP stack to start.  
 *
 *
 *
 *
 * Edit Date/Ver   Edit Description
 * ==============  =======================================================
 *
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <tx_api.h>
#include "nacbus.h"
#include "bsp_api.h"
#include "nastatus.h"
#include "string.h"



int ftp_init_flash_download (void);

/*
 * Size of the stack for the receiver call back thread.
 */
#define STACK_SIZE          (8192)

/*
 * Bit rate for the CAN bus.  Make sure this is correct.
 */
#define CAN_BUS_BIT_RATE        (500000)

#define CAN_INTERFACE           (0)

/*
 * ID of request message we will send periodically.
 */
#define REQUEST_MESSAGE_FROM_US         NA_CBUS_CONVERT_11BIT_ID(0x123)

/*
 * ID of request message we will respond to from the receiver
 * call back function.
 */
#define REQUEST_MESSAGE_FROM_NETWORK    NA_CBUS_CONVERT_11BIT_ID(0x111)

/*
 * ID of the request message we will set up the driver to respond to
 * automatically.
 */
#define REQUEST_FOR_AUTOMATIC_REPLY     NA_CBUS_CONVERT_11BIT_ID(0x112)

/*
 * ID of the data message we will send periodically.
 */
#define DATA_MESSAGE_FROM_US            NA_CBUS_CONVERT_11BIT_ID(0x098)

/*
 * ID of the data message we will accept from the network.
 */
#define DATA_MESSAGE_FROM_NETWORK       NA_CBUS_CONVERT_11BIT_ID(0x076)


/*
 * Number of seconds the main loop will delay between periodic transmits.
 */
#define LOOP_DELAY                      (2)



#define ALL_BITS_SIGNIFICANT        (0xffffffff)
/*
 * This message will be sent automatically by the driver whenever we
 * receive a request message with the ID REQUEST_FOR_AUTOMATIC_REPLY.
 *
 * We will update the contents of the last four bytes of this message
 * with the contents of data messages received from other nodes.
 */
static BYTE automaticReplyData[] = {0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x00};

/*
 * This message will be sent by the receiver call back function whenever we
 * receive a request message with the ID REQUEST_MESSAGE_FROM_NETWORK.
 * The last 4 bytes will contain a count of requests received so far.
 */
static BYTE replyMessage[] = {0x10, 0x20, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00};

/*
 * A message with the ID DATA_MESSAGE_FROM_US will be sent periodically with
 * this data.
 */
static BYTE dataMessage[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};


/*
 * The table below is used to report any error on any function call to the
 * CAN driver.  You do not have to worry about this code.
 */
#define NA_CBUS_FACILITY_CODE                       (NASTATUS_CBUS)
const char *errorLookupTable[] =
{
    "NA_SUCCESS",
    "NASTATUS_CBUS_BAD_INTERFACE",
    "NASTATUS_CBUS_BAD_ARGUMENT",
    "NASTATUS_CBUS_NO_BAUD_RATE",
    "NASTATUS_CBUS_NOT_STOPPED",
    "NASTATUS_CBUS_NOT_RUNNING",
    "NASTATUS_CBUS_OUT_OF_RESOURCES",
    "NASTATUS_CBUS_NO_RECEIVER",
    "NASTATUS_CBUS_RECEIVER_ALREADY_INSTALLED",
    "NASTATUS_CBUS_NOT_OPEN",
    "NASTATUS_CBUS_ALREADY_OPEN",
    "NASTATUS_CBUS_OFF_BUS",
    "NASTATUS_CBUS_RTRS_ALREADY_ALLOCATED",
    "NASTATUS_CBUS_RTRS_NOT_ALLOCATED"
};

const unsigned MAX_ERROR_CODE = asizeof(errorLookupTable);



/*
 * I use this macro to examine the return code from CAN function calls.  If 
 * a function returns in error the macro will report the error and exit.  
 *
 * There is no reason why you have to use a macro like this.  I am doing it
 * only because I don't want to write code everywhere I make a function call
 * to check the return value.
 */
#define HANDLE_ERROR(fn)                                    \
        {                                                           \
            NaStatus completionCode = fn;                           \
            if (completionCode != NA_SUCCESS)                       \
            {                                                       \
                reportError(# fn , completionCode, __FILE__, __LINE__);     \
            }                                                       \
        }                                                           \

/*
 * Utility function to report an error and exit.  If the error is one of the 
 * codes in our lookup table above, then we will translate it into a string
 * to make it more readable.
 */
void reportError(char *functionName, NaStatus ccode, char *filename, int lineNumber)
{
    unsigned facilityCode = ccode & NASTATUS_FAC_MASK;
    unsigned errorIndex = ccode & 0xffff;
    
    if ((facilityCode == NA_CBUS_FACILITY_CODE) && (errorIndex < MAX_ERROR_CODE))
    {
        printf ("%s returned error %s at line %d in file %s.\n", functionName, 
                errorLookupTable[errorIndex], lineNumber, filename);
    }
    else
    {
        printf ("%s returned error 0x%8.8X at line %d in file %s.\n", functionName,
                (unsigned int)ccode, lineNumber, filename);
    }
    
    tx_thread_suspend(tx_thread_identify());
}






/*
 * This function is our receiver call back function.  It is called by the CAN driver
 * whenever a frame is received that matches one of our CAN filters.  This function 
 * is called by a thread and can use any NET+OS API as well as printf.
 *
 *      1.  Each CAN frame is printed to standard output.
 *      2.  If it is a request with the ID REQUEST_MESSAGE_FROM_NETWORK, then send
 *          a reply message.
 *      3.  If the driver sent an automatic reply, then print a message saying so.
 *      4.  If it is a data message, then update the automatic reply with data
 *          from this message.
 */
void receiveFn(unsigned interface, NaCanId_t id, unsigned flags, BYTE *buffer, unsigned length)
{
    const char *frameTypeString[] = {"standard", "extended"};
    unsigned frameType = (id & NA_CBUS_CANID_IS_EXTENDED_FRAME) != 0;
    static unsigned count = 0;
    
    if (id & NA_CBUS_CANID_IS_REQUEST)
    {
        /*
         * If we received a request message, then print the ID for it.
         */
        printf("%d Request Message with %s ID received.\n", count, frameTypeString[frameType]);
        printf("    ID = 0x%8.8X\n", id & NA_CBUS_CANID_MASK);
        if ((id & NA_CBUS_CANID_MASK) == REQUEST_MESSAGE_FROM_NETWORK)
        {
            /*
             * This code demonstrates how to send a reply from the receiver call back.
             * Replies should be sent this way for requests that are not time critical.
             */
            HANDLE_ERROR(naCBusTransmit(CAN_INTERFACE, REQUEST_MESSAGE_FROM_NETWORK, replyMessage, sizeof(replyMessage))); 
            printf("    Receiver thread sent a reply.\n");
            if (sizeof(replyMessage) == 8)
            {
                /*
                 * This code is not needed.  All that it is doing is copying the count
                 * of requests received so far into the replyMessage.  I'm doing this
                 * just so that the reply changes from time to time.
                 */
                memcpy(&replyMessage[4], &count, 4);
            }
        }
        if (flags & NA_CBUS_SENT_AUTO_RESPONSE)
        {
            /*
             * The driver can send the reply if the request is time critical.  In 
             * this case, the driver will send the reply before passing the message
             * onto the thread.  The driver will set the NA_CBUS_SENT_AUTO_RESPONSE
             * bit in the flags field to indicate that the reply has already been
             * sent.
             */
            printf("    Driver sent an automatic reply.\n");
        }
    }
    else
    {
        /*
         * We will branch here if we received a data message.  We print out the
         * message ID and the data.
         */
        unsigned idx;
        
        if ((sizeof(automaticReplyData) == 8) && (length >= 4))
        {
            /*
             * This little bit of code is not doing anything essential to
             * the process of receiving a data message.  It is copying 
             * the 1st 4 bytes of the data message into the last 4 bytes of
             * the automatic reply message.  I'm just doing this to demonstrate
             * how you would change an automatic reply message on the fly.
             *
             * Note that simply copying the data into automaticReplyData is not
             * sufficient.  You have to call naCBusAutoReplySet to update the automatic
             * reply message.
             */
            memcpy(&automaticReplyData[4], buffer, 4);
            HANDLE_ERROR(naCBusAutoReplySet(CAN_INTERFACE, 0, REQUEST_FOR_AUTOMATIC_REPLY, automaticReplyData, sizeof(automaticReplyData)));
        }
        
        printf("%d Data Message with %s ID received.\n", count, frameTypeString[frameType]);
        printf("    ID = 0x%8.8X\n", id & NA_CBUS_CANID_MASK);
        printf("    Data: ");
        
        for (idx = 0; idx < length; idx++)
        {
            printf("%2.2X ", buffer[idx]);
        }
        printf ("\n");
    }
    count++;
}





/*
 * This is the entry point for the user application.  This application 
 * demonstrates how to use the CAN API.  
 *
 *      1.  It opens and configures the CAN driver.  Make sure you
 *          have set CAN_BUS_BIT_RATE to the correct bit rate for
 *          the CAN bus.
 *      2.  It sets up filters which determine which CAN messages 
 *          will be received by the controller.
 *      3.  It sets up an automatic reply to the CAN Request message
 *          with the ID REQUEST_FOR_AUTOMATIC_REPLY.
 *      4.  It periodically sends two CAN messages.  A data message 
 *          with the ID DATA_MESSAGE_FROM_US, and a Request with the
 *          ID REQUEST_MESSAGE_FROM_US.
 *
 * In addition, the receiver call back function handles the messages we
 * receive, including sending replies to request messages with the
 * ID REQUEST_MESSAGE_FROM_NETWORK.
 *          
 */
void applicationStart (void)

{
    /*
     * This function call has nothing to do with CAN.  It sets up an FTP
     * server which can be used to update the contents of flash.  This
     * is standard for all NET+OS example applications.
     */
    ftp_init_flash_download ();
    
    /*
     * Open the CAN driver and set the CAN bus rate.
     */
    HANDLE_ERROR(naCBusOpen(CAN_INTERFACE));
    HANDLE_ERROR(naCBusBpsSet(CAN_INTERFACE, CAN_BUS_BIT_RATE));
    
    /*
     * It's very important to run at the correct bus rate, so explicitly
     * tell the user what rate we are running at.
     */
    if (CAN_BUS_BIT_RATE == 1000000)
    {
        printf("\nThe CAN bus rate has been set to 1 Megabit/s.\n\n");
    }
    else
    {
        printf("\nThe CAN bus rate has been set to %d Kilobytes/s.\n\n", CAN_BUS_BIT_RATE/1000);
    }
    
    /*
     * Set up the filters.  The first filter allows data messages sent in reply to
     * our request message to be received.  The next two filters allow the request
     * messages we are expecting to be received.  The last filter allows the data
     * message we are expecting to be received.
     */
    HANDLE_ERROR(naCBusFilterSet(CAN_INTERFACE, 0, REQUEST_MESSAGE_FROM_US, ALL_BITS_SIGNIFICANT));
    HANDLE_ERROR(naCBusFilterSet(CAN_INTERFACE, 1, NA_CBUS_CANID_IS_REQUEST | REQUEST_MESSAGE_FROM_NETWORK, ALL_BITS_SIGNIFICANT));
    HANDLE_ERROR(naCBusFilterSet(CAN_INTERFACE, 2, NA_CBUS_CANID_IS_REQUEST | REQUEST_FOR_AUTOMATIC_REPLY, ALL_BITS_SIGNIFICANT));
    HANDLE_ERROR(naCBusFilterSet(CAN_INTERFACE, 3, DATA_MESSAGE_FROM_NETWORK, ALL_BITS_SIGNIFICANT));

    /*
     * Set up our receiver call back function.
     */
    HANDLE_ERROR(naCBusReceiverThreadInstall(CAN_INTERFACE, receiveFn, STACK_SIZE, NABspHighPriority, NABspHighPriority));
    
    /*
     * Set up our automatic reply.  The first call allocates one automatic reply.
     * The second call sets the data and ID for the reply.
     */
    HANDLE_ERROR(naCBusAutoReplyAllocate(CAN_INTERFACE, 1));
    HANDLE_ERROR(naCBusAutoReplySet(CAN_INTERFACE, 0, REQUEST_FOR_AUTOMATIC_REPLY, automaticReplyData, sizeof(automaticReplyData)));
    
    /*
     * Start the CAN driver and controller.  We will start receiving messages.
     */
    HANDLE_ERROR(naCBusStart(CAN_INTERFACE));
    
    /*
     * This loop sends a data message and a request message every LOOP_DELAY seconds.
     */
    while (1)
    {
        HANDLE_ERROR(naCBusTransmit(CAN_INTERFACE, DATA_MESSAGE_FROM_US, dataMessage, sizeof(dataMessage))); 
        HANDLE_ERROR(naCBusTransmit(CAN_INTERFACE, NA_CBUS_CANID_IS_REQUEST | REQUEST_MESSAGE_FROM_US, NULL, 0)); 
        tx_thread_sleep(LOOP_DELAY * NABspTicksPerSecond);
    }

}




/*
 * This function has nothing to do with CAN.  It is required by all NET+OS
 * applications.
 */
void applicationTcpDown (void)

{
    static int ticksPassed = 0;

    ticksPassed++;
/*
 * Code to handle error condition if the stack doesn't come up goes here.
 */
}
