From 1e6300ae4614b2d8d74687240b2985f3128bc41b Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Mon, 19 Aug 2024 16:52:02 +0800
Subject: [PATCH] Add led/pwm API source code
---
hal/api/leds.c | 332 +++++++++++++++++++++++
hal/api/libgpiod/build.sh | 118 ++++++++
hal/api/libgpiod/makefile | 11
hal/api/pwm.c | 309 ++++++++++++++++++++++
hal/api/makefile | 54 +++
5 files changed, 824 insertions(+), 0 deletions(-)
diff --git a/hal/api/leds.c b/hal/api/leds.c
new file mode 100644
index 0000000..1918a0b
--- /dev/null
+++ b/hal/api/leds.c
@@ -0,0 +1,332 @@
+/*********************************************************************************
+ * Copyright: (C) 2024 LingYun IoT System Studio
+ * All rights reserved.
+ *
+ * Filename: led.c
+ * Description: This file is used to control RGB 3-colors LED
+ *
+ *
+ * Pin connection:
+ * RGB Led Module IGKBoard
+ * R <-----> #Pin33
+ * G <-----> #Pin35
+ * B <-----> #Pin37
+ * GND <-----> GND
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <gpiod.h>
+
+#define DELAY 300
+
+#define ON 1
+#define OFF 0
+
+/* Three LEDs number */
+enum
+{
+ LED_R = 0,
+ LED_G,
+ LED_B,
+ LEDCNT,
+};
+
+enum
+{
+ ACTIVE_HIGH, /* High level will turn led on */
+ ACTIVE_LOW, /* Low level will turn led on */
+};
+
+/* Three LEDs hardware information */
+typedef struct led_s
+{
+ const char *name; /* RGB 3-color LED name */
+ int chip_num; /* RGB 3-color LED connect chip */
+ int gpio_num; /* RGB 3-color LED connect line */
+ int active; /* RGB 3-color LED active level */
+ struct gpiod_line_request *request; /* libgpiod gpio request handler */
+} led_t;
+
+static led_t leds_info[LEDCNT] =
+{
+ {"red", 0, 23, ACTIVE_HIGH, NULL }, /* GPIO1_IO23 on chip0 line 23, active high */
+ {"green", 4, 1, ACTIVE_HIGH, NULL }, /* GPIO5_IO01 on chip4 line 1, active high */
+ {"blue", 4, 8, ACTIVE_HIGH, NULL }, /* GPIO5_IO08 on chip4 line 8, active high */
+};
+
+/* Three LEDs API context */
+typedef struct leds_s
+{
+ led_t *leds; /* led pointer to leds_info */
+ int count; /* led count */
+} leds_t;
+
+
+/* function declaration */
+int init_led(leds_t *leds);
+int term_led(leds_t *leds);
+int turn_led(leds_t *leds, int which, int cmd);
+static inline void msleep(unsigned long ms);
+
+
+int g_stop = 0;
+
+void sig_handler(int signum)
+{
+ switch( signum )
+ {
+ case SIGINT:
+ case SIGTERM:
+ g_stop = 1;
+
+ default:
+ break;
+ }
+
+ return ;
+}
+
+int main(int argc, char *argv[])
+{
+ int rv;
+ leds_t leds =
+ {
+ .leds = leds_info,
+ .count = LEDCNT,
+ };
+
+ if( (rv=init_led(&leds)) < 0 )
+ {
+ printf("initial leds gpio failure, rv=%d\n", rv);
+ return 1;
+ }
+ printf("initial RGB Led gpios okay\n");
+
+ signal(SIGINT, sig_handler);
+ signal(SIGTERM, sig_handler);
+
+ while( !g_stop )
+ {
+ turn_led(&leds, LED_R, ON);
+ msleep(DELAY);
+ turn_led(&leds, LED_R, OFF);
+ msleep(DELAY);
+
+ turn_led(&leds, LED_G, ON);
+ msleep(DELAY);
+ turn_led(&leds, LED_G, OFF);
+ msleep(DELAY);
+
+ turn_led(&leds, LED_B, ON);
+ msleep(DELAY);
+ turn_led(&leds, LED_B, OFF);
+ msleep(DELAY);
+ }
+
+ term_led(&leds);
+ return 0;
+}
+
+int term_led(leds_t *leds)
+{
+ int i;
+ led_t *led;
+
+ printf("terminate RGB Led gpios\n");
+
+ if( !leds )
+ {
+ printf("Invalid input arguments\n");
+ return -1;
+ }
+
+ for(i=0; i<leds->count; i++)
+ {
+ led = &leds->leds[i];
+
+ if( led->request )
+ {
+ turn_led(leds, i, OFF);
+ gpiod_line_request_release(led->request);
+ }
+ }
+
+ return 0;
+}
+
+
+int init_led(leds_t *leds)
+{
+ led_t *led;
+ int i, rv = 0;
+ char chip_dev[32];
+ struct gpiod_chip *chip; /* gpio chip */
+ struct gpiod_line_settings *settings; /* gpio direction, bias, active_low, value */
+ struct gpiod_line_config *line_cfg; /* gpio line */
+ struct gpiod_request_config *req_cfg; /* gpio consumer, it can be NULL */
+
+
+ if( !leds )
+ {
+ printf("Invalid input arguments\n");
+ return -1;
+ }
+
+
+ /* defined in libgpiod-2.0/lib/line-settings.c:
+
+ struct gpiod_line_settings {
+ enum gpiod_line_direction direction;
+ enum gpiod_line_edge edge_detection;
+ enum gpiod_line_drive drive;
+ enum gpiod_line_bias bias;
+ bool active_low;
+ enum gpiod_line_clock event_clock;
+ long debounce_period_us;
+ enum gpiod_line_value output_value;
+ };
+ */
+ settings = gpiod_line_settings_new();
+ if (!settings)
+ {
+ printf("unable to allocate line settings\n");
+ rv = -2;
+ goto cleanup;
+ }
+
+ /* defined in libgpiod-2.0/lib/line-config.c
+
+ struct gpiod_line_config {
+ struct per_line_config line_configs[LINES_MAX];
+ size_t num_configs;
+ enum gpiod_line_value output_values[LINES_MAX];
+ size_t num_output_values;
+ struct settings_node *sref_list;
+ };
+ */
+
+ line_cfg = gpiod_line_config_new();
+ if (!line_cfg)
+ {
+ printf("unable to allocate the line config structure");
+ rv = -2;
+ goto cleanup;
+ }
+
+
+ /* defined in libgpiod-2.0/lib/request-config.c:
+
+ struct gpiod_request_config {
+ char consumer[GPIO_MAX_NAME_SIZE];
+ size_t event_buffer_size;
+ };
+ */
+ req_cfg = gpiod_request_config_new();
+ if (!req_cfg)
+ {
+ printf("unable to allocate the request config structure");
+ rv = -2;
+ goto cleanup;
+ }
+
+ for(i=0; i<leds->count; i++)
+ {
+ led = &leds->leds[i];
+
+ snprintf(chip_dev, sizeof(chip_dev), "/dev/gpiochip%d", led->chip_num);
+ chip = gpiod_chip_open(chip_dev);
+ if( !chip )
+ {
+ printf("open gpiochip failure, maybe you need running as root\n");
+ rv = -3;
+ goto cleanup;
+ }
+
+ /* Set as output direction, active low and default level as inactive */
+ gpiod_line_settings_reset(settings);
+ gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_settings_set_active_low(settings, led->active);
+ gpiod_line_settings_set_output_value(settings, GPIOD_LINE_VALUE_INACTIVE);
+
+ /* set gpio line */
+ gpiod_line_config_reset(line_cfg);
+ gpiod_line_config_add_line_settings(line_cfg, &led->gpio_num, 1, settings);
+
+ /* Can be NULL for default settings. */
+ gpiod_request_config_set_consumer(req_cfg, led->name);
+
+ /* Request a set of lines for exclusive usage. */
+ led->request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+
+ gpiod_chip_close(chip);
+ //printf("request %5s led[%d] for gpio output okay\n", led->name, led->gpio);
+ }
+
+cleanup:
+
+ if( rv< 0 )
+ term_led(leds);
+
+ if( line_cfg )
+ gpiod_line_config_free(line_cfg);
+
+ if( req_cfg )
+ gpiod_request_config_free(req_cfg);
+
+ if( settings )
+ gpiod_line_settings_free(settings);
+
+ return rv;
+}
+
+int turn_led(leds_t *leds, int which, int cmd)
+{
+ led_t *led;
+ int rv = 0;
+ int value = 0;
+
+ if( !leds || which<0 || which>=leds->count )
+ {
+ printf("Invalid input arguments\n");
+ return -1;
+ }
+
+ led = &leds->leds[which];
+
+ value = OFF==cmd ? GPIOD_LINE_VALUE_INACTIVE : GPIOD_LINE_VALUE_ACTIVE;
+
+ gpiod_line_request_set_value(led->request, led->gpio_num, value);
+
+ return 0;
+}
+
+static inline void msleep(unsigned long ms)
+{
+ struct timespec cSleep;
+ unsigned long ulTmp;
+
+ cSleep.tv_sec = ms / 1000;
+ if (cSleep.tv_sec == 0)
+ {
+ ulTmp = ms * 10000;
+ cSleep.tv_nsec = ulTmp * 100;
+ }
+ else
+ {
+ cSleep.tv_nsec = 0;
+ }
+
+ nanosleep(&cSleep, 0);
+
+ return ;
+}
diff --git a/hal/api/libgpiod/build.sh b/hal/api/libgpiod/build.sh
new file mode 100755
index 0000000..6009e21
--- /dev/null
+++ b/hal/api/libgpiod/build.sh
@@ -0,0 +1,118 @@
+#!/bin/bash
+
+# library name and version
+# Official: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
+LIB_NAME=libgpiod-2.0
+PACK_SUFIX=tar.gz
+
+# Cross compiler for cross compile on Linux server
+CROSS_COMPILE=arm-linux-gnueabihf-
+
+# this project absolute path
+PRJ_PATH=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
+
+# binaries install path
+PREFIX_PATH=$PRJ_PATH/install
+
+# check installed or not file
+INST_FILE=$PREFIX_PATH/lib/libgpiod.so
+
+#+-------------------------+
+#| Shell script functions |
+#+-------------------------+
+
+function pr_error() {
+ echo -e "\033[40;31m $1 \033[0m"
+}
+
+function pr_warn() {
+ echo -e "\033[40;33m $1 \033[0m"
+}
+
+function pr_info() {
+ echo -e "\033[40;32m $1 \033[0m"
+}
+
+function check_result()
+{
+ if [ $? != 0 ] ; then
+ pr_error $1
+ fi
+}
+
+function do_export()
+{
+ pr_warn "set cross(${CROSS_COMPILE})"
+
+ # export cross toolchain
+ export CC=${CROSS_COMPILE}gcc
+ export CXX=${CROSS_COMPILE}g++
+ export AS=${CROSS_COMPILE}as
+ export AR=${CROSS_COMPILE}ar
+ export LD=${CROSS_COMPILE}ld
+ export NM=${CROSS_COMPILE}nm
+ export RANLIB=${CROSS_COMPILE}ranlib
+ export OBJDUMP=${CROSS_COMPILE}objdump
+ export STRIP=${CROSS_COMPILE}strip
+
+ # export cross configure
+ export CONFIG_CROSS=" --build=i686-pc-linux --host=arm-linux "
+
+ # Clear LDFLAGS and CFLAGS
+ export LDFLAGS=
+ export CFLAGS=
+}
+
+function do_fetch()
+{
+ if [ -e ${INST_FILE} ] ; then
+ pr_warn "$LIB_NAME compile and installed alredy"
+ exit ;
+ fi
+
+ if [ -d $LIB_NAME ] ; then
+ pr_warn "$LIB_NAME fetch already"
+ return ;
+ fi
+
+ if [ ! -f ${LIB_NAME}.${PACK_SUFIX} ] ; then
+ wget https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/snapshot/${LIB_NAME}.${PACK_SUFIX}
+ check_result "ERROR: download ${LIB_NAME} failure"
+ fi
+
+ pr_warn "$LIB_NAME download already, decompress it now"
+ tar -xzf ${LIB_NAME}.${PACK_SUFIX}
+}
+
+function do_build()
+{
+ cd $LIB_NAME
+
+ ./autogen.sh
+
+ do_export
+
+ echo "ac_cv_func_malloc_0_nonnull=yes" > arm-linux.cache
+ ./configure --prefix=${PREFIX_PATH} ${CONFIG_CROSS} --enable-static \
+ --cache-file=arm-linux.cache --enable-tools
+ check_result "ERROR: configure ${LIB_NAME} failure"
+
+ make -j ${JOBS} && make install
+ check_result "ERROR: compile ${LIB_NAME} failure"
+}
+
+function do_clean()
+{
+ rm -rf ${LIB_NAME}*
+ rm -rf install
+}
+
+if [[ $# == 1 && $1 == -c ]] ;then
+ pr_warn "start clean $LIB_NAME"
+ do_clean
+ exit;
+fi
+
+do_fetch
+
+do_build
diff --git a/hal/api/libgpiod/makefile b/hal/api/libgpiod/makefile
new file mode 100644
index 0000000..4cc8cac
--- /dev/null
+++ b/hal/api/libgpiod/makefile
@@ -0,0 +1,11 @@
+
+all: update_cross
+ @./build.sh
+
+clean:
+ @./build.sh -c
+
+update_cross:
+ifdef CROSS_COMPILE
+ sed -i 's|^CROSS_COMPILE=.*|CROSS_COMPILE=${CROSS_COMPILE}|g' build.sh
+endif
diff --git a/hal/api/makefile b/hal/api/makefile
new file mode 100644
index 0000000..0c3525e
--- /dev/null
+++ b/hal/api/makefile
@@ -0,0 +1,54 @@
+#********************************************************************************
+# Copyright: (C) 2023 LingYun IoT System Studio
+# All rights reserved.
+#
+# Filename: Makefile
+# Description: This file used to compile all the C file to respective binary,
+# and it will auto detect cross compile or local compile.
+#
+# Version: 1.0.0(11/08/23)
+# Author: Guo Wenxue <guowenxue@gmail.com>
+# ChangeLog: 1, Release initial version on "11/08/23 16:18:43"
+#
+#*******************************************************************************
+
+PWD=$(shell pwd)
+INSTPATH=/tftp
+
+CROSS_COMPILE=arm-linux-gnueabihf-
+CC=${CROSS_COMPILE}gcc
+
+LDFLAGS += -lm
+
+SRCS = $(wildcard ${VPATH}/*.c)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+SRCFILES = $(wildcard *.c)
+BINARIES=$(SRCFILES:%.c=%)
+
+# libgpiod compile install path
+LIBGPIOD_PATH=libgpiod/install
+CFLAGS+=-I ${LIBGPIOD_PATH}/include
+LDFLAGS+=-L ${LIBGPIOD_PATH}/lib -lgpiod
+
+all: libs binaries install
+
+libs:
+ make -C libgpiod CROSS_COMPILE=${CROSS_COMPILE}
+
+binaries: ${BINARIES}
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
+install:
+ cp $(BINARIES) ${INSTPATH}
+
+clean:
+ @rm -f *.o *.lo $(BINARIES)
+
+distclean: clean
+ @rm -f tags cscope*
+ @make clean -C libgpiod
+
+.PHONY: clean entry
diff --git a/hal/api/pwm.c b/hal/api/pwm.c
new file mode 100644
index 0000000..408d1bc
--- /dev/null
+++ b/hal/api/pwm.c
@@ -0,0 +1,309 @@
+/*********************************************************************************
+ * Copyright: (C) 2021 LingYun IoT System Studio
+ * All rights reserved.
+ *
+ * Filename: pwm.c
+ * Description: This file is used to control PWM buzzer/Led
+ *
+ * Pin connection:
+ * PWM Module Raspberry Pi Board
+ * VCC <-----> 5V
+ * buzzer <-----> #Pin32(BCM GPIO12)
+ * Led <-----> #Pin33(BCM GPIO13)
+ * GND <-----> GND
+ *
+ * /boot/config.txt:
+ *
+ * dtoverlay=pwm,pin=12,func=4 (Buzzer)
+ * dtoverlay=pwm,pin=13,func=4 (Led)
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+#include <libgen.h>
+
+#define PWMCHIP_PATH "/sys/class/pwm/pwmchip0"
+
+#define ENABLE 1
+#define DISABLE 0
+
+int init_pwm(int channel, int freq, int duty);
+int turn_pwm(int channel, int status);
+int term_pwm(int channel);
+static inline void msleep(unsigned long ms);
+
+static inline void banner(const char *progname)
+{
+ printf("%s program Version v1.0.0\n", progname);
+ printf("Copyright (C) 2023 LingYun IoT System Studio.\n");
+}
+
+static void program_usage(const char *progname)
+{
+
+ printf("Usage: %s [OPTION]...\n", progname);
+ printf(" This is pwm control program. \n");
+
+ printf(" -c[channel ] Specify PWM channel, such as 0\n");
+ printf(" -f[freq ] Specify PWM frequency, default 2500(Hz)\n");
+ printf(" -d[duty ] Specify PWM duty, default 50(50%%)\n");
+ printf(" -s[status ] Specify PWM status: 1->on(default), 0->off\n");
+ printf(" -h[help ] Display this help information\n");
+ printf(" -v[version ] Display the program version\n");
+ printf("\n");
+
+ printf("Example buzzer : %s -c 0 -f 2750 -d 50 -s 1\n", progname);
+ printf("Example Led : %s -c 1 -f 100 -d 50 -s 1\n", progname);
+ printf("Example disable: %s -c 0 -s 0\n", progname);
+
+ printf("\n");
+ banner(progname);
+ return;
+}
+
+int main(int argc, char **argv)
+{
+ int rv;
+ char *progname=NULL;
+ int channel = -1;
+ int freq = 2500;
+ int duty = 50;
+ int status = ENABLE;
+
+ struct option long_options[] = {
+ {"channel", required_argument, NULL, 'c'},
+ {"freq", required_argument, NULL, 'f'},
+ {"duty", required_argument, NULL, 'd'},
+ {"status", required_argument, NULL, 's'},
+ {"version", no_argument, NULL, 'v'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ progname = basename(argv[0]);
+
+ /* Parser the command line parameters */
+ while ((rv = getopt_long(argc, argv, "c:f:d:s:vh", long_options, NULL)) != -1)
+ {
+ switch (rv)
+ {
+ case 'c': /* Set pwm channel, such as 0,1 */
+ channel = atoi(optarg);
+ break;
+
+ case 'f': /* Set pwm frequency */
+ freq = atoi(optarg);
+ break;
+
+ case 'd': /* Set pwm duty cycle */
+ duty = atoi(optarg);
+ break;
+
+ case 's': /* Set pwm status, 0 for disable and 1 for enable */
+ status = atoi(optarg);
+ break;
+
+ case 'v': /* Get software version */
+ banner(progname);
+ return EXIT_SUCCESS;
+
+ case 'h': /* Get help information */
+ program_usage(progname);
+ return 0;
+
+ default:
+ break;
+ }
+ }
+
+ if(channel < 0 )
+ {
+ program_usage(progname);
+ return 0;
+ }
+
+ if( status )
+ {
+ if( (rv=init_pwm(channel, freq, duty)) < 0 )
+ {
+ printf("initial PWM failure, rv=%d\n", rv);
+ return 1;
+ }
+
+ turn_pwm(channel, ENABLE);
+ }
+ else
+ {
+ term_pwm(channel);
+ }
+
+ return 0;
+}
+
+/* check PWM $channel export or not */
+int check_pwm(int channel)
+{
+ char path[256];
+
+ /* check /sys/class/pwm/pwmchip0/pwmN exist or not */
+ snprintf(path, sizeof(path), "%s/pwm%d", PWMCHIP_PATH, channel);
+ return access(path, F_OK) ? 0 : 1;
+}
+
+/* export($export=1)/unexport($export=0) PWM $channel */
+int export_pwm(int channel, int export)
+{
+ int fd;
+ char buf[32];
+ char path[256];
+
+ if( export && check_pwm(channel) )
+ return 0; /* export already when export */
+ else if( !export && !check_pwm(channel) )
+ return 0; /* unexport already when unexport */
+
+ /* export PWM channel by echo N > /sys/class/pwm/pwmchip0/export */
+ snprintf(path, sizeof(path), "%s/%s", PWMCHIP_PATH, export?"export":"unexport");
+ if( (fd=open(path, O_WRONLY)) < 0 )
+ {
+ printf("open '%s' failed: %s\n", path, strerror(errno));
+ return -3;
+ }
+
+ snprintf(buf, sizeof(buf), "%d", channel);
+ write(fd, buf, strlen(buf));
+
+ msleep(100);
+
+ if( export && check_pwm(channel) )
+ return 0; /* export already when export */
+ else if( !export && !check_pwm(channel) )
+ return 0; /* unexport already when unexport */
+
+ return -4;
+}
+
+/* configure PWM $channel */
+int config_pwm(int channel, int freq, int duty)
+{
+ int fd;
+ char buf[32];
+ char path[256];
+ int period;
+ int duty_cycle;
+
+ if( !check_pwm(channel) )
+ return -2;
+
+ /* open PWM period file and write period in ns */
+ snprintf(path, sizeof(path), "%s/pwm%d/period", PWMCHIP_PATH, channel);
+ if( (fd=open(path, O_WRONLY)) < 0 )
+ {
+ printf("open '%s' failed: %s\n", path, strerror(errno));
+ return -3;
+ }
+ period = 1000000000/freq;
+ snprintf(buf, sizeof(buf), "%d", period);
+ write(fd, buf, strlen(buf));
+
+ /* open PWM duty_cycle file and write duty */
+ snprintf(path, sizeof(path), "%s/pwm%d/duty_cycle", PWMCHIP_PATH, channel);
+ if( (fd=open(path, O_WRONLY)) < 0 )
+ {
+ printf("open '%s' failed: %s\n", path, strerror(errno));
+ return -3;
+ }
+ duty_cycle = (period*duty) / 100;
+ snprintf(buf, sizeof(buf), "%d", duty_cycle);
+ write(fd, buf, strlen(buf));
+
+ return 0;
+}
+
+int init_pwm(int channel, int freq, int duty)
+{
+ int rv;
+ char buf[32];
+ char path[256];
+
+ if( (rv=export_pwm(channel, 1)) )
+ {
+ printf("export PWM channel[%d] failed, rv=%d\n", channel, rv);
+ return rv;
+ }
+
+ if( (rv=config_pwm(channel, freq, duty)) )
+ {
+ printf("config PWM channel[%d] failed, rv=%d\n", channel, rv);
+ return rv;
+ }
+
+ printf("config pwm%d with freq[%d] duty[%d] okay\n", channel, freq, duty);
+
+ return 0;
+}
+
+int turn_pwm(int channel, int status)
+{
+ int fd;
+ char buf[32];
+ char path[256];
+
+ if( !check_pwm(channel) )
+ return -1;
+
+ /* open PWM enable file and enable(1)/disable(0) it */
+ snprintf(path, sizeof(path), "%s/pwm%d/enable", PWMCHIP_PATH, channel);
+ if( (fd=open(path, O_WRONLY)) < 0 )
+ {
+ printf("open '%s' failed: %s\n", path, strerror(errno));
+ return -3;
+ }
+ snprintf(buf, sizeof(buf), "%d", status?1:0);
+ write(fd, buf, strlen(buf));
+
+ printf("pwm[%d] %s\n", channel, status?"enable":"disable");
+
+ return 0;
+}
+
+int term_pwm(int channel)
+{
+ if( !check_pwm(channel) )
+ return 0;
+
+ turn_pwm(channel, DISABLE);
+ export_pwm(channel, 0);
+
+ return 0;
+}
+
+static inline void msleep(unsigned long ms)
+{
+ struct timespec cSleep;
+ unsigned long ulTmp;
+
+ cSleep.tv_sec = ms / 1000;
+ if (cSleep.tv_sec == 0)
+ {
+ ulTmp = ms * 10000;
+ cSleep.tv_nsec = ulTmp * 100;
+ }
+ else
+ {
+ cSleep.tv_nsec = 0;
+ }
+
+ nanosleep(&cSleep, 0);
+
+ return ;
+}
--
Gitblit v1.9.1