gclib 2.5.0
Galil Communications Library
Loading...
Searching...
No Matches
Examples

Controller Addresses

A core feature of gclib is the ability to connect to a controller over ethernet, serial, or PCI, using a single connection API.

  • C Use gclib_addresses() to see the different addresses that are available.

    • Code
      #include <gclib.h>
      #include <stdio.h>
      int main(int argc, char* argv[]) {
      char addresses[1024];
      gclib_addresses(addresses, sizeof(addresses));
      printf("Address, Model, Serial\n%s\n", addresses);
      }
      gclib_result gclib_addresses(char *addresses, size_t len)
      Show address, model, and serial of detected controllers, where available. Detected controllers are ne...
    • Output
      > .\addresses.exe
      Address, Model, Serial
      192.168.0.40, DMC4040 Rev 1.3i, 10601
      COM5, DMC-41x3
      GALILPCI0

    If using an ethernet controller that doesn't have an IP address yet, it will show up in gclib_ip_requests(). Use gclib_assign_ip() to give the controller an IP. If successful, the controller will begin showing up in gclib_addresses() under the new address.

    • Code
      #include <gclib.h>
      #include <stdio.h>
      int main(int argc, char* argv[]) {
      char result[1024];
      gclib_ip_requests(result, sizeof(result));
      printf("Address, Model, Serial\n%s\n", result);
      gclib_assign_ip("00:50:4C:20:29:69", "192.168.0.40");
      }
      gclib_result gclib_assign_ip(const char *mac, const char *ip)
      Assign IP to a controller.
      gclib_result gclib_ip_requests(char *ip_requests, size_t len)
      Show MAC address, model, and serial of all controllers requesting IP addresses, comma-separated....
    • Output
      > .\ip-requests.exe
      Address, Model, Serial
      00:50:4C:20:29:69, DMC4000, 10601
  • C++ Use gclib::addresses() to see the different addresses that are available.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      std::cout << "Address, Model, Serial\n" << gclib::addresses() << "\n";
      }
      std::string addresses()
      Show address, model, and serial of detected controllers, where available. Detected controllers are ne...
      Definition gclib.hpp:261
    • Output
      > .\addresses.exe
      Address, Model, Serial
      192.168.0.40, DMC4040 Rev 1.3i, 10601
      COM5, DMC-41x3
      GALILPCI0

    If using an ethernet controller that doesn't have an IP address yet, it will show up in gclib::ip_requests(). Use gclib::assign_ip() to give the controller an IP. If successful, the controller will begin showing up in gclib::addresses() under the new address.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      std::cout << "Address, Model, Serial" << std::endl << gclib::ip_requests() << std::endl;
      gclib::assign_ip("00:50:4C:20:29:69", "192.168.0.40");
      }
      std::string ip_requests()
      Show MAC address, model, and serial of all controllers requesting IP addresses. Detected controllers ...
      Definition gclib.hpp:273
      void assign_ip(std::string mac, std::string ip)
      Definition gclib.hpp:274
    • Output
      > .\ip-requests.exe
      Address, Model, Serial
      00:50:4C:20:29:69, DMC4000, 10601
  • LabVIEW Use addresses to see the different addresses that are available.

    Addresses.vi
    • Front Panel  
    • Block Diagram  

    If using an ethernet controller that doesn't have an IP address yet, it will show up in ip requests. Use assign ip to give the controller an IP. If successful, the controller will begin showing up in addresses under the new address.

    IP Requests.vi
    • Front Panel  
    • Block Diagram  

Connection Management

  • C To use a controller with gclib, first pass the address to gclib_open() to receive a handle to the connection, which will be used in all gclib calls which operate on that connection. After you are done, close the connection with gclib_close().
    Note
    If you need to change the baud rate, call gclib_set_baud_rate() after gclib_open().
    • Code
      #include <gclib.h>
      #include <stdio.h>
      int main(int argc, char* argv[]) {
      gclib_handle h = 0;
      char address[32], revision[1024];
      uint32_t serial;
      gclib_open(&h, argv[1]);
      gclib_address(h, address, sizeof(address));
      gclib_revision_information(h, revision, sizeof(revision));
      gclib_serial_number(h, &serial);
      printf("Address: %s\nRevision: %s\nSerial: %i\n", address, revision, serial);
      }
      gclib_result gclib_close(gclib_handle *h)
      Close connection to controller.
      gclib_result gclib_address(gclib_handle h, char *address, size_t len)
      Get connection address.
      gclib_result gclib_open(gclib_handle *h, const char *address)
      Open a connection to a controller.
      gclib_result gclib_serial_number(gclib_handle h, uint32_t *serial_number)
      Get serial number from controller.
      gclib_result gclib_revision_information(gclib_handle h, char *rev_info, size_t len)
      Get revision information (^R^V) from controller.
      struct gclib_context * gclib_handle
      A handle to an open connection given by gclib_open() for use in future API calls.
      Definition gclib.h:23
    • Output
      > .\connection.exe 192.168.0.40
      Address: 192.168.0.40
      Revision: DMC4040 Rev 1.3i
      Serial: 10601
      
    Attention
    If the program exits before calling gclib_close(), the controller may be left in an inconsistent state.
  • C++ To use a controller with gclib, pass the address and an optional baud rate (for serial connections) to gclib::Controller() to receive a controller object.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      gclib::Controller dmc(argv[1]);
      std::cout << "Address: " << dmc.address() << "\n";
      std::cout << "Revision: " << dmc.revision_information() << "\n";
      std::cout << "Serial: " << dmc.serial_number() << "\n";
      }
      Manages a connection to a controller.
      Definition gclib.hpp:303
    • Output
      > .\connection.exe 192.168.0.40
      Address: 192.168.0.40
      Revision: DMC4040 Rev 1.3i
      Serial: 10601
      
  • LabVIEW To use a controller with gclib, first pass the address to open to receive a handle to the connection, which will be used in all gclib calls which operate on that connection. After you are done, close the connection with close.

    Connection.vi
    • Front Panel
    • Block Diagram
    Attention
    If the program exits before calling close, the controller may be left in an inconsistent state.

Commands

  • C To issue commands, use gclib_command() with an open connection. The following example uses gclib_command() to implement a basic terminal.

    • Code
      #include <gclibo.h>
      #include <stdio.h>
      int main(int argc, char* argv[]) {
      gclib_handle h = NULL;
      char command[80];
      char response[1024];
      gclib_open(&h, argv[1]);
      gclib_revision_information(h, response, sizeof(response));
      printf("Connected to %s.\nPress %s to exit.\n:", response,
      #ifdef WIN32
      "Ctrl+Z then Enter"
      #else
      "Ctrl+D"
      #endif
      );
      while (fgets(command, sizeof(command), stdin)) {
      gclib_command(h, command, response, sizeof(response));
      printf("%s%s:", response, strlen(response) ? "\n" : "");
      }
      printf("\n");
      return 0;
      }
      gclib_result gclib_command(gclib_handle h, const char *command, char *buf, size_t len)
      Issues a command to the controller and provides the response.
    • Output
      > .\commands.exe 192.168.0.40
      Connected to DMC4040 Rev 1.3i.
      Press Ctrl+Z then Enter to exit.
      :MG "Hello World"
      Hello World
      :^Z
  • C++ To issue commands, use gclib::Controller::command() with an open connection. The following example uses gclib::Controller::command() to demonstrate using templated return types.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      gclib::Controller dmc(argv[1]);
      std::cout << "Command WH returned " << dmc.command("WH") << "\n";
      std::cout << "Command MG@AN[1] returned " << dmc.command<double>("MG@AN[1]") << "\n";
      std::cout << "Command MG_BN returned " << dmc.command<int>("MG_BN") << "\n";
      }
    • Output
      > .\commands.exe 192.168.0.40
      Command WH returned IHA
      Command MG@AN[1] returned 2.583
      Command MG_BN returned 10601
  • LabVIEW To issue commands, use command with an open connection.

    Commands.vi
    • Front Panel
    • Block Diagram

Errors

  • C All gclib functions provide a gclib_result value to indicate the error, with zero (GCLIB_SUCCESS) indicating success. Use gclib_error() to get a string description of the error.

  • C++ If the underlying C API returns an error, a gclib::error exception will be thrown with the error code in gclib::error::result(). Use gclib::error::what() to get an error string, if available.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      gclib::Controller dmc(argv[1]);
      try {
      dmc.command("invalid");
      } catch (gclib::error& err) {
      std::cout << err.code() << "\n";
      std::cout << "gclib error: " << err.code().value() << "\n";
      std::cout << "error code description: " << err.code().message() << "\n";
      std::cout << "error string: " << err.what() << "\n";
      }
      }
      Thrown when the underlying C library returns a nonzero gclib_result.
      Definition gclib.hpp:49
    • Output
      > .\errors.exe 192.168.0.40
      Command "invalid" caused error code 1
      TC1 returned: 1 Unrecognized command
  • LabVIEW Standard error chaining is supported by gclib. See gclib_result for a full list of error codes.
    Errors.vi
    • Front Panel
    • Block Diagram

Program & Arrays

  • C Use gclib_program() to get the controller's program, and use gclib_set_program() to set it.

    • Code
      #include <gclib.h>
      #include <stdio.h>
      int main(int argc, char* argv[]) {
      char program[1024];
      gclib_open(&h, argv[1]);
      "#AUTO\n"
      "MG \"Hello World\"\n"
      "EN", NULL);
      gclib_program(h, program, sizeof(program));
      printf("%s\n", program);
      }
      gclib_result gclib_set_program(gclib_handle h, const char *program, const char *insert)
      Set the program on the controller.
      gclib_result gclib_program(gclib_handle h, char *program, size_t len)
      Get the controller's current program.
    • Output
      > .\program.exe 192.168.0.40
      MG "Hello World"
      EN

    Use gclib_array() to get an array from the controller, and use gclib_set_array() to set it. Use the start and end arguments to transfer only a subset of the array.

    • Code
      #include <gclib.h>
      #include <stdio.h>
      int main(int argc, char* argv[]) {
      char array[128];
      gclib_open(&h, argv[1]);
      gclib_command(h, "DM test[5]", NULL, 0);
      gclib_set_array(h, "test", "1,2,3,4,5", 0, 4);
      gclib_array(h, "test", array, sizeof(array), 1, 3);
      printf("%s\n", array);
      gclib_command(h, "DA test[5]", NULL, 0);
      }
      gclib_result gclib_set_array(gclib_handle h, const char *name, const char *buf, size_t start, size_t end)
      Set an array on the controller.
      gclib_result gclib_array(gclib_handle h, const char *name, char *buf, size_t len, size_t start, size_t end)
      Get an array from the controller.
    • Output
      > .\arrays.exe 192.168.0.40
      2.0000, 3.0000, 4.0000
  • C++ Use gclib::Controller::program() to get the controller's program, and use gclib::Controller::set_program() to set it.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      gclib::Controller dmc(argv[1]);
      dmc.set_program(
      "#AUTO\n"
      "MG \"Hello World\"\n"
      "EN");
      std::cout << "" << dmc.program() << "\n";
      }
    • Output
      > .\program.exe 192.168.0.40
      MG "Hello World"
      EN

    Use gclib::Controller::array() to get an array from the controller, and use gclib::Controller::set_array() to set it. Use the start and end arguments to transfer only a subset of the array.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      gclib::Controller controller(argv[1]);
      controller.command("DM test[5]");
      controller.set_array("test", "1,2,3,4,5", 0, 4);
      std::cout << controller.array("test", 1, 3) << "\n";
      controller.command("DA test[5]");
      }
    • Output
      > .\arrays.exe 192.168.0.40
      2.0000, 3.0000, 4.0000
  • LabVIEW Use program to get the controller's program, and use set program to set it.

    Program.vi
    • Front Panel
    • Block Diagram

    Use array to get an array from the controller, and use set array to set it.

    • Use the first and last inputs to transfer only part of the array.
    Arrays.vi
    • Front Panel
    • Block Diagram

Unsolicited Data

The unsolicited data API can be used in blocking mode or callback mode.

Blocking mode is simpler to use, but has tradeoffs. If you want unsolicited data as soon as it arrives, you must block the thread to wait for it, which may not be ideal. If you want to keep the thread running, then you must periodically check for queued unsolicited data, which can add unwanted latency.

Callback mode allows your thread to stay running while enabling immediate response to unsolicited data. When data arrives, your callback function will be invoked on a separate, dedicated thread. Due to this, callback mode can be more complicated to use if you are not familiar with thread synchronization.

  • C

    For a full list of data record fields, see the Data Record API.

    Note
    Controllers with default settings will not generate interrupts or data records. Use gclib_set_interrupts() and gclib_set_data_records() to configure your controller if needed.
  • C++

    • Blocking For synchronous usage, subscribe without providing a callback or user data pointer.
      dmc.subscribe_messages();
      Once subscribed, you can then wait a specified amount of time for unsolicited data to arrive.
      // Time out if message doesn't arrive within one second
      dmc.message(1000);
      • Code
        #include <gclib.hpp>
        #include <iostream>
        int main(int argc, char* argv[]) {
        gclib::Controller dmc(argv[1]);
        dmc.subscribe_messages();
        dmc.subscribe_interrupts();
        dmc.subscribe_data_records();
        dmc.set_interrupts(gclib::Interrupt::ProgramStopped);
        dmc.set_data_records(8);
        dmc.set_program("MG \"Hello World\"; EN");
        dmc.command("XQ");
        std::cout << "Got message: " << dmc.message() << "\n";
        std::cout << "Got interrupt type: " << static_cast<unsigned int>(dmc.interrupt().type) << "\n";
        std::cout << "Got data record, sample " << dmc.data_record().sample() << "\n";
        dmc.set_interrupts(gclib::Interrupt::NoInterrupts);
        dmc.set_data_records(0);
        }
        @ ProgramStopped
        If multiple threads are running, this interrupt is only triggered when all threads are finished.
        Definition gclib.hpp:100
      • Output
        > .\unsolicited.exe 192.168.0.40
        Got message Hello World
        Got data record, sample 39306
        Got interrupt 240
    • Callback For asynchronous usage, subscribe with a callback function. Each time unsolicited data arrives, your callback will be invoked.
      dmc.subscribe_messages([](std::string message) {
      std::cout << "Message received: " << message;
      });
      Attention
      The callback will be invoked on a separate thread. Be sure to protect any shared data!
      • Code
        #include <gclib.hpp>
        #include <iostream>
        #include <chrono>
        #include <thread>
        int main(int argc, char* argv[]) {
        gclib::Controller dmc(argv[1]);
        dmc.subscribe_messages([](std::string message) {
        std::cout << "Got message: " << message << "\n";
        });
        dmc.subscribe_interrupts([](gclib::Interrupt interrupt) {
        std::cout << "Got interrupt status byte: " << static_cast<unsigned int>(interrupt.status) << "\n";
        });
        dmc.subscribe_data_records([](gclib::DataRecord data_record) {
        std::cout << "Got data record, sample " << data_record.sample() << "\n";
        });
        dmc.set_interrupts(gclib::Interrupt::ProgramStopped);
        dmc.set_data_records(200);
        dmc.set_program("WT 100; MG \"Hello World\"; EN");
        dmc.command("XQ");
        std::this_thread::sleep_for(std::chrono::milliseconds(300));
        }
        uint16_t sample()
        Definition gclib.hpp:200
        uint8_t status
        The raw status byte generated by the controller. See the EI command reference for all possible values...
        Definition gclib.hpp:112
      • Output
        > .\callback.exe 192.168.0.40
        Got message Hello World
        Got data record, sample 39306
        Got interrupt 240

    For a full list of data record fields, see gclib::DataRecord.

    Note
    Controllers with default settings will not generate interrupts or data records. Use gclib::Controller::set_interrupts() and gclib::Controller::set_data_records() to configure your controller if needed.
  • LabVIEW To receive unsolicited data, you must first subscribe to the desired unsolicited data using subscribe messages, subscribe interrupts, or subscribe data records.

    Once subscribed, use message, interrupt, and data record alongside an optional timeout to wait for unsolicited data.

    Unsolicited.vi
    • Front Panel
    • Block Diagram

Galil Connect

Galil Connect allows gclib to issue commands through a remote gcaps server. This makes debugging closed or distant systems much easier.

  • C On the device hosting the remote gcaps server, use gclib_set_published().

    • Code
      #include <gclib.h>
      #include <stdio.h>
      #include <stdbool.h>
      int main(int argc, char* argv[]) {
      printf("Published remote gcaps server \"%s\"\n", argv[1]);
      }
      gclib_result gclib_set_published(const char *name)
      Set published status of local gcaps server.
    • Output
      > .\server.exe pi
      Published remote gcaps server "pi"

    On the client, use gclib_list_servers() to view all available gcaps servers. Pass a server name to gclib_set_server() for future gclib calls to be routed through that gcaps server. When done, pass NULL to gclib_set_server() to disconnect from the remote gcaps server.

  • C++ On the device hosting the remote gcaps server, use gclib::set_published().

    • Code
      #include <gclib.hpp>
      #include <iostream>
      int main(int argc, char* argv[]) {
      std::cout << "Published remote gcaps server: " << argv[1] << "\n";
      }
      void set_published(std::string name={})
      Publish local gcaps server as name, or unpublish if name is empty.
      Definition gclib.hpp:300
    • Output
      > .\server.exe pi
      Published remote gcaps server "pi"

    On the client, use gclib::list_servers() to view all available gcaps servers. Pass a server name to gclib::set_server() for future gclib calls to be routed through that gcaps server. When done, call gclib::set_server() with no arguments to disconnect from the remote gcaps server.

  • LabVIEW On the device hosting the remote gcaps server (in this example a Raspberry Pi), use set published.

    Server.vi
    • Front Panel
    • Block Diagram

    On the client, use list servers to view all available gcaps servers. Pass a server name to set server for future gclib calls to be routed through that gcaps server. When done, pass an empty string to set server to disconnect from the remote gcaps server.

    Client.vi
    • Front Panel
    • Block Diagram

Example Project: Record and Replay

This project contains two example programs.

  • C The 'Record' example uses RA in continuous mode along with gclib_array() to allow recording movement for an arbitrary amount of time. It produces a file with the recorded positions of Axis A.

    • Code
      #include <gclib.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <time.h>
      #include "sleep.h"
      void check(gclib_result ret, gclib_handle h) {
      char error[128];
      if (ret == GCLIB_SUCCESS) {
      return;
      } else if (ret == GCLIB_COMMAND_ERROR) {
      gclib_command(h, "TC1", error, sizeof(error));
      printf("%s\n", error);
      }
      fprintf(stderr, "Error %i: %s\n", ret, gclib_error(h));
      exit(ret);
      }
      int main(int argc, char* argv[]) {
      if (argc != 3) {
      fprintf(stderr, "Usage: record.exe ADDRESS SECONDS\n");
      return 1;
      }
      char* buf = (char*)malloc(16384);
      union GDataRecord record;
      size_t bytesReturned;
      gclib_handle h = NULL;
      if (gclib_open(&h, argv[1]) != GCLIB_SUCCESS) {
      fprintf(stderr, "Failed to open connection to controller");
      exit(1);
      }
      char arrayName[5];
      sprintf(arrayName, "posA");
      gclib_command(h, "MO", NULL, 0);
      gclib_command(h, "DM posA[1000]", NULL, 0);
      gclib_command(h, "RA posA[]", NULL, 0);
      gclib_command(h, "RD _TPA", NULL, 0);
      gclib_command(h, "RC 1,-1000", NULL, 0);
      size_t start = 0, end;
      char* positions = (char*)malloc(16384);
      char* token;
      int count;
      time_t startTime = time(NULL);
      FILE* file = fopen("positions.txt", "w");
      while (difftime(time(NULL), startTime) < atof(argv[2])) {
      msleep(500);
      gclib_command(h, "MG_RD", buf, 16384);
      end = atoi(buf);
      check(gclib_array(h, arrayName, positions, 16384, start, end < start ? 0 : end), h);
      printf("%zu\n", strlen(positions));
      if (end < start) {
      check(gclib_array(h, arrayName, buf, 16384, 0, end), h);
      printf("%zu\n", strlen(buf));
      strcat(positions, ", ");
      strcat(positions, buf);
      }
      count = end - start;
      if (end < start)
      count += 1000;
      for (int i = 0; i < count; i++) {
      token = strtok( i == 0 ? positions : NULL, " ,");
      if (token == NULL)
      break;
      fprintf(file, "%s", token);
      fputc('\n', file);
      }
      start = end;
      }
      fclose(file);
      gclib_command(h, "RC 0", NULL, 0);
      }
      @ GCLIB_SUCCESS
      Definition gclib.h:30
      Data record union, containing all structs and a generic byte array accessor.
    • Output
      > .\record.exe 192.168.0.40 5

    The 'Replay' example uses the file produced by 'Record' along with CM to accurately reproduce the recorded movement. Note that axis A must be properly set up for motion.

    • Code
      #include <gclib.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include "sleep.h"
      void check(gclib_result ret, gclib_handle h) {
      char error[128];
      if (ret == GCLIB_SUCCESS)
      return;
      if (ret == GCLIB_COMMAND_ERROR) {
      gclib_command(h, "TC1", error, sizeof(error));
      printf("%s\n", error);
      }
      fprintf(stderr, "Error %i: %s\n", ret, gclib_error(h));
      exit(ret);
      }
      int main(int argc, char* argv[]) {
      if (argc != 2) {
      fprintf(stderr, "Usage: replay.exe ADDRESS\n");
      return 0;
      }
      char* buf = (char*)malloc(16384);
      GCon h = NULL;
      if (gclib_open(&h, argv[1]) != GCLIB_SUCCESS) {
      fprintf(stderr, "Failed to open connection to controller");
      exit(1);
      }
      gclib_command(h, "MG_CM", NULL, 0);
      int contourSpace = atof(buf);
      gclib_command(h, "SH A", NULL, 0);
      gclib_command(h, "CM A", NULL, 0);
      gclib_command(h, "DT -1", NULL, 0);
      FILE* f = fopen("positions.txt", "r");
      if (f == NULL) {
      fprintf(stderr, "Failed to open positions.txt");
      return 1;
      }
      int lastPosition;
      int position;
      fgets(buf, 16384, f);
      lastPosition = atof(buf);
      while (fgets(buf, 16384, f)) {
      position = atof(buf);
      sprintf(buf, "CD %i", position - lastPosition);
      lastPosition = position;
      if (gclib_command(h, buf, NULL, 0) == GCLIB_COMMAND_ERROR) {
      check(gclib_command(h, "MG_TC", buf, 16384), h);
      if ((int)atof(buf) == 32) {
      gclib_command(h, "MG_DT", buf, 16384);
      if ((int)atof(buf) == -1)
      gclib_command(h, "DT 1", NULL, 0);
      msleep(100);
      }
      }
      }
      do {
      gclib_command(h, "MG_CM", buf, 0);
      } while ((int)atof(buf) < contourSpace);
      fclose(f);
      gclib_command(h, "CD 0=0", NULL, 0);
      gclib_command(h, "MO", NULL, 0);
      }
      struct gclib_context * GCon
      Connection handle. Unique for each connection in process. Assigned a non-zero value in GOpen().
    • Output
      > .\replay.exe 192.168.0.40
  • C++ The 'Record' example uses RA in continuous mode along with gclib::Controller::array() to allow recording movement for an arbitrary amount of time. It produces a file with the recorded positions of Axis A.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      #include <thread>
      #include <chrono>
      #include <algorithm>
      #include <fstream>
      int main(int argc, char* argv[]) {
      if (argc != 3) {
      std::cerr << "Usage: record.exe ADDRESS SECONDS\n";
      return 1;
      }
      gclib::Controller dmc(argv[1]);
      try {
      auto file = std::ofstream("positions.txt", std::ios::trunc);
      if (!file) {
      std::cerr << "Failed to open positions.txt";
      return 1;
      }
      dmc.command("MO");
      dmc.command("DM posA[1000]");
      dmc.command("RA posA[]");
      dmc.command("RD _TPA");
      dmc.command("RC 1,-1000");
      size_t start = 0, end;
      std::string token;
      auto start_time = std::chrono::steady_clock::now();
      while (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start_time).count() < std::atoi(argv[2])) {
      std::this_thread::sleep_for(std::chrono::milliseconds{500});
      end = std::stod(dmc.command("MG_RD"));
      std::string positions = dmc.array("posA", start, end < start ? 0 : end);
      if (end < start) {
      positions += ", " + dmc.array("posA", 0, end);
      }
      std::replace(positions.begin(), positions.end(), ',', '\n');
      file << positions << " \n";
      start = end;
      }
      } catch (gclib::error& err) {
      std::cout << "Error " << err.code().value() << ": " << err.what();
      exit(err.code().value());
      }
      dmc.command("RC 0");
      }
    • Output
      > .\record.exe 192.168.0.40 5

    The 'Replay' example uses the file produced by 'Record' along with CM to accurately reproduce the recorded movement. Note that axis A must be properly set up for motion.

    • Code
      #include <gclib.hpp>
      #include <iostream>
      #include <chrono>
      #include <thread>
      #include <fstream>
      #include <string>
      int main(int argc, char* argv[]) {
      if (argc != 2) {
      std::cerr << "Usage: replay.exe ADDRESS\n";
      return 0;
      }
      try {
      gclib::Controller dmc(argv[1]);
      int contourSpace = std::stod(dmc.command("MG_CM"));
      dmc.command("SH A");
      dmc.command("CM A");
      dmc.command("DT -1");
      std::ifstream file("positions.txt");
      if (!file) {
      std::cerr << "Failed to open positions.txt";
      return 1;
      }
      int lastPosition;
      int position;
      std::string line;
      std::getline(file, line);
      lastPosition = std::stod(line);
      while (std::getline(file, line)) {
      position = std::stod(line);
      try {
      dmc.command("CD " + std::to_string(position - lastPosition));
      } catch (gclib::error& err) {
      if (err.code().value() != gclib::CommandError) {
      throw;
      }
      if (dmc.command<int>("MG_TC") == 32) {
      if (dmc.command<int>("MG_DT") == -1) {
      dmc.command("DT 1");
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      }
      }
      lastPosition = position;
      }
      while (dmc.command<int>("MG_CM") < contourSpace) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      }
      file.close();
      dmc.command("CD 0=0");
      dmc.command("MO");
      } catch (gclib::error& err) {
      std::cout << "Error " << (int)err.code().value() << ": " << err.what();
      exit(err.code().value());
      }
      }
    • Output
      > .\replay.exe 192.168.0.40