/*
* extensions.c:
* Part of the GPIO program to test, peek, poke and otherwise
* noodle with the GPIO hardware on the Raspberry Pi.
* Copyright (c) 2012-2013 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wiringPi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with wiringPi. If not, see .
***********************************************************************
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "extensions.h"
extern int wiringPiDebug ;
#ifndef TRUE
# define TRUE (1==1)
# define FALSE (1==2)
#endif
// Local structure to hold details
struct extensionFunctionStruct
{
const char *name ;
int (*function)(char *progName, int pinBase, char *params) ;
} ;
/*
* extractInt:
* Check & return an integer at the given location (prefixed by a :)
*********************************************************************************
*/
static char *extractInt (char *progName, char *p, int *num)
{
if (*p != ':')
{
fprintf (stderr, "%s: colon expected\n", progName) ;
return NULL ;
}
++p ;
if (!isdigit (*p))
{
fprintf (stderr, "%s: digit expected\n", progName) ;
return NULL ;
}
*num = strtol (p, NULL, 0) ;
while (isdigit (*p))
++p ;
return p ;
}
/*
* extractStr:
* Check & return a string at the given location (prefixed by a :)
*********************************************************************************
*/
static char *extractStr (char *progName, char *p, char **str)
{
char *q, *r ;
if (*p != ':')
{
fprintf (stderr, "%s: colon expected\n", progName) ;
return NULL ;
}
++p ;
if (!isprint (*p))
{
fprintf (stderr, "%s: character expected\n", progName) ;
return NULL ;
}
q = p ;
while ((*q != 0) && (*q != ':'))
++q ;
*str = r = calloc (q - p + 2, 1) ; // Zeros it
while (p != q)
*r++ = *p++ ;
return p ;
}
/*
* doExtensionMcp23008:
* MCP23008 - 8-bit I2C GPIO expansion chip
* mcp23002:base:i2cAddr
*********************************************************************************
*/
static int doExtensionMcp23008 (char *progName, int pinBase, char *params)
{
int i2c ;
if ((params = extractInt (progName, params, &i2c)) == NULL)
return FALSE ;
if ((i2c < 0x03) || (i2c > 0x77))
{
fprintf (stderr, "%s: i2c address (0x%X) out of range\n", progName, i2c) ;
return FALSE ;
}
mcp23008Setup (pinBase, i2c) ;
return TRUE ;
}
/*
* doExtensionMcp23016:
* MCP230016- 16-bit I2C GPIO expansion chip
* mcp23016:base:i2cAddr
*********************************************************************************
*/
static int doExtensionMcp23016 (char *progName, int pinBase, char *params)
{
int i2c ;
if ((params = extractInt (progName, params, &i2c)) == NULL)
return FALSE ;
if ((i2c < 0x03) || (i2c > 0x77))
{
fprintf (stderr, "%s: i2c address (0x%X) out of range\n", progName, i2c) ;
return FALSE ;
}
mcp23016Setup (pinBase, i2c) ;
return TRUE ;
}
/*
* doExtensionMcp23017:
* MCP230017- 16-bit I2C GPIO expansion chip
* mcp23017:base:i2cAddr
*********************************************************************************
*/
static int doExtensionMcp23017 (char *progName, int pinBase, char *params)
{
int i2c ;
if ((params = extractInt (progName, params, &i2c)) == NULL)
return FALSE ;
if ((i2c < 0x03) || (i2c > 0x77))
{
fprintf (stderr, "%s: i2c address (0x%X) out of range\n", progName, i2c) ;
return FALSE ;
}
mcp23017Setup (pinBase, i2c) ;
return TRUE ;
}
/*
* doExtensionMcp23s08:
* MCP23s08 - 8-bit SPI GPIO expansion chip
* mcp23s08:base:spi:port
*********************************************************************************
*/
static int doExtensionMcp23s08 (char *progName, int pinBase, char *params)
{
int spi, port ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI address (%d) out of range\n", progName, spi) ;
return FALSE ;
}
if ((params = extractInt (progName, params, &port)) == NULL)
return FALSE ;
if ((port < 0) || (port > 7))
{
fprintf (stderr, "%s: port address (%d) out of range\n", progName, port) ;
return FALSE ;
}
mcp23s08Setup (pinBase, spi, port) ;
return TRUE ;
}
/*
* doExtensionMcp23s17:
* MCP23s17 - 16-bit SPI GPIO expansion chip
* mcp23s17:base:spi:port
*********************************************************************************
*/
static int doExtensionMcp23s17 (char *progName, int pinBase, char *params)
{
int spi, port ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI address (%d) out of range\n", progName, spi) ;
return FALSE ;
}
if ((params = extractInt (progName, params, &port)) == NULL)
return FALSE ;
if ((port < 0) || (port > 7))
{
fprintf (stderr, "%s: port address (%d) out of range\n", progName, port) ;
return FALSE ;
}
mcp23s17Setup (pinBase, spi, port) ;
return TRUE ;
}
/*
* doExtensionSr595:
* Shift Register 74x595
* sr595:base:pins:data:clock:latch
*********************************************************************************
*/
static int doExtensionSr595 (char *progName, int pinBase, char *params)
{
int pins, data, clock, latch ;
// Extract pins
if ((params = extractInt (progName, params, &pins)) == NULL)
return FALSE ;
if ((pins < 8) || (pins > 32))
{
fprintf (stderr, "%s: pin count (%d) out of range - 8-32 expected.\n", progName, pins) ;
return FALSE ;
}
if ((params = extractInt (progName, params, &data)) == NULL)
return FALSE ;
if ((params = extractInt (progName, params, &clock)) == NULL)
return FALSE ;
if ((params = extractInt (progName, params, &latch)) == NULL)
return FALSE ;
sr595Setup (pinBase, pins, data, clock, latch) ;
return TRUE ;
}
/*
* doExtensionPcf8574:
* Digital IO (Crude!)
* pcf8574:base:i2cAddr
*********************************************************************************
*/
static int doExtensionPcf8574 (char *progName, int pinBase, char *params)
{
int i2c ;
if ((params = extractInt (progName, params, &i2c)) == NULL)
return FALSE ;
if ((i2c < 0x03) || (i2c > 0x77))
{
fprintf (stderr, "%s: i2c address (0x%X) out of range\n", progName, i2c) ;
return FALSE ;
}
pcf8574Setup (pinBase, i2c) ;
return TRUE ;
}
/*
* doExtensionPcf8591:
* Analog IO
* pcf8591:base:i2cAddr
*********************************************************************************
*/
static int doExtensionPcf8591 (char *progName, int pinBase, char *params)
{
int i2c ;
if ((params = extractInt (progName, params, &i2c)) == NULL)
return FALSE ;
if ((i2c < 0x03) || (i2c > 0x77))
{
fprintf (stderr, "%s: i2c address (0x%X) out of range\n", progName, i2c) ;
return FALSE ;
}
pcf8591Setup (pinBase, i2c) ;
return TRUE ;
}
/*
* doExtensionMax31855:
* Analog IO
* max31855:base:spiChan
*********************************************************************************
*/
static int doExtensionMax31855 (char *progName, int pinBase, char *params)
{
int spi ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI channel (%d) out of range\n", progName, spi) ;
return FALSE ;
}
max31855Setup (pinBase, spi) ;
return TRUE ;
}
/*
* doExtensionMcp3002:
* Analog IO
* mcp3002:base:spiChan
*********************************************************************************
*/
static int doExtensionMcp3002 (char *progName, int pinBase, char *params)
{
int spi ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI channel (%d) out of range\n", progName, spi) ;
return FALSE ;
}
mcp3002Setup (pinBase, spi) ;
return TRUE ;
}
/*
* doExtensionMcp3004:
* Analog IO
* mcp3004:base:spiChan
*********************************************************************************
*/
static int doExtensionMcp3004 (char *progName, int pinBase, char *params)
{
int spi ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI channel (%d) out of range\n", progName, spi) ;
return FALSE ;
}
mcp3004Setup (pinBase, spi) ;
return TRUE ;
}
/*
* doExtensionMax5322:
* Analog O
* max5322:base:spiChan
*********************************************************************************
*/
static int doExtensionMax5322 (char *progName, int pinBase, char *params)
{
int spi ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI channel (%d) out of range\n", progName, spi) ;
return FALSE ;
}
max5322Setup (pinBase, spi) ;
return TRUE ;
}
/*
* doExtensionMcp4802:
* Analog IO
* mcp4802:base:spiChan
*********************************************************************************
*/
static int doExtensionMcp4802 (char *progName, int pinBase, char *params)
{
int spi ;
if ((params = extractInt (progName, params, &spi)) == NULL)
return FALSE ;
if ((spi < 0) || (spi > 1))
{
fprintf (stderr, "%s: SPI channel (%d) out of range\n", progName, spi) ;
return FALSE ;
}
mcp4802Setup (pinBase, spi) ;
return TRUE ;
}
/*
* doExtensionSn3218:
* Analog Output (LED Driver)
* sn3218:base
*********************************************************************************
*/
static int doExtensionSn3218 (char *progName, int pinBase, char *params)
{
sn3218Setup (pinBase) ;
return TRUE ;
}
/*
* doExtensionMcp3422:
* Analog IO
* mcp3422:base:i2cAddr
*********************************************************************************
*/
static int doExtensionMcp3422 (char *progName, int pinBase, char *params)
{
int i2c, sampleRate, gain ;
if ((params = extractInt (progName, params, &i2c)) == NULL)
return FALSE ;
if ((i2c < 0x03) || (i2c > 0x77))
{
fprintf (stderr, "%s: i2c address (0x%X) out of range\n", progName, i2c) ;
return FALSE ;
}
if ((params = extractInt (progName, params, &sampleRate)) == NULL)
return FALSE ;
if ((sampleRate < 0) || (sampleRate > 3))
{
fprintf (stderr, "%s: sample rate (%d) out of range\n", progName, sampleRate) ;
return FALSE ;
}
if ((params = extractInt (progName, params, &gain)) == NULL)
return FALSE ;
if ((gain < 0) || (gain > 3))
{
fprintf (stderr, "%s: gain (%d) out of range\n", progName, gain) ;
return FALSE ;
}
mcp3422Setup (pinBase, i2c, sampleRate, gain) ;
return TRUE ;
}
/*
* doExtensionDrcS:
* Interface to a DRC Serial system
* drcs:base:pins:serialPort:baud
*********************************************************************************
*/
static int doExtensionDrcS (char *progName, int pinBase, char *params)
{
char *port ;
int pins, baud ;
if ((params = extractInt (progName, params, &pins)) == NULL)
return FALSE ;
if ((pins < 1) || (pins > 100))
{
fprintf (stderr, "%s: pins (%d) out of range (2-100)\n", progName, pins) ;
return FALSE ;
}
if ((params = extractStr (progName, params, &port)) == NULL)
return FALSE ;
if (strlen (port) == 0)
{
fprintf (stderr, "%s: serial port device name required\n", progName) ;
return FALSE ;
}
if ((params = extractInt (progName, params, &baud)) == NULL)
return FALSE ;
if ((baud < 1) || (baud > 4000000))
{
fprintf (stderr, "%s: baud rate (%d) out of range\n", progName, baud) ;
return FALSE ;
}
drcSetupSerial (pinBase, pins, port, baud) ;
return TRUE ;
}
/*
* Function list
*********************************************************************************
*/
struct extensionFunctionStruct extensionFunctions [] =
{
{ "mcp23008", &doExtensionMcp23008 },
{ "mcp23016", &doExtensionMcp23016 },
{ "mcp23017", &doExtensionMcp23017 },
{ "mcp23s08", &doExtensionMcp23s08 },
{ "mcp23s17", &doExtensionMcp23s17 },
{ "sr595", &doExtensionSr595 },
{ "pcf8574", &doExtensionPcf8574 },
{ "pcf8591", &doExtensionPcf8591 },
{ "mcp3002", &doExtensionMcp3002 },
{ "mcp3004", &doExtensionMcp3004 },
{ "mcp4802", &doExtensionMcp4802 },
{ "mcp3422", &doExtensionMcp3422 },
{ "max31855", &doExtensionMax31855 },
{ "max5322", &doExtensionMax5322 },
{ "sn3218", &doExtensionSn3218 },
{ "drcs", &doExtensionDrcS },
{ NULL, NULL },
} ;
/*
* doExtension:
* Load in a wiringPi extension
*********************************************************************************
*/
int doExtension (char *progName, char *extensionData)
{
char *p ;
char *extension = extensionData ;
struct extensionFunctionStruct *extensionFn ;
int pinBase = 0 ;
// Get the extension extension name by finding the first colon
p = extension ;
while (*p != ':')
{
if (!*p) // ran out of characters
{
fprintf (stderr, "%s: extension name not terminated by a colon\n", progName) ;
return FALSE ;
}
++p ;
}
*p++ = 0 ;
if (!isdigit (*p))
{
fprintf (stderr, "%s: pinBase number expected after extension name\n", progName) ;
return FALSE ;
}
while (isdigit (*p))
{
if (pinBase > 1000000000)
{
fprintf (stderr, "%s: pinBase too large\n", progName) ;
return FALSE ;
}
pinBase = pinBase * 10 + (*p - '0') ;
++p ;
}
if (pinBase < 64)
{
fprintf (stderr, "%s: pinBase (%d) too small. Minimum is 64.\n", progName, pinBase) ;
return FALSE ;
}
// Search for extensions:
for (extensionFn = extensionFunctions ; extensionFn->name != NULL ; ++extensionFn)
{
if (strcmp (extensionFn->name, extension) == 0)
return extensionFn->function (progName, pinBase, p) ;
}
fprintf (stderr, "%s: extension %s not found\n", progName, extension) ;
return FALSE ;
}