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