Initial commit
This commit is contained in:
commit
5af2be7e5b
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
build/
|
19
CMakeLists.txt
Normal file
19
CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(relaycontrol LANGUAGES C)
|
||||||
|
|
||||||
|
set(CFLAGS "${CFLAGS} -Wall -Wextra -pedantic -Wformat-overflow=2 -Wformat-security -Winit-self -Wstrict-overflow=2 -Wstringop-overflow=2 -Walloc-zero -Wduplicated-branches -Wduplicated-cond -Wtrampolines -Wfloat-equal -Wshadow -Wunsafe-loop-optimizations -Wparentheses -fanalyzer -fstack-protector")
|
||||||
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
endif()
|
||||||
|
if (CMAKE_BUILD_TYPE EQUAL "Debug")
|
||||||
|
set(CFLAGS "${CFLAGS} -Og")
|
||||||
|
elseif (CMAKE_BUILD_TYPE EQUAL "Release")
|
||||||
|
set(CFLAGS "${CFLAGS} -O2 -Werror")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(relaycntl
|
||||||
|
src/main.c
|
||||||
|
)
|
||||||
|
set_property(TARGET relaycntl PROPERTY C_STANDARD 99)
|
||||||
|
|
||||||
|
install(TARGETS relaycntl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
13
LICENSE
Normal file
13
LICENSE
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
25
README.md
Normal file
25
README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Raspberry PI General Purpose Input/Output Controller
|
||||||
|
|
||||||
|
This is a simple GPIO pin controller for UNIX-like kernels/systems.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- CMake
|
||||||
|
- ANSI C compiler
|
||||||
|
- UNIX standard library
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
First, generate the build files with CMake:
|
||||||
|
```
|
||||||
|
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Second, install the binary:
|
||||||
|
```
|
||||||
|
cd build/
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
WTFPL
|
99
src/main.c
Normal file
99
src/main.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define GPIO_IFACE_MISSING = -1
|
||||||
|
#define GPIO_PIN_EXP_FAIL = -2
|
||||||
|
#define GPIO_DIR_CONT_FAIL = -3
|
||||||
|
#define GPIO_SWITCH_FAIL = -4
|
||||||
|
#define GPIO_PIN_UNX_NF = -5
|
||||||
|
#define GPIO_PIN_UNX_FAIL = -6
|
||||||
|
|
||||||
|
#define GPIO_PREFIX "/sys/class/gpio/"
|
||||||
|
#define GPIO_EXPORT "export"
|
||||||
|
#define GPIO_UNEXPORT "unexport"
|
||||||
|
|
||||||
|
#define MAX_PATHLEN 512
|
||||||
|
|
||||||
|
#define PRINTERRANDRET(mesg, varfmt, var) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "%s \"%" varfmt "\". %s (%i)\n", mesg, var, strerror(errno), errno); \
|
||||||
|
return 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t exportPin(signed int pinno);
|
||||||
|
ssize_t setPinDirection(signed int pinno, char* value);
|
||||||
|
ssize_t setPinValue(signed int pinno, int value);
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int pinno = (argc > 1) ? atoi(argv[1]) : 0;
|
||||||
|
bool value = (argc > 2) ? atoi(argv[2]) : 0;
|
||||||
|
if (pinno != exportPin(pinno))
|
||||||
|
return -1;
|
||||||
|
if (pinno != setPinDirection(pinno, "out"))
|
||||||
|
return -1;
|
||||||
|
if (pinno != setPinValue(pinno, value))
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t exportPin(signed int pinno)
|
||||||
|
{
|
||||||
|
if (chdir(GPIO_PREFIX) != 0)
|
||||||
|
PRINTERRANDRET("Failed to change directory to", "s", GPIO_PREFIX);
|
||||||
|
char buffer[MAX_PATHLEN];
|
||||||
|
int fd;
|
||||||
|
ssize_t nbytes;
|
||||||
|
if ((fd = open(GPIO_EXPORT, O_WRONLY)) < 0)
|
||||||
|
PRINTERRANDRET("Failed to open export", "s", GPIO_EXPORT);
|
||||||
|
if ((nbytes = snprintf(buffer, MAX_PATHLEN, "%i", pinno)) <= 0)
|
||||||
|
PRINTERRANDRET("Couldn't format pin number as string", "i", pinno);
|
||||||
|
if (write(fd, buffer, nbytes) != nbytes && errno != EBUSY)
|
||||||
|
PRINTERRANDRET("Couldn't write pin number to the exporter", "i", pinno);
|
||||||
|
if (close(fd) != 0)
|
||||||
|
PRINTERRANDRET("Couldn't close exporter", "i", pinno);
|
||||||
|
return pinno;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t setPinDirection(signed int pinno, char* value)
|
||||||
|
{
|
||||||
|
if (chdir(GPIO_PREFIX) != 0)
|
||||||
|
PRINTERRANDRET("Failed to change directory to", "s", GPIO_PREFIX);
|
||||||
|
char buffer[MAX_PATHLEN];
|
||||||
|
int fd;
|
||||||
|
ssize_t nbytes;
|
||||||
|
if ((nbytes = snprintf(buffer, MAX_PATHLEN, "gpio%i/direction", pinno)) <= 0)
|
||||||
|
PRINTERRANDRET("Couldn't format pin path as string", "i", pinno);
|
||||||
|
if ((fd = open(buffer, O_WRONLY)) < 0)
|
||||||
|
PRINTERRANDRET("Failed to open pin path.", "s", GPIO_EXPORT);
|
||||||
|
if (write(fd, value, strlen(value)) != nbytes && errno != EBUSY)
|
||||||
|
PRINTERRANDRET("Couldn't write pin direction", "i", pinno);
|
||||||
|
if (close(fd) != 0)
|
||||||
|
PRINTERRANDRET("Couldn't close pin direction file", "i", pinno);
|
||||||
|
return pinno;
|
||||||
|
}
|
||||||
|
ssize_t setPinValue(signed int pinno, int value)
|
||||||
|
{
|
||||||
|
if (chdir(GPIO_PREFIX) != 0)
|
||||||
|
PRINTERRANDRET("Failed to change directory to", "s", GPIO_PREFIX);
|
||||||
|
char buffer[MAX_PATHLEN];
|
||||||
|
int fd;
|
||||||
|
ssize_t nbytes;
|
||||||
|
if ((nbytes = snprintf(buffer, MAX_PATHLEN, "gpio%i/value", pinno)) <= 0)
|
||||||
|
PRINTERRANDRET("Couldn't format pin path as string", "i", pinno);
|
||||||
|
if ((fd = open(buffer, O_WRONLY)) < 0)
|
||||||
|
PRINTERRANDRET("Failed to open pin path.", "s", GPIO_EXPORT);
|
||||||
|
if ((nbytes = snprintf(buffer, MAX_PATHLEN, "%i", value)) <= 0)
|
||||||
|
PRINTERRANDRET("Couldn't format pin value as string", "i", value);
|
||||||
|
if (write(fd, buffer, nbytes) != nbytes && errno != EBUSY)
|
||||||
|
PRINTERRANDRET("Couldn't write pin value", "i", pinno);
|
||||||
|
if (close(fd) != 0)
|
||||||
|
PRINTERRANDRET("Couldn't close pin value file", "i", pinno);
|
||||||
|
return pinno;
|
||||||
|
}
|
58
src/main.py
Normal file
58
src/main.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import time
|
||||||
|
import sys
|
||||||
|
import errno
|
||||||
|
|
||||||
|
GPIO_IFACE_MISSING = -1
|
||||||
|
GPIO_PIN_EXP_FAIL = -2
|
||||||
|
GPIO_DIR_CONT_FAIL = -3
|
||||||
|
GPIO_SWITCH_FAIL = -4
|
||||||
|
GPIO_PIN_UNX_NF = -5
|
||||||
|
GPIO_PIN_UNX_FAIL = -6
|
||||||
|
|
||||||
|
PINLISTMISS = -1
|
||||||
|
PINLISTTOKFAIL = -2
|
||||||
|
|
||||||
|
def preparePin(pinno):
|
||||||
|
try: x = open('/sys/class/gpio/export', 'w')
|
||||||
|
except:
|
||||||
|
return GPIO_IFACE_MISSING
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
x.write(f'{pinno}')
|
||||||
|
x.close()
|
||||||
|
except OSError as e:
|
||||||
|
if (e.errno != errno.EBUSY): # Busy devices are already exported
|
||||||
|
return GPIO_PIN_EXP_FAIL
|
||||||
|
return
|
||||||
|
for i in range(0,5):
|
||||||
|
try: g = open(f'/sys/class/gpio/gpio{pinno}/direction', 'w')
|
||||||
|
except:
|
||||||
|
if (i == 4):
|
||||||
|
return GPIO_DIR_CONT_FAIL
|
||||||
|
else: time.sleep(1)
|
||||||
|
else:
|
||||||
|
try: g.write('out')
|
||||||
|
except:
|
||||||
|
g.close()
|
||||||
|
return GPIO_SWITCH_FAIL
|
||||||
|
else:
|
||||||
|
g.close()
|
||||||
|
break
|
||||||
|
|
||||||
|
def closePin(pinno):
|
||||||
|
try: x = open('/sys/class/gpio/unexport', 'w')
|
||||||
|
except: return GPIO_PIN_UNX_NF
|
||||||
|
else:
|
||||||
|
try: x.write(pinno)
|
||||||
|
except: return GPIO_PIN_UNX_FAIL
|
||||||
|
finally: x.close()
|
||||||
|
|
||||||
|
try: preparePin(sys.argv[1])
|
||||||
|
except GPIO_SWITCH_FAIL: print(f'GPIO Pin direction couldn\'t be switched to out. {sys.argv[1]}')
|
||||||
|
except GPIO_DIR_CONT_FAIL: print(f'GPIO Pin control couldn\'t be opened. {sys.argv[1]}')
|
||||||
|
except GPIO_PIN_EXP_FAIL: print(f'GPIO Pin couldn\'t be exported. P: {sys.argv[1]}')
|
||||||
|
except GPIO_IFACE_MISSING: print(f'GPIO Export interface couldn\'t be opened. {sys.argv[1]}')
|
||||||
|
|
||||||
|
with open(f'/sys/class/gpio/gpio{sys.argv[1]}/value', 'w') as x:
|
||||||
|
if (len(sys.argv) == 3): x.write(sys.argv[2])
|
||||||
|
else: x.write('0')
|
Loading…
Reference in New Issue
Block a user