content: /*
   *                         Vortex OpenSplice
   *
   *   This software and documentation are Copyright 2006 to TO_YEAR ADLINK
   *   Technology Limited, its affiliated companies and licensors. All rights
   *   reserved.
   *
   *   Licensed under the Apache License, Version 2.0 (the "License");
   *   you may not use this file except in compliance with the License.
   *   You may obtain a copy of the License at
   *
   *       http://www.apache.org/licenses/LICENSE-2.0
   *
   *   Unless required by applicable law or agreed to in writing, software
   *   distributed under the License is distributed on an "AS IS" BASIS,
   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *   See the License for the specific language governing permissions and
   *   limitations under the License.
   *
   */
  
  /**
   * The RoundTrip example consists of a Ping and a Pong application. Ping sends sample
   * to Pong by writing to the Ping partition which Pong subscribes to. Pong them sends them
   * back to Ping by writing on the Pong partition which Ping subscribes to. Ping measure
   * the amount of time taken to write and read each sample as well as the total round trip
   * time to send a sample to Pong and receive it back.
   *
   * This class performs the Ping role in this example.
   */
  class Ping_impl
  {
      /**
       * Performs the Ping role in this example.
       */
      public void run (String args[])
      {
          try
          {
              int status;
  
              /** Initialise entities */
              final Entities e = new Entities("ping", "pong");
  
              Runtime.getRuntime().addShutdownHook(new Thread()
              {
                  public void run()
                  {
                      e.terminated.set_trigger_value(true);
                  }
              });
  
              int payloadSize = 0;
              long numSamples = 0;
              long timeOut = 0;
  
              /** Interpret arguments */
              Exception usage = new Exception(
                  "Usage (parameters must be supplied in order):\n" +
                  "./ping [payloadSize (bytes, 0 - 65536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]\n" +
                  "./ping quit - ping sends a quit signal to pong.\n" +
                  "Defaults:\n" +
                  "./ping 0 0 0");
              if(args.length == 1)
              {
                  if(args[0].equals("quit"))
                  {
                      /** Wait for pong to run */
                      System.out.println("Waiting for pong to run...");
                      DDS.PublicationMatchedStatusHolder pms = new DDS.PublicationMatchedStatusHolder();
                      status = e.writer.get_publication_matched_status(pms);
                      ExampleError.CheckStatus(status, "ping, e.writer.get_publication_matched_status");
                      while(pms.value.current_count == 0)
                      {
                          status = e.writer.get_publication_matched_status(pms);
                          ExampleError.CheckStatus(status, "ping, e.writer.get_publication_matched_status");
                          Thread.sleep(500);
                      }
                      System.out.println("Sending termination request");
                      /** Dispose an instance to signify that pong should quit if "quit" is supplied as an argument to ping */
                      RoundTripModule.DataType data = new RoundTripModule.DataType();
  
                      status = e.writer.dispose(data, DDS.HANDLE_NIL.value);
                      ExampleError.CheckStatus(status, "ping, e.writer.dispose");
                      Thread.sleep(1000);
                      return;
                  }
                  else if(args[0].equals("-h") || args[0].equals("--help"))
                  {
                      throw usage;
                  }
              }
              if(args.length >= 1)
              {
                  payloadSize = Integer.parseInt(args[0]);
  
                  if(payloadSize > 65536)
                  {
                      throw usage;
                  }
              }
              if(args.length >= 2)
              {
                  numSamples = Integer.parseInt(args[1]);
              }
              if(args.length >= 3)
              {
                  timeOut = Integer.parseInt(args[2]);
              }
  
              System.out.println("# payloadSize: " + payloadSize + " | numSamples: " + numSamples +
                  " | timeOut: " + timeOut + "\n");
  
              long startTime;
              long preWriteTime;
              long postWriteTime;
              long preTakeTime;
              long postTakeTime;
              ExampleUtilities.TimeStats writeAccess = new ExampleUtilities.TimeStats();
              ExampleUtilities.TimeStats readAccess = new ExampleUtilities.TimeStats();
              ExampleUtilities.TimeStats roundTrip = new ExampleUtilities.TimeStats();
              ExampleUtilities.TimeStats writeAccessOverall = new ExampleUtilities.TimeStats();
              ExampleUtilities.TimeStats readAccessOverall = new ExampleUtilities.TimeStats();
              ExampleUtilities.TimeStats roundTripOverall = new ExampleUtilities.TimeStats();
              DDS.Duration_t waitTimeout = new DDS.Duration_t(1, 0);
              RoundTripModule.DataType data = new RoundTripModule.DataType(new byte[payloadSize]);
              for(int i = 0; i < payloadSize; i++)
              {
                  data.payload[i] = (byte)1;
              }
              DDS.ConditionSeqHolder conditions = new DDS.ConditionSeqHolder();
              RoundTripModule.DataTypeSeqHolder samples = new RoundTripModule.DataTypeSeqHolder();
              DDS.SampleInfoSeqHolder info = new DDS.SampleInfoSeqHolder();
  
              startTime = ExampleUtilities.GetTime();
              System.out.println("# Warming up to stabilise performance...");
              boolean warmUp = true;
              while(!e.terminated.get_trigger_value() && (ExampleUtilities.GetTime() -
                  startTime) / ExampleUtilities.US_IN_ONE_SEC < 5)
              {
                  status = e.writer.write(data, DDS.HANDLE_NIL.value);
                  ExampleError.CheckStatus(status, "ping, e.writer.write");
                  status = e.waitSet._wait(conditions, waitTimeout);
                  if(status != DDS.RETCODE_TIMEOUT.value)
                  {
                      ExampleError.CheckStatus(status, "ping, e.waitSet.wait");
                      status = e.reader.take(samples, info, DDS.LENGTH_UNLIMITED.value,
                          DDS.ANY_SAMPLE_STATE.value, DDS.ANY_VIEW_STATE.value, DDS.ANY_INSTANCE_STATE.value);
                      ExampleError.CheckStatus(status, "ping, e.reader.take");
                      status = e.reader.return_loan(samples, info);
                      ExampleError.CheckStatus(status, "ping, e.reader.return_loan");
                  }
              }
              if(!e.terminated.get_trigger_value())
              {
                  warmUp = false;
                  System.out.println("# Warm up complete.\n");
  
                  System.out.println("# Round trip measurements (in us)");
                  System.out.println("#             Round trip time [us]         Write-access time [us]       Read-access time [us]");
                  System.out.println("# Seconds     Count   median      min      Count   median      min      Count   median      min");
              }
  
              startTime = ExampleUtilities.GetTime();
              long elapsed = 0;
              for(long i = 0; !e.terminated.get_trigger_value() && (numSamples == 0 || i < numSamples); i++)
              {
                  /** Write a sample that pong can send back */
                  preWriteTime = ExampleUtilities.GetTime();
                  status = e.writer.write(data, DDS.HANDLE_NIL.value);
                  postWriteTime = ExampleUtilities.GetTime();
                  ExampleError.CheckStatus(status, "ping, e.writer.write");
  
                  /** Wait for response from pong */
                  status = e.waitSet._wait(conditions, waitTimeout);
                  if(status != DDS.RETCODE_TIMEOUT.value)
                  {
                      ExampleError.CheckStatus(status, "ping, e.waitSet._wait");
  
                      /** Take sample and check that it is valid */
                      preTakeTime = ExampleUtilities.GetTime();
                      status = e.reader.take(samples, info, DDS.LENGTH_UNLIMITED.value,
                          DDS.ANY_SAMPLE_STATE.value, DDS.ANY_VIEW_STATE.value, DDS.ANY_INSTANCE_STATE.value);
                      postTakeTime = ExampleUtilities.GetTime();
                      ExampleError.CheckStatus(status, "ping, e.reader.take");
  
                      if(!e.terminated.get_trigger_value())
                      {
                          if(samples.value.length != 1)
                          {
                              Exception exception = new Exception(
                                  "ERROR: Ping received " + samples.value.length + " samples but " +
                                  "was expecting 1. Are multiple pong applications running?");
                              throw exception;
                          }
                          else if(!info.value[0].valid_data)
                          {
                              Exception exception = new Exception(
                                  "ERROR: Ping received an invalid sample. Has pong terminated already?");
                              throw exception;
                          }
                      }
                      status = e.reader.return_loan(samples, info);
                      ExampleError.CheckStatus(status, "ping, e.reader.return_loan");
  
                      /** Update stats */
                      writeAccess.AddMicroseconds(postWriteTime - preWriteTime);
                      readAccess.AddMicroseconds(postTakeTime - preTakeTime);
                      roundTrip.AddMicroseconds(postTakeTime - preWriteTime);
                      writeAccessOverall.AddMicroseconds(postWriteTime - preWriteTime);
                      readAccessOverall.AddMicroseconds(postTakeTime - preTakeTime);
                      roundTripOverall.AddMicroseconds(postTakeTime - preWriteTime);
  
                      /** Print stats each second */
                      if((postTakeTime - startTime) > ExampleUtilities.US_IN_ONE_SEC || (i >= 1 && i == numSamples))
                      {
                          System.out.printf("%9d %9d %8.0f %8d %10d %8.0f %8d %10d %8.0f %8d\n",
                                  elapsed + 1,
                                  roundTrip.count,
                                  roundTrip.GetMedian(),
                                  roundTrip.min,
                                  writeAccess.count,
                                  writeAccess.GetMedian(),
                                  writeAccess.min,
                                  readAccess.count,
                                  readAccess.GetMedian(),
                                  readAccess.min);
  
                          /** Reset stats for next run */
                          roundTrip.Reset();
                          writeAccess.Reset();
                          readAccess.Reset();
  
                          /** Set values for next run */
                          startTime = ExampleUtilities.GetTime();
                          elapsed++;
                      }
                  }
                  else
                  {
                      elapsed += waitTimeout.sec;
                  }
                  if(timeOut >= 1 && elapsed == timeOut)
                  {
                      status = e.terminated.set_trigger_value(true);
                      ExampleError.CheckStatus(status, "ping, e.terminated.set_trigger_value");
                  }
              }
  
              if(!warmUp)
              {
                  /** Print overall stats */
                  System.out.printf("\n%9s %9d %8.0f %8d %10d %8.0f %8d %10d %8.0f %8d\n",
                          "# Overall",
                          roundTripOverall.count,
                          roundTripOverall.GetMedian(),
                          roundTripOverall.min,
                          writeAccessOverall.count,
                          writeAccessOverall.GetMedian(),
                          writeAccessOverall.min,
                          readAccessOverall.count,
                          readAccessOverall.GetMedian(),
                          readAccessOverall.min);
              }
          }
          catch(Exception e)
          {
              System.out.println(e);
          }
      }
  }
  