conradv
Posts: 6
Joined: Thu Sep 06, 2012 1:54 pm

GPIO LED showing network connection

Sat Feb 09, 2013 5:45 pm

Hi,

I want to have a set of LEDs showing the state of the RPi. I have found that GPIO14 shows the state of the filesystem so that can be used to know if the system is on or off. However, I would like to add an LED to show if the network is connected or not. I know that the RPi has the onboard LEDs showing this state but I need to have an external LED to show the network state. Ideally, I would drive the LED from the GPIO pins and not solder directly on the RPi.

I have a sort of semi functional solution but when I unplug the network cable, it does not turn off the LED.

Code: Select all

#include <stdio.h>
#include <wiringPi.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>

#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <stdlib.h>

#define NETLED	0

void show_address_info( struct ifaddrs *ifa ){
  struct sockaddr_in *s4;
  struct sockaddr_in6 *s6;
  /* ipv6 addresses have to fit in this buffer */
  char buf[64];

  if (AF_INET == ifa->ifa_addr->sa_family){
    s4 = (struct sockaddr_in *)(ifa->ifa_addr);
    if (NULL == inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s4->sin_addr), buf, sizeof(buf))){
      printf("%s: inet_ntop failed!\n", ifa->ifa_name);
	digitalWrite(NETLED, 0);
    } else {
      printf("IPv4 addr %s: %s\n", ifa->ifa_name, buf);
	digitalWrite(NETLED, 1);
    }
  }
  else if (AF_INET6 == ifa->ifa_addr->sa_family) {
    s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
    if (NULL == inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s6->sin6_addr), buf, sizeof(buf))) {
      printf("%s: inet_ntop failed!\n", ifa->ifa_name);
    } else {
      printf("IPv6 addr %s: %s\n", ifa->ifa_name, buf);
      }
  }

}


int main(int argc, char *argv[])
{
  if (wiringPiSetup () == -1)
    return 1 ;

  pinMode(NETLED, OUTPUT);
  
  struct ifaddrs *myaddrs, *ifa;
  int status;
  
for(;;){
  status = getifaddrs(&myaddrs);
  if (status != 0){
    perror("getifaddrs failed!");
    exit(1);
  }

  for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next){
    if (NULL == ifa->ifa_addr){
      continue;
    }
    if ((ifa->ifa_flags & IFF_UP) == 0) {
      continue;
    }
    show_address_info(ifa);
  }
  freeifaddrs(myaddrs);
  delay(1000);
}
  return 0;

}
Thanks in advance

Conrad

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: GPIO LED showing network connection

Sat Feb 09, 2013 8:14 pm

I think your check is basically flawed - you're looking for the IP address on the interface - which is going to stay there if you unplug the cable - although it's possible that some "network managers" will remove the IP address if they detect that the cable is unplugged..

So... You need to go deeper to work out if the cable is unplugged, or hasn't had an address yet - so you can use the above to see if it's had an address ,but to see if the cable is unplugged then look at the mii-tool command.

e.g. sudo mii-tool eth0

I've actually no idea what that does internally, but the source code is available, so getting it and working out what it does to detect cable presence - or not would be your next task! (or you could just call mii-tool once a second and parse the ouput...)

-Gordon
--
Gordons projects: https://projects.drogon.net/

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: GPIO LED showing network connection

Sat Feb 09, 2013 10:12 pm

Here is a simple C application that will print the current state of an interface. You can enter the interface name as an argument, otherwise it defaults to eth0.

if_flags.c:

Code: Select all

/********************************************************************/
/* Simple network interface status application                      */
/* Opens a socket and gets the interface flags for the selected     */
/* interface (or eth0)                                              */
/*                                                                  */
/* Prints flag values of interest to stdout                         */
/*                                                                  */
/*  Build: gcc -o if_flags if_flags.c                               */
/*                                                                  */
/* W. Greathouse 9-Feb-2013                                         */
/*                                                                  */
/* Source code published "as is" and with no restrictions on use    */
/********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>     
#include <sys/ioctl.h>  /* ioctl()  */
#include <sys/socket.h> /* socket() */
#include <arpa/inet.h>  
#include <unistd.h>     /* close()  */
#include <linux/if.h>   /* struct ifreq */

struct IF_FLAG_INFO { int flag; char *tstr; char *fstr; } if_flag_info[] =
{
    { IFF_UP,           "Interface Up",     "Interface Down",   },
    { IFF_BROADCAST,    "Broadcast",        "No broadcast",     },
    { IFF_DEBUG,        "Debug enabled",    NULL,               },
    { IFF_LOOPBACK,     "Loopback",         NULL,               },
    { IFF_POINTOPOINT,  "Point to Point",   NULL,               },
    { IFF_POINTOPOINT,  "No trailers",      NULL,               },
    { IFF_RUNNING,      "Running",          NULL,               },
    { IFF_NOARP,        "No ARP",           NULL,               },
    { IFF_PROMISC,      "Promiscuous mode", NULL,               },
    { IFF_ALLMULTI,     "Rcv all multicast",NULL,               },
    { IFF_MASTER,       "Master",           NULL,               },
    { IFF_SLAVE,        "Slave",            NULL,               },
    { IFF_MULTICAST,    "Multicast",        "No multicast"      },
    { 0,                NULL,               NULL,               }
};

int main(int argc, char* argv[])
{
    int i;
    int fd;
    int rc;
    struct ifreq ethreq;
    char *ifname = "eth0";

    if (argc > 1)
        ifname = argv[1];

    /* Open a dummy socket so we have a descriptor for ioctl */
    fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd < 0)
    {
        perror("socket");
        return(1);
    }

    memset(&ethreq, 0, sizeof(ethreq));

    /* set the name of the interface we wish to check */
    strncpy(ethreq.ifr_name, ifname, IFNAMSIZ);

    /* grab flags associated with this interface */
    rc = ioctl(fd, SIOCGIFFLAGS, &ethreq);
    if (rc < 0)
    {
        perror("ioctl");
        return(2);
    }

    printf("Flags for %s\n", ifname);
    for (i=0; if_flag_info[i].flag != 0; i++)
    {
        if (ethreq.ifr_flags & if_flag_info[i].flag && if_flag_info[i].tstr)
            printf("  %s\n", if_flag_info[i].tstr);
        else if (if_flag_info[i].fstr)
            printf("  %s\n", if_flag_info[i].fstr);
    }

    close(fd);

    return 0;
}
Example:

Code: Select all

[email protected] ~ $ ./if_flags
Flags for eth0
  Interface Up
  Broadcast
  Multicast
[email protected] ~ $ ./if_flags wlan0
Flags for wlan0
  Interface Up
  Broadcast
  Running
  Multicast
The "Running" state is probably of interest for determining if the network cable is connected/disconnected for eth0. In the example above, I do not have an Ethernet cable connected, so I do not have a "Running" status.

Enjoy!
Bill

conradv
Posts: 6
Joined: Thu Sep 06, 2012 1:54 pm

Re: GPIO LED showing network connection

Sun Feb 10, 2013 8:02 pm

Thanks for your suggestions. Will try them and will let you know the outcome.

Return to “Automation, sensing and robotics”