/*

MICROCHIP SOFTWARE NOTICE AND DISCLAIMER:  
You may use this software, and any derivatives created by any person or entity 
by or on your behalf, exclusively with Microchip�s products.  Microchip and its 
licensors retain all ownership and intellectual property rights in the 
accompanying software and in all derivatives hereto.  

This software and any accompanying information is for suggestion only.  
It does not modify Microchip�s standard warranty for its products.  You agree 
that you are solely responsible for testing the software and determining its 
suitability.  Microchip has no obligation to modify, test, certify, or support 
the software.

THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS".  NO WARRANTIES, WHETHER 
EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES 
OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE APPLY 
TO THIS SOFTWARE, ITS INTERACTION WITH MICROCHIP�S PRODUCTS, COMBINATION WITH 
ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION. 

IN NO EVENT, WILL MICROCHIP BE LIABLE, WHETHER IN CONTRACT, WARRANTY, TORT 
(INCLUDING NEGLIGENCE OR BREACH OF STATUTORY DUTY), STRICT LIABILITY, INDEMNITY, 
CONTRIBUTION, OR OTHERWISE, FOR ANY INDIRECT, SPECIAL, PUNITIVE, EXEMPLARY, 
INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, FOR COST OR EXPENSE OF ANY KIND 
WHATSOEVER RELATED TO THE SOFTWARE, HOWSOEVER CAUSED, EVEN IF MICROCHIP HAS BEEN 
ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST 
EXTENT ALLOWABLE BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY 
RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, THAT YOU 
HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE 
TERMS.

*/

package lin_library_api_demo;

// Import classes
import lindllresource.LINdll;
import lindllresource.model.LINWorkingFrame;
import com.microchip.mcu8.communications.controllers.USBHID4Controller;
import com.microchip.mcu8.communications.core.Controller;
import exceptions.CommandFailureException;
import java.util.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.collections.ListChangeListener;
import javax.xml.bind.ValidationException;


public class LIN_Library_API_Demo {
    
    // LIN classic checksum calculation routine
    public static int LIN_getChecksum( int length, byte[] data ){
        int checksum = 0;

        for (byte i = 0; i < length; i++){
            checksum = checksum + (0xFF&data[i]);

            if(checksum >= 256)
                checksum -= 255;
        }

        checksum = 0xFF & (~checksum);

        return checksum;
    }

    // PID calculation routine
    public static byte LIN_getPID( byte frame_id ){
        int ID0 =  frame_id & 0x01;
        int ID1 = (frame_id & 0x02) >> 1;
        int ID2 = (frame_id & 0x04) >> 2;
        int ID3 = (frame_id & 0x08) >> 3;
        int ID4 = (frame_id & 0x10) >> 4;
        int ID5 = (frame_id & 0x20) >> 5;
        int P0;
        int P1;
        int pid;

        P0 = ID0 ^ ID1 ^ ID2 ^ ID4;
        P1 = ~(ID1 ^ ID3 ^ ID4 ^ ID5);

        pid = (frame_id&0x3F) + (P0<<6) + (P1<<7);

        return (byte)pid;
    }

    public static void main(String[] args) {
        // TODO code application logic here

        try {
            // Select and Initialize the lowest level communication protocol from the host
            // In this case we use USB since the LIN Analyzer Tool interfaces as a USB device
            Controller hid4java = new USBHID4Controller("A04");

            // Initialize the LIN DLL Library by passing in the communication reference
            LINdll initdll = new LINdll(hid4java);

            // Add a listener to the model to observe the LIN frames on the bus
            // Here you can listen the messages from the LIN bus, includding those transmitted by the tool
            initdll.getModel().readLINFrames.addListener(new ListChangeListener<LINWorkingFrame>() {
                @Override
                public void onChanged(ListChangeListener.Change<? extends LINWorkingFrame> c) {
                    if(c.next()) {
                        // Log LIN Frame information on the console

                        Formatter formatterFrameData = new Formatter();
                        for (byte b : c.getAddedSubList().get(0).FrameInfo.FrameData) {
                           formatterFrameData.format("%02X ", b);
                        }

                        Logger.getGlobal().info( String.format(
                            "Timestamp: %f  Baud: %d  PID(ID): %02X(%02X)  Length: %d  Data&Checksum: %s  Error: %d", 
                              c.getAddedSubList().get(0).FrameInfo.time,                // timestamp
                              (0xFFFF & c.getAddedSubList().get(0).FrameInfo.baud ),    // baudrate
                              (0xFF & c.getAddedSubList().get(0).FrameInfo.FrameID ),   // frame PID
                              (0x3F & c.getAddedSubList().get(0).FrameInfo.FrameID ),   // frame ID
                              (0xFF & c.getAddedSubList().get(0).FrameInfo.bytecount ), // length (including checksum)
                              formatterFrameData.toString(),                            // data bytes & checksum
                              (0xFFFF & c.getAddedSubList().get(0).FrameInfo.m_OnReceive_error ) // 0=No Error;      1=Bus Time-out Error;  3=Timer Error; 
                                                                                                 // 4=Status Error;  5=Event Marker Error;  6=Next Frame Header Received Error
                            ));
                    }    
                }
            });

            // Library Initialization
            initdll.startReadContinuos();   // Start the LIN continuous read process

            // Initialize the LIN Serial Analyzer hardware Tool
            initdll.getController().getCommandFactory().getConfigurePICKitSerial().execute(10, true);  
            initdll.getController().getCommandFactory().getSet_Buffer_Flush_Parameters().execute(true, 
                    true, (byte)10, 10);

            /*****************************************************************************************/       
            /**** Initialization ends here. You can write your custom application from this point ****/       
            /*****************************************************************************************/       

            // Set/Change the baud rate
            initdll.getController().getCommandFactory().getChangeLINBaudRate().execute( 19200 );

            // Prepare the message
            byte frameID = (byte)0x05;                              // Frame ID
            byte framePID = LIN_getPID( frameID );                  // Frame PID
            int length = 8;                                         // data length (0 .. 8)
            byte[] messageDataAndChecksum = new byte[ length + 1 ]; // add one more byte for checksum

            for (byte i = 0; i < length; i++){
                messageDataAndChecksum[i] = (byte)(0x10*(i+1));       // message data bytes
            }

            int checksumClassic = LIN_getChecksum( messageDataAndChecksum.length-1, messageDataAndChecksum );

            // Add the checksum on last position
            messageDataAndChecksum[ messageDataAndChecksum.length-1 ] = (byte) checksumClassic;

            // Transmit a LIN Frames with Master as the publisher. 
            initdll.getController().getCommandFactory().getTransmitCommand().execute( messageDataAndChecksum, 
                    framePID );

            Thread.sleep(500); // Wait a while

            // Transmit a 2nd frame 
            initdll.getController().getCommandFactory().getTransmitCommand().execute( messageDataAndChecksum, 
                    framePID );

            // Wait for the bus to respond. 
            // This delay is only for the demo. It won't be needed in your application.
            Thread.sleep(2000);  

            // Clean Up before exiting 
            initdll.stopReadContinuos();   // Stop the continuous bus read process
            hid4java.Disconnect();         // Disconnect from the USB device

            System.exit(0);            
        } catch (ValidationException | InterruptedException | CommandFailureException ex) {
            Logger.getLogger( LIN_Library_API_Demo.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

}

