Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package spi-tools for openSUSE:Factory checked in at 2026-08-01 19:57:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/spi-tools (Old) and /work/SRC/openSUSE:Factory/.spi-tools.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "spi-tools" Sat Aug 1 19:57:00 2026 rev:7 rq:1369015 version:1.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/spi-tools/spi-tools.changes 2023-01-03 15:06:11.934801764 +0100 +++ /work/SRC/openSUSE:Factory/.spi-tools.new.16738/spi-tools.changes 2026-08-01 19:57:02.075152981 +0200 @@ -1,0 +2,20 @@ +Tue Jul 21 08:44:53 UTC 2026 - Frantisek Simorda <[email protected]> + +- update to 1.1.0: + * [FIX] Parameter reading and parsing in `spi-pipe`. + * [FIX] parameter reading and parsing in `spi-config`. + * Update copyright dates. + * [FIX] wrong declaration of `-r` option in `spi-pipe`. + * [FIX] Some small errors in `spi-tools` detected by an AI. + * [FIX] Typo in `spi-config` man page. + * Merge pull request #33 from parsamajidi21/master + * README: Example of building binaries for Android devices + * add sample Android.bp to build within an Android tree + * [DOC] Working on `README.md`. + * [DEV] Add a `CMakeLists.txt` file for cmake build system. + * [DEV] Only write new configuration in `spi-pipe` if something changed. + * Merge pull request #32 from mjsir911/master + * Allow CFLAGS to be passed to ./configure + * [FIX] Typo in `spi-config` man page. + +------------------------------------------------------------------- Old: ---- spi-tools-1.0.2.tar.gz New: ---- spi-tools-1.1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ spi-tools.spec ++++++ --- /var/tmp/diff_new_pack.FiGAL4/_old 2026-08-01 19:57:02.683173678 +0200 +++ /var/tmp/diff_new_pack.FiGAL4/_new 2026-08-01 19:57:02.687173815 +0200 @@ -1,7 +1,7 @@ # # spec file for package spi-tools # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: spi-tools -Version: 1.0.2 +Version: 1.1.0 Release: 0 Summary: A set of SPI tools for Linux License: GPL-2.0-or-later ++++++ spi-tools-1.0.2.tar.gz -> spi-tools-1.1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/Android.bp new/spi-tools-1.1.0/Android.bp --- old/spi-tools-1.0.2/Android.bp 1970-01-01 01:00:00.000000000 +0100 +++ new/spi-tools-1.1.0/Android.bp 2026-06-08 18:09:54.000000000 +0200 @@ -0,0 +1,96 @@ +# Android.bp for the spi-tools project. +# +# Copyright 2025 Parsa Majidi ([email protected]) +# +# License GPLv3+: This is free software: you are free to change and +# redistribute it.There is NO WARRANTY, to the extent permitted by law. + +// spi-tools + + +genrule { + name: "generate_config_h", + srcs: [ + "src/config.h.cmake.in" + ], + out: [ + "config.h" + ], + cmd: "cp $(in) $(out)", +} + +cc_library { + name: "spi-tools", + defaults: [ + "spi_defaults", + ], + generated_headers: [ + "generate_config_h", + ], + export_generated_headers: [ + "generate_config_h", + ], +} + +cc_defaults { + name: "spi_defaults", + device_specific: true, + cpp_std: "gnu++17", + cflags: [ + // You may want to edit this with the version from configure.ac of + // the release you are using. + "-DGPIOD_VERSION_STR=\"unstable\"", + ], + cppflags: [ + // Google C++ style is to not use exceptions, but this library does + // use them. + "-fexceptions", + ], + // Google C++ style is to not use runtime type information, but this + // library does use it. + rtti: true, +} + +// +// spi tools +// + +phony { + name: "spi_tools", + required: [ + "spi-config", + "spi-pipe", + ], +} + +cc_binary { + name: "spi-config", + defaults: [ + "spi_defaults", + "spi_tools_defaults", + ], + srcs: [ + "src/spi-config.c", + ], +} + +cc_binary { + name: "spi-pipe", + defaults: [ + "spi_defaults", + "spi_tools_defaults", + ], + srcs: [ + "src/spi-pipe.c", + ], +} + +cc_defaults { + name: "spi_tools_defaults", + srcs: [ + "src/spi-tools.c", + ], + shared_libs: [ + "spi-tools", + ], +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/CMakeLists.txt new/spi-tools-1.1.0/CMakeLists.txt --- old/spi-tools-1.0.2/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/spi-tools-1.1.0/CMakeLists.txt 2026-06-08 18:09:54.000000000 +0200 @@ -0,0 +1,20 @@ +####################################################################### +# CMakeLists.txt for the spi-tools project. +# +# Copyright 2024 Christophe BLAESS (https://www.blaess.fr/christophe). +# +# License GPLv3+: This is free software: you are free to change and +# redistribute it.There is NO WARRANTY, to the extent permitted by law. +# +####################################################################### + +cmake_minimum_required(VERSION 3.0) +project(SPI_TOOLS VERSION 1.0.2) + +configure_file(src/config.h.cmake.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config.h) + +add_executable(spi-config src/spi-config.c src/spi-tools.c src/spi-tools.h) +add_executable(spi-pipe src/spi-pipe.c src/spi-tools.c src/spi-tools.h) + +install(TARGETS spi-config DESTINATION /usr/bin) +install(TARGETS spi-pipe DESTINATION /usr/bin) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/README.md new/spi-tools-1.1.0/README.md --- old/spi-tools-1.0.2/README.md 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/README.md 2026-06-08 18:09:54.000000000 +0200 @@ -2,7 +2,7 @@ This package contains some simple command line tools to help using Linux spidev devices. -Version 1.0.2 +Version 1.1.0 ## Content @@ -25,6 +25,10 @@ ## Installation +There's two ways to install `spi-tools`: using Autotools or using Cmake. + +### Autotools + First, get the latest version on https://github.com/cpb-/spi-tools.git. Then enter the directory and execute: @@ -43,6 +47,8 @@ You can use `make uninstall` (with `sudo`) to remove the installed files. +### Cmake + ## Usage ### spi-config usage @@ -55,11 +61,15 @@ * `-l --lsb={0,1}` LSB first (1) or MSB first (0). * `-b --bits=[7...]` bits per word. * `-s --speed=<int>` set the speed in Hz. -* `-r --spirdy={0,1}` set the SPI_READY spi mode flag. +* `-r --spirdy={0,1}` set the SPI_READY spi mode flag. * `-w --wait` block, keeping the file descriptor open. * `-h --help` help screen. * `-v --version` display the version number. +* Some examples using a build folder under the source tree root: + +Android : `cmake -DCMAKE_TOOLCHAIN_FILE=~/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=android-21 -DANDROID_ABI=armeabi-v7a .. && make` + #### Read the current configuration ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/configure.ac new/spi-tools-1.1.0/configure.ac --- old/spi-tools-1.0.2/configure.ac 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/configure.ac 2026-06-08 18:09:54.000000000 +0200 @@ -61,13 +61,13 @@ if test x"$debugit" = x"yes"; then AC_DEFINE([DEBUG],[],[Debug Mode]) - AM_CFLAGS="-g -Wall -Werror -Wno-uninitialized -O0" - AM_CXXFLAGS="-g -Wall -Werror -Wno-uninitialized -O0" + AM_CFLAGS="$CFLAGS -g -Wall -Werror -Wno-uninitialized -O0" + AM_CXXFLAGS="$CXXFLAGS -g -Wall -Werror -Wno-uninitialized -O0" AC_MSG_NOTICE([Debug Mode on.]) else AC_DEFINE([NDEBUG],[],[No-debug Mode]) - AM_CFLAGS="-O0 $AM_CFLAGS" - AM_CXXFLAGS="-O0 $AM_CXXFLAGS" + AM_CFLAGS="-O0 $AM_CFLAGS $CFLAGS" + AM_CXXFLAGS="-O0 $AM_CXXFLAGS $CXXFLAGS" AC_MSG_NOTICE([Debug Mode off.]) fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/man/spi-config.1 new/spi-tools-1.1.0/man/spi-config.1 --- old/spi-tools-1.0.2/man/spi-config.1 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/man/spi-config.1 2026-06-08 18:09:54.000000000 +0200 @@ -29,7 +29,7 @@ \fB\-r\fR, \fB\-\-spirdy\fR=\fI{0,1}\fR set the SPI READY mode flag. .TP -\fB\-s\fR, \fB\-\-wait +\fB\-w\fR, \fB\-\-wait block, keeping the file descriptor open. See \fBWAIT OPTION\fR below. .TP \fB\-h\fR, \fB\-\-help\fR @@ -41,16 +41,16 @@ .SS "SPI MODES" .TP mode 0 -low iddle level, sample on leading edge. +low idle level, sample on leading edge. .TP mode 1 -low iddle level, sample on trailing edge. +low idle level, sample on trailing edge. .TP mode 2 -high iddle level, sample on leading edge. +high idle level, sample on leading edge. .TP mode 3 -high iddle level, sample on trailing edge. +high idle level, sample on trailing edge. .SS "WAIT OPTION" On some platforms, the speed is reset to a default value when the file descriptor is closed. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/src/config.h.cmake.in new/spi-tools-1.1.0/src/config.h.cmake.in --- old/spi-tools-1.0.2/src/config.h.cmake.in 1970-01-01 01:00:00.000000000 +0100 +++ new/spi-tools-1.1.0/src/config.h.cmake.in 2026-06-08 18:09:54.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#define VERSION "@SPI_TOOLS_VERSION_MAJOR@.@SPI_TOOLS_VERSION_MINOR@.@SPI_TOOLS_VERSION_PATCH@" + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/src/spi-config.c new/spi-tools-1.1.0/src/spi-config.c --- old/spi-tools-1.0.2/src/spi-config.c 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/src/spi-config.c 2026-06-08 18:09:54.000000000 +0200 @@ -1,7 +1,7 @@ /* * spidev configuration tool. * - * (c) 2014 Christophe BLAESS <[email protected]> + * (c) 2014-2026 Christophe BLAESS <[email protected]> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,40 +18,36 @@ * */ +// ---------------------- System headers. + #include <fcntl.h> #include <getopt.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include "config.h" + +// ---------------------- Project headers. + +#include "config.h" #include "spi-tools.h" -static char *project = "spi-config"; +// ---------------------- Private macros declarations. +// ---------------------- Private types and structures. -static void display_usage(const char * name) -{ - fprintf(stderr, "usage: %s options...\n", name); - fprintf(stderr, " options:\n"); - fprintf(stderr, " -d --device=<dev> use the given spi-dev character device.\n"); - fprintf(stderr, " -q --query print the current configuration.\n"); - fprintf(stderr, " -m --mode=[0-3] use the selected spi mode:\n"); - fprintf(stderr, " 0: low idle level, sample on leading edge,\n"); - fprintf(stderr, " 1: low idle level, sample on trailing edge,\n"); - fprintf(stderr, " 2: high idle level, sample on leading edge,\n"); - fprintf(stderr, " 3: high idle level, sample on trailing edge.\n"); - fprintf(stderr, " -l --lsb={0,1} LSB first (1) or MSB first (0).\n"); - fprintf(stderr, " -b --bits=[7...] bits per word.\n"); - fprintf(stderr, " -s --speed=<int> set the speed in Hz.\n"); - fprintf(stderr, " -r --spirdy={0,1} consider SPI_RDY signal (1) or ignore it (0).\n"); - fprintf(stderr, " -w --wait block keeping the file descriptor open to avoid speed reset.\n"); - fprintf(stderr, " -h --help this screen.\n"); - fprintf(stderr, " -v --version display the version number.\n"); +// ---------------------- Private method declarations. -} +static void display_usage(const char * name); + + +// ---------------------- Private variables. +static const char project[] = "spi-config"; + + +// ---------------------- Public methods int main (int argc, char * argv[]) { @@ -79,6 +75,7 @@ int val; int query_only = 0; int wait = 0; + int changed = 0; new_config.spi_mode = -1; new_config.lsb_first = -1; @@ -96,7 +93,7 @@ exit(EXIT_SUCCESS); case 'v': fprintf(stderr, "%s - %s\n", project, VERSION); - fprintf(stderr, "Copyright (c) 2014-2021 Christophe Blaess. (license GPLv2)\n"); + fprintf(stderr, "Copyright (c) 2014-2026 Christophe Blaess. (license GPLv2)\n"); fprintf(stderr, "This is free software. You are free to change and redistribute it.\n"); fprintf(stderr, "There is NO WARRANTY, to the extent permitted by law.\n"); exit(EXIT_SUCCESS); @@ -109,11 +106,13 @@ case 'm': if (Parse_spi_mode(optarg, &new_config) != 0) exit(EXIT_FAILURE); + changed = 1; break; case 'l': if (Parse_lsb_first(optarg, &new_config) != 0) exit(EXIT_FAILURE); + changed = 1; break; case 'b': @@ -122,17 +121,20 @@ fprintf(stderr, "%s: wrong bits per word value [7...]\n", argv[0]); exit(EXIT_FAILURE); } + changed = 1; new_config.bits_per_word = val; break; case 's': if (Parse_spi_speed(optarg, &new_config) != 0) exit(EXIT_FAILURE); + changed = 1; break; case 'r': if (Parse_spi_ready(optarg, &new_config) != 0) exit(EXIT_FAILURE); + changed = 1; break; default: @@ -141,6 +143,16 @@ } } + if (optind < argc) { + fprintf(stderr, "%s: unexpected argument: %s\n", argv[0], argv[optind]); + exit(EXIT_FAILURE); + } + + if (query_only && changed) { + fprintf(stderr, "%s: `-q` cannot be used with configuration options.\n", argv[0]); + exit(EXIT_FAILURE); + } + if (device == NULL) { fprintf(stderr, "%s: no device specified (use option -h for help).\n", argv[0]); exit(EXIT_FAILURE); @@ -187,3 +199,28 @@ return EXIT_SUCCESS; } + +// ---------------------- Private methods + +static void display_usage(const char * name) +{ + fprintf(stderr, "usage: %s options...\n", name); + fprintf(stderr, " options:\n"); + fprintf(stderr, " -d --device=<dev> use the given spi-dev character device.\n"); + fprintf(stderr, " -q --query print the current configuration.\n"); + fprintf(stderr, " -m --mode=[0-3] use the selected spi mode:\n"); + fprintf(stderr, " 0: low idle level, sample on leading edge,\n"); + fprintf(stderr, " 1: low idle level, sample on trailing edge,\n"); + fprintf(stderr, " 2: high idle level, sample on leading edge,\n"); + fprintf(stderr, " 3: high idle level, sample on trailing edge.\n"); + fprintf(stderr, " -l --lsb={0,1} LSB first (1) or MSB first (0).\n"); + fprintf(stderr, " -b --bits=[7...] bits per word.\n"); + fprintf(stderr, " -s --speed=<int> set the speed in Hz.\n"); + fprintf(stderr, " -r --spirdy={0,1} consider SPI_RDY signal (1) or ignore it (0).\n"); + fprintf(stderr, " -w --wait block keeping the file descriptor open to avoid speed reset.\n"); + fprintf(stderr, " -h --help this screen.\n"); + fprintf(stderr, " -v --version display the version number.\n"); + +} + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/src/spi-pipe.c new/spi-tools-1.1.0/src/spi-pipe.c --- old/spi-tools-1.0.2/src/spi-pipe.c 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/src/spi-pipe.c 2026-06-08 18:09:54.000000000 +0200 @@ -1,7 +1,7 @@ /* * spidev data transfer tool. * - * (c) 2014-2021 Christophe BLAESS <[email protected]> + * (c) 2014-2026 Christophe BLAESS <[email protected]> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,6 +18,9 @@ * */ +// ---------------------- System headers. + +#include <errno.h> #include <fcntl.h> #include <getopt.h> #include <stdint.h> @@ -25,32 +28,30 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> + + +// ---------------------- Project headers. + #include "config.h" #include "spi-tools.h" -static char *project = "spi-pipe"; -static void display_usage(const char *name) -{ - fprintf(stderr, "usage: %s options...\n", name); - fprintf(stderr, " options:\n"); - fprintf(stderr, " -d --device=<dev> Use the given spi-dev character device.\n"); - fprintf(stderr, " -m --mode=[0-3] Use the selected spi mode:\n"); - fprintf(stderr, " 0: low idle level, sample on leading edge,\n"); - fprintf(stderr, " 1: low idle level, sample on trailing edge,\n"); - fprintf(stderr, " 2: high idle level, sample on leading edge,\n"); - fprintf(stderr, " 3: high idle level, sample on trailing edge.\n"); - fprintf(stderr, " -s --speed=<speed> Maximum SPI clock rate (in Hz).\n"); - fprintf(stderr, " -l --lsb={0,1} LSB first (1) or MSB first (0).\n"); - fprintf(stderr, " -B --bits=[7...] Bits per word.\n"); - fprintf(stderr, " -b --blocksize=<int> transfer block size in byte.\n"); - fprintf(stderr, " -n --number=<int> number of blocks to transfer (-1 = infinite).\n"); - fprintf(stderr, " -h --help this screen.\n"); - fprintf(stderr, " -v --version display the version number.\n"); -} +// ---------------------- Private macros declarations. + +// ---------------------- Private types and structures. + +// ---------------------- Private method declarations. + +static void display_usage(const char *name); +static int full_write(int fd, const void *buffer, size_t length); + + +// ---------------------- Private variables. +static const char project[] = "spi-pipe"; +// ---------------------- Public methods int main (int argc, char *argv[]) { @@ -65,6 +66,7 @@ {"lsb", required_argument, NULL, 'l' }, {"mode", required_argument, NULL, 'm' }, {"bits", required_argument, NULL, 'B' }, + {"ready", required_argument, NULL, 'r' }, {"help", no_argument, NULL, 'h' }, {"version", no_argument, NULL, 'v' }, {0, 0, 0, 0 } @@ -77,10 +79,10 @@ spi_config_t prev_config; spi_config_t new_config; - int block_size = 1; - int blocks_count = -1; - int offset = 0; - int nb = 0; + size_t block_size = 1; + int blocks_count = -1; + size_t offset = 0; + size_t nb = 0; new_config.spi_mode = -1; new_config.lsb_first = -1; @@ -89,7 +91,7 @@ new_config.spi_ready = -1; - while ((opt = getopt_long(argc, argv, "d:s:b:l:m:n:B:rhv", options, &long_index)) >= 0) { + while ((opt = getopt_long(argc, argv, "d:s:b:l:m:n:B:r:hv", options, &long_index)) >= 0) { switch(opt) { case 'h': display_usage(argv[0]); @@ -97,7 +99,7 @@ case 'v': fprintf(stderr, "%s - %s\n", project, VERSION); - fprintf(stderr, "Copyright (c) 2014-2021 Christophe Blaess. (license GPLv2)\n"); + fprintf(stderr, "Copyright (c) 2014-2026 Christophe Blaess. (license GPLv2)\n"); fprintf(stderr, "This is free software. You are free to change and redistribute it.\n"); fprintf(stderr, "There is NO WARRANTY, to the extent permitted by law.\n"); exit(EXIT_SUCCESS); @@ -132,11 +134,8 @@ break; case 'b': - if ((sscanf(optarg, "%d", &block_size) != 1) - || (block_size <= 0)) { - fprintf(stderr, "%s: wrong blocksize\n", argv[0]); + if (Parse_spi_bits_per_word(optarg, &new_config) != 0) exit(EXIT_FAILURE); - } break; case 'n': @@ -155,20 +154,20 @@ if (((rx_buffer = malloc(block_size)) == NULL) || ((tx_buffer = malloc(block_size)) == NULL)) { - fprintf(stderr, "%s: not enough memory to allocate two %d bytes buffers\n", + fprintf(stderr, "%s: not enough memory to allocate two %ld bytes buffers\n", argv[0], block_size); exit(EXIT_FAILURE); } - memset(rx_buffer, 0, block_size); - memset(tx_buffer, 0, block_size); - if (device == NULL) { fprintf(stderr, "%s: no device specified (use option -h for help).\n", argv[0]); exit(EXIT_FAILURE); } - fd = open(device, O_RDONLY); + memset(rx_buffer, 0, block_size); + memset(tx_buffer, 0, block_size); + + fd = open(device, O_RDWR); if (fd < 0) { perror(device); exit(EXIT_FAILURE); @@ -186,14 +185,15 @@ if (new_config.bits_per_word == -1) new_config.bits_per_word = prev_config.bits_per_word; - if (new_config.spi_speed == -1) + if (new_config.spi_speed == 0) new_config.spi_speed = prev_config.spi_speed; if (new_config.spi_ready == -1) new_config.spi_ready = prev_config.spi_ready; - if (Write_spi_configuration(fd, &new_config) != 0) - exit(EXIT_FAILURE); + if (memcmp(&prev_config, &new_config, sizeof(spi_config_t)) != 0) + if (Write_spi_configuration(fd, &new_config) != 0) + exit(EXIT_FAILURE); while ((blocks_count > 0) || (blocks_count == -1)) { for (offset = 0; offset < block_size; offset += nb) { @@ -208,8 +208,10 @@ perror("SPI_IOC_MESSAGE"); break; } - if (write(STDOUT_FILENO, rx_buffer, offset) <= 0) + if (full_write(STDOUT_FILENO, rx_buffer, offset) < 0) { + perror("write"); break; + } if (blocks_count > 0) blocks_count --; } @@ -217,11 +219,55 @@ free(rx_buffer); free(tx_buffer); - if (Write_spi_configuration(fd, &prev_config) != 0) - exit(EXIT_FAILURE); + if (memcmp(&prev_config, &new_config, sizeof(spi_config_t)) != 0) + if (Write_spi_configuration(fd, &prev_config) != 0) + exit(EXIT_FAILURE); if (blocks_count != 0) return EXIT_FAILURE; return EXIT_SUCCESS; } + + +// ---------------------- Private methods + +static void display_usage(const char *name) +{ + fprintf(stderr, "usage: %s options...\n", name); + fprintf(stderr, " options:\n"); + fprintf(stderr, " -d --device=<dev> Use the given spi-dev character device.\n"); + fprintf(stderr, " -m --mode=[0-3] Use the selected spi mode:\n"); + fprintf(stderr, " 0: low idle level, sample on leading edge,\n"); + fprintf(stderr, " 1: low idle level, sample on trailing edge,\n"); + fprintf(stderr, " 2: high idle level, sample on leading edge,\n"); + fprintf(stderr, " 3: high idle level, sample on trailing edge.\n"); + fprintf(stderr, " -s --speed=<speed> Maximum SPI clock rate (in Hz).\n"); + fprintf(stderr, " -l --lsb={0,1} LSB first (1) or MSB first (0).\n"); + fprintf(stderr, " -B --bits=[7...] Bits per word.\n"); + fprintf(stderr, " -r --ready={0,1} Spi ready mode.\n"); + fprintf(stderr, " -b --blocksize=<int> Transfer block size in byte.\n"); + fprintf(stderr, " -n --number=<int> Number of blocks to transfer (-1 = infinite).\n"); + fprintf(stderr, " -h --help This screen.\n"); + fprintf(stderr, " -v --version Display the version number.\n"); +} + + + +static int full_write(int fd, const void *buffer, size_t length) +{ + const uint8_t *ptr = buffer; + size_t done = 0; + + while (done < length) { + ssize_t n = write(fd, ptr + done, length - done); + if (n > 0) { + done += (size_t)n; + continue; + } + if ((n < 0) && (errno == EINTR)) + continue; + return -1; + } + return 0; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/src/spi-tools.c new/spi-tools-1.1.0/src/spi-tools.c --- old/spi-tools-1.0.2/src/spi-tools.c 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/src/spi-tools.c 2026-06-08 18:09:54.000000000 +0200 @@ -1,7 +1,7 @@ /* * spidev tools. * - * (c) 2014-2021 Christophe BLAESS <[email protected]> + * (c) 2014-2026 Christophe BLAESS <[email protected]> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,27 +19,50 @@ */ +// ---------------------- System headers. + +#include <errno.h> #include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <linux/spi/spidev.h> #include <sys/ioctl.h> + +// ---------------------- Project headers. + #include "spi-tools.h" +// ---------------------- Private macros declarations. + +// ---------------------- Private types and structures. + +// ---------------------- Private method declarations. + +static int parse_int_with_range(const char *s, int min, int max, int *value); + +// ---------------------- Private variables. + +// ---------------------- Public methods int Read_spi_configuration(int fd, spi_config_t *config) { uint8_t u8; uint32_t u32; + if (config == NULL) { + errno = EINVAL; + return -1; + } + if (ioctl(fd, SPI_IOC_RD_MODE, &u8) < 0) { perror("SPI_IOC_RD_MODE"); return -1; } config->spi_mode = u8 & 0x03; - config->spi_ready = ((config->spi_mode & SPI_READY) ? 1 : 0); + config->spi_ready = ((u8 & SPI_READY) ? 1 : 0); if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &u8) < 0) { perror("SPI_IOC_RD_LSB_FIRST"); @@ -64,35 +87,61 @@ -int Write_spi_configuration(int fd, spi_config_t *config) +int Write_spi_configuration(int fd, const spi_config_t *config) { uint8_t u8; uint32_t u32; - u8 = config->spi_mode; - if (config->spi_ready == 1) - u8 |= SPI_READY; - if (ioctl(fd, SPI_IOC_WR_MODE, &u8) < 0) { - perror("SPI_IOC_WR_MODE"); + if (config == NULL) { + errno = EINVAL; return -1; } - u8 = (config->lsb_first ? 1 : 0); - if (ioctl(fd, SPI_IOC_WR_LSB_FIRST, &u8) < 0) { - perror("SPI_IOC_WR_LSB_FIRST"); - return -1; - } - - u8 = config->bits_per_word; - if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &u8) < 0) { - perror("SPI_IOC_WR_BITS_PER_WORD"); - return -1; - } - - u32 = config->spi_speed; - if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &u32) < 0) { - perror("SPI_IOC_WR_MAX_SPEED_HZ"); - return -1; + if (config->spi_mode >= 0 || config->spi_ready >= 0) { + if (ioctl(fd, SPI_IOC_RD_MODE, &u8) < 0) { + perror("SPI_IOC_RD_MODE"); + return -1; + } + if (config->spi_mode >= 0) { + u8 &= ~0x03; + u8 |= config->spi_mode; + } + + if (config->spi_ready >= 0) { + if (config->spi_ready) + u8 |= SPI_READY; + else + u8 &= ~SPI_READY; + } + + if (ioctl(fd, SPI_IOC_WR_MODE, &u8) < 0) { + perror("SPI_IOC_WR_MODE"); + return -1; + } + } + + if (config->lsb_first >= 0) { + u8 = (config->lsb_first ? 1 : 0); + if (ioctl(fd, SPI_IOC_WR_LSB_FIRST, &u8) < 0) { + perror("SPI_IOC_WR_LSB_FIRST"); + return -1; + } + } + + if (config->bits_per_word >= 0) { + u8 = config->bits_per_word; + if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &u8) < 0) { + perror("SPI_IOC_WR_BITS_PER_WORD"); + return -1; + } + } + + if (config->spi_speed > 0) { + u32 = config->spi_speed; + if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &u32) < 0) { + perror("SPI_IOC_WR_MAX_SPEED_HZ"); + return -1; + } } return 0; @@ -101,9 +150,11 @@ int Parse_spi_mode(const char *optarg, spi_config_t *config) { - if ((sscanf(optarg, "%d", &(config->spi_mode)) != 1) - || (config->spi_mode < 0) || (config->spi_mode > 3)) { - fprintf(stderr, "Error: wrong SPI mode ([0-3]): %s\n", optarg); + if (config == NULL) + return -1; + + if (parse_int_with_range(optarg, 0, 3, &(config->spi_mode)) != 0) { + fprintf(stderr, "Error: wrong SPI mode ([0-3]): %s\n", optarg ? optarg : "(null)"); return -1; } return 0; @@ -113,9 +164,11 @@ int Parse_lsb_first(const char *optarg, spi_config_t *config) { - if ((sscanf(optarg, "%d", &(config->lsb_first)) != 1) - || (config->lsb_first < 0) || (config->lsb_first > 1)) { - fprintf(stderr, "Error: wrong LSB value ([0,1]): %s\n", optarg); + if (config == NULL) + return -1; + + if (parse_int_with_range(optarg, 0, 1, &(config->lsb_first)) != 0) { + fprintf(stderr, "Error: wrong LSB value ([0,1]): %s\n", optarg ? optarg : "(null)"); return -1; } return 0; @@ -125,9 +178,11 @@ int Parse_spi_speed(const char *optarg, spi_config_t *config) { - if ((sscanf(optarg, "%d", &(config->spi_speed)) != 1) - || (config->spi_speed < 0) || (config->spi_speed > 100000000)) { - fprintf(stderr, "Error: invalid SPI speed ([0-100000000]): %s\n", optarg); + if (config == NULL) + return -1; + + if (parse_int_with_range(optarg, 0, 100000000, &(config->spi_speed)) != 0) { + fprintf(stderr, "Error: invalid SPI speed ([0-100000000]): %s\n", optarg ? optarg : "(null)"); return -1; } return 0; @@ -137,9 +192,11 @@ int Parse_spi_ready(const char *optarg, spi_config_t *config) { - if ((sscanf(optarg, "%d", &(config->spi_ready)) != 1) - || (config->spi_ready < 0) || (config->spi_ready > 1)) { - fprintf(stderr, "Error: wrong SPI-ready value ([0, 1]): %s\n", optarg); + if (config == NULL) + return -1; + + if (parse_int_with_range(optarg, 0, 1, &(config->spi_ready)) != 0) { + fprintf(stderr, "Error: wrong SPI-ready value ([0, 1]): %s\n", optarg ? optarg : "(null)"); return -1; } return 0; @@ -149,9 +206,11 @@ int Parse_spi_bits_per_word(const char *optarg, spi_config_t *config) { - if ((sscanf(optarg, "%d", &(config->bits_per_word)) != 1) - || (config->bits_per_word < 7)) { - fprintf(stderr, "Error: wrong bits-per-word value ([0, 1]): %s\n", optarg); + if (config == NULL) + return -1; + + if (parse_int_with_range(optarg, 7, 255, &(config->bits_per_word)) != 0) { + fprintf(stderr, "Error: wrong bits-per-word value ([7, 255]): %s\n", optarg ? optarg : "(null)"); return -1; } return 0; @@ -159,7 +218,7 @@ -int Transfer_spi_buffers(int fd, void *tx_buffer, void *rx_buffer, size_t length) +int Transfer_spi_buffers(int fd, const void *tx_buffer, void *rx_buffer, size_t length) { struct spi_ioc_transfer transfer = { .tx_buf = 0, @@ -170,6 +229,17 @@ .bits_per_word = 0, }; + + if (length > UINT32_MAX) { + errno = EINVAL; + return -1; + } + + if ((length > 0) && (tx_buffer == NULL) && (rx_buffer == NULL)) { + errno = EINVAL; + return -1; + } + transfer.rx_buf = (unsigned long)rx_buffer; transfer.tx_buf = (unsigned long)tx_buffer; transfer.len = length; @@ -179,3 +249,28 @@ return 0; } + + +// ---------------------- Private methods + +static int parse_int_with_range(const char *str, int min, int max, int *value) +{ + char *end = NULL; + long tmpvalue; + + if ((str == NULL) || (value == NULL)) + return -1; + + errno = 0; + tmpvalue = strtol(str, &end, 0); + if ((errno != 0) || (end == str) || (*end != '\0')) + return -1; + + if ((tmpvalue < min) || (tmpvalue > max)) + return -1; + + *value = (int)tmpvalue; + + return 0; +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spi-tools-1.0.2/src/spi-tools.h new/spi-tools-1.1.0/src/spi-tools.h --- old/spi-tools-1.0.2/src/spi-tools.h 2022-08-18 16:42:22.000000000 +0200 +++ new/spi-tools-1.1.0/src/spi-tools.h 2026-06-08 18:09:54.000000000 +0200 @@ -21,21 +21,23 @@ #ifndef SPI_TOOLS_H #define SPI_TOOLS_H +#include <stddef.h> + typedef struct spi_config { - int spi_mode; // [0-3] (-1 when not configured). - int lsb_first; // {0,1} (-1 when not configured). - int bits_per_word; // [7...] (-1 when not configured). - int spi_speed; // 0 when not configured. - int spi_ready; // {0,1} (-1 when not configured). + int spi_mode; // [0-3] (-1 when not configured). + int lsb_first; // {0,1} (-1 when not configured). + int bits_per_word; // [7...] (-1 when not configured). + unsigned int spi_speed; // 0 when not configured. + int spi_ready; // {0,1} (-1 when not configured). } spi_config_t; int Read_spi_configuration(int fd, spi_config_t *config); -int Write_spi_configuration(int fd, spi_config_t *config); +int Write_spi_configuration(int fd, const spi_config_t *config); int Parse_spi_mode(const char *optarg, spi_config_t *config); @@ -47,7 +49,7 @@ int Parse_spi_bits_per_word(const char *optarg, spi_config_t *config); -int Transfer_spi_buffers(int fd, void *tx_buffer, void *rx_buffer, size_t length); +int Transfer_spi_buffers(int fd, const void *tx_buffer, void *rx_buffer, size_t length); #endif
