pin_control: fib lib gitignore
This commit is contained in:
parent
3da3cd544b
commit
e841e69b47
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -87,7 +87,6 @@ dist/
|
||||||
downloads/
|
downloads/
|
||||||
eggs/
|
eggs/
|
||||||
.eggs/
|
.eggs/
|
||||||
lib/
|
|
||||||
lib64/
|
lib64/
|
||||||
parts/
|
parts/
|
||||||
sdist/
|
sdist/
|
||||||
|
|
156
pin_control/lib/pin_control.c
Normal file
156
pin_control/lib/pin_control.c
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <gpiod.h>
|
||||||
|
|
||||||
|
#include <pin_control.h>
|
||||||
|
|
||||||
|
// https://docs.kernel.org/driver-api/gpio/using-gpio.html
|
||||||
|
|
||||||
|
#define GPIO_CHIP "gpiochip0"
|
||||||
|
|
||||||
|
struct gpiod_chip *chip;
|
||||||
|
|
||||||
|
int init_gpio() {
|
||||||
|
cleanup_gpio();
|
||||||
|
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_chip_open_by_name.html
|
||||||
|
chip = gpiod_chip_open_by_name(GPIO_CHIP);
|
||||||
|
if (!chip) {
|
||||||
|
perror("[pin_control] gpiod_chip_open_by_name(\"" GPIO_CHIP "\")");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_gpio() {
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_chip_close.html
|
||||||
|
if (chip) {
|
||||||
|
gpiod_chip_close(chip);
|
||||||
|
chip = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_pin_state(int pin, int state) {
|
||||||
|
int ret = -1;
|
||||||
|
if (!chip) {
|
||||||
|
perror("[pin_control] attempt to set GPIO line for invalid chip");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_chip_get_line.html
|
||||||
|
struct gpiod_line *line = gpiod_chip_get_line(chip, pin); // this may need an offset
|
||||||
|
if (!line) {
|
||||||
|
perror("[pin_control] gpiod_chip_get_line()");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_request_output.html
|
||||||
|
if (gpiod_line_request_output(line, "house-leds", state) < 0) {
|
||||||
|
perror("[pin_control] gpiod_line_request_output()");
|
||||||
|
goto exit_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_set_value.html
|
||||||
|
if (gpiod_line_set_value(line, state) < 0) {
|
||||||
|
perror("[pin_control] gpiod_line_set_value()");
|
||||||
|
goto exit_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
exit_line:
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_release.html
|
||||||
|
gpiod_line_release(line);
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int turn_on_pin(int pin) {
|
||||||
|
return set_pin_state(pin, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int turn_off_pin(int pin) {
|
||||||
|
return set_pin_state(pin, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int probe_pin(int pin) {
|
||||||
|
int ret = -1;
|
||||||
|
if (!chip) {
|
||||||
|
perror("[pin_control] attempt to read GPIO line for invalid chip");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gpiod_line *line = gpiod_chip_get_line(chip, pin);
|
||||||
|
if (!line) {
|
||||||
|
perror("[pin_control] gpiod_chip_get_line()");
|
||||||
|
goto exit;
|
||||||
|
} else if (gpiod_line_request_input(line, "house-leds") < 0) {
|
||||||
|
perror("[pin_control] gpiod_line_request_input()");
|
||||||
|
goto exit_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpiod_line_get_value(line);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("[pin_control] gpiod_line_get_value()");
|
||||||
|
goto exit_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_line:
|
||||||
|
// https://libgpiod-dlang.dpldocs.info/gpiod.gpiod_line_release.html
|
||||||
|
gpiod_line_release(line);
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int turn_on_all_pins() {
|
||||||
|
for (int pin = 0; pin <= 5; pin++)
|
||||||
|
if (turn_on_pin(pin) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int turn_off_all_pins() {
|
||||||
|
for (int pin = 0; pin <= 5; pin++) {
|
||||||
|
if (turn_off_pin(pin) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int button_presssed(int event, unsigned int pin, const struct timespec * timestamp, void *data) {
|
||||||
|
(void) event;
|
||||||
|
(void) timestamp;
|
||||||
|
* (int *) data = (int) pin;
|
||||||
|
return GPIOD_CTXLESS_EVENT_POLL_RET_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wait_for_button_press(const unsigned pins[static 5]) {
|
||||||
|
// https://www.lane-fu.com/linuxmirror/libgpiod/doc/html/group______high__level____.html#ga3ac28eb59bbd31b8b2298f76047d377d
|
||||||
|
|
||||||
|
int pressed_pin = -1;
|
||||||
|
|
||||||
|
struct timespec ts = {
|
||||||
|
.tv_sec = 3600,
|
||||||
|
.tv_nsec = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = gpiod_ctxless_event_monitor_multiple(
|
||||||
|
GPIO_CHIP,
|
||||||
|
GPIOD_CTXLESS_EVENT_FALLING_EDGE,
|
||||||
|
pins,
|
||||||
|
5,
|
||||||
|
true,
|
||||||
|
"house-leds",
|
||||||
|
&ts, // big timout
|
||||||
|
NULL,
|
||||||
|
button_presssed,
|
||||||
|
&pressed_pin);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("[pin_control] gpiod_ctxless_event_monitor_multiple()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pressed_pin;
|
||||||
|
}
|
226
pin_control/lib/v4l2.c
Normal file
226
pin_control/lib/v4l2.c
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
// Derivado de https://gist.github.com/jayrambhia/5866483
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
#include <pin_control.h>
|
||||||
|
|
||||||
|
static int xioctl(int fd, int request, void *arg)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
do r = ioctl (fd, request, arg);
|
||||||
|
while (-1 == r && EINTR == errno);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int print_caps(int fd)
|
||||||
|
{
|
||||||
|
struct v4l2_capability caps = {};
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps))
|
||||||
|
{
|
||||||
|
perror("Querying Capabilities");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf( "Driver Caps:\n"
|
||||||
|
" Driver: \"%s\"\n"
|
||||||
|
" Card: \"%s\"\n"
|
||||||
|
" Bus: \"%s\"\n"
|
||||||
|
" Version: %d.%d\n"
|
||||||
|
" Capabilities: %08x\n",
|
||||||
|
caps.driver,
|
||||||
|
caps.card,
|
||||||
|
caps.bus_info,
|
||||||
|
(caps.version>>16)&&0xff,
|
||||||
|
(caps.version>>24)&&0xff,
|
||||||
|
caps.capabilities);
|
||||||
|
|
||||||
|
|
||||||
|
struct v4l2_cropcap cropcap = {0};
|
||||||
|
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap))
|
||||||
|
{
|
||||||
|
perror("Querying Cropping Capabilities");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf( "Camera Cropping:\n"
|
||||||
|
" Bounds: %dx%d+%d+%d\n"
|
||||||
|
" Default: %dx%d+%d+%d\n"
|
||||||
|
" Aspect: %d/%d\n",
|
||||||
|
cropcap.bounds.width, cropcap.bounds.height, cropcap.bounds.left, cropcap.bounds.top,
|
||||||
|
cropcap.defrect.width, cropcap.defrect.height, cropcap.defrect.left, cropcap.defrect.top,
|
||||||
|
cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator);
|
||||||
|
|
||||||
|
struct v4l2_fmtdesc fmtdesc = {0};
|
||||||
|
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
char fourcc[5] = {0};
|
||||||
|
char c, e;
|
||||||
|
printf(" FMT : CE Desc\n--------------------\n");
|
||||||
|
while (0 == xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||||
|
{
|
||||||
|
strncpy(fourcc, (char *)&fmtdesc.pixelformat, 4);
|
||||||
|
c = fmtdesc.flags & 1? 'C' : ' ';
|
||||||
|
e = fmtdesc.flags & 2? 'E' : ' ';
|
||||||
|
printf(" %s: %c%c %s\n", fourcc, c, e, fmtdesc.description);
|
||||||
|
fmtdesc.index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct v4l2_format fmt = {0};
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = 640;
|
||||||
|
fmt.fmt.pix.height = 480;
|
||||||
|
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
|
||||||
|
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
{
|
||||||
|
perror("Setting Pixel Format");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
|
||||||
|
printf( "Selected Camera Mode:\n"
|
||||||
|
" Width: %d\n"
|
||||||
|
" Height: %d\n"
|
||||||
|
" PixFmt: %s\n"
|
||||||
|
" Field: %d\n",
|
||||||
|
fmt.fmt.pix.width,
|
||||||
|
fmt.fmt.pix.height,
|
||||||
|
fourcc,
|
||||||
|
fmt.fmt.pix.field);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_mmap(int fd, uint8_t **buffer, size_t *buffer_len)
|
||||||
|
{
|
||||||
|
struct v4l2_requestbuffers req = {0};
|
||||||
|
req.count = 1;
|
||||||
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req))
|
||||||
|
{
|
||||||
|
perror("Requesting Buffer");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct v4l2_buffer buf = {0};
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = 0;
|
||||||
|
if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Querying Buffer");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buffer = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
|
||||||
|
*buffer_len = buf.length;
|
||||||
|
|
||||||
|
printf("Length: %d\nAddress: %p\n", buf.length, *buffer);
|
||||||
|
printf("Image Length: %d\n", buf.bytesused);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int capture_frame(int fd)
|
||||||
|
{
|
||||||
|
struct v4l2_buffer buf = {0};
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = 0;
|
||||||
|
if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Query Buffer");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
|
||||||
|
{
|
||||||
|
perror("Start Capture");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
struct timeval tv = {0};
|
||||||
|
tv.tv_sec = 2;
|
||||||
|
int r = select(fd+1, &fds, NULL, NULL, &tv);
|
||||||
|
if(-1 == r)
|
||||||
|
{
|
||||||
|
perror("Waiting for Frame");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Retrieving Frame");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_image(const char *out, uint8_t *buffer, size_t buffer_len)
|
||||||
|
{
|
||||||
|
printf ("saving image\n");
|
||||||
|
|
||||||
|
int fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "open(\"%s\"): %m\n", out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
while (buffer_len) {
|
||||||
|
ssize_t written = write(fd, buffer, buffer_len);
|
||||||
|
if (written < 0) {
|
||||||
|
perror("write()");
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += written;
|
||||||
|
buffer_len -= written;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int capture_image(const char *out)
|
||||||
|
{
|
||||||
|
int fd = open("/dev/video0", O_RDWR);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("Opening video device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
size_t buffer_len;
|
||||||
|
|
||||||
|
int ret = print_caps(fd)
|
||||||
|
|| init_mmap(fd, &buffer, &buffer_len)
|
||||||
|
|| capture_frame(fd)
|
||||||
|
|| save_image(out, buffer, buffer_len);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
if (buffer)
|
||||||
|
munmap(buffer, buffer_len);
|
||||||
|
|
||||||
|
return ret ? -1 : 0;
|
||||||
|
}
|
Loading…
Reference in a new issue