// Test of CiA 401 device


// SVN $Date: 2021-02-26 15:31:18 +0100 (Fr, 26. Feb 2021) $
// SVN $Rev: 35191 $
// SVN $Author: ged $


// configuration settings
const DUT_NodeID = 32
const SDO_gap_time_ms = 10;

const TEST_NONE = 0;
const TEST_BOOTUP = 1;
const TEST_SDO_301 = 2;
const TEST_PDO = 3;
const TEST_DIG_IN = 4;

const EXPECTED_DEVICETYPE = 0xf0191;
const EXPECTED_VENDOR = 793;

const PDO_EVENT_TIME = 1000;
const PDO_CHECK_TIME = 10000;

////////////////////////////////////////////////////////////////////////////////////
var currentTest = TEST_NONE;
var lastResult = 0;
// Variables for PDO test
var pdoReceiveCount = 0;
var pdoExpectedReceiveCount = 0;

// Variables for Digital Input Test
var digitalInputTestRunning = 0;
var previousDigitalInput = -1;
var digitalInputTimer = 0;

// Function to check if we are connected or not
function checkConnection() {
	if(canconnection.isConnected()) {
		return true;
	} else {
		util.print("Error - Not connected.");
		return false;
	}
}

// This function will register a CAN ID corresponding to bootup of DUT_NodeID
function registerBootup() {
	if(checkConnection()) {
		return can.registerCanEvent(0x700 + DUT_NodeID, "id700Handler");
	} else {
		return false;
	}
}

// Callback for the PDO 
function pdoReceiveHandler(id, rtrFlag, dlc, d0, d1, d2, d3, d4, d5, d6, d7) {
    if(currentTest === TEST_PDO) {
		pdoReceiveCount++;
	}
}

// Callback for the bootup
function id700Handler(id, rtrFlag, dlc, d0, d1, d2, d3, d4, d5, d6, d7) {
	if ((currentTest === TEST_BOOTUP) && (id === (DUT_NodeID + 0x700))) {
        lastResult = 1;
    }
}

// Simple function to reset the device
function testResetDevice() {
	if(checkConnection()) {
		util.print("Send NMT Command Reset Application")
		nmt.resetApplNode(DUT_NodeID)
	}
}

function testBootupDevice() {
    if( registerBootup() === true ) {
		util.print("Send NMT Command Reset Application")
		currentTest = TEST_BOOTUP;
		lastResult = 0;
		nmt.resetApplNode(DUT_NodeID)

		cnt = 0;
		// Wait a certain time and check if lastresult is set to 1 via Bootup callback
		while (lastResult === 0) {
			util.msleep(10);
			if (lastResult === 1) {
				util.print("Test passed: Boot-up received.")
				break;
			}
			cnt++;

			if (cnt > 10) {
				util.print("Test FAILED");
				break;
			}
		} 
	}
}

function testBasicCiA301() {
    if( checkConnection() === true ) {
		util.print("Test Object 0x1000")
		currentTest = TEST_SDO_301;
		lastResult = 0;

		// Read device type and compare it with the expected one
		result = sdo.read(0x1000,0, UNSIGNED32)
		if (result === EXPECTED_DEVICETYPE) {
			util.print("Test passed: Expected device type received")
		} else {
			util.print("Test FAILED: " + result);
		}

		// Read the device name and compare it
		result = sdo.read(0x1008, 0, 9)
		if (result === "Generic IO module according CiA 401") {
			util.print("Test passed: Generic IO module according CiA 401 received")
		} else {
			util.print("Test FAILED: " + result);
		}
	}
}

// This function is called after a certain timeout and compares the expected with the real received PDO count
function checkPdoReceiveCount()
{
	util.print("Received " + pdoReceiveCount + " PDOs of " + pdoExpectedReceiveCount + " expected PDOs");
	
	// stop pdo event
	var result = sdo.write(0x1800, 0x05, 0x06, 0);
    if(result !== "SDO_OK") {
		util.print("ERROR - Could not set event time");
	} 
}

function testPDOEvent() {
	// Check for connection
	if(checkConnection()) {
		
		// read the cob id 
		var cobId = sdo.read(0x1800, 0x01, UNSIGNED32);
				
		// register for the cob id
		if(can.registerCanEvent(cobId, "pdoReceiveHandler")) {
		
			pdoReceiveCount = 0;
			pdoExpectedReceiveCount = PDO_CHECK_TIME / PDO_EVENT_TIME;
			currentTest = TEST_PDO;
			// write PDO event time
			var result = sdo.write(0x1800, 0x05, 0x06, PDO_EVENT_TIME);
            if(result !== "SDO_OK") {
				util.print("ERROR - Could not set event time");
			} else {
				// call checkPdoReceiveCount after timeout
				var timerId = util.after(PDO_CHECK_TIME + 500, "checkPdoReceiveCount()");
				util.print("PDO Test Running ... ");
			}
		} else {
			util.print("Error - Cannot register COB ID");
		}
	}
}

function digitalInputTest() {
    if(currentTest === TEST_DIG_IN) {
		// Read Digital input object and compare it with the previous one
		var result = sdo.read(0x6000, 0x01, UNSIGNED8);
        if((result !== "SDO_NOT_CONNECTED") && (result !== "SDO_ERROR")) {
            if(result !== previousDigitalInput) {
				util.print("Digital Input changed to " + result);
				previousDigitalInput = result;
			}
		} else {
			util.print(result);
		}
	}
}

function testDigitalIOByUserInput()
{
    if(digitalInputTestRunning === false) {
		digitalInputTestRunning = true;
		
		currentTest = TEST_DIG_IN;
		util.userMessage("Digital Input Test", "Please change the digital input, changed values will printed out.", 0);
		// Read digital input every 200 ms
		digitalInputTimer = util.every(200, "digitalInputTest()");
		button.setName(6, "Stop digital input test");
	} else {
		// stop the timer
		button.setName(6, "Test digital inputs");
		util.deleteTimer(digitalInputTimer);
		digitalInputTestRunning = false;	
	}
}

function handleCanConnection()
{
	// Toggle the connection and change button name depending on connection state
    if(canconnection.isConnected() === false) {
		canconnection.connect();
		enableButtons(true);
		button.setName(1, "Disconnect from CAN")
	} else {
		util.deleteTimer(digitalInputTimer);
		canconnection.disconnect();
		enableButtons(false);
		button.setName(1, "Connect to CAN")
	}
}

function enableButtons(enable) {
	for(i = 2; i <= 10; i++) {		
		if((i != 7) && (i != 9)) {
			button.setEnabled(i, enable)
		}
	}
}

function saveCanLog() {
	// open a dialog to save file
	f = filedialog.getSaveFileName("Select file to save CAN log","C:/Daten/temp","ZIP (*.zip)");
	if(f != "") {
		util.saveLog(f);
	}
}

function prepareButtons() {
	
    button.setName(2, "Reset Device")
    button.setEnabled(2, true)
    button.setCommand(2, "testResetDevice();")

    button.setName(3, "Reset Device and test bootup")
    button.setEnabled(3, true)
    button.setCommand(3, "testBootupDevice();")

    button.setName(4, "Test basic 301 objects")
    button.setEnabled(4, true)
    button.setCommand(4, "testBasicCiA301();")


	button.setName(5, "Test PDO Event Transmission")
    button.setEnabled(5, true)
    button.setCommand(5, "testPDOEvent();")

    button.setName(6, "Test digital inputs");
    button.setEnabled(6, true)
    button.setCommand(6, "util.after(100, \"testDigitalIOByUserInput()\")")
	
	button.setName(7, "")
    button.setEnabled(7, false)
	
	button.setName(8, "Save CAN Log")
    button.setEnabled(8, true)
    button.setCommand(8, "util.after(100, \"saveCanLog()\")")
	
	button.setName(9, "")
    button.setEnabled(9, false)
    button.setCommand(9, "util.clear();")
	
    button.setName(10, "Clear");
    button.setEnabled(10, true)
    button.setCommand(10, "util.clear();")

    option.setName(1, "Detailed output");
    option.setEnabled(1, true);

    option.setName(2, "Log CAN");
    option.setEnabled(2, false);
	option.setChecked(2, true);
	
	if(canconnection.isConnected()) {
		button.setName(1, "Disconnect from CAN")
		enableButtons(true);
	} else {
		button.setName(1, "Connect to CAN")
		enableButtons(false);
	}
	
    button.setEnabled(1, true)
    button.setCommand(1, "handleCanConnection()")
}

// start scripting here
prepareButtons();

// set the node id for this session
sdo.setNodeId(DUT_NodeID);

// clear output window
util.clear();
util.print("CiA 401 device Test");

