/**************************************************************************************************
  Filename:       znp-bringup.zjs
  Revised:        $Date:$
  Revision:       $Revision:$

  Description:    This file is a test script bring up ZC and ZR.


  Copyright 2010 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/


/**************************************************************************************************
  Instructions:

  Connect a device to be a ZC to a COM nicknamed “C” and another to a COM named “R”

**************************************************************************************************/
import System;
import System.Text;
import TI.ZPI2;

class TheScript
{
  // Set to 'true' when running the ZNP in order to reset the devices and startup the network.
  private var ZNP_RUN : boolean = true;
  private var SUCCESS : int = 0;

  // Set this variable to the script engine's nickname for the COM port to the target device.
  private var ZR_Com : String = "COM5";
  private var ZC_Com : String = "COM3";

  // Set this variable to 'true' to enable the display of log messages (i.e. verbose mode).
  private var showLogMsgs : boolean = true;

  // Variables set by the incoming message handler to enable "re-try until success" looping.
  private var gotRstRsp           : boolean = false;
  private var gotCfgRsp           : boolean = false;
  private var gotRegRsp           : boolean = false;
  private var gotStartRsp         : boolean = false;
  private var gotStateRsp         : boolean = false;
  private var gotAfReqExtRsp      : boolean = false;
  private var gotAfIncExt         : boolean = false;
  private var gotAfStoreRsp       : boolean = false;
  private var gotAfRetrieveRsp    : boolean = false;

  private var profileId           : UInt16  = 0x0104;  // HA Profile ID
  private var endPoint            : Byte    = 0x0C;    // SampleSW has endpoint 12 so we use that
  private var inClusterCnt        : Byte    = 1;
  private var outClusterCnt       : Byte    = 1;
  private var inClusterList = new Array(inClusterCnt);
  private var outClusterList = new Array(outClusterCnt);

  private var NV_STARTUP_OPTION     : Byte = 0x03;
  private var NV_STARTUP_OPTION_VAL : Byte = 0x03;	// 0x03 = clear configuration
  private var NV_STARTUP_LEN        : Byte = 1;

  private var cfgArr = new Array(256);        // Make big enough for any configuration item.
  private var retrieveBuf = new Array(1024);  // Make big enough for any huge message attempted.
  private var retrieveTot           : UInt16 = 741;
  private var retrieveLen           : Byte = 247;
  private var retrieveIdx           : UInt16;

  // Main class function that effects the work of this test script.
  function run() {
    for (var idx = 1; idx <= inClusterCnt; idx++)
    {
      inClusterList[idx] = idx;
    }
    for (var idx = 1; idx <= outClusterCnt; idx++)
    {
      outClusterList[idx] = idx;
    }

    // Subscribe to the incoming message handler.
    ZEngine.add_OnMessageZPI2(this.msgHandler);

    if (ZNP_RUN)
    {
      // Force a device out of the boot loader wait routine (no bad effect when SBL is not present).
      //sysReset(ZC_Com);

      // Set the Startup_Option to Clear Configuration and reset to effect the action.
      //cfgArr[0] = NV_STARTUP_OPTION_VAL;
      //writeCfg(ZC_Com , NV_STARTUP_OPTION, NV_STARTUP_LEN, cfgArr);
      //sysReset(ZC_Com);

      // Force a device out of the boot loader wait routine (no bad effect when SBL is not present).
      sysReset(ZR_Com);

      // Set the Startup_Option to Clear Configuration and reset to effect the action.
      cfgArr[0] = NV_STARTUP_OPTION_VAL;
      writeCfg(ZR_Com , NV_STARTUP_OPTION, NV_STARTUP_LEN, cfgArr);
      sysReset(ZR_Com);

      // Setup the device type, panId & channel mask and reset to effect the settings.
      cfgArr[0] = 0x00;                    // Set Logical Device Type to ZC.
      //writeCfg(ZC_Com, 0x87, 0x01, cfgArr);
      cfgArr[0] = 0x01;                    // Set Logical Device Type to ZR.
      writeCfg(ZR_Com, 0x87, 0x01, cfgArr);
      cfgArr[0] = 0x22; cfgArr[1] = 0x06;  // Set Pan Id to 0x0622 // Change this to anything you need to test
      //writeCfg(ZC_Com, 0x83, 0x02, cfgArr);
      writeCfg(ZR_Com, 0x83, 0x02, cfgArr);
      cfgArr[0] = 0x00; cfgArr[1] = 0x00; cfgArr[2] = 0x08; cfgArr[3] = 0x00;
                                         // Set Channel Mask to 0x00100000  // 20 - 0x14
					 // Set Channel Maks to 0x00080000  // 19 - 0x13 - Current channel mask
      //writeCfg(ZC_Com, 0x84, 0x04, cfgArr);
      writeCfg(ZR_Com, 0x84, 0x04, cfgArr);
	  cfgArr[0] = 0xAA; cfgArr[1] = 0xBB;
      //writeCfg(ZC_Com,0x62, 16, cfgArr); //program the NWK Key 1st two bytes are AA and BB
      // Start the devices on the network.
      //startReq(ZC_Com);
      startReq(ZR_Com);
    }

    ZEngine.Complete(true);
  }


  // Handler for incoming messages.
  function msgHandler(comm : String, id : MESSAGE_ID, msg : Object) {
    switch (id)
    {
    case MESSAGE_ID.SYS_RESET_RESPONSE:
    {
      gotRstRsp = true;
      break;
    }

    case MESSAGE_ID.ZB_WRITE_CONFIGURATION_RSP:
    {
      var cfgRsp : ZB_WRITE_CONFIGURATION_RSP = msg;

      if (cfgRsp.Status == SUCCESS)
      {
        gotCfgRsp = true;
      }
      break;
    }

    case MESSAGE_ID.AF_REGISTER_SRSP:
    {
      var regRsp : AF_REGISTER_SRSP = msg;

      if (regRsp.Status == SUCCESS)
      {
        gotRegRsp = true;
      }
      break;
    }

    case MESSAGE_ID.ZB_START_REQUEST_RSP:
    {
      gotStartRsp = true;
      break;
    }

    case MESSAGE_ID.ZDO_STATE_CHANGE_IND:
    {
      var zdoStateInd : ZDO_STATE_CHANGE_IND = msg;

      // { DEV_END_DEVICE, DEV_ROUTER, DEV_ZB_COORD } : { 6, 7, 9 }
      if ((zdoStateInd.State == 6) || (zdoStateInd.State == 7) || (zdoStateInd.State == 9))
      {
        gotStateRsp = true;
      }
      break;
    }

    case MESSAGE_ID.AF_DATA_REQUEST_EXT_SRSP:
    {
      var afRegExtRsp : AF_DATA_REQUEST_EXT_SRSP = msg;

      if (afRegExtRsp.Status == SUCCESS)
      {
        gotAfReqExtRsp = true;
      }
      break;
    }

    case MESSAGE_ID.AF_DATA_STORE_SRSP:
    {
      var afStoreRsp : AF_DATA_STORE_SRSP = msg;

      if (afStoreRsp.Status == SUCCESS)
      {
        gotAfStoreRsp = true;
      }
      break;
    }

    case MESSAGE_ID.AF_INCOMING_MSG_EXT:
    {
      var afIncExt : AF_INCOMING_MSG_EXT = msg;
      afDataRetrieve(comm, msg);
      gotAfIncExt = true;
      break;
    }

    case MESSAGE_ID.AF_DATA_RETRIEVE_SRSP:
    {
      var afRetrieveRsp : AF_DATA_RETRIEVE_SRSP = msg;

      if (afRetrieveRsp.Status == SUCCESS)
      {
        var index = retrieveIdx;

        for (var idx = 0; idx < afRetrieveRsp.Length; idx++, index++)
        {
          retrieveBuf[index] = afRetrieveRsp.Data[idx];
        }

        gotAfRetrieveRsp = true;
      }
      break;
    }

    default:
      break;
    }
  }


  // Send a ZB_SYSTEM_RESET message until success.
  function sysReset(comm : String) {
    var req : ZB_SYSTEM_RESET = new ZB_SYSTEM_RESET();
    gotRstRsp = false;

    while (!gotRstRsp)
    {
      logMsg("ZB_SYSTEM_RESET  to " + comm);
      ZEngine.Send(comm, req);
      ZEngine.Pause(50);

      // Sending SYS_STACK_TUNE as a way to get a 0x07 byte to the SBL before a 0xF8 byte.
      // An 0x07 byte forces the immediate run of valid code.
      //sysStackTune(comm, 7, 7);
      //ZEngine.Pause(300);
    }
  }


  // Send a SYS_STACK_TUNE message.
  function sysStackTune(comm : String, Operation: Byte, Value: Byte) {
    var req : SYS_STACK_TUNE = new SYS_STACK_TUNE();
    req.Operation = Operation;
    req.Value = Value;

    logMsg("SYS_STACK_TUNE to " + comm);
    ZEngine.Send(comm, req);
  }


  // Send a ZB_WRITE_CONFIGURATION message.
  function writeCfg(comm : String, cfgId : Byte, len : Byte,  value : Array ) {
    var req : ZB_WRITE_CONFIGURATION = new ZB_WRITE_CONFIGURATION();
    req.ConfigId = cfgId;
    req.Len = len;
		req.Value = new byte[len];

    for (var idx = 0; idx < len; idx++)
    {
      req.Value[idx] = value[idx];
    }

    gotCfgRsp = false;
    while (!gotCfgRsp)
    {
      logMsg("ZB_WRITE_CONFIGURATION  to " + comm);
      ZEngine.Send(comm, req);
      ZEngine.Pause(200);
    }
  }


  // Send a ZB_AF_REGISTER_REQUEST message.
  function afReg(comm : String) {
    var req : AF_REGISTER  = new AF_REGISTER ();
    req.AppProfID = profileId;
    req.EndPoint = endPoint;
    req.AppInClusterList = inClusterList;
    req.AppNumInClusters = inClusterCnt;
    req.AppOutClusterList = outClusterList;
    req.AppNumOutClusters = outClusterCnt;

    gotRegRsp = false;
    while (!gotRegRsp)
    {
      logMsg("ZB_AF_REGISTER_REQUEST to " + comm);
      ZEngine.Send(comm, req);
      ZEngine.Pause(200);
    }
  }


  // Send a ZB_START_REQUEST message.
  function startReq(comm : String) {
    var req : ZB_START_REQUEST  = new ZB_START_REQUEST();

    gotStateRsp = false;
    while (!gotStateRsp)
    {
      gotStartRsp = false;
      while (!gotStartRsp)
      {
        logMsg("ZB_START_REQUEST  to " + comm);
        ZEngine.Send(comm, req);
        ZEngine.Pause(1000);
      }
      ZEngine.Pause(5000);
    }
  }


  /* Make a huge data request via an AF_DATA_REQUEST_EXT message and store the huge data.
   * Since the max MT payload is 250 & the store message header is 3, the max bytes per store
   * is 247. So to simplify the script just use 3 X 247 = 741.
   * Note that we are simultaneously proving the max capacity of 250 bytes per MT message here.
   */
  function afDataReqFrag(comm : String) {
    var req : AF_DATA_REQUEST_EXT = new AF_DATA_REQUEST_EXT();

    req.DstAddrMode = 2;  // Addr16Bit = 2
    req.DstAddr[0] = 0; req.DstAddr[1] = 0;  // Short address 0x0000 is for ZC.
    req.DstEndPoint = endPoint;
    req.DstPanId = 0;  // Zero signifies not Inter-PAN.
    req.SrcEndpoint = endPoint;
    req.ClusterID = 1;  // Startup initialization makes cluster Id's 1,2,3... up to count.
    req.TransID = 0;  // Trans Id is a don't care.
    req.Options = 0;  // AF_TX_OPTIONS_NONE = 0
    req.Radius = 15;  // AF_DEFAULT_RADIUS = 15
    req.Len = retrieveTot;

    gotAfReqExtRsp = false;
    while (!gotAfReqExtRsp)
    {
      logMsg("AF_DATA_REQUEST_EXT to " + comm);
      ZEngine.Send(comm, req);
      ZEngine.Pause(3000);
    }

    var index : UInt16 = 0;
    var fragLen : Byte = retrieveLen;
    var fragBuf : Byte[] = new Byte[fragLen];
    for (var idx = 0; idx < fragLen; idx++)
    {
      fragBuf[idx] = idx;
    }
    afDataStore(comm, index, fragLen, fragBuf);
    index += fragLen;

    // Change the frag data to enhance verification reliability on Rx.
    for (idx = 0; idx < fragLen; idx++)
    {
      fragBuf[idx]++;
    }
    afDataStore(comm, index, fragLen, fragBuf);
    index += fragLen;

    // Change the frag data again to enhance verification reliability on Rx.
    for (idx = 0; idx < fragLen; idx++)
    {
      // Without a type-cast, the script promotes fragBuf[] to int at run-time.
      fragBuf[idx] = (Byte)(idx * 2);
    }
    afDataStore(comm, index, fragLen, fragBuf);

    // A store of zero length indicates to send it OTA.
    afDataStore(comm, 0, 0, fragBuf);
  }


  // Send a AF_DATA_STORE message.
  function afDataStore(comm : String, index : UInt16, len : Byte, buf : Byte[]) {
    var req : AF_DATA_STORE = new AF_DATA_STORE();

    req.Index = index;
    req.Length = len;

    for (var idx = 0; idx < len; idx++)
    {
      req.Data[idx] = buf[idx];
    }

    gotAfStoreRsp = false;
    while (!gotAfStoreRsp)
    {
      logMsg("AF_DATA_STORE to " + comm);
      ZEngine.Send(comm, req);
      ZEngine.Pause(100);
    }
  }


  // Send a series of AF_DATA_RETRIEVE message(s) to get the data of an incoming huge message.
  function afDataRetrieve(comm : String, msgIn : AF_INCOMING_MSG_EXT) {
    var req : AF_DATA_RETRIEVE = new AF_DATA_RETRIEVE();

    req.Timestamp = msgIn.Timestamp;
    req.Length = retrieveLen;

    for (retrieveIdx = 0; retrieveIdx < msgIn.Len; retrieveIdx += retrieveLen)
    {
      req.Index = retrieveIdx;

      gotAfRetrieveRsp = false;
      while (!gotAfRetrieveRsp)
      {
        logMsg("AF_DATA_RETRIEVE to " + comm);
        ZEngine.Send(comm, req);
        ZEngine.Pause(100);
      }
    }

    /* Retrieve request with zero length indicates to flush the message and free the dynamic
     * memory. If this request fails, the device times out the incoming huge message buffer and
     * flushes it automatically, so no loop here.
     */
    req.Length = 0;
    logMsg("AF_DATA_RETRIEVE to " + comm);
    ZEngine.Send(comm, req);
    ZEngine.Pause(100);
  }


  // Verify the data in the global retrieveBuf[] according to what was sent in afDataReqFrag().
  function verifyMsgIn() : boolean {
    /* At first writing of this script, the afDataReqFrag() sent 741 bytes.
     * The first 247 bytes were 0-247; the next 247 bytes were 1-248; and the last 247 bytes were
     * calculated as twice the corresponding index.
     */
    var index = 0;

    for (var idx = 0; idx < retrieveLen; idx++, index++)
    {
      if (retrieveBuf[index] != idx)
      {
        break;
      }
    }

    for (var idx = 1; idx <= retrieveLen; idx++, index++)
    {
      if (retrieveBuf[index] != idx)
      {
        break;
      }
    }

    for (var idx = 0; idx < retrieveLen; idx++, index++)
    {
      if (retrieveBuf[index] != (Byte)(idx * 2))
      {
        break;
      }
    }

    if (index < retrieveTot)
    {
      return false;
    }
    else
    {
      return true;
    }
  }


  // Display a log message if log messages are enabled.
  function logMsg(theMsg : String) {
    if (showLogMsgs)
    {
      ZEngine.WriteLog(theMsg);  // Display the message.
    }
  }
} // End of TheScript class.


// The script engine will execute the following code.
var script:TheScript = new TheScript();
script.run();


/**************************************************************************************************
*/
