element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Industrial Automation
  • Technologies
  • More
Industrial Automation
Blog AVNET SmartEdge IIOT Gateway: C Program for the Industrial I/O
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Industrial Automation to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 15 Jan 2021 6:24 PM Date Created
  • Views 1188 views
  • Likes 4 likes
  • Comments 1 comment
  • iiot
  • industrial
  • avnet
  • smartedge
  • gateway
Related
Recommended

AVNET SmartEdge IIOT Gateway: C Program for the Industrial I/O

Jan Cumps
Jan Cumps
15 Jan 2021

The SmartEdge IIOT GatewaySmartEdge IIOT Gateway is a Raspberry Pi 3 Compute based industrial Linux box.

It runs Raspbian with some additions. There's a set of industrial hardware extensions. In this blog I revisit the industrial I/O. I create a C program that controls the inputs and outputs.

image

 

API

 

Use the Industrial inputs and outputs from a C program. Pretend to make a simple API.

It's an intermediate exercise in my far away goal to use these pins in OpenPLC.

 

The API:

 

static PINHANDLE openInOut(char *pin, PINDIRECTION direction)
static void closeInOut(PINHANDLE fp)
static void setHigh(PINHANDLE fp, bool high)
static bool getHigh(PINHANDLE fp)

 

Four functions to deal with the pins.

 

  • Use openInOut() to indicate that you want to use one of the industrial in- or outouts.
    In the pin isn't set up yet, this will be done when you call this initialiser.
  • closeInOut() is the cleanup at the end. It releases resources.
    It doesn't reset pin states though. Everything you altered will stay that way.
  • setHigh() drives output pins.
  • getHigh() reads input pins.

Looking back I could have used read() and write() but it is what it is.

 

How to use the API?

 

Straightforward. You initialise the pins and use them.

This is my test program: When you push a switch attached to Input 1, a led connected to Output 1 will light up:

  • Read an input (I1).
  • Set output (O1) to the same value.

 

  PINHANDLE pO1 = openInOut(GPIO_O1, OUTDIRECTION);
  PINHANDLE pI1 = openInOut(GPIO_I1, INDIRECTION);

  bool state = false;
  setHigh(pO1, state);
  while(!usleep(100000)) {
    if(state != getHigh(pI1)) {
      state = !state;
      setHigh(pO1, state);
    }
  }

 

You can see the result in the animation at the top of the blog post.

 

Full Code

 

 

To help understand the code, I'm summarising the Linux level commands that are used in the C source.

 

echo 200 >/sys/class/gpio/export  
echo 201 >/sys/class/gpio/export  
echo in > /sys/class/gpio/gpio200/direction 
echo out > /sys/class/gpio/gpio201/direction 

cat /sys/class/gpio/gpio201/value

echo 0 > /sys/class/gpio/gpio201/value  
echo 1 > /sys/class/gpio/gpio201/value 

 

The same calls are done here, if/when needed.

This is just a few tens of lines.

 

#include<unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#define GPIODIR "/sys/class/gpio"
#define EXPORTFILE GPIODIR "/export"
#define GPIODIR_PT2 "/gpio"
#define GPIO_O1 "201"
#define GPIO_I1 "200"

#define PINHANDLE FILE *
#define PINDIRECTION bool
#define OUTDIRECTION true
#define INDIRECTION false

// longest string used + 1
#define BUFFLEN sizeof GPIODIR GPIODIR_PT2 GPIO_O1 "/directionX"

/*
 * jc: this comes from the source of raspberry gpio utility
 * changeOwner:
 *  Change the ownership of the file to the real userId of the calling
 *  program so we can access it.
 *********************************************************************************
 */
//static void changeOwner (char *file)
//{
//  uid_t uid = getuid () ;
//  uid_t gid = getgid () ;
//
//  if (chown (file, uid, gid) != 0)
//  {
//    // todo error here
//  }
//}

static bool dirExists (char *dir)
{
  bool retval = false;
  // check if our pin is exported
  DIR* d = opendir(dir);
  if (d) {
    /* Directory exists. */
    closedir(d);
    retval = true;
  }
  return retval;
}

static PINHANDLE openInOut(char *pin, PINDIRECTION direction)
{
  PINHANDLE retval = NULL;
  char buffer[BUFFLEN];
  strcpy(buffer, GPIODIR);
  strcat(buffer, GPIODIR_PT2);
  strcat(buffer, pin);


  // check if our pin is exported
  if (!dirExists(buffer)) {
    FILE *fp;
    fp = fopen(EXPORTFILE, "w");
    fputs(pin, fp);
    fclose(fp);
  }

  // get size of buffer at this point
  // this point will be used later to build
  // the path to the character driver too.

  int buflen = strlen(buffer);
  // set to direction
  {
    FILE *fp;
    strcat(buffer, "/direction");
    fp = fopen(buffer, "w");
    if (direction) { //output
      fputs("out", fp);
    } else { // input
      fputs("in", fp);
    }
    fclose(fp);
  }

  // get file handle to the character driver
  {
    char* start = buffer + buflen;
    strcpy(start, "/value");
    if (direction) { // output
      retval = fopen(buffer, "w");
    } else { // input
      retval = fopen(buffer, "r");
    }
    // unbuffered, so that a read and write are direct
    // linked to the character driver
    setvbuf(retval, NULL, _IONBF, 0);
  }
  return retval;
}

static void closeInOut(PINHANDLE fp) {
  fclose(fp);
}

static void setHigh(PINHANDLE fp, bool high) {
  if(high) {
    fputs("1", fp);
  } else {
    fputs("0", fp);
  }
//  fflush(fp); I switched to an unbuffered stream.
}

static bool getHigh(PINHANDLE fp) {
  char buffer[2];
  rewind(fp);
  fread(buffer, sizeof buffer[0], 1, fp);
  return (buffer[0] == '1');
}

int main(void) {
  PINHANDLE pO1 = openInOut(GPIO_O1, OUTDIRECTION);
  PINHANDLE pI1 = openInOut(GPIO_I1, INDIRECTION);

  bool state = false;
  setHigh(pO1, state);
  while(!usleep(100000)) {
    if(state != getHigh(pI1)) {
      state = !state;
      setHigh(pO1, state);
    }
  }

  closeInOut(pI1);
  closeInOut(pO1);
}

 

There are some little additional functions I didn't mention in my summary:

In the case that the pin is not in the right state, or never used before, the code does the management to set everything up.

The program does not need to be executed by root, but the user has to be part of the gpio group.

 

Related Blog
Industrial I/O
Use the Industrial I/O
Control Industrial I/O directly from GPIO Pins
C Program for the Industrial I/O
Control Industrial I/O directly from Node-RED
Display Industrial I/O on Node-RED Dashboard
CAN Bus
Use the Isolated CAN
CAN programming in C on Linux: Filter and Mask
2020 Linux Image
The 2020 Linux Image and IoTConnect Scripts
Understand the Custom Scripts and Services (Pt. 1: intro and reset button service)
Understand the Custom Scripts and Services (Pt. 2: led service)
Understand the Custom Scripts and Services (Pt. 3: IoT Connect service)
  • Sign in to reply
  • DAB
    DAB over 4 years ago

    Nice post Jan.

     

    DAB

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube