Integrate Everything

I’ve been trying to create a proof-of-concept program that makes use of the open source FINS library I came across here:

The first obstacle I encountered was that there does not appear to be any examples on the Internet that use this library. In my experience, this means one of two things:

  1. What I am trying to do is so simple that no one else has bothered writing it up, or
  2. I am going about it entirely the wrong way and am so far off the right course that no one else has gotten to this place.

I looked into the source code itself, for I had noticed some discrepancies between the published documentation and actual function calls. Since the source code is almost always correct, it seemed like a good place to start.

I got a skeleton program written and it seemed able to connect to the PLC, in this case a CP1L-EM30DR-D on loan from Omron. However, any subsequent command I tried to execute, such as finslib_cpu_unit_status_read() or finslib_cpu_unit_data_read() or finslib_memory_area_read_uint16() all failed with the same error message indicating that too many errors had occurred and that the connection had been terminated.

tcpdump showed that the test program was in fact connecting to the PLC, but little more could be gleaned from the hex dumps it spat out. I began to walk through the library code, inserting some console chatter to try to find out exactly where each call was failing. I corrected a few mistakes I’d made. One thing that became apparent was that some of the initialization only takes place if you pass it a null pointer for the fins_sys_tp* parameter. I was creating a fins_sys_tp struct, initializing it to zeroes and passing the address of this structure to finslib_tcp_connect(), which of course then skipped all the initialization. Because of this, the connection type was set to “unknown” by default, so the communication functions all would error out immediately. Passing finslib_tcp_connect() a null pointer instead yielded the correct result.

The next thing I needed to correct was that my model of PLC was not known to the library, so it left another variable, plc_mode, set to FINS_MODE_UNKNOWN. This too, caused communication functions to fail to send data, since they did not know what format to use. As a test, I modified the library to try using CV mode on my model of CPU, which it seemed to like as all the functions invoked after that returned much more meaningful return values, and tcpdump got a lot more excited.

After that, the rest of my proof-of-concept tests proceeded much more to my liking. I was able to read and write directly to the CIO memory on the PLC, which in turn activated and de-activated outputs and LEDs on the unit. Next up I will try to read some input values (the PLC is about 30 km away from me at the moment) but I expect the remainder of the tests will go much more smoothly. Thus, we now have a much clearer path to developing the FINS Buscom plugin!

Here is my test code, in case it may help anyone else save several days of head scratching and Googling:

 * Program: libfins Test Program
 * File:    test.c
 * Author:  John Finlay
 * This file is licensed under the MIT License as stated below
 * Copyright (c) 2019 John Finlay
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.

#include "include/fins.h"

int main() {

	/* Initialize */

	int err = 0, err_max = 10;
	struct fins_sys_tp *c = NULL;

	// memset(&c, 0, sizeof(struct fins_sys_tp)); // Not needed - finslib_tcp_connect() only sets up default variables if it is passed a NULL pointer.
	// init_system(&c, err_max);

	/* Connect to the PLC */

	struct fins_sys_tp *sys = finslib_tcp_connect(c, "", 9600, 1,
			5, 0, 1, 10, 0, &err, err_max);
	printf("Connection Call:   Error Code was [%u]\n", err);

	char err_msg[64];
	finslib_errmsg(err, err_msg, 64);
	printf("Connection Call:   Error Message Was: [%s]\n", err_msg);

	/* Find out what kind of PLC we are talking to */

	struct fins_cpudata_tp cpudata;

	int cuer = finslib_cpu_unit_data_read(sys, &cpudata);

	finslib_errmsg(cuer, err_msg, 64);
			"Read CPU Data:     Error Message Was: [%d] [%s] - sys->error_count = [%u] sockfd: [%u]\n",
			cuer, err_msg, sys->error_count, sys->sockfd);

	/* Read CPU Status */

	struct fins_cpustatus_tp cpustat;
	int cpustat_ret = finslib_cpu_unit_status_read(sys, &cpustat);
	finslib_errmsg(cpustat_ret, err_msg, 64);
	printf("CPU Unit Stat Read Error Message Was: [%s]\n", err_msg);

	/* Read Memory Area */

	uint16_t arr[2048];
	int i;
	for (i = 0; i < 2048; i++) {
		arr[i] = 0;
	} // Could use memset...

	int num = 16;
	int read_ret = finslib_memory_area_read_uint16(sys, "CIO100.0", arr, num);

	finslib_errmsg(read_ret, err_msg, 64);
	printf("Memory Area Read Error Message Was: [%s]\n", err_msg);

	for (i = 0; i < num; i++) {
		printf("arr[%u] = [%u]\n", i, arr[i]);

	/* Write Memory Area */

	for (i = 0; i < 2048; i++) {
		arr[i] = 0;
	} // Again, could use memset...

	num = 16;
	int write_ret = finslib_memory_area_write_uint16(sys, "CIO100.0", arr, num);
	finslib_errmsg(write_ret, err_msg, 64);
	printf("Memory Area Write Error Message Was: [%s]\n", err_msg);

	for (i = 0; i < num; i++) {
		printf("arr[%u] = [%u]\n", i, arr[i]);

	/* Read Error Log */

	struct fins_errordata_tp errordat;
	size_t num_to_read = 1;
	size_t num_read = 0;
	int err_ret = finslib_error_log_read(sys, &errordat, 0, &num_to_read,

	finslib_errmsg(err_ret, err_msg, 64);
			"Read Error Log:    Error Message Was: [%s] - Requested: [%zu] Records That Were Read: [%zu]\n",
			err_msg, num_to_read, num_read);

	/* Read CPU Data */

	struct fins_cpudata_tp cpuinfo;

	int cpu_ret = finslib_cpu_unit_data_read(sys, &cpuinfo);

	finslib_errmsg(cpu_ret, err_msg, 64);
	printf("CPU Unit Data Read Error Message Was: [%s]\n", err_msg);

	/* Disconnect */

	printf("Connection closed.\n");
	return 0;

Compile with the following command:

gcc -Wall test.c -o test -Llib -lfins

Already April!

Venturii Buscom has seen tremendous development over the past month, and what may even be an architecture shift for the entire Venturii platform. Whereas I used to create separate modules whose sole existence was to communicate with one type of device, service or system, I found that I was having to re-use a lot of the foundational code in each module. This resulted in many copies of essentially the same thing, but applying bug fixes and feature additions became tedious and repetitive and in some cases, intermittent. Therefore I had an epiphany one morning as I was working on Buscom – why not modularize the communication code?

I wandered down the path of this thought process and came upon a system whereby clearly marked delineation points became apparent between what would be the base module (Buscom) and the differentiated code necessary for communicating with each disparate system. It made sense to me to separate this code into plug-ins, each of which could utilize the same base code Buscom was providing for establishing socket or serial communication with a thing, as well as the backbone communication to Decider. This lead to the rapid development of three plug-ins concurrently, each of which was growing off the same trunk of code.

Naturally one can still deploy multiple instances of Buscom, and indeed one could continue to utilize a single instance of it to house the communication pathway between a single system and the rest of Venturii. Thus there would still be all the benefits of an individual module communicating with an individual system, without the drawbacks of having to maintain multiple copies of the same pieces of code.

This new architecture has me so excited that I am planning to develop (or in some cases, re-develop) more integrations in the near future using it. Indeed it expedites the development process significantly, allowing more time to be spent on the actual integration and less in preparation for it. Look for a new integration announcement in the next month or so!

Winter Theme

With all the snow we’ve been having, it seemed only fitting to update the theme of this blog. The background picture is a shot I took of an accumulation of snow built up on the fence in my back yard one bright, sunny morning. I thought it looked rather pretty, and the snow has the effect, by design, of blending into the background, making it appear as though this web site is buried in it. I suppose in some ways, it is. Let me know what you think of the new layout; this is a theme I’ve wanted to use for some time, but it required some modification before it suited the nature of this page.

I’ve been working feverishly on the code development of Buscom, which is already working as a simple connector module, allowing direct communication to and from serial, IP and pipe-connected devices and services and Venturii Decider. Now it is also learning to speak Modbus, and there is more in store in the coming days!

The VDAC MID-1 Rev 2.2 is nearing completion, and I have only a few more touchups to do on the PCB design before I submit this third round of prototypes to fab. I’ve picked up a nice little rework station since assembling the last prototypes so I am hoping these next ones can be done a lot smoother. Better yet, it would be awesome if we could get them done by the Pick ‘n Place machine! Unfortunately I may not be able to wait that long.

The latest module coming to Venturii is perhaps one of the most versatile ones created to date! Venturii BusCom is a connector module for talking to any device, program or system that can communicate over a Serial connection (RS-232, RS-485, RS-422, TTL, etc.), an IP connection (TCP Client, TCP Server, UDP Client, UDP Server) or a Unix pipe. This module will basically open up Venturii to countless device types and systems, allowing data to be exchanged in both directions with them. Stay tuned!