mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
Moved inteno projects that should be public to their own repos.
The repos are now available from public.inteno.se This does not include broadcom-utils.
This commit is contained in:
parent
416807ec6d
commit
a88e8ca92a
118 changed files with 146 additions and 28349 deletions
|
|
@ -9,10 +9,22 @@ include $(TOPDIR)/rules.mk
|
|||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=bcmhotproxy
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=13
|
||||
|
||||
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
|
||||
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
|
||||
PKG_SOURCE_VERSION:=63a265031b870a0aa6b45352cf28224518a31638
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/bcmhotproxy
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:bcmhotproxy
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
STAMP_PREPARED:=$(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
|
@ -26,24 +38,16 @@ define Package/bcmhotproxy/description
|
|||
This package contains a Daemon that will listen to link events from broadcoms adsl driver and etherent driver and proxy them to hotplug
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
$(CP) ./files/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
target=$(firstword $(subst -, ,$(BOARD)))
|
||||
|
||||
MAKE_FLAGS += TARGET="$(target)"
|
||||
TARGET_CFLAGS += -Dtarget_$(target)=1 -Wall
|
||||
|
||||
|
||||
define Package/bcmhotproxy/install
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_DIR) $(1)/etc/
|
||||
$(INSTALL_DIR) $(1)/etc/init.d/
|
||||
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/etc/init.d/* $(1)/etc/init.d/
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bcmhotproxy $(1)/sbin/
|
||||
endef
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
CC = gcc
|
||||
CFLAGS += -Wall
|
||||
|
||||
obj = bcmhotproxy.o brcmdaemon.o
|
||||
|
||||
bcmhotproxy: $(obj) $(obj.$(TARGET))
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* bcmhotproxy -- a proxy to send messages from broadcom drivers to userspace
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: Strhuan Blomquist
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
#include "bcmhotproxy.h"
|
||||
|
||||
int netlink_init() {
|
||||
int sock_fd;
|
||||
sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_BRCM_MONITOR);
|
||||
if(sock_fd<0)
|
||||
return -1;
|
||||
return sock_fd;
|
||||
}
|
||||
int hotplug_call(struct hotplug_arg arg)
|
||||
{
|
||||
char str[512];
|
||||
int ret;
|
||||
memset(str, '\0', sizeof(512));
|
||||
syslog(LOG_INFO, "ACTION=%s INTERFACE=%s /sbin/hotplug-call %s", arg.action,arg.inteface,arg.subsystem);
|
||||
sprintf(str, "ACTION=%s INTERFACE=%s /sbin/hotplug-call %s",arg.action,arg.inteface,arg.subsystem);
|
||||
ret=system(str);
|
||||
return ret;
|
||||
}
|
||||
hotplug_arg createargumetstruct(char *hotplugmsg)
|
||||
{
|
||||
hotplug_arg arg;
|
||||
char argumets[3][20];
|
||||
char * pch;
|
||||
int x=0;
|
||||
pch = strtok (hotplugmsg," ");
|
||||
while (pch != NULL){
|
||||
strcpy(argumets[x],pch);
|
||||
pch = strtok (NULL, " ");
|
||||
x++;
|
||||
}
|
||||
strncpy(arg.action,argumets[0],sizeof(arg.action));
|
||||
strncpy(arg.inteface,argumets[1],sizeof(arg.action));
|
||||
strncpy(arg.subsystem,argumets[2],sizeof(arg.action));
|
||||
|
||||
return arg;
|
||||
|
||||
}
|
||||
|
||||
int netlink_bind(int sock_fd) {
|
||||
|
||||
struct sockaddr_nl src_addr;
|
||||
memset(&src_addr, 0, sizeof(src_addr));
|
||||
src_addr.nl_family = AF_NETLINK;
|
||||
src_addr.nl_pid = getpid(); /* self pid */
|
||||
src_addr.nl_groups = 1; //multicast Group
|
||||
|
||||
bind(sock_fd, (struct sockaddr*)&src_addr,sizeof(src_addr));
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&src_addr,sizeof(src_addr))) {
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
int dispatcher() {
|
||||
struct sockaddr_nl dest_addr;
|
||||
struct nlmsghdr *nlh = NULL;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
hotplug_arg arg;
|
||||
int sock_fd;
|
||||
/* Initlize the netlink socket */
|
||||
sock_fd=netlink_init();
|
||||
if (sock_fd == -1) {
|
||||
fprintf(stderr, "Unable to Intitlize netlink socket.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Bind the netlink socket */
|
||||
sock_fd=netlink_bind(sock_fd);
|
||||
if (sock_fd == -1) {
|
||||
fprintf(stderr, "Unable to Listen to netlink socket.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* destination address to listen to */
|
||||
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
|
||||
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
|
||||
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
|
||||
nlh->nlmsg_pid = getpid();
|
||||
nlh->nlmsg_flags = 0;
|
||||
|
||||
/* Fill the netlink message header */
|
||||
iov.iov_base = (void *)nlh;
|
||||
iov.iov_len = nlh->nlmsg_len;
|
||||
msg.msg_name = (void *)&dest_addr;
|
||||
msg.msg_namelen = sizeof(dest_addr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
|
||||
/* Read message from kernel */
|
||||
while(1){
|
||||
recvmsg(sock_fd, &msg, 0);
|
||||
switch (nlh->nlmsg_type)
|
||||
{
|
||||
case MSG_NETLINK_BRCM_WAKEUP_MONITOR_TASK:
|
||||
case MSG_NETLINK_BRCM_LINK_STATUS_CHANGED:
|
||||
/*process the message */
|
||||
fprintf(stderr, "No Handle\n");
|
||||
break;
|
||||
case MSG_NETLINK_BRCM_LINK_HOTPLUG:
|
||||
arg=createargumetstruct((char *)NLMSG_DATA(nlh));
|
||||
if(hotplug_call(arg)){
|
||||
fprintf(stderr, "Unable to call hotplug.\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
close(sock_fd);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef BCMHOTPROXY_H
|
||||
#define BCMHOTPROXY_H 1
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#define MSG_NETLINK_BRCM_WAKEUP_MONITOR_TASK 0X1000
|
||||
|
||||
#define MSG_NETLINK_BRCM_LINK_STATUS_CHANGED 0X2000
|
||||
|
||||
#define MSG_NETLINK_BRCM_LINK_HOTPLUG 0X3000
|
||||
#define MAX_PAYLOAD 1024 /* maximum payload size*/
|
||||
#ifndef NETLINK_BRCM_MONITOR
|
||||
#define NETLINK_BRCM_MONITOR 25
|
||||
#endif
|
||||
typedef struct hotplug_arg hotplug_arg;
|
||||
|
||||
struct hotplug_arg
|
||||
{
|
||||
char action[20];
|
||||
char inteface[20];
|
||||
char subsystem[20];
|
||||
|
||||
};
|
||||
#endif
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
#include "brcmdaemon.h"
|
||||
|
||||
/**************************************************************************
|
||||
Function: Print Usage
|
||||
|
||||
Description:
|
||||
Output the command-line options for this daemon.
|
||||
|
||||
Params:
|
||||
@argc - Standard argument count
|
||||
@argv - Standard argument array
|
||||
|
||||
Returns:
|
||||
returns void always
|
||||
**************************************************************************/
|
||||
void PrintUsage(int argc, char *argv[]) {
|
||||
if (argc >=1) {
|
||||
printf("Usage: %s -h -n\n", argv[0]);
|
||||
printf(" Options: \n");
|
||||
printf(" -ntDon't fork off as a daemon.\n");
|
||||
printf(" -htShow this help screen.\n");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: signal_handler
|
||||
|
||||
Description:
|
||||
This function handles select signals that the daemon may
|
||||
receive. This gives the daemon a chance to properly shut
|
||||
down in emergency situations. This function is installed
|
||||
as a signal handler in the 'main()' function.
|
||||
|
||||
Params:
|
||||
@sig - The signal received
|
||||
|
||||
Returns:
|
||||
returns void always
|
||||
**************************************************************************/
|
||||
void signal_handler(int sig) {
|
||||
|
||||
switch(sig) {
|
||||
case SIGHUP:
|
||||
syslog(LOG_WARNING, "Received SIGHUP signal.");
|
||||
break;
|
||||
case SIGTERM:
|
||||
syslog(LOG_WARNING, "Received SIGTERM signal.");
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_WARNING, "Unhandled signal (%d) %s", strsignal(sig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: main
|
||||
|
||||
Description:
|
||||
The c standard 'main' entry point function.
|
||||
|
||||
Params:
|
||||
@argc - count of command line arguments given on command line
|
||||
@argv - array of arguments given on command line
|
||||
|
||||
Returns:
|
||||
returns integer which is passed back to the parent process
|
||||
**************************************************************************/
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
#if defined(DEBUG)
|
||||
int daemonize = 0;
|
||||
#else
|
||||
int daemonize = 0;
|
||||
#endif
|
||||
|
||||
// Setup signal handling before we start
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGQUIT, signal_handler);
|
||||
|
||||
int c;
|
||||
while( (c = getopt(argc, argv, "nh|help")) != -1) {
|
||||
switch(c){
|
||||
case 'h':
|
||||
PrintUsage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
case 'n':
|
||||
daemonize = 0;
|
||||
break;
|
||||
default:
|
||||
PrintUsage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "%s daemon starting up", DAEMON_NAME);
|
||||
|
||||
// Setup syslog logging - see SETLOGMASK(3)
|
||||
#if defined(DEBUG)
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||
#else
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
|
||||
#endif
|
||||
|
||||
/* Our process ID and Session ID */
|
||||
pid_t pid, sid;
|
||||
|
||||
if (daemonize) {
|
||||
syslog(LOG_INFO, "starting the daemonizing process");
|
||||
|
||||
/* Fork off the parent process */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* If we got a good PID, then
|
||||
we can exit the parent process. */
|
||||
if (pid > 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Change the current working directory */
|
||||
if ((chdir("/")) < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Close out the standard file descriptors */
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
dispatcher();
|
||||
syslog(LOG_INFO, "%s daemon exiting", DAEMON_NAME);
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef BRCMDAEMON_H
|
||||
#define BRCMDAEMON_H 1
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define DAEMON_NAME "brcmnetlink"
|
||||
#define PID_FILE "/var/run/brcmnetlink.pid"
|
||||
#endif
|
||||
|
|
@ -9,10 +9,22 @@ include $(TOPDIR)/rules.mk
|
|||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=broadcom-nvram
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
|
||||
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
|
||||
PKG_SOURCE_VERSION:=8b6018d9ce5e292f0a4a3e86f8fa7d8bc003c3fb
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/broadcom-nvram
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:broadcom-nvram
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
STAMP_PREPARED:=$(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
|
@ -33,11 +45,6 @@ define Package/bcmnvram/description
|
|||
Broadcom nvram to uci wrapper
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
target=$(firstword $(subst -, ,$(BOARD)))
|
||||
|
||||
MAKE_FLAGS += TARGET="$(target)"
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
# Makefile for broadcom nvram to uci wrapper
|
||||
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
OBJS = nvram_emu_lib.o ucix.o main.o
|
||||
|
||||
all: libnvram main
|
||||
|
||||
dynamic: all
|
||||
|
||||
libnvram: nvram_emu_lib.o
|
||||
$(CC) -c $(CFLAGS) $(LDFLAGS) -fPIC -o ucix_shared.o ucix.c -luci
|
||||
$(CC) -c $(CFLAGS) $(LDFLAGS) -fPIC -o nvram_emu_lib.o nvram_emu_lib.c -luci
|
||||
$(CC) $(LDFLAGS) -shared -Wl,-soname,libnvram.so -o libnvram.so nvram_emu_lib.o ucix_shared.o -luci
|
||||
|
||||
main: main.o ucix.o
|
||||
$(CC) $(LDFLAGS) -o uci_test main.o ucix.o -luci
|
||||
|
||||
clean:
|
||||
rm -f libnvram.so ucix_shared.o uci_test ${OBJS}
|
||||
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// uci test program Copyright Benjamin Larsson 2012 <benjamin@southpole.se>
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
const char *ucitmp;
|
||||
|
||||
ctx = ucix_init("broadcom");
|
||||
if(!ctx)
|
||||
printf("Failed to load config file");
|
||||
|
||||
ucitmp = ucix_get_option(ctx, "broadcom", "nvram", "test");
|
||||
printf("test = %s\n",ucitmp);
|
||||
ucix_add_section(ctx, "broadcom", "nvram", "broadcom");
|
||||
ucix_add_option(ctx, "broadcom", "nvram", "test", "tomte");
|
||||
ucix_add_option(ctx, "broadcom", "nvram", "test2", "tomte2");
|
||||
printf("Hello world\n");
|
||||
ucix_commit(ctx, "broadcom");
|
||||
ucitmp = ucix_get_option(ctx, "broadcom", "nvram", "test");
|
||||
printf("test = %s\n",ucitmp);
|
||||
ucix_cleanup(ctx);
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
/** Broadcom libnvram.so compatible wrapper
|
||||
*
|
||||
* Copyright 2012 Benjamin Larsson <benjamin@southpole.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
|
||||
provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "uci.h"
|
||||
|
||||
|
||||
struct uci_context *ctx = NULL;
|
||||
struct uci_ptr ptr;
|
||||
int nvram_inited = 0;
|
||||
int nvram_debug = 0;
|
||||
|
||||
/** Function prototypes are taken from bcmnvram.h Copyright Broadcom Corporation.
|
||||
* Only some of the nvram_* functions exposed from libnvram.so are implemented.
|
||||
* get, getall, unset, set, commit
|
||||
*/
|
||||
|
||||
|
||||
/* uci does not support . in the key part, replace it with _ */
|
||||
|
||||
static const char * filter_dots_in_string(char *key) {
|
||||
int length = 0;
|
||||
int i;
|
||||
length = strlen(key);
|
||||
for (i=0 ; i<length ; i++) {
|
||||
if (key[i] == '.')
|
||||
key[i] = '_';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static void nvram_display_section(struct uci_section *s)
|
||||
{
|
||||
struct uci_element *e;
|
||||
struct uci_option *o;
|
||||
|
||||
printf("%s.%s=%s\n", s->package->e.name, s->e.name, s->type);
|
||||
uci_foreach_element(&s->options, e) {
|
||||
o = uci_to_option(e);
|
||||
printf("%s.%s.%s=%s\n", o->section->package->e.name, o->section->e.name, o->e.name, o->v.string);
|
||||
}
|
||||
}
|
||||
|
||||
void nvram_init() {
|
||||
if (!nvram_inited) {
|
||||
ctx = ucix_init("broadcom");
|
||||
if(!ctx) {
|
||||
printf("Failed to load config file \"broadcom\"\n");
|
||||
return;
|
||||
}
|
||||
ucix_add_section(ctx, "broadcom", "nvram", "broadcom");
|
||||
ucix_add_option(ctx, "broadcom", "nvram", "init", "1");
|
||||
ucix_commit(ctx, "broadcom");
|
||||
nvram_debug = ucix_get_option_int(ctx, "broadcom", "nvram", "debug");
|
||||
nvram_inited = 1;
|
||||
if (nvram_debug)
|
||||
printf("nvram_init()\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the value of an NVRAM variable. The pointer returned may be
|
||||
* invalid after a set.
|
||||
* @param name name of variable to get
|
||||
* @return value of variable or NULL if undefined
|
||||
*/
|
||||
const char * nvram_get(const char *name) {
|
||||
const char *ucitmp;
|
||||
nvram_init();
|
||||
ucitmp = ucix_get_option(ctx, "broadcom", "nvram", filter_dots_in_string(name));
|
||||
if (nvram_debug)
|
||||
printf("%s=nvram_get(%s)\n", ucitmp, name);
|
||||
|
||||
return ucitmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the value of an NVRAM variable. The name and value strings are
|
||||
* copied into private storage. Pointers to previously set values
|
||||
* may become invalid. The new value may be immediately
|
||||
* retrieved but will not be permanently stored until a commit.
|
||||
* @param name name of variable to set
|
||||
* @param value value of variable
|
||||
* @return 0 on success and errno on failure
|
||||
*/
|
||||
int nvram_set(const char *name, const char *value) {
|
||||
nvram_init();
|
||||
ucix_add_option(ctx, "broadcom", "nvram", filter_dots_in_string(name), value);
|
||||
ucix_commit(ctx, "broadcom");
|
||||
if (nvram_debug)
|
||||
printf("nvram_set(%s, %s)\n", filter_dots_in_string(name), value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unset an NVRAM variable. Pointers to previously set values
|
||||
* remain valid until a set.
|
||||
* @param name name of variable to unset
|
||||
* @return 0 on success and errno on failure
|
||||
* NOTE: use nvram_commit to commit this change to flash.
|
||||
*/
|
||||
int nvram_unset(const char *name){
|
||||
nvram_init();
|
||||
ucix_del(ctx, "broadcom", "nvram", filter_dots_in_string(name));
|
||||
ucix_commit(ctx, "broadcom");
|
||||
if (nvram_debug)
|
||||
printf("nvram_unset(%s)\n", filter_dots_in_string(name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Commit NVRAM variables to permanent storage. All pointers to values
|
||||
* may be invalid after a commit.
|
||||
* NVRAM values are undefined after a commit.
|
||||
* @return 0 on success and errno on failure
|
||||
*/
|
||||
int nvram_commit(void){
|
||||
nvram_init();
|
||||
ucix_commit(ctx, "broadcom");
|
||||
if (nvram_debug)
|
||||
printf("nvram_commit()\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get all NVRAM variables (format name=value\0 ... \0\0).
|
||||
* @param buf buffer to store variables
|
||||
* @param count size of buffer in bytes
|
||||
* @return 0 on success and errno on failure
|
||||
*/
|
||||
int nvram_getall(char *nvram_buf, int count) {
|
||||
nvram_init();
|
||||
|
||||
ptr.package = "broadcom";
|
||||
ptr.section = "nvram";
|
||||
|
||||
if (uci_lookup_ptr(ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return 1;
|
||||
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return 1;
|
||||
|
||||
nvram_display_section(ptr.s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <uci_config.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
static struct uci_ptr ptr;
|
||||
|
||||
static inline int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
memset(&ptr, 0, sizeof(ptr));
|
||||
ptr.package = p;
|
||||
ptr.section = s;
|
||||
ptr.option = o;
|
||||
ptr.value = t;
|
||||
return uci_lookup_ptr(ctx, &ptr, NULL, true);
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init(const char *config_file)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
uci_add_delta_path(ctx, "/var/state");
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init_path(const char *path, const char *config_file)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if(path)
|
||||
uci_set_confdir(ctx, path);
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ucix_cleanup(struct uci_context *ctx)
|
||||
{
|
||||
uci_free_context(ctx);
|
||||
}
|
||||
|
||||
void ucix_save(struct uci_context *ctx)
|
||||
{
|
||||
uci_set_savedir(ctx, "/tmp/.uci/");
|
||||
uci_save(ctx, NULL);
|
||||
}
|
||||
|
||||
void ucix_save_state(struct uci_context *ctx)
|
||||
{
|
||||
uci_set_savedir(ctx, "/var/state/");
|
||||
uci_save(ctx, NULL);
|
||||
}
|
||||
|
||||
const char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
const char *value = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return NULL;
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return NULL;
|
||||
e = ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_SECTION:
|
||||
value = uci_to_section(e)->type;
|
||||
break;
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(ptr.o->type) {
|
||||
case UCI_TYPE_STRING:
|
||||
value = ptr.o->v.string;
|
||||
break;
|
||||
default:
|
||||
value = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def)
|
||||
{
|
||||
const char *tmp = ucix_get_option(ctx, p, s, o);
|
||||
int ret = def;
|
||||
|
||||
if (tmp)
|
||||
ret = atoi(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, t))
|
||||
return;
|
||||
uci_set(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, o, (t)?(t):("")))
|
||||
return;
|
||||
uci_set(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_option(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if(!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_delete(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if(!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_revert(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&ptr.p->sections, e)
|
||||
if (!strcmp(t, uci_to_section(e)->type))
|
||||
cb(e->name, priv);
|
||||
}
|
||||
|
||||
int ucix_commit(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
return uci_commit(ctx, &ptr.p, false);
|
||||
}
|
||||
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#ifndef _UCI_H__
|
||||
#define _UCI_H__
|
||||
struct uci_context* ucix_init(const char *config_file);
|
||||
struct uci_context* ucix_init_path(const char *path, const char *config_file);
|
||||
void ucix_cleanup(struct uci_context *ctx);
|
||||
void ucix_save(struct uci_context *ctx);
|
||||
void ucix_save_state(struct uci_context *ctx);
|
||||
const char* ucix_get_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
int ucix_get_option_int(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, int def);
|
||||
void ucix_add_section(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *t);
|
||||
void ucix_add_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, const char *t);
|
||||
void ucix_add_option_int(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, int t);
|
||||
int ucix_commit(struct uci_context *ctx, const char *p);
|
||||
void ucix_revert(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
void ucix_del(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o);
|
||||
#endif
|
||||
|
|
@ -9,8 +9,21 @@ include $(TOPDIR)/rules.mk
|
|||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=peripheral_manager
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_VERSION:=33e6a0266eb3459de56b31858e4eb797623cfd5c
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/peripheral_manager
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:peripheral_manager
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
# support parallel build
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
|
|
@ -27,7 +40,7 @@ define Package/peripheral_manager
|
|||
CATEGORY:=Utilities
|
||||
TITLE:=Application deamon for handling of peripheral
|
||||
URL:=
|
||||
DEPENDS:=+libuci +libubus +libblobmsg-json +bcmkernel
|
||||
DEPENDS:=+libuci +libubus +libblobmsg-json bcmkernel
|
||||
endef
|
||||
|
||||
define Package/peripheral_manager/description
|
||||
|
|
@ -39,23 +52,13 @@ TARGET_CPPFLAGS := \
|
|||
-I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx \
|
||||
$(TARGET_CPPFLAGS)
|
||||
|
||||
# In future get the git. unpack it in src.
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
$(CP) ./files/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Package/peripheral_manager/install
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/
|
||||
$(INSTALL_DIR) $(1)/etc/init.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/peripheral_manager $(1)/sbin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gpio_test $(1)/sbin/
|
||||
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/etc/init.d/* $(1)/etc/init.d/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,peripheral_manager))
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
#PRG_VERSION := $(shell cd @top_srcdir@; if ! git describe --tags ;then echo version-$(PACKAGE_VERSION) ;fi )
|
||||
|
||||
AM_CFLAGS = $(OUR_CFLAGS)
|
||||
|
||||
bin_PROGRAMS = peripheral_manager
|
||||
dist_data_DATA = configs/hw
|
||||
|
||||
peripheral_manager_SOURCES = \
|
||||
src/peripheral_manager.c \
|
||||
src/ucix.c \
|
||||
src/ucix.h \
|
||||
src/server.c \
|
||||
src/server.h \
|
||||
src/led.c \
|
||||
src/led.h \
|
||||
src/sim_led.c \
|
||||
src/button.h \
|
||||
src/button.c \
|
||||
src/sim_button.c \
|
||||
src/catv.c \
|
||||
src/catv_monitor.c \
|
||||
src/catv.h \
|
||||
src/smbus.c \
|
||||
src/smbus.h \
|
||||
src/i2c.c \
|
||||
src/i2c.h \
|
||||
src/sfp.c \
|
||||
src/sfp.h
|
||||
|
||||
if BRCM_BOARD
|
||||
|
||||
bin_PROGRAMS += vox_test gpio_test
|
||||
|
||||
peripheral_manager_SOURCES += \
|
||||
src/gpio_led.c \
|
||||
src/gpio_led.h \
|
||||
src/gpio_button.c \
|
||||
src/gpio_button.h \
|
||||
src/gpio.c \
|
||||
src/gpio.h \
|
||||
src/gpio_shift_register.c \
|
||||
src/gpio_shift_register.h \
|
||||
src/touch_sx9512.c \
|
||||
src/touch_sx9512.h \
|
||||
src/sx9512.c \
|
||||
src/sx9512.h \
|
||||
src/vox.h \
|
||||
src/vox.c \
|
||||
src/prox_px3220.c
|
||||
|
||||
vox_test_SOURCES = \
|
||||
src/vox_test.c \
|
||||
src/gpio.c \
|
||||
src/gpio.h
|
||||
|
||||
gpio_test_SOURCES = \
|
||||
src/gpio_test.c \
|
||||
src/gpio.c \
|
||||
src/gpio.h \
|
||||
src/gpio_shift_register.c \
|
||||
src/gpio_shift_register.h \
|
||||
src/smbus.c \
|
||||
src/smbus.h \
|
||||
src/i2c.c \
|
||||
src/i2c.h \
|
||||
src/sx9512.c \
|
||||
src/sx9512.h
|
||||
|
||||
endif
|
||||
|
||||
peripheral_manager_LDADD = $(UCI_LIB) $(UBOX_LIB) $(UBUS_LIB) -lm
|
||||
|
||||
peripheral_manager_CFLAGS = $(AM_CFLAGS) -DPRG_VERSION=\"$(PRG_VERSION)\"
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
# test config for peripheral_manager
|
||||
# only contain options that peripheral_manager needs and that can be used
|
||||
# when compiling to host (not target hardware)
|
||||
|
||||
config board 'board'
|
||||
option hardware 'CG300'
|
||||
|
||||
# for CATV parsing we need this hardware
|
||||
# option hardware 'EG300'
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example for low level button.
|
||||
#
|
||||
#
|
||||
|
||||
config sim_button sim_buttons
|
||||
list buttons sim_button_A
|
||||
list buttons sim_button_B
|
||||
list buttons sim_button_c
|
||||
list buttons sim_button_d
|
||||
list buttons sim_button_e
|
||||
|
||||
config sim_button sim_button_A
|
||||
option addr 10
|
||||
option active hi
|
||||
|
||||
config sim_button sim_button_B
|
||||
option addr 11
|
||||
option active low
|
||||
|
||||
config sim_button sim_button_c
|
||||
option addr 12
|
||||
option active hi
|
||||
|
||||
config sim_button sim_button_d
|
||||
option addr 13
|
||||
option active hi
|
||||
|
||||
config sim_button sim_button_e
|
||||
option addr 14
|
||||
option active hi
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example for mapping system button to driver button.
|
||||
#
|
||||
# mapping serveral "functions" buttons to one physical can be done with the long press option
|
||||
# if
|
||||
#
|
||||
# this is a list of all button names. perifmanger will read this list then read out the specific button config
|
||||
|
||||
config button_map button_map
|
||||
list buttonnames RESET
|
||||
list buttonnames Wireless
|
||||
list buttonnames WPS
|
||||
list buttonnames DECTS
|
||||
list buttonnames DECTL
|
||||
list buttonnames TOUCH_NEAR
|
||||
list buttonnames TOUCH_FAR
|
||||
option minpress 100 # default minimum time a button nedes to be pressed.
|
||||
|
||||
config button_map RESET
|
||||
# list button gpio_reset
|
||||
list button sim_button_A # driver that is used for this button
|
||||
option minpress 5000 # don't allow button unless pressed for 5 seconds.
|
||||
option hotplug resetbutton
|
||||
|
||||
config button_map Wireless
|
||||
list button sim_button_B # driver that is used for this button
|
||||
list button sim_button_c # we support user having to press two at the same time to register a button event.
|
||||
option minpress 1000
|
||||
option hotplug ecobutton
|
||||
|
||||
# long press example one or the other of touch_near or touch_far will trigger not booth.
|
||||
|
||||
config button_map TOUCH_NEAR
|
||||
list button gpio_reset
|
||||
# list button sim_button_d # driver that is used for this button
|
||||
option hotplug touch_near
|
||||
|
||||
config button_map TOUCH_FAR
|
||||
list button sim_button_d # driver that is used for this button
|
||||
option longpress 3000 # this button has a long press option.
|
||||
option hotplug touch_far
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example for low level led driver.
|
||||
# here we list what the led can do and any info the driver needs to know to controll the led.
|
||||
#
|
||||
# would proably be smarter to name the leds as the color and not just A B C.
|
||||
# but this is an example to show there is no connection with the name and what it
|
||||
# does.
|
||||
#
|
||||
config sim_led sim_leds
|
||||
list leds sim_led_A
|
||||
list leds sim_led_B
|
||||
list leds sim_led_C
|
||||
|
||||
config sim_led sim_led_A
|
||||
option addr 1
|
||||
option color green
|
||||
option breading no
|
||||
|
||||
config sim_led sim_led_B
|
||||
option addr 7
|
||||
option color red
|
||||
option breading no
|
||||
|
||||
config sim_led sim_led_C
|
||||
option addr 3
|
||||
option color blue
|
||||
option breading yes
|
||||
option fadein yes
|
||||
option fadeout yes
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# gpio leds
|
||||
#
|
||||
config gpio_led gpio_leds
|
||||
list leds Status_green
|
||||
list leds Status_red
|
||||
list leds Wireless_green
|
||||
list leds Wireless_blue
|
||||
list leds WAN_green
|
||||
list leds WAN_yellow
|
||||
|
||||
config gpio_led Status_green
|
||||
option addr 39
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led Status_red
|
||||
option addr 38
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led Wireless_green
|
||||
option addr 37
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led Wireless_blue
|
||||
option addr 36
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led WAN_green
|
||||
option addr 9
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led WAN_yellow
|
||||
option addr 10
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# gpio buttons
|
||||
#
|
||||
|
||||
config gpio_button gpio_buttons
|
||||
list buttons gpio_reset
|
||||
|
||||
config gpio_button gpio_reset
|
||||
option addr 32
|
||||
option active low
|
||||
# option feedback
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example mapping sim leds to system leds.
|
||||
#
|
||||
# the led_action list can be from one entry and up.
|
||||
#
|
||||
# led_action, list of leds to set.
|
||||
# button_action. list of button events to send out
|
||||
# effect_action, list of special effects to activate. (dim display.....)
|
||||
#
|
||||
|
||||
config led_map led_map
|
||||
list functions status
|
||||
list functions wifi
|
||||
list functions wps
|
||||
|
||||
config led_map led_status
|
||||
list led_action_ok 'sim_led_A = ON'
|
||||
list led_action_ok 'sim_led_B = OFF'
|
||||
list led_action_off 'sim_led_A = OFF'
|
||||
list led_action_off 'sim_led_B = OFF'
|
||||
list led_action_notice 'sim_led_A = FLASH_SLOW'
|
||||
list led_action_notice 'sim_led_B = OFF'
|
||||
list led_action_alert 'sim_led_A = OFF'
|
||||
list led_action_alert 'sim_led_B = FLASH_SLOW'
|
||||
list led_action_error 'sim_led_A = OFF'
|
||||
list led_action_error 'sim_led_B = FLASH_FAST'
|
||||
|
||||
config led_map led_wps
|
||||
# list led_action_ok 'WPS_green=ON'
|
||||
# list led_action_off 'WPS_green=OFF'
|
||||
# list led_action_notice 'WPS_green=FLASH_SLOW'
|
||||
# list led_action_alert 'WPS_green=FLASH_FAST'
|
||||
# list led_action_error 'WPS_green=OFF'
|
||||
|
||||
config led_map led_wifi
|
||||
# list led_action_ok 'Wireless_green = ON'
|
||||
# list led_action_ok 'Wireless_blue = OFF'
|
||||
# list led_action_eok 'Wireless_green = OFF'
|
||||
# list led_action_eok 'Wireless_blue = ON'
|
||||
# list led_action_off 'Wireless_green = OFF'
|
||||
# list led_action_off 'Wireless_blue = OFF'
|
||||
# list led_action_notice 'Wireless_green = FLASH_SLOW'
|
||||
# list led_action_notice 'Wireless_blue = OFF'
|
||||
# list led_action_alert 'Wireless_green = OFF'
|
||||
# list led_action_alert 'Wireless_blue = FLASH_SLOW'
|
||||
# list led_action_error 'Wireless_green = OFF'
|
||||
# list led_action_error 'Wireless_blue = FLASH_FAST'
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# function superfunctions
|
||||
#
|
||||
# Used when one led is controlled by seferal different functions
|
||||
# here we map in what state the underlying normal functions should have
|
||||
# to set a state, and what action to take in that state.
|
||||
|
||||
|
||||
# list available super functions.
|
||||
config led_map led_map
|
||||
list functions super_a
|
||||
|
||||
config led_map led_super_a
|
||||
list led_action_ok sim_led_C=ON
|
||||
list super_ok 'wifi_ok, wps_ok'
|
||||
|
||||
list led_action_off sim_led_C=OFF
|
||||
list super_off 'wifi_off, wps_off'
|
||||
|
||||
list led_action_notice sim_led_C=FLASH_SLOW
|
||||
list super_notice 'wifi_notice'
|
||||
list super_notice 'wps_notice'
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
dnl init stuff needs to be first in file
|
||||
AC_INIT([peripheral_manager], [0.1], [Kenneth Johansson <kenneth@southpole.se>])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
||||
CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
|
||||
-std=gnu11 \
|
||||
-pipe \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-inline \
|
||||
-Wundef \
|
||||
"-Wformat=2 -Wformat-security -Wformat-nonliteral" \
|
||||
-Wlogical-op \
|
||||
-Wsign-compare \
|
||||
-Wmissing-include-dirs \
|
||||
-Wold-style-definition \
|
||||
-Wpointer-arith \
|
||||
-Winit-self \
|
||||
-Wdeclaration-after-statement \
|
||||
-Wfloat-equal \
|
||||
-Wsuggest-attribute=noreturn \
|
||||
-Wmissing-prototypes \
|
||||
-Wstrict-prototypes \
|
||||
-Wredundant-decls \
|
||||
-Wmissing-declarations \
|
||||
-Wmissing-noreturn \
|
||||
-Wshadow \
|
||||
-Wendif-labels \
|
||||
-Wstrict-aliasing=2 \
|
||||
-Wwrite-strings \
|
||||
-Wno-long-long \
|
||||
-Wno-overlength-strings \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-unused-result \
|
||||
-Werror=overflow \
|
||||
-Wdate-time \
|
||||
-Wnested-externs \
|
||||
-ffast-math \
|
||||
-fno-common \
|
||||
-fdiagnostics-show-option \
|
||||
-fno-strict-aliasing \
|
||||
-fvisibility=hidden \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fstack-protector \
|
||||
-fstack-protector-strong \
|
||||
-fPIE \
|
||||
--param=ssp-buffer-size=4])
|
||||
|
||||
AC_SUBST([OUR_CFLAGS], "$with_cflags")
|
||||
|
||||
dnl check for uci , its manadatory
|
||||
AC_SEARCH_LIBS([uci_load], [uci], [], [AC_MSG_ERROR([*** UCI library not found])])
|
||||
|
||||
dnl check ubox , its manadatory
|
||||
AC_SEARCH_LIBS([uloop_init], [ubox], [], [AC_MSG_ERROR([*** UBOX library not found])])
|
||||
|
||||
dnl chek ubus , its manadatory
|
||||
AC_SEARCH_LIBS([ubus_connect], [ubus], [], [AC_MSG_ERROR([*** UBUS library not found])])
|
||||
|
||||
dnl check for board.h file
|
||||
AC_CHECK_HEADERS(board.h, AM_CONDITIONAL(BRCM_BOARD, true), AM_CONDITIONAL(BRCM_BOARD, false))
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([
|
||||
$PACKAGE_NAME $VERSION
|
||||
CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
|
||||
CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
||||
LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
|
||||
])
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
dnl Macros to check the presence of generic (non-typed) symbols.
|
||||
dnl Copyright (c) 2006-2008 Diego Pettenò <flameeyes@gmail.com>
|
||||
dnl Copyright (c) 2006-2008 xine project
|
||||
dnl Copyright (c) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2, or (at your option)
|
||||
dnl any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
dnl 02110-1301, USA.
|
||||
dnl
|
||||
dnl As a special exception, the copyright owners of the
|
||||
dnl macro gives unlimited permission to copy, distribute and modify the
|
||||
dnl configure scripts that are the output of Autoconf when processing the
|
||||
dnl Macro. You need not follow the terms of the GNU General Public
|
||||
dnl License when using or distributing such scripts, even though portions
|
||||
dnl of the text of the Macro appear in them. The GNU General Public
|
||||
dnl License (GPL) does govern all other use of the material that
|
||||
dnl constitutes the Autoconf Macro.
|
||||
dnl
|
||||
dnl This special exception to the GPL applies to versions of the
|
||||
dnl Autoconf Macro released by this project. When you make and
|
||||
dnl distribute a modified version of the Autoconf Macro, you may extend
|
||||
dnl this special exception to the GPL to apply to your modified version as
|
||||
dnl well.
|
||||
|
||||
dnl Check if FLAG in ENV-VAR is supported by compiler and append it
|
||||
dnl to WHERE-TO-APPEND variable
|
||||
dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG])
|
||||
|
||||
AC_DEFUN([CC_CHECK_FLAG_APPEND], [
|
||||
AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2],
|
||||
AS_TR_SH([cc_cv_$2_$3]),
|
||||
[eval "AS_TR_SH([cc_save_$2])='${$2}'"
|
||||
eval "AS_TR_SH([$2])='-Werror $3'"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; } ])],
|
||||
[eval "AS_TR_SH([cc_cv_$2_$3])='yes'"],
|
||||
[eval "AS_TR_SH([cc_cv_$2_$3])='no'"])
|
||||
eval "AS_TR_SH([$2])='$cc_save_$2'"])
|
||||
|
||||
AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes],
|
||||
[eval "$1='${$1} $3'"])
|
||||
])
|
||||
|
||||
dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2])
|
||||
AC_DEFUN([CC_CHECK_FLAGS_APPEND], [
|
||||
for flag in $3; do
|
||||
CC_CHECK_FLAG_APPEND($1, $2, $flag)
|
||||
done
|
||||
])
|
||||
|
||||
dnl Check if the flag is supported by linker (cacheable)
|
||||
dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
|
||||
|
||||
AC_DEFUN([CC_CHECK_LDFLAGS], [
|
||||
AC_CACHE_CHECK([if $CC supports $1 flag],
|
||||
AS_TR_SH([cc_cv_ldflags_$1]),
|
||||
[ac_save_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $1"
|
||||
AC_LINK_IFELSE([int main() { return 1; }],
|
||||
[eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
|
||||
[eval "AS_TR_SH([cc_cv_ldflags_$1])="])
|
||||
LDFLAGS="$ac_save_LDFLAGS"
|
||||
])
|
||||
|
||||
AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
|
||||
[$2], [$3])
|
||||
])
|
||||
|
||||
dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
|
||||
dnl the current linker to avoid undefined references in a shared object.
|
||||
AC_DEFUN([CC_NOUNDEFINED], [
|
||||
dnl We check $host for which systems to enable this for.
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
|
||||
case $host in
|
||||
dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
|
||||
dnl are requested, as different implementations are present; to avoid problems
|
||||
dnl use -Wl,-z,defs only for those platform not behaving this way.
|
||||
*-freebsd* | *-openbsd*) ;;
|
||||
*)
|
||||
dnl First of all check for the --no-undefined variant of GNU ld. This allows
|
||||
dnl for a much more readable command line, so that people can understand what
|
||||
dnl it does without going to look for what the heck -z defs does.
|
||||
for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
|
||||
CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
|
||||
break
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST([LDFLAGS_NOUNDEFINED])
|
||||
])
|
||||
|
||||
dnl Check for a -Werror flag or equivalent. -Werror is the GCC
|
||||
dnl and ICC flag that tells the compiler to treat all the warnings
|
||||
dnl as fatal. We usually need this option to make sure that some
|
||||
dnl constructs (like attributes) are not simply ignored.
|
||||
dnl
|
||||
dnl Other compilers don't support -Werror per se, but they support
|
||||
dnl an equivalent flag:
|
||||
dnl - Sun Studio compiler supports -errwarn=%all
|
||||
AC_DEFUN([CC_CHECK_WERROR], [
|
||||
AC_CACHE_CHECK(
|
||||
[for $CC way to treat warnings as errors],
|
||||
[cc_cv_werror],
|
||||
[CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
|
||||
[CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_CHECK_ATTRIBUTE], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
|
||||
AS_TR_SH([cc_cv_attribute_$1]),
|
||||
[ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
|
||||
[eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
|
||||
[eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
])
|
||||
|
||||
AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
|
||||
[AC_DEFINE(
|
||||
AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
|
||||
[Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
|
||||
)
|
||||
$4],
|
||||
[$5])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[constructor],,
|
||||
[void __attribute__((constructor)) ctor() { int a; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[format], [format(printf, n, n)],
|
||||
[void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[format_arg], [format_arg(printf)],
|
||||
[char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[visibility_$1], [visibility("$1")],
|
||||
[void __attribute__((visibility("$1"))) $1_function() { }],
|
||||
[$2], [$3])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[nonnull], [nonnull()],
|
||||
[void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[unused], ,
|
||||
[void some_function(void *foo, __attribute__((unused)) void *bar);],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[sentinel], ,
|
||||
[void some_function(void *foo, ...) __attribute__((sentinel));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[deprecated], ,
|
||||
[void some_function(void *foo, ...) __attribute__((deprecated));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[alias], [weak, alias],
|
||||
[void other_function(void *foo) { }
|
||||
void some_function(void *foo) __attribute__((weak, alias("other_function")));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[malloc], ,
|
||||
[void * __attribute__((malloc)) my_alloc(int n);],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_PACKED], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[packed], ,
|
||||
[struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_CONST], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[const], ,
|
||||
[int __attribute__((const)) twopow(int n) { return 1 << n; } ],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_FLAG_VISIBILITY], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
|
||||
[cc_cv_flag_visibility],
|
||||
[cc_flag_visibility_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
|
||||
cc_cv_flag_visibility='yes',
|
||||
cc_cv_flag_visibility='no')
|
||||
CFLAGS="$cc_flag_visibility_save_CFLAGS"])
|
||||
|
||||
AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
|
||||
[AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
|
||||
[Define this if the compiler supports the -fvisibility flag])
|
||||
$1],
|
||||
[$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_FUNC_EXPECT], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([if compiler has __builtin_expect function],
|
||||
[cc_cv_func_expect],
|
||||
[ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
|
||||
[int some_function() {
|
||||
int a = 3;
|
||||
return (int)__builtin_expect(a, 3);
|
||||
}])],
|
||||
[cc_cv_func_expect=yes],
|
||||
[cc_cv_func_expect=no])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
])
|
||||
|
||||
AS_IF([test "x$cc_cv_func_expect" = "xyes"],
|
||||
[AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
|
||||
[Define this if the compiler supports __builtin_expect() function])
|
||||
$1],
|
||||
[$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
|
||||
[cc_cv_attribute_aligned],
|
||||
[ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
for cc_attribute_align_try in 64 32 16 8 4 2; do
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int main() {
|
||||
static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
|
||||
return c;
|
||||
}])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
|
||||
done
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_aligned" != "x"; then
|
||||
AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
|
||||
[Define the highest alignment supported])
|
||||
fi
|
||||
])
|
||||
|
|
@ -1,545 +0,0 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
#include "config.h"
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include "log.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "touch_sx9512.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
|
||||
static struct ubus_context *global_ubus_ctx;
|
||||
static struct blob_buf bblob;
|
||||
|
||||
static void button_ubus_interface_event(struct ubus_context *ubus_ctx, char *button, button_state_t pressed);
|
||||
|
||||
static void button_ubus_interface_event(struct ubus_context *ubus_ctx, char *button, button_state_t pressed)
|
||||
{
|
||||
char s[UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN];
|
||||
s[0]=0;
|
||||
strcat(s, UBUS_BUTTON_NAME_PREPEND);
|
||||
strcat(s, button);
|
||||
blob_buf_init(&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "action", pressed ? "pressed" : "released");
|
||||
ubus_send_event(ubus_ctx, s, bblob.head);
|
||||
}
|
||||
|
||||
|
||||
/* used to map in the driver buttons to a function button */
|
||||
struct button_drv_list {
|
||||
struct list_head list;
|
||||
struct timespec pressed_time;
|
||||
struct button_drv *drv;
|
||||
};
|
||||
|
||||
/**/
|
||||
struct function_button {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
int dimming;
|
||||
char *hotplug;
|
||||
char *hotplug_long;
|
||||
int minpress;
|
||||
int longpress; /* negative value means valid if mintime < time < abs(longpress ) */
|
||||
/* positive value means valid if time > longpreass */
|
||||
/* zero value means valid if time > mintime */
|
||||
struct list_head drv_list; /* list of all driver button that is needed to activate this button function */
|
||||
};
|
||||
|
||||
/* PUT every button from drivers into a list */
|
||||
struct drv_button_list{
|
||||
struct list_head list;
|
||||
struct button_drv *drv;
|
||||
};
|
||||
|
||||
/* list of all driver buttons added by drivers. */
|
||||
static LIST_HEAD(drv_buttons_list);
|
||||
|
||||
/* list containing all function buttons read from config file */
|
||||
static LIST_HEAD(buttons);
|
||||
|
||||
|
||||
void button_add( struct button_drv *drv)
|
||||
{
|
||||
struct drv_button_list *drv_node = malloc(sizeof(struct drv_button_list));
|
||||
|
||||
DBG(1,"called with button name [%s]", drv->name);
|
||||
drv_node->drv = drv;
|
||||
|
||||
list_add(&drv_node->list, &drv_buttons_list);
|
||||
}
|
||||
|
||||
static struct button_drv *get_drv_button(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_buttons_list) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
if (! strcmp(node->drv->name, name))
|
||||
return node->drv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct function_button *get_button(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if (! strcmp(node->name, name))
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! Read state for single button
|
||||
static button_state_t read_button_state(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
#ifdef HAVE_BOARD_H
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if(!strcmp(node->name, name)) {
|
||||
button_state_t state=BUTTON_ERROR;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv) {
|
||||
if(drv_node->drv->func->get_state(drv_node->drv))
|
||||
return BUTTON_PRESSED;
|
||||
else
|
||||
state=BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return BUTTON_ERROR;
|
||||
}
|
||||
|
||||
struct button_status {
|
||||
char name[BUTTON_MAX_NAME_LEN];
|
||||
button_state_t state;
|
||||
};
|
||||
|
||||
struct button_status_all {
|
||||
int n;
|
||||
struct button_status status[BUTTON_MAX];
|
||||
};
|
||||
|
||||
|
||||
//! Read states for all buttons
|
||||
static struct button_status_all * read_button_states(void)
|
||||
{
|
||||
static struct button_status_all p;
|
||||
struct list_head *i;
|
||||
p.n=0;
|
||||
#ifdef HAVE_BOARD_H
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
button_state_t state=BUTTON_ERROR;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
strcpy(p.status[p.n].name, node->name);
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv) {
|
||||
if(drv_node->drv->func->get_state(drv_node->drv))
|
||||
state=BUTTON_PRESSED;
|
||||
else
|
||||
state=BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
p.status[p.n].state = state;
|
||||
p.n++;
|
||||
}
|
||||
return &p;
|
||||
}
|
||||
|
||||
static void dump_drv_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_buttons_list) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
DBG(1,"button name = [%s]",node->drv->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_buttons_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
DBG(1,"button name = [%s]",node->name);
|
||||
{
|
||||
struct list_head *j;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv != NULL)
|
||||
DBG(1,"%13s drv button name = [%s]","",drv_node->drv->name);
|
||||
}
|
||||
DBG(1,"%13s minpress = %d","",node->minpress);
|
||||
DBG(1,"%13s longpress = %d","",node->longpress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Run the hotplug command associated with function button
|
||||
//! @retval 0 ok
|
||||
static int button_hotplug_cmd(const char *name, bool longpress)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if(!strcmp(node->name, name)) {
|
||||
char str[512];
|
||||
char *hotplug = node->hotplug;
|
||||
if(longpress && node->hotplug_long)
|
||||
hotplug = node->hotplug_long;
|
||||
if(!hotplug)
|
||||
return 1;
|
||||
DBG(1, "send key %s [%s] to system %s", node->name, hotplug, longpress ? "(longpress)" : "");
|
||||
snprintf(str, 512, "ACTION=register INTERFACE=%s /sbin/hotplug-call button &", hotplug);
|
||||
system(str);
|
||||
syslog(LOG_INFO, "%s",str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int timer_started(struct button_drv_list *button_drv)
|
||||
{
|
||||
if (button_drv->pressed_time.tv_sec == 0 )
|
||||
if (button_drv->pressed_time.tv_nsec == 0 )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void timer_start(struct button_drv_list *button_drv)
|
||||
{
|
||||
clock_gettime(CLOCK_MONOTONIC, &button_drv->pressed_time);
|
||||
}
|
||||
|
||||
static void timer_stop(struct button_drv_list *button_drv)
|
||||
{
|
||||
button_drv->pressed_time.tv_sec = 0;
|
||||
button_drv->pressed_time.tv_nsec = 0;
|
||||
}
|
||||
|
||||
|
||||
static button_press_type_t timer_valid(struct button_drv_list *button_drv, int mtimeout, int longpress)
|
||||
{
|
||||
struct timespec now;
|
||||
int sec;
|
||||
int nsec;
|
||||
int time_elapsed;
|
||||
|
||||
if (timer_started(button_drv)) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
sec = now.tv_sec - button_drv->pressed_time.tv_sec;
|
||||
nsec = now.tv_nsec - button_drv->pressed_time.tv_nsec;
|
||||
time_elapsed = sec*1000 + nsec/1000000;
|
||||
if ( mtimeout < time_elapsed) {
|
||||
if (longpress && (longpress < time_elapsed))
|
||||
return BUTTON_PRESS_LONG;
|
||||
return BUTTON_PRESS_SHORT;
|
||||
}
|
||||
}
|
||||
return BUTTON_PRESS_NONE;
|
||||
}
|
||||
|
||||
#define BUTTON_TIMEOUT 100
|
||||
static void button_handler(struct uloop_timeout *timeout);
|
||||
static struct uloop_timeout button_inform_timer = { .cb = button_handler };
|
||||
|
||||
static void button_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct list_head *i;
|
||||
int r;
|
||||
// DBG(1, "");
|
||||
|
||||
#ifdef HAVE_BOARD_H
|
||||
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
|
||||
/* clean out indicator status, set by any valid press again if we find it */
|
||||
led_pressindicator_set(PRESS_NONE);
|
||||
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if (drv_node->drv) {
|
||||
button_press_type_t time_type;
|
||||
button_state_t st = drv_node->drv->func->get_state(drv_node->drv);
|
||||
|
||||
if (st == BUTTON_PRESSED ) {
|
||||
if (! timer_started(drv_node)) {
|
||||
timer_start(drv_node);
|
||||
DBG(1, " %s pressed", drv_node->drv->name);
|
||||
// button_ubus_interface_event(global_ubus_ctx, node->name, BUTTON_PRESSED);
|
||||
}
|
||||
|
||||
time_type = timer_valid(drv_node, node->minpress, node->longpress);
|
||||
if( time_type == BUTTON_PRESS_LONG )
|
||||
led_pressindicator_set(PRESS_LONG);
|
||||
if( time_type == BUTTON_PRESS_SHORT )
|
||||
led_pressindicator_set(PRESS_SHORT);
|
||||
}
|
||||
|
||||
if (st == BUTTON_RELEASED ) {
|
||||
if (timer_started(drv_node)) {
|
||||
DBG(1, " %s released", drv_node->drv->name);
|
||||
if((r=timer_valid(drv_node, node->minpress, node->longpress))) {
|
||||
button_ubus_interface_event(global_ubus_ctx, node->name, BUTTON_RELEASED);
|
||||
if(node->dimming)
|
||||
led_dimming();
|
||||
DBG(1, " %s released timer_valid=%d", drv_node->drv->name,r);
|
||||
button_hotplug_cmd(node->name, r==BUTTON_PRESS_LONG);
|
||||
}
|
||||
}
|
||||
timer_stop(drv_node);
|
||||
}
|
||||
// DBG(1, " %s state = %d", drv_node->drv->name,st);
|
||||
}
|
||||
}
|
||||
}
|
||||
uloop_timeout_set(&button_inform_timer, BUTTON_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
static int button_state_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
// button_state_t state = read_button_state(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN);
|
||||
blob_buf_init(&bblob, 0);
|
||||
|
||||
switch(read_button_state(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN)) {
|
||||
case BUTTON_RELEASED:
|
||||
blobmsg_add_string(&bblob, "state", "released");
|
||||
break;
|
||||
case BUTTON_PRESSED:
|
||||
blobmsg_add_string(&bblob, "state", "pressed");
|
||||
break;
|
||||
default:
|
||||
blobmsg_add_string(&bblob, "state", "error");
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int button_press_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
button_hotplug_cmd(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN, 0);
|
||||
blob_buf_init(&bblob, 0);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int button_press_long_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
button_hotplug_cmd(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN, 1);
|
||||
blob_buf_init(&bblob, 0);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int buttons_state_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
int i;
|
||||
static struct button_status_all *p;
|
||||
p = read_button_states();
|
||||
blob_buf_init(&bblob, 0);
|
||||
for(i=0;i < p->n; i++) {
|
||||
switch(p->status[i].state) {
|
||||
case BUTTON_RELEASED:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "released");
|
||||
break;
|
||||
case BUTTON_PRESSED:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "pressed");
|
||||
break;
|
||||
default:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "error");
|
||||
}
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct ubus_method button_methods[] = {
|
||||
// { .name = "status", .handler = button_status_method },
|
||||
{ .name = "state", .handler = button_state_method },
|
||||
{ .name = "press", .handler = button_press_method },
|
||||
{ .name = "press_long", .handler = button_press_long_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type button_object_type = UBUS_OBJECT_TYPE("button", button_methods);
|
||||
|
||||
|
||||
static const struct ubus_method buttons_methods[] = {
|
||||
{ .name = "state", .handler = buttons_state_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type buttons_object_type = UBUS_OBJECT_TYPE("buttons", buttons_methods);
|
||||
|
||||
static struct ubus_object buttons_object = { .name = "buttons", .type = &buttons_object_type, .methods = buttons_methods, .n_methods = ARRAY_SIZE(buttons_methods), };
|
||||
|
||||
|
||||
void button_init( struct server_ctx *s_ctx)
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttonnames);
|
||||
int default_minpress = 100;
|
||||
char *s;
|
||||
int r;
|
||||
|
||||
global_ubus_ctx=s_ctx->ubus_ctx;
|
||||
|
||||
/* register buttons object with ubus */
|
||||
if((r=ubus_add_object(s_ctx->ubus_ctx, &buttons_object)))
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(r));
|
||||
|
||||
/* read out default global options */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "button_map", "minpress");
|
||||
DBG(1, "default minpress = [%s]", s);
|
||||
if (s){
|
||||
default_minpress = strtol(s,0,0);
|
||||
}
|
||||
|
||||
/* read function buttons from section button_map */
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"button_map", "buttonnames", &buttonnames);
|
||||
list_for_each_entry(node, &buttonnames, list) {
|
||||
struct function_button *function;
|
||||
|
||||
// DBG(1, "value = [%s]",node->val);
|
||||
|
||||
function = malloc(sizeof(struct function_button));
|
||||
memset(function,0,sizeof(struct function_button));
|
||||
function->name = node->val;
|
||||
|
||||
/* read out dimming */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "dimming");
|
||||
DBG(1, "dimming = [%s]", s);
|
||||
if (s){
|
||||
function->dimming = 1;
|
||||
}else
|
||||
function->dimming = 0;
|
||||
|
||||
/* read out minpress */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "minpress");
|
||||
DBG(1, "minpress = [%s]", s);
|
||||
if (s){
|
||||
function->minpress = strtol(s,0,0);
|
||||
}else
|
||||
function->minpress = default_minpress;
|
||||
|
||||
/* read out long_press */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "longpress");
|
||||
DBG(1, "longpress = [%s]", s);
|
||||
if (s){
|
||||
function->longpress = strtol(s,0,0);
|
||||
}
|
||||
|
||||
/* read out hotplug option */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "hotplug");
|
||||
DBG(1, "hotplug = [%s]", s);
|
||||
if (s){
|
||||
function->hotplug = s;
|
||||
}
|
||||
|
||||
/* read out hotplug option for longpress */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "hotplug_long");
|
||||
DBG(1, "hotplug_long = [%s]", s);
|
||||
if (s){
|
||||
function->hotplug_long = s;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&function->drv_list);
|
||||
|
||||
{
|
||||
struct ucilist *drv_node;
|
||||
LIST_HEAD(head);
|
||||
int num = 0;
|
||||
|
||||
/* read out all driver buttons that needs to be pressed for this button function. */
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,function->name, "button", &head);
|
||||
|
||||
list_for_each_entry(drv_node, &head, list) {
|
||||
struct button_drv_list *new_button;
|
||||
|
||||
num++;
|
||||
DBG(1,"function %s -> drv button %s", function->name, drv_node->val);
|
||||
|
||||
new_button = malloc(sizeof(struct button_drv_list));
|
||||
memset(new_button,0,sizeof(struct button_drv_list));
|
||||
|
||||
new_button->drv = get_drv_button(drv_node->val);
|
||||
|
||||
if(new_button->drv == NULL){
|
||||
syslog(LOG_WARNING, "%s wanted drv button [%s] but it can't be found. check spelling.",
|
||||
function->name,
|
||||
drv_node->val);
|
||||
}
|
||||
|
||||
list_add( &new_button->list, &function->drv_list);
|
||||
}
|
||||
if (num == 0 )
|
||||
syslog(LOG_WARNING, "Function %s did not have any mapping to a driver button", function->name);
|
||||
}
|
||||
|
||||
list_add(&function->list, &buttons);
|
||||
|
||||
/* register each button with ubus */
|
||||
{
|
||||
struct ubus_object *ubo;
|
||||
char name[UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN];
|
||||
ubo = malloc(sizeof(struct ubus_object));
|
||||
memset(ubo, 0, sizeof(struct ubus_object));
|
||||
|
||||
snprintf(name, UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN, "%s%s", UBUS_BUTTON_NAME_PREPEND, node->val);
|
||||
ubo->name = strdup(name);
|
||||
ubo->methods = button_methods;
|
||||
ubo->n_methods = ARRAY_SIZE(button_methods);
|
||||
ubo->type = &button_object_type;
|
||||
if((r=ubus_add_object(s_ctx->ubus_ctx, ubo)))
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(r));
|
||||
}
|
||||
}
|
||||
|
||||
uloop_timeout_set(&button_inform_timer, BUTTON_TIMEOUT);
|
||||
|
||||
dump_drv_list();
|
||||
dump_buttons_list();
|
||||
}
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef BUTTON_H
|
||||
#define BUTTON_H
|
||||
#include "server.h"
|
||||
|
||||
#define BUTTON_MAX 32
|
||||
#define BUTTON_MAX_NAME_LEN 16
|
||||
#define UBUS_BUTTON_NAME_PREPEND "button."
|
||||
#define UBUS_BUTTON_NAME_PREPEND_LEN sizeof(UBUS_BUTTON_NAME_PREPEND)
|
||||
|
||||
typedef enum {
|
||||
BUTTON_RELEASED,
|
||||
BUTTON_PRESSED,
|
||||
BUTTON_ERROR,
|
||||
} button_state_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_PRESS_NONE,
|
||||
BUTTON_PRESS_SHORT,
|
||||
BUTTON_PRESS_LONG,
|
||||
} button_press_type_t;
|
||||
|
||||
struct button_drv;
|
||||
|
||||
struct button_drv_func {
|
||||
button_state_t (*get_state)(struct button_drv *); /* Get button state, on,off ... */
|
||||
};
|
||||
|
||||
struct button_drv {
|
||||
const char *name; /* name, set in the confg file,has to be uniq */
|
||||
void *priv; /* for use by the driver */
|
||||
struct button_drv_func *func; /* function pointers for reading the button */
|
||||
};
|
||||
|
||||
void button_add( struct button_drv *drv);
|
||||
void button_init( struct server_ctx *s_ctx);
|
||||
|
||||
#endif /* BUTTON_H */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef CATV_H
|
||||
#include "libubus.h"
|
||||
|
||||
#include "ucix.h"
|
||||
|
||||
struct catv_handler;
|
||||
|
||||
struct catv_handler * catv_init(struct uci_context *uci_ctx, const char * i2c_bus, int i2c_addr_a0,int i2c_addr_a2);
|
||||
void catv_destroy(struct catv_handler *h);
|
||||
int catv_ubus_populate(struct catv_handler *h, struct ubus_context *ubus_ctx);
|
||||
|
||||
#endif /* CATV_H */
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "log.h"
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include "libubus.h"
|
||||
#include <uci_config.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
typedef enum {
|
||||
STATE_OFF,
|
||||
STATE_OK,
|
||||
STATE_NOTICE,
|
||||
STATE_ALERT,
|
||||
STATE_ERROR,
|
||||
}state_t;
|
||||
|
||||
state_t state;
|
||||
|
||||
static struct ubus_context *ubus_ctx;
|
||||
static char *ubus_socket;
|
||||
|
||||
#define CATV_MONITOR_TIME (1000 * 10) /* 10 sec in ms */
|
||||
|
||||
void catv_monitor_init(struct server_ctx *s_ctx);
|
||||
void catv_monitor_set_socket(char *socket_name);
|
||||
|
||||
static void set_led(state_t state);
|
||||
static int is_enabled(void);
|
||||
|
||||
static void catv_monitor_handler(struct uloop_timeout *timeout);
|
||||
struct uloop_timeout catv_monitor_timer = { .cb = catv_monitor_handler };
|
||||
|
||||
static void
|
||||
catv_status_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
uint32_t rem;
|
||||
const char *data;
|
||||
|
||||
rem = blob_len(msg);
|
||||
|
||||
__blob_for_each_attr(cur, blob_data(msg), rem) {
|
||||
if (!strcmp("RF enable", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
if (!strncasecmp("on", data, 2))
|
||||
*(int*)req->priv = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*(int*)req->priv = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static int is_enabled(void)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf b;
|
||||
int enabled = 0;
|
||||
int ret;
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, "catv", &id)) {
|
||||
DBG(4, "Failed to look up catv object\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&b, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
ret = ubus_invoke(ubus_ctx, id, "status", b.head, catv_status_cb, &enabled, 3000);
|
||||
|
||||
if (ret)
|
||||
DBG(1,"catv_monitor: ret = %s", ubus_strerror(ret));
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static void
|
||||
catv_vpd_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
uint32_t rem;
|
||||
const char *data = "-inf";
|
||||
|
||||
rem = blob_len(msg);
|
||||
|
||||
/* no response */
|
||||
if ( rem == 0 ) {
|
||||
state = STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
__blob_for_each_attr(cur, blob_data(msg), rem) {
|
||||
if (!strcmp("VPD", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
}
|
||||
}
|
||||
|
||||
/* no cable */
|
||||
if (!strcmp("-inf", data)) {
|
||||
state = STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
catv_alarm_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
uint32_t rem;
|
||||
const char *data = "-inf";
|
||||
|
||||
rem = blob_len(msg);
|
||||
|
||||
/* no response */
|
||||
if ( rem == 0 ) {
|
||||
state = STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
__blob_for_each_attr(cur, blob_data(msg), rem) {
|
||||
if (!strcasecmp("Alarm VPD HI", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_ALERT;
|
||||
}
|
||||
}else if (!strcasecmp("Alarm VPD LO", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_ALERT;
|
||||
}
|
||||
}else if (!strcasecmp("Warning VPD HI", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_NOTICE;
|
||||
}
|
||||
}else if (!strcasecmp("Warning VPD LO", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_NOTICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void catv_monitor_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf b;
|
||||
int ret;
|
||||
|
||||
/* start to set new state to OK */
|
||||
/* then checks turn on different errors */
|
||||
state = STATE_OK;
|
||||
|
||||
if (is_enabled()) {
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, "catv", &id)) {
|
||||
DBG(1, "Failed to look up catv object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&b, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
/* first check alarms, they set notice/alert if present */
|
||||
ret = ubus_invoke(ubus_ctx, id, "alarm", b.head, catv_alarm_cb, 0, 3000);
|
||||
if (ret)
|
||||
DBG(1,"ret = %s", ubus_strerror(ret));
|
||||
|
||||
/* then check cable in, it sets Error,*/
|
||||
ret = ubus_invoke(ubus_ctx, id, "vpd", b.head, catv_vpd_cb, 0, 3000);
|
||||
if (ret)
|
||||
DBG(1,"ret = %s", ubus_strerror(ret));
|
||||
}else
|
||||
state = STATE_OFF;
|
||||
|
||||
set_led(state);
|
||||
|
||||
uloop_timeout_set(&catv_monitor_timer, CATV_MONITOR_TIME);
|
||||
}
|
||||
|
||||
static void set_led(state_t lstate)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf b;
|
||||
int ret;
|
||||
static state_t old_state = -1;
|
||||
|
||||
if ( lstate == old_state )
|
||||
return;
|
||||
old_state = lstate;
|
||||
|
||||
memset(&b, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
switch (lstate) {
|
||||
case STATE_OFF:
|
||||
blobmsg_add_string(&b, "state", "off"); break;
|
||||
case STATE_OK:
|
||||
blobmsg_add_string(&b, "state", "ok"); break;
|
||||
case STATE_NOTICE:
|
||||
blobmsg_add_string(&b, "state", "notice"); break;
|
||||
case STATE_ALERT:
|
||||
blobmsg_add_string(&b, "state", "alert"); break;
|
||||
case STATE_ERROR:
|
||||
blobmsg_add_string(&b, "state", "error"); break;
|
||||
}
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, "led.ext", &id)) {
|
||||
DBG(1, "Failed to look up led.ext object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ubus_invoke(ubus_ctx, id, "set", b.head, NULL, 0, 3000);
|
||||
|
||||
if ( ret )
|
||||
DBG(1,"catv_moitor: set led failed [%s]", ubus_strerror(ret));
|
||||
}
|
||||
|
||||
void catv_monitor_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
ubus_ctx = ubus_connect(ubus_socket);
|
||||
if (!ubus_ctx) {
|
||||
syslog(LOG_ERR,"catv monitor: Failed to connect to ubus\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* start monitor timer */
|
||||
uloop_timeout_set(&catv_monitor_timer, CATV_MONITOR_TIME);
|
||||
}
|
||||
|
||||
void catv_monitor_set_socket(char *socket_name)
|
||||
{
|
||||
if (socket_name)
|
||||
ubus_socket = strdup(socket_name);
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include "gpio.h"
|
||||
#include "log.h"
|
||||
|
||||
#define DEVFILE_BRCM_BOARD "/dev/brcmboard"
|
||||
|
||||
static int brcmboard = -1;
|
||||
|
||||
|
||||
int board_ioctl_init(void) {
|
||||
if (brcmboard == -1){
|
||||
brcmboard = open(DEVFILE_BRCM_BOARD, O_RDWR);
|
||||
if ( brcmboard == -1 ) {
|
||||
syslog(LOG_ERR, "failed to open: %s", DEVFILE_BRCM_BOARD);
|
||||
return 1;
|
||||
}
|
||||
DBG(1, "fd %d allocated\n", brcmboard);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_buf_len, int offset) {
|
||||
BOARD_IOCTL_PARMS IoctlParms = {0};
|
||||
|
||||
IoctlParms.string = string_buf;
|
||||
IoctlParms.strLen = string_buf_len;
|
||||
IoctlParms.offset = offset;
|
||||
IoctlParms.action = action;
|
||||
IoctlParms.buf = (char*)"";
|
||||
IoctlParms.result = 0;
|
||||
|
||||
if (brcmboard != -1){
|
||||
if ( ioctl(brcmboard, ioctl_id, &IoctlParms) < 0 ) {
|
||||
syslog(LOG_ERR, "ioctl: %d failed", ioctl_id);
|
||||
return(-255);
|
||||
}
|
||||
|
||||
}
|
||||
return IoctlParms.result;
|
||||
}
|
||||
|
||||
|
||||
gpio_state_t gpio_get_state(gpio_t gpio)
|
||||
{
|
||||
return board_ioctl(BOARD_IOCTL_GET_GPIO, 0, 0, NULL, gpio, 0);
|
||||
}
|
||||
|
||||
void gpio_set_state(gpio_t gpio, gpio_state_t state)
|
||||
{
|
||||
board_ioctl(BOARD_IOCTL_SET_GPIO, 0, 0, NULL, gpio, state);
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <board.h>
|
||||
|
||||
typedef int gpio_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_STATE_LOW,
|
||||
GPIO_STATE_HIGH,
|
||||
} gpio_state_t;
|
||||
|
||||
int board_ioctl_init(void);
|
||||
int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_buf_len, int offset);
|
||||
#define gpio_init() board_ioctl_init()
|
||||
gpio_state_t gpio_get_state(gpio_t gpio);
|
||||
void gpio_set_state(gpio_t gpio, gpio_state_t state);
|
||||
|
||||
#endif /* GPIO_H */
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "button.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "gpio.h"
|
||||
#include <board.h>
|
||||
|
||||
void gpio_button_init(struct server_ctx *s_ctx);
|
||||
|
||||
struct gpio_button_data {
|
||||
int addr;
|
||||
int active;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
static button_state_t gpio_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
struct gpio_button_data *p = (struct gpio_button_data *)drv->priv;
|
||||
int value;
|
||||
|
||||
value = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, p->addr, 0);
|
||||
|
||||
if(p->active)
|
||||
p->state = !!value;
|
||||
else
|
||||
p->state = !value;
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func func = {
|
||||
.get_state = gpio_button_get_state,
|
||||
};
|
||||
|
||||
void gpio_button_init(struct server_ctx *s_ctx) {
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"gpio_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct gpio_button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct gpio_button_data));
|
||||
memset(data,0,sizeof(struct gpio_button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "active");
|
||||
data->active = -1;
|
||||
if (s){
|
||||
if (!strncasecmp("hi",s,2))
|
||||
data->active = 1;
|
||||
else if (!strncasecmp("low",s,3))
|
||||
data->active = 0;
|
||||
|
||||
}
|
||||
DBG(1, "active = %d", data->active);
|
||||
|
||||
data->button.func = &func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
}
|
||||
|
||||
gpio_init();
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <board.h>
|
||||
#include "led.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_shift_register.h"
|
||||
|
||||
gpio_shift_register_t led_gpio_shift_register;
|
||||
|
||||
void gpio_led_init(struct server_ctx *s_ctx);
|
||||
|
||||
typedef enum {
|
||||
LOW,
|
||||
HI,
|
||||
UNKNOWN,
|
||||
} active_t;
|
||||
|
||||
typedef enum {
|
||||
MODE_UNKNOWN,
|
||||
DIRECT,
|
||||
SHIFTREG_BRCM,
|
||||
SHIFTREG_GPIO,
|
||||
} gpio_mode_t;
|
||||
|
||||
struct gpio_led_data {
|
||||
int addr;
|
||||
active_t active;
|
||||
int state;
|
||||
gpio_mode_t mode;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
static int gpio_led_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct gpio_led_data *p = (struct gpio_led_data *)drv->priv;
|
||||
int bit_val = 0;
|
||||
|
||||
if(state) {
|
||||
if(p->active)
|
||||
bit_val=1;
|
||||
} else {
|
||||
if(!p->active)
|
||||
bit_val=1;
|
||||
}
|
||||
|
||||
p->state = state;
|
||||
|
||||
switch (p->mode) {
|
||||
case DIRECT:
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, p->addr, bit_val);
|
||||
break;
|
||||
case SHIFTREG_BRCM:
|
||||
board_ioctl( BOARD_IOCTL_LED_CTRL, 0, 0, NULL, p->addr, bit_val);
|
||||
break;
|
||||
case SHIFTREG_GPIO:
|
||||
gpio_shift_register_cached_set(&led_gpio_shift_register, p->addr, bit_val);
|
||||
break;
|
||||
default:
|
||||
DBG(1,"access mode not supported [%d,%s]", p->mode, p->led.name);
|
||||
}
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static led_state_t gpio_led_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct gpio_led_data *p = (struct gpio_led_data *)drv->priv;
|
||||
DBG(1, "state for %s", drv->name);
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = gpio_led_set_state,
|
||||
.get_state = gpio_led_get_state,
|
||||
};
|
||||
|
||||
void gpio_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
int gpio_shiftreg_clk=0, gpio_shiftreg_dat=1, gpio_shiftreg_mask=2, gpio_shiftreg_bits=0;
|
||||
char *s;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_clk")))
|
||||
gpio_shiftreg_clk = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_clk = [%d]", gpio_shiftreg_clk);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_dat")))
|
||||
gpio_shiftreg_dat = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_dat = [%d]", gpio_shiftreg_dat);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_mask")))
|
||||
gpio_shiftreg_mask = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_mask = [%d]", gpio_shiftreg_mask);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_bits")))
|
||||
gpio_shiftreg_bits = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_bits = [%d]", gpio_shiftreg_bits);
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"gpio_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct gpio_led_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct gpio_led_data));
|
||||
memset(data,0,sizeof(struct gpio_led_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s) {
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "mode");
|
||||
DBG(1, "mode = [%s]", s);
|
||||
if (s) {
|
||||
|
||||
if (!strncasecmp("direct",s,3))
|
||||
data->mode = DIRECT;
|
||||
else if (!strncasecmp("sr",s,5))
|
||||
data->mode = SHIFTREG_BRCM;
|
||||
else if (!strncasecmp("csr",s,4))
|
||||
data->mode = SHIFTREG_GPIO;
|
||||
else
|
||||
DBG(1, "Mode %s : Not supported!", s);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "active");
|
||||
DBG(1, "active = [%s]", s);
|
||||
if (s) {
|
||||
data->active = UNKNOWN;
|
||||
if (!strncasecmp("hi",s,3))
|
||||
data->active = HI;
|
||||
if (!strncasecmp("low",s,3))
|
||||
data->active = LOW;
|
||||
}
|
||||
data->led.func = &func;
|
||||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
}
|
||||
gpio_init();
|
||||
gpio_shift_register_init(&led_gpio_shift_register, gpio_shiftreg_clk, gpio_shiftreg_dat, gpio_shiftreg_mask, gpio_shiftreg_bits);
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#include "gpio_shift_register.h"
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
int gpio_shift_register_init(gpio_shift_register_t *p, gpio_t gpio_clk, gpio_t gpio_dat, gpio_t gpio_mask, int size)
|
||||
{
|
||||
p->clk=gpio_clk;
|
||||
p->dat=gpio_dat;
|
||||
p->mask=gpio_mask;
|
||||
p->size=size;
|
||||
p->state_cache=0;
|
||||
gpio_set_state(p->clk, 0);
|
||||
gpio_set_state(p->dat, 0);
|
||||
gpio_set_state(p->mask, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_shift_register_set(gpio_shift_register_t *p, int state)
|
||||
{
|
||||
int i;
|
||||
if(!p->size)
|
||||
return;
|
||||
gpio_set_state(p->mask, 0); //mask low
|
||||
for(i=p->size; i; i--) {
|
||||
gpio_set_state(p->clk, 0); //clk low
|
||||
gpio_set_state(p->dat, (state>>(i-1)) & 1); //place bit
|
||||
gpio_set_state(p->clk, 1); //clk high
|
||||
}
|
||||
gpio_set_state(p->mask, 1); //mask high / sreg load
|
||||
p->state_cache=state; //update internal register copy
|
||||
}
|
||||
|
||||
|
||||
void gpio_shift_register_cached_set(gpio_shift_register_t *p, shift_register_index_t index, gpio_state_t state)
|
||||
{
|
||||
if(!p->size)
|
||||
return;
|
||||
if(!(index < p->size)) {
|
||||
syslog(LOG_ERR, "index %d out of bounds", index);
|
||||
return;
|
||||
}
|
||||
//update internal register copy
|
||||
if(state)
|
||||
p->state_cache |= (1<<index);
|
||||
else
|
||||
p->state_cache &= ~(1<<index);
|
||||
gpio_shift_register_set(p, p->state_cache);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef GPIO_SHIFT_REGISTER_H
|
||||
#define GPIO_SHIFT_REGISTER_H
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
typedef int shift_register_index_t;
|
||||
|
||||
typedef struct {
|
||||
gpio_t clk;
|
||||
gpio_t dat;
|
||||
gpio_t mask;
|
||||
int size;
|
||||
int state_cache;
|
||||
} gpio_shift_register_t;
|
||||
|
||||
int gpio_shift_register_init(gpio_shift_register_t *p, gpio_t gpio_clk, gpio_t gpio_dat, gpio_t gpio_mask, int size);
|
||||
void gpio_shift_register_set(gpio_shift_register_t *p, int state);
|
||||
void gpio_shift_register_cached_set(gpio_shift_register_t *p, shift_register_index_t address, gpio_state_t bit_val);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,376 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
//#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
//#include <limits.h>
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
//#include <syslog.h>
|
||||
//#include <config.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "smbus.h"
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_shift_register.h"
|
||||
#include "sx9512.h"
|
||||
|
||||
#define DEV_I2C "/dev/i2c-0"
|
||||
|
||||
int verbose, debug_level;
|
||||
|
||||
|
||||
#define CMDS \
|
||||
X(NONE, "none", 0, 0, "", "") \
|
||||
X(GPIO_GET, "gpio_get", 1, 1, "Get pin state", "<pin>") \
|
||||
X(GPIO_SET, "gpio_set", 2, 2, "Set pin state", "<pin> <state>") \
|
||||
X(SH_SET, "sh_set", 5, 5, "Set shift register state", "<clk> <dat> <mask> <size> <state>") \
|
||||
X(SMBUS_READ, "smbus_read", 3, 3, "Read from I2C/SMBUS device", "<addr> <reg> <len>") \
|
||||
X(SMBUS_WRITE, "smbus_write", 3, 3, "Write to I2C/SMBUS device", "<addr> <reg> <hex_data>") \
|
||||
X(SX9512_BUTTON, "sx9512_button", 0, 0, "Read SX9512 buttons (endless loop)", "") \
|
||||
X(SX9512_READ, "sx9512_read", 0, 0, "Look at configuration data (compare to default)", "") \
|
||||
X(SX9512_INIT, "sx9512_init", 0, 1, "Init SX9512 config to device defaults", "[device]") \
|
||||
X(SX9512_NVM_LOAD, "sx9512_nvm_load", 0, 0, "SX9512 load values from NVM", "") \
|
||||
X(SX9512_NVM_STORE, "sx9512_nvm_store", 0, 0, "SX9512 store config to NVM", "") \
|
||||
X(SX9512_RESET, "sx9512_reset", 0, 0, "Send reset command to SX9512", "")
|
||||
|
||||
|
||||
#define X(id, str, min_arg, max_arg, desc, arg_desc) CMD_##id,
|
||||
enum { CMDS CMDS_AMOUNT } cmd;
|
||||
#undef X
|
||||
|
||||
struct cmd {
|
||||
const char *str;
|
||||
int min_arg, max_arg;
|
||||
const char *desc, *arg_desc;
|
||||
};
|
||||
|
||||
#define X(id, str, min_arg, max_arg, desc, arg_desc) { str, min_arg, max_arg, desc, arg_desc },
|
||||
const struct cmd cmd_data[] = { CMDS };
|
||||
#undef X
|
||||
|
||||
|
||||
#define SX9512_DEVCFGS \
|
||||
X(NONE, "none" ) \
|
||||
X(DEFAULT, "default") \
|
||||
X(CLEAR, "clear" ) \
|
||||
X(CG300, "cg300" ) \
|
||||
X(CG301, "cg301" ) \
|
||||
X(EG300, "eg300" ) \
|
||||
X(DG400, "dg400" )
|
||||
|
||||
#define X(a, b) SX9512_DEVCFG_##a,
|
||||
enum sx9512_devcfg { SX9512_DEVCFGS SX9512_DEVCFG_AMOUNT };
|
||||
#undef X
|
||||
|
||||
#define X(a, b) b,
|
||||
const char *sx9512_devcfg_str[] = { SX9512_DEVCFGS };
|
||||
#undef X
|
||||
|
||||
|
||||
static enum sx9512_devcfg sx9512_devcfg_str_to_id(const char *s)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<SX9512_DEVCFG_AMOUNT; i++) {
|
||||
if(!strcmp(s, sx9512_devcfg_str[i]))
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void print_usage(char *prg_name)
|
||||
{
|
||||
int i;
|
||||
char tmp[64];
|
||||
printf("Usage: %s [options...] <cmd> <arg(s)>\n", prg_name);
|
||||
printf("Options:\n");
|
||||
printf(" -v, --verbose Verbose output\n");
|
||||
printf(" -h, --help Show this help screen.\n");
|
||||
printf("Commands:\n");
|
||||
for(i=0;i<CMDS_AMOUNT;i++) {
|
||||
sprintf(tmp, "%s %s", cmd_data[i].str, cmd_data[i].arg_desc);
|
||||
printf(" %-40.40s %s\n", tmp, cmd_data[i].desc);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, ch, r, fd=0;
|
||||
int pin, state;
|
||||
int pin_clk, pin_dat, pin_mask;
|
||||
gpio_shift_register_t p;
|
||||
int addr=0, s, n, l;
|
||||
enum sx9512_devcfg devcfg=0;
|
||||
uint8_t tmp[32];
|
||||
char *str_value=0, *eptr, str_hex[3];
|
||||
struct sx9512_reg_nvm nvm, nvm_def;
|
||||
while(1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
ch = getopt_long(argc, argv, "vh", long_options, &option_index);
|
||||
if(ch == -1)
|
||||
break;
|
||||
switch (ch) {
|
||||
case 'v':
|
||||
verbose=1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//i=argc-optind;
|
||||
if((argc-optind)<1) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: need cmd");
|
||||
}
|
||||
for(i=0;i<CMDS_AMOUNT;i++) {
|
||||
if(!strcmp(argv[optind], cmd_data[i].str))
|
||||
cmd=i;
|
||||
}
|
||||
if(!cmd) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: bad cmd %s", argv[optind]);
|
||||
}
|
||||
optind++;
|
||||
if((argc-optind)<cmd_data[cmd].min_arg) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: too few arguments");
|
||||
}
|
||||
if((argc-optind)>cmd_data[cmd].max_arg) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: too many arguments");
|
||||
}
|
||||
switch(cmd) {
|
||||
case CMD_GPIO_GET:
|
||||
case CMD_GPIO_SET:
|
||||
case CMD_SH_SET:
|
||||
gpio_init();
|
||||
break;
|
||||
case CMD_SMBUS_READ:
|
||||
case CMD_SMBUS_WRITE:
|
||||
addr=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
if(verbose)
|
||||
printf("Open I2C device %s\n", DEV_I2C);
|
||||
fd = open(DEV_I2C, O_RDWR);
|
||||
if(fd < 0)
|
||||
error(-1, errno, "could not open %s", DEV_I2C);
|
||||
if(verbose)
|
||||
printf("Set I2C addr=%02x\n", addr);
|
||||
if(ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
error(0, errno, "could not set address %x for i2c chip", addr);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CMD_SX9512_BUTTON:
|
||||
case CMD_SX9512_READ:
|
||||
case CMD_SX9512_INIT:
|
||||
case CMD_SX9512_NVM_LOAD:
|
||||
case CMD_SX9512_NVM_STORE:
|
||||
case CMD_SX9512_RESET:
|
||||
if((fd=sx9512_init(DEV_I2C, SX9512_I2C_ADDRESS, NULL))<0)
|
||||
error(-1, errno, "could not init SX9512");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
case CMD_GPIO_GET:
|
||||
pin=strtol(argv[optind],0,0);
|
||||
if(verbose)
|
||||
printf("Get gpio %d state\n", pin);
|
||||
r=gpio_get_state(pin);
|
||||
if(verbose)
|
||||
printf("state=%d\n", r);
|
||||
return(r);
|
||||
case CMD_GPIO_SET:
|
||||
pin=strtol(argv[optind],0,0);
|
||||
optind++;
|
||||
state=strtol(argv[optind],0,0);
|
||||
if(state!=0 && state!=1) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: bad state %d", state);
|
||||
}
|
||||
if(verbose)
|
||||
printf("Set gpio %d state to %d\n", pin, state);
|
||||
gpio_set_state(pin, state);
|
||||
break;
|
||||
case CMD_SH_SET:
|
||||
pin_clk=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
pin_dat=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
pin_mask=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
s=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
state=strtol(argv[optind],NULL,16);
|
||||
if(verbose)
|
||||
printf("Set shift register (clk=%d, dat=%d, mask=%d, size=%d) state to %X\n", pin_clk, pin_dat, pin_mask, s, state);
|
||||
gpio_shift_register_init(&p, pin_clk, pin_dat, pin_mask, s);
|
||||
gpio_shift_register_set(&p, state);
|
||||
break;
|
||||
case CMD_SMBUS_READ:
|
||||
s=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
n=strtol(argv[optind],NULL,0);
|
||||
if(s+n>256)
|
||||
n=256-s;
|
||||
if(verbose)
|
||||
printf("smbus read start (addr=%02x, reg=%02x, len=%d)\n", addr, s, n);
|
||||
for(i=s; i<(s+n); i+=32) {
|
||||
l=n-(i-s);
|
||||
if(l>32)
|
||||
l=32;
|
||||
if(verbose)
|
||||
printf("smbus read (reg=%02x, len=%d)\n", i, l);
|
||||
r=i2c_smbus_read_i2c_block_data(fd, i, l, (__u8 *)&tmp);
|
||||
if(r<0) {
|
||||
error(0, errno, "I2C read error (%d)", r);
|
||||
close(fd);
|
||||
return(-1);
|
||||
}
|
||||
printf("%02X:", i/32);
|
||||
for(j=0; j<l; j++)
|
||||
printf("%02x", tmp[j]);
|
||||
printf("\n");
|
||||
}
|
||||
close(fd);
|
||||
if(n==1)
|
||||
return(tmp[0]);
|
||||
break;
|
||||
case CMD_SMBUS_WRITE:
|
||||
s=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
str_value = argv[optind];
|
||||
n=strlen(str_value);
|
||||
if(n%2)
|
||||
error(-1, errno, "Error: odd length hex value %s", str_value);
|
||||
n>>=1;
|
||||
if(s+n>256)
|
||||
n=256-s;
|
||||
if(verbose)
|
||||
printf("smbus write start (addr=%02x, reg=%02x, len=%d, val=%s)\n", addr, s, n, str_value);
|
||||
for(i=0; i<n; i+=32) {
|
||||
l=n-i;
|
||||
if(l>32)
|
||||
l=32;
|
||||
str_hex[2]=0;
|
||||
for(j=0; j<l; j++) {
|
||||
str_hex[0]=str_value[(i+j)<<1];
|
||||
str_hex[1]=str_value[((i+j)<<1)+1];
|
||||
tmp[j]=strtol(str_hex, &eptr,16);
|
||||
if((errno != 0 && tmp[j] == 0) || eptr==str_hex)
|
||||
error(-1, errno, "hex conversion error at %d (%s)", j, str_hex);
|
||||
}
|
||||
if(verbose)
|
||||
printf("smbus write (reg=%02x, len=%d, val=%.*s)\n", s+i, l, l*2, str_value+(i*2));
|
||||
r=i2c_smbus_write_i2c_block_data(fd, s+i, l, tmp);
|
||||
if(r<0) {
|
||||
error(0, errno, "I2C write error (%d)", r);
|
||||
close(fd);
|
||||
return(-1);
|
||||
}
|
||||
printf("%02X:", i/32);
|
||||
for(j=0; j<l; j++)
|
||||
printf("%02x ", tmp[j]);
|
||||
printf("\n");
|
||||
}
|
||||
close(fd);
|
||||
break;
|
||||
case CMD_SX9512_BUTTON:
|
||||
while(1) {
|
||||
if(verbose)
|
||||
printf("Start reading buttons from SX9512\n");
|
||||
struct sx9512_touch_state touch_state;
|
||||
if(sx9512_read_status_cached(fd, &touch_state))
|
||||
error(-1, errno, "I2C read error");
|
||||
//printf("[state %02X]\n", touch_state.state);
|
||||
if(touch_state.touched)
|
||||
printf("[touch %02X]\n", touch_state.touched);
|
||||
if(touch_state.released)
|
||||
printf("[release %02X]\n", touch_state.released);
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
break;
|
||||
case CMD_SX9512_READ:
|
||||
if(verbose)
|
||||
printf("Read SX9512 registers (and compare to defaults)\n");
|
||||
sx9512_reg_nvm_init_defaults(&nvm_def, 0xff, 0xff);
|
||||
if(sx9512_reg_nvm_read(fd, &nvm))
|
||||
error(-1, errno, "while reading nvm registers");
|
||||
s=sizeof(nvm);
|
||||
for(i=0; i<s; i++)
|
||||
printf("%02x: %02x (%02x)0 %s\n", SX9512_REG_NVM_AREA_START+i, ((uint8_t *)&nvm)[i], ((uint8_t *)&nvm_def)[i], sx9512_reg_name(SX9512_REG_NVM_AREA_START+i));
|
||||
break;
|
||||
case CMD_SX9512_INIT:
|
||||
if((argc-optind)==1)
|
||||
devcfg = sx9512_devcfg_str_to_id(argv[optind]);
|
||||
switch(devcfg) {
|
||||
case SX9512_DEVCFG_DEFAULT:
|
||||
sx9512_reg_nvm_init_defaults(&nvm, 0xff, 0xff);
|
||||
break;
|
||||
case SX9512_DEVCFG_CLEAR:
|
||||
memset(&nvm, 0, sizeof(nvm));
|
||||
break;
|
||||
case SX9512_DEVCFG_CG300:
|
||||
sx9512_reg_nvm_init_cg300(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_CG301:
|
||||
sx9512_reg_nvm_init_cg301(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_EG300:
|
||||
sx9512_reg_nvm_init_eg300(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_DG400:
|
||||
sx9512_reg_nvm_init_dg400(&nvm);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: bad device arg, valid options are:\n");
|
||||
for(i=0;i<SX9512_DEVCFG_AMOUNT;i++)
|
||||
fprintf(stderr, "%s ", sx9512_devcfg_str[i]);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
if(verbose)
|
||||
printf("Init SX9512 registers to %s\n", sx9512_devcfg_str[devcfg]);
|
||||
if(sx9512_reg_nvm_write(fd, &nvm))
|
||||
error(-1, errno, "while writing nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_NVM_LOAD:
|
||||
if(sx9512_reg_nvm_load(fd))
|
||||
error(-1, errno, "while loading nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_NVM_STORE:
|
||||
if(sx9512_reg_nvm_store(fd))
|
||||
error(-1, errno, "while storing nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_RESET:
|
||||
if(sx9512_reset(fd))
|
||||
error(-1, errno, "while trying to reset");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "smbus.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
|
||||
void dump_i2c(int fd,int start,int stop)
|
||||
{
|
||||
int i;
|
||||
int res;
|
||||
|
||||
for (i=start ; i < stop; i++) {
|
||||
res = i2c_smbus_read_byte_data(fd,i);
|
||||
if (res < 0){perror("i2c error\n");}
|
||||
DBG(1,"/dev/i2c-0 READ %d = 0x%02x\n",i,(unsigned char)res);
|
||||
}
|
||||
}
|
||||
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long funcs_needed)
|
||||
{
|
||||
int fd = open(bus, O_RDWR);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_INFO,"%s: could not open %s\n",__func__, bus);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
syslog(LOG_INFO,"%s: could not set address %x for i2c chip\n",
|
||||
__func__, addr);
|
||||
error:
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
if(funcs_needed) {
|
||||
unsigned long funcs;
|
||||
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
|
||||
syslog(LOG_INFO,"%s: could not get I2C_FUNCS\n",__func__);
|
||||
goto error;
|
||||
}
|
||||
if((funcs & funcs_needed) != funcs_needed) {
|
||||
syslog(LOG_INFO,"%s: lacking I2C capabilities, have %lx, need %lx\n",
|
||||
__func__, funcs, funcs_needed);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
void dump_i2c(int fd,int start,int stop);
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long functions_needed);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,934 +0,0 @@
|
|||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
#include "log.h"
|
||||
#include "led.h"
|
||||
|
||||
static struct blob_buf bblob;
|
||||
|
||||
typedef enum {
|
||||
LED_OFF,
|
||||
LED_OK,
|
||||
LED_EOK,
|
||||
LED_NOTICE,
|
||||
LED_ALERT,
|
||||
LED_ERROR,
|
||||
LED_CUSTOM,
|
||||
LED_ACTION_MAX,
|
||||
} led_action_t;
|
||||
|
||||
typedef enum {
|
||||
LEDS_NORMAL,
|
||||
LEDS_PROXIMITY,
|
||||
LEDS_SILENT,
|
||||
LEDS_INFO,
|
||||
LEDS_TEST,
|
||||
LEDS_PROD,
|
||||
LEDS_RESET,
|
||||
LEDS_ALLON,
|
||||
LEDS_ALLOFF,
|
||||
LEDS_MAX,
|
||||
} leds_state_t;
|
||||
|
||||
/* Names for led_action_t */
|
||||
static const char * const fn_actions[LED_ACTION_MAX] =
|
||||
{ "off", "ok", "eok", "notice", "alert", "error", "custom"};
|
||||
|
||||
/* Names for led_state_t */
|
||||
static const char* const led_states[LED_STATES_MAX] =
|
||||
{ "off", "on", "flash_slow", "flash_fast","pulsing", "fadeon", "fadeoff" };
|
||||
|
||||
/* Names for leds_state_t */
|
||||
static const char* const leds_states[LEDS_MAX] =
|
||||
{ "normal", "proximity", "silent", "info", "test", "production", "reset", "allon" , "alloff"};
|
||||
|
||||
/* lowest level, contain states, timers,pointer to driver for a single physical led.*/
|
||||
struct led {
|
||||
struct list_head list;
|
||||
led_state_t state; /* state that this led should have, set from the config file */
|
||||
struct led_drv *drv;
|
||||
};
|
||||
|
||||
struct super_functions {
|
||||
struct list_head list;
|
||||
led_action_t state; /* state that the function need to match */
|
||||
struct function_led *function;
|
||||
};
|
||||
|
||||
struct super_list {
|
||||
struct list_head list;
|
||||
struct list_head sf_list; /* this list contains states that needs to match for this super fuction action to be active */
|
||||
};
|
||||
|
||||
/*middle layer contains lists of leds /buttons/... that should be set to a specific state */
|
||||
struct function_action {
|
||||
const char *name; /* If name is set this led action is in use by the board. */
|
||||
struct list_head led_list;
|
||||
struct list_head button_list;
|
||||
struct list_head super_list; /* list of super function lists */
|
||||
};
|
||||
|
||||
/* main struct for the function leds.*/
|
||||
struct function_led {
|
||||
const char *name; /* If name is set this led function is in use by the board. */
|
||||
led_action_t state; /* state of the function led. contain what action is currently set */
|
||||
int dimming; /* should this led be dimmed */
|
||||
int brightness; /* Brightness of the led */
|
||||
int timeout; /* if time is after */
|
||||
int press_indicator; /* record if this is part of press indictor */
|
||||
struct function_action actions[LED_ACTION_MAX];
|
||||
};
|
||||
|
||||
struct function_led *leds; /* Array of functions, LED_FUNCTIONS + super_functions */
|
||||
static int total_functions; /* number of entries in leds array */
|
||||
|
||||
static leds_state_t global_state; /* global state for the leds,overrids individual states */
|
||||
static press_t press_state; /* global state for the press indicator */
|
||||
|
||||
static led_action_t dimming_level; /* The min level where dimming should not happen on led */
|
||||
static int dimming_timeout; /* The time to turn on leds when we have dimming on */
|
||||
static int dimming_count; /* as long as this is not zero show all leds */
|
||||
|
||||
#define FLASH_TIMEOUT 250 /* this is the delay for the update loop. 4 times a second */
|
||||
#define FLASH_HZ (1000/FLASH_TIMEOUT)
|
||||
|
||||
int get_index_by_name(const char *const*array, int max, const char *name);
|
||||
int get_index_for_function(const char *name);
|
||||
struct led_drv *get_drv_led(char *name);
|
||||
static void dump_drv_list(void);
|
||||
static void dump_led(void);
|
||||
static void all_leds_off(void);
|
||||
static void all_leds_on(void);
|
||||
static void all_leds(led_state_t state);
|
||||
static const char * get_function_action( const char *s, struct function_led **function, int *action);
|
||||
static void super_update(void);
|
||||
|
||||
/* we find out the index for a match in an array of char pointers containing max number of pointers */
|
||||
int get_index_by_name(const char *const*array, int max, const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < max ; i++ ){
|
||||
if (!strcasecmp(name, array[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_index_for_function(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0 ; i < total_functions; i++) {
|
||||
if (!strcasecmp(name, leds[i].name))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PUT every led from drivers into a list */
|
||||
struct drv_led_list{
|
||||
struct list_head list;
|
||||
struct led_drv *drv;
|
||||
};
|
||||
LIST_HEAD(drv_leds_list);
|
||||
|
||||
void led_add( struct led_drv *drv)
|
||||
{
|
||||
struct drv_led_list *drv_node = malloc(sizeof(struct drv_led_list));
|
||||
|
||||
DBG(1,"called with led name [%s]", drv->name);
|
||||
drv_node->drv = drv;
|
||||
|
||||
list_add(&drv_node->list, &drv_leds_list);
|
||||
}
|
||||
|
||||
static void all_leds(led_state_t state) {
|
||||
struct drv_led_list *node;
|
||||
DBG(1, "set to state %d",state);
|
||||
|
||||
list_for_each_entry(node, &drv_leds_list, list) {
|
||||
node->drv->func->set_state( node->drv, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void all_leds_off(void) {
|
||||
all_leds(OFF);
|
||||
}
|
||||
|
||||
static void all_leds_on(void) {
|
||||
all_leds(ON);
|
||||
}
|
||||
|
||||
#define TEST_TIMEOUT 250
|
||||
static void test_handler(struct uloop_timeout *timeout);
|
||||
static struct uloop_timeout test_inform_timer = { .cb = test_handler };
|
||||
|
||||
static void test_handler(struct uloop_timeout *timeout) {
|
||||
|
||||
static int cnt = 0;
|
||||
static led_state_t state = OFF;
|
||||
|
||||
static struct drv_led_list *led;
|
||||
DBG(1,"cnt = %d state %d",cnt,state);
|
||||
|
||||
/* flash all leads 2 times.*/
|
||||
if ( cnt < 4) {
|
||||
cnt++;
|
||||
if (state == OFF){
|
||||
all_leds_on();
|
||||
state = ON;
|
||||
}else{
|
||||
all_leds_off();
|
||||
state = OFF;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (global_state == LEDS_RESET){
|
||||
cnt = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* cycle through every led once */
|
||||
if (cnt == 4 ) {
|
||||
cnt++;
|
||||
led = list_first_entry(&drv_leds_list, struct drv_led_list, list );
|
||||
}
|
||||
if (cnt == 5 ) {
|
||||
if (state == OFF){
|
||||
led->drv->func->set_state(led->drv, ON);
|
||||
state = ON;
|
||||
}else{
|
||||
led->drv->func->set_state(led->drv, OFF);
|
||||
/* was this the last led ? if so stop */
|
||||
if ( list_is_last(&led->list, &drv_leds_list) ){
|
||||
cnt = 0;
|
||||
state = OFF;
|
||||
goto done;
|
||||
}else{ /* nope more leds in list. get next and turn it on */
|
||||
led = (struct drv_led_list *)led->list.next;
|
||||
led->drv->func->set_state(led->drv, ON);
|
||||
state = ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
if (global_state == LEDS_TEST || global_state == LEDS_RESET)
|
||||
uloop_timeout_set(&test_inform_timer, TEST_TIMEOUT);
|
||||
else{
|
||||
cnt = 0;
|
||||
state = OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* go over the driver list for any led name that matches name and returna pointer to driver. */
|
||||
struct led_drv *get_drv_led(char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_leds_list) {
|
||||
struct drv_led_list *node = list_entry(i, struct drv_led_list, list);
|
||||
if (!strcmp(node->drv->name, name))
|
||||
return node->drv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dump_drv_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_leds_list) {
|
||||
struct drv_led_list *node = list_entry(i, struct drv_led_list, list);
|
||||
DBG(1,"led name = [%s]",node->drv->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_led(void)
|
||||
{
|
||||
int i,j;
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
if ( leds[i].actions[j].name != NULL ) {
|
||||
struct led *led;
|
||||
struct super_list *sl;
|
||||
|
||||
/* print out action list */
|
||||
list_for_each_entry(led, &leds[i].actions[j].led_list, list) {
|
||||
DBG(1,"%-15s %-8s %-15s %-10s",
|
||||
leds[i].name,
|
||||
leds[i].actions[j].name,
|
||||
led->drv->name,
|
||||
led_states[led->state]);
|
||||
}
|
||||
/* print out super function list */
|
||||
list_for_each_entry(sl, &leds[i].actions[j].super_list, list) {
|
||||
struct super_functions *sf;
|
||||
DBG(1," AND list");
|
||||
list_for_each_entry(sf, &sl->sf_list, list) {
|
||||
DBG(1,"\tfunction [%s] action [%s]",sf->function->name, fn_actions[sf->state]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* loop over every function, if it is a super function update the state */
|
||||
static void super_update(void)
|
||||
{
|
||||
int i,j;
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
if ( leds[i].actions[j].name != NULL ) {
|
||||
struct super_list *sl;
|
||||
list_for_each_entry(sl, &leds[i].actions[j].super_list, list) {
|
||||
struct super_functions *sf;
|
||||
int status = 0;
|
||||
// DBG(1," AND list");
|
||||
list_for_each_entry(sf, &sl->sf_list, list) {
|
||||
// DBG(1,"\tfunction [%s] action [%s]",sf->function->name, fn_actions[sf->state]);
|
||||
if (sf->function->state == sf->state ) {
|
||||
status = 1;
|
||||
} else {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status){
|
||||
leds[i].state = j;
|
||||
DBG(3,"\tSet super function [%s] to action [%s]",leds[i].name, fn_actions[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return 0 = OK, -1 = error */
|
||||
static int set_function_led(const char* fn_name, const char* action) {
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
int act_idx = get_index_by_name(fn_actions , LED_ACTION_MAX, action );
|
||||
struct led *led;
|
||||
|
||||
if(led_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid led name [%s]", fn_name);
|
||||
return -1;
|
||||
}
|
||||
if(act_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid action [%s] for led [%s]", action, fn_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
leds[led_idx].state = act_idx;
|
||||
|
||||
list_for_each_entry(led, &leds[led_idx].actions[act_idx].led_list, list) {
|
||||
if (led->drv){
|
||||
led->drv->func->set_state(led->drv, led->state);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brightness_function_led(const char* fn_name, int brightness) {
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
struct led *led;
|
||||
|
||||
if(led_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid led name [%s]", fn_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
leds[led_idx].brightness = brightness;
|
||||
|
||||
list_for_each_entry(led, &leds[led_idx].actions[ leds[led_idx].state ].led_list, list) {
|
||||
if (led->drv){
|
||||
if (led->drv->func->set_brightness){
|
||||
led->drv->func->set_brightness(led->drv, brightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timeout_function_led(const char* fn_name, int timeout) {
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
|
||||
if(led_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid led name [%s]", fn_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* store timeout as number of passes on the flash loop */
|
||||
/* in the loop decrement the timeout */
|
||||
leds[led_idx].timeout = FLASH_HZ * timeout;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
LED_STATE,
|
||||
LED_BRIGHTNESS,
|
||||
LED_TIMEOUT,
|
||||
__LED_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy led_policy[] = {
|
||||
[LED_STATE] = { .name = "state", .type = BLOBMSG_TYPE_STRING },
|
||||
[LED_BRIGHTNESS] = { .name = "brightness", .type = BLOBMSG_TYPE_INT32 },
|
||||
[LED_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
|
||||
};
|
||||
|
||||
static int led_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__LED_MAX];
|
||||
char* state;
|
||||
int number;
|
||||
char *fn_name = strchr(obj->name, '.') + 1;
|
||||
|
||||
blobmsg_parse(led_policy, ARRAY_SIZE(led_policy), tb, blob_data(msg), blob_len(msg));
|
||||
if (tb[LED_STATE]) {
|
||||
state = blobmsg_data(tb[LED_STATE]);
|
||||
DBG(1,"set led [%s]->[%s]", fn_name, state);
|
||||
if (set_function_led(fn_name, state) ){
|
||||
return UBUS_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[LED_BRIGHTNESS]) {
|
||||
number = blobmsg_get_u32(tb[LED_BRIGHTNESS]);
|
||||
DBG(1,"set brightness [%s]->[%x]", fn_name, number);
|
||||
if (brightness_function_led(fn_name, number) ){
|
||||
return UBUS_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[LED_TIMEOUT]) {
|
||||
number = blobmsg_get_u32(tb[LED_TIMEOUT]);
|
||||
DBG(1,"set timeout [%s]->[%x]", fn_name, number);
|
||||
timeout_function_led(fn_name, number);
|
||||
} else // remove timeout
|
||||
timeout_function_led(fn_name, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_status_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
char *fn_name = strchr(obj->name, '.') + 1;
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
DBG(1,"for led %s",leds[led_idx].name);
|
||||
|
||||
blob_buf_init (&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "state",fn_actions[leds[led_idx].state]);
|
||||
blobmsg_add_u32(&bblob, "brightness",leds[led_idx].brightness);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leds_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__LED_MAX];
|
||||
|
||||
blobmsg_parse(led_policy, ARRAY_SIZE(led_policy), tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
if (tb[LED_STATE]) {
|
||||
char* state;
|
||||
int state_idx;
|
||||
|
||||
state = blobmsg_data(tb[LED_STATE]);
|
||||
state_idx = get_index_by_name(leds_states, LEDS_MAX , state);
|
||||
|
||||
if (state_idx == -1) {
|
||||
syslog(LOG_WARNING, "leds_set_method: Unknown state %s.", state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
global_state = state_idx;
|
||||
|
||||
if (global_state == LEDS_INFO) {
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
if (global_state == LEDS_PROD) {
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
if (global_state == LEDS_TEST || global_state == LEDS_RESET) {
|
||||
all_leds_off();
|
||||
uloop_timeout_set(&test_inform_timer, TEST_TIMEOUT);
|
||||
}
|
||||
if (global_state == LEDS_ALLON) {
|
||||
all_leds_on();
|
||||
}
|
||||
if (global_state == LEDS_ALLOFF) {
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
DBG(1,"led global state set to [%s] wanted [%s]", leds_states[global_state], state);
|
||||
}else
|
||||
syslog(LOG_WARNING, "Unknown attribute [%s]", (char *)blob_data(msg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leds_status_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
|
||||
blob_buf_init (&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "state", leds_states[global_state]);
|
||||
DBG(1,"leds global state is [%s]",leds_states[global_state]);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ubus_method led_methods[] = {
|
||||
UBUS_METHOD("set", led_set_method, led_policy),
|
||||
{ .name = "status", .handler = led_status_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type led_object_type =
|
||||
UBUS_OBJECT_TYPE("led", led_methods);
|
||||
|
||||
static const struct ubus_method leds_methods[] = {
|
||||
UBUS_METHOD("set", leds_set_method, led_policy),
|
||||
{ .name = "status", .handler = leds_status_method },
|
||||
// { .name = "proximity", .handler = leds_proximity_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type leds_object_type =
|
||||
UBUS_OBJECT_TYPE("leds", leds_methods);
|
||||
|
||||
#define LED_OBJECTS 1
|
||||
static struct ubus_object led_objects[LED_OBJECTS] = {
|
||||
{ .name = "leds", .type = &leds_object_type, .methods = leds_methods, .n_methods = ARRAY_SIZE(leds_methods), },
|
||||
};
|
||||
|
||||
static void flash_handler(struct uloop_timeout *timeout);
|
||||
static struct uloop_timeout flash_inform_timer = { .cb = flash_handler };
|
||||
|
||||
static void flash_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
static int counter = 1; /* bit 0 is fast flash bit 2 is slow flash */
|
||||
int i;
|
||||
led_state_t slow=OFF,fast=OFF;
|
||||
counter++;
|
||||
|
||||
/* count down dimming to zero */
|
||||
if (dimming_count)
|
||||
dimming_count--;
|
||||
|
||||
if (counter & 1 )
|
||||
fast = ON;
|
||||
if (counter & 4 )
|
||||
slow = ON;
|
||||
|
||||
super_update();
|
||||
|
||||
if (global_state == LEDS_NORMAL ||
|
||||
global_state == LEDS_INFO ) {
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
struct led *led;
|
||||
if (leds[i].press_indicator && (press_state != PRESS_NONE) ) {
|
||||
// DBG(1,"INDICATE_PRESS on %s",leds[i].name);
|
||||
list_for_each_entry(led, &leds[i].actions[leds[i].state].led_list, list) {
|
||||
if (led->drv){
|
||||
if (press_state == PRESS_LONG)
|
||||
led->drv->func->set_state(led->drv, ON);
|
||||
else
|
||||
led->drv->func->set_state(led->drv, fast);
|
||||
}
|
||||
}
|
||||
|
||||
/* normal operation, flash else reset state */
|
||||
} else {
|
||||
led_action_t action_state = leds[i].state;
|
||||
|
||||
/* in case of info mode suppress OK state. that is if OK -> turn it into OFF */
|
||||
if (global_state == LEDS_INFO) {
|
||||
if (action_state == LED_OK)
|
||||
action_state = LED_OFF;
|
||||
}
|
||||
|
||||
/* is this function dimmed ? */
|
||||
if (leds[i].dimming) {
|
||||
/* if timer is not active we should dimm */
|
||||
if (!dimming_count){
|
||||
if (action_state < dimming_level)
|
||||
action_state = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* is there a timeout on this led ?*/
|
||||
if (leds[i].timeout) {
|
||||
leds[i].timeout--;
|
||||
/* if it has timedout set state to OFF */
|
||||
if (! leds[i].timeout) {
|
||||
leds[i].state = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(led, &leds[i].actions[action_state].led_list, list) {
|
||||
|
||||
if (led->state == FLASH_FAST) {
|
||||
if (led->drv) {
|
||||
if (led->drv->func->support) {
|
||||
if (led->drv->func->support(led->drv, FLASH_FAST)) {
|
||||
/* hardware support flash */
|
||||
led->drv->func->set_state(led->drv, FLASH_FAST);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* emulate flash with on/off */
|
||||
led->drv->func->set_state(led->drv, fast);
|
||||
}
|
||||
}else if (led->state == FLASH_SLOW) {
|
||||
if (led->drv) {
|
||||
if (led->drv->func->support) {
|
||||
if (led->drv->func->support(led->drv, FLASH_SLOW)) {
|
||||
/* hardware support flash */
|
||||
led->drv->func->set_state(led->drv, FLASH_SLOW);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* emulate flash with on/off */
|
||||
led->drv->func->set_state(led->drv, slow);
|
||||
}
|
||||
}else{
|
||||
if (led->drv)
|
||||
led->drv->func->set_state(led->drv, led->state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uloop_timeout_set(&flash_inform_timer, FLASH_TIMEOUT);
|
||||
}
|
||||
|
||||
void led_pressindicator_set(press_t type){
|
||||
|
||||
/* press long has prio over short so if it's already set to long do not change */
|
||||
if (type == PRESS_SHORT && press_state == PRESS_LONG)
|
||||
return;
|
||||
|
||||
press_state = type;
|
||||
}
|
||||
|
||||
void led_dimming(void){
|
||||
|
||||
/* we resuse the flash timer and decrement dimmming_count on every loop */
|
||||
/* set the intial value so that we get the correct timeout */
|
||||
dimming_count = dimming_timeout * (1000/FLASH_TIMEOUT);
|
||||
}
|
||||
|
||||
/*
|
||||
input: s, string of comma separated function_action names, 'wifi_ok, wps_ok'
|
||||
|
||||
return:
|
||||
NULL if no valid function actionpair found.
|
||||
pointer to start of unused part of string.
|
||||
|
||||
fills in the function pointer with NULL or a real function
|
||||
fills in action with 0 or real index (include 0),
|
||||
|
||||
*/
|
||||
const char * get_function_action( const char *s, struct function_led **function, int *action)
|
||||
{
|
||||
const char *first, *last, *end, *p;
|
||||
char func[100], act[20];
|
||||
|
||||
DBG(1,"start [%s]", s);
|
||||
|
||||
*function = NULL;
|
||||
*action = 0;
|
||||
|
||||
/* if string is zero length give up. */
|
||||
if ( 0 == strlen(s))
|
||||
return NULL;
|
||||
|
||||
end = s + strlen(s);
|
||||
|
||||
/* find first alpha char */
|
||||
while (!isalnum(*s)){
|
||||
s++;
|
||||
if (s == end)
|
||||
return NULL;
|
||||
}
|
||||
first = s;
|
||||
|
||||
/* find , or end of string or space/tab */
|
||||
while ( (*s != ',') && (!isblank(*s))) {
|
||||
s++;
|
||||
if (s == end)
|
||||
break;
|
||||
}
|
||||
last = s;
|
||||
|
||||
/* scan backwards for _ */
|
||||
while (*s != '_' && s > first){
|
||||
s--;
|
||||
}
|
||||
|
||||
/* if we could not find a _ char bail out */
|
||||
if (*s != '_')
|
||||
return NULL;
|
||||
|
||||
/* extract function name */
|
||||
p = first;
|
||||
while (p != s) {
|
||||
func[p-first] = *p;
|
||||
p++;
|
||||
}
|
||||
func[p-first] = 0;
|
||||
|
||||
/* extract action name */
|
||||
p = s + 1;
|
||||
while (p != last) {
|
||||
act[p-(s+1)] = *p;
|
||||
p++;
|
||||
}
|
||||
act[p-(s+1)] = 0;
|
||||
|
||||
DBG(1,"function[%s] action[%s] func_idx %d", func, act, get_index_for_function(func));
|
||||
*function = &leds[get_index_for_function(func)];
|
||||
*action = get_index_by_name(fn_actions , LED_ACTION_MAX, act );
|
||||
|
||||
if (*last == ',')
|
||||
last++;
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
/* when this is called all driver leds needs to exist */
|
||||
void led_init( struct server_ctx *s_ctx)
|
||||
{
|
||||
int i,j;
|
||||
LIST_HEAD(led_map_list);
|
||||
struct ucilist *map_node;
|
||||
const char *s;
|
||||
|
||||
dump_drv_list();
|
||||
|
||||
/* register leds with ubus */
|
||||
for (i=0 ; i<LED_OBJECTS ; i++) {
|
||||
int ret = ubus_add_object(s_ctx->ubus_ctx, &led_objects[i]);
|
||||
if (ret)
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(ret));
|
||||
}
|
||||
|
||||
/* read out the function leds */
|
||||
ucix_get_option_list( s_ctx->uci_ctx, "hw", "led_map", "functions" , &led_map_list);
|
||||
|
||||
total_functions = 0;
|
||||
list_for_each_entry(map_node, &led_map_list, list) {
|
||||
total_functions++;
|
||||
}
|
||||
|
||||
leds = malloc(sizeof(struct function_led) * total_functions);
|
||||
memset(leds, 0, sizeof(struct function_led) * total_functions);
|
||||
|
||||
/* set function name & regiter with ubus */
|
||||
i = 0;
|
||||
list_for_each_entry(map_node, &led_map_list, list) {
|
||||
char name[100];
|
||||
int ret;
|
||||
struct ubus_object *ubo;
|
||||
ubo = malloc(sizeof(struct ubus_object));
|
||||
memset(ubo, 0, sizeof(struct ubus_object));
|
||||
|
||||
leds[i].name = strdup(map_node->val);
|
||||
|
||||
sprintf(name, "led.%s", leds[i].name);
|
||||
ubo->name = strdup(name);
|
||||
ubo->methods = led_methods;
|
||||
ubo->n_methods = ARRAY_SIZE(led_methods);
|
||||
ubo->type = &led_object_type;
|
||||
|
||||
ret = ubus_add_object(s_ctx->ubus_ctx, ubo);
|
||||
if (ret)
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(ret));
|
||||
i++;
|
||||
}
|
||||
|
||||
/* we create a top list of led functions */
|
||||
/* that list contains a new list of actions */
|
||||
/* every action contains led actions lists */
|
||||
/* the led states is attached to the drv_leds lists */
|
||||
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
char led_fn_name[256];
|
||||
char led_action[256];
|
||||
|
||||
LIST_HEAD(led_action_list);
|
||||
struct ucilist *node;
|
||||
snprintf(led_fn_name, 256, "led_%s", leds[i].name);
|
||||
snprintf(led_action, 256, "led_action_%s", fn_actions[j]);
|
||||
ucix_get_option_list( s_ctx->uci_ctx, "hw", led_fn_name, led_action , &led_action_list);
|
||||
|
||||
INIT_LIST_HEAD( &leds[i].actions[j].led_list );
|
||||
|
||||
if (!list_empty(&led_action_list)) {
|
||||
|
||||
/* Found led with action, init structs */
|
||||
leds[i].state = LED_OFF;
|
||||
leds[i].brightness = 100;
|
||||
|
||||
leds[i].actions[j].name = fn_actions[j];
|
||||
|
||||
/* fill in led actions */
|
||||
DBG(2,"%-15s has led actions %s -> ", led_fn_name, fn_actions[j]);
|
||||
list_for_each_entry(node, &led_action_list, list) {
|
||||
char led_name[256],led_state[256];
|
||||
struct led *led;
|
||||
struct led_drv *drv;
|
||||
char *c;
|
||||
s = strdup(node->val);
|
||||
led_name[0]=0;
|
||||
led_state[0]=0;
|
||||
|
||||
/* get pointer to low level led driver. by removing the = sign and
|
||||
storing the remaining two strings.
|
||||
*/
|
||||
c = strchr(s,'=');
|
||||
if( c == NULL)
|
||||
continue; /* no = found, abort */
|
||||
*c = ' ';
|
||||
|
||||
sscanf(s, "%s %s", led_name, led_state);
|
||||
drv = get_drv_led(led_name);
|
||||
|
||||
if (drv) {
|
||||
led = malloc(sizeof(struct led));
|
||||
led->drv = drv;
|
||||
led->state = get_index_by_name(led_states, LED_STATES_MAX, led_state);
|
||||
list_add(&led->list, &leds[i].actions[j].led_list);
|
||||
}else {
|
||||
syslog(LOG_ERR,"Config specified use of led name [%s]. But it's not registerd with a led driver.", led_name);
|
||||
}
|
||||
DBG(2, "%-35s%s","",node->val);
|
||||
free((void*)s);
|
||||
}
|
||||
|
||||
/* fill in button actions */
|
||||
|
||||
/* fill in xxx actions */
|
||||
}else {
|
||||
DBG(2,"%-15s has no actions -> %s", led_fn_name, fn_actions[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read in functions that have function list (super functions) */
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
char led_fn_name[256];
|
||||
char super_action[256];
|
||||
LIST_HEAD(super_action_list);
|
||||
struct ucilist *node;
|
||||
snprintf(led_fn_name, 256, "led_%s", leds[i].name);
|
||||
snprintf(super_action, 256, "super_%s", fn_actions[j]);
|
||||
ucix_get_option_list( s_ctx->uci_ctx, "hw", led_fn_name, super_action , &super_action_list);
|
||||
INIT_LIST_HEAD( &leds[i].actions[j].super_list );
|
||||
|
||||
if (!list_empty(&super_action_list)) {
|
||||
DBG(1,"A:%s %s is a super function ",led_fn_name,super_action);
|
||||
|
||||
list_for_each_entry(node, &super_action_list, list) {
|
||||
struct function_led *function;
|
||||
int action_ix;
|
||||
struct super_list *sl = malloc(sizeof(struct super_list));
|
||||
memset(sl, 0, sizeof(struct super_list));
|
||||
list_add(&sl->list, &leds[i].actions[j].super_list);
|
||||
INIT_LIST_HEAD( &sl->sf_list );
|
||||
|
||||
DBG(1,"add to super list %s",node->val);
|
||||
|
||||
s = node->val;
|
||||
while ((s = get_function_action(s, &function, &action_ix))){
|
||||
if (function) {
|
||||
struct super_functions *sf = malloc(sizeof(struct super_functions));
|
||||
memset(sf, 0, sizeof(struct super_functions));
|
||||
sf->state = action_ix;
|
||||
sf->function = function;
|
||||
list_add(&sf->list, &sl->sf_list);
|
||||
DBG(1,"C %s %s",function->name, fn_actions[action_ix]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
DBG(1,"A:%s %s is a normal function ",led_fn_name,super_action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* setup and read dimming options for led */
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(dimm_list);
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "led_map", "dimming_level");
|
||||
dimming_level = LED_OFF;
|
||||
if (s) {
|
||||
DBG(1,"Dimming init");
|
||||
for(i=0 ; i < LED_ACTION_MAX ; i++) {
|
||||
if (! strncasecmp(s, fn_actions[i], strlen(fn_actions[i]))){
|
||||
dimming_level = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "led_map", "dimming_on");
|
||||
dimming_timeout = 0;
|
||||
if (s) {
|
||||
dimming_timeout = strtol(s, NULL, 0);
|
||||
}
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"led_map", "dimming", &dimm_list);
|
||||
list_for_each_entry(node, &dimm_list, list) {
|
||||
int ix;
|
||||
s = node->val;
|
||||
ix = get_index_for_function(s);
|
||||
if (ix != -1){
|
||||
leds[ix].dimming = 1;
|
||||
DBG(1,"dimming on led [%s]", leds[ix].name);
|
||||
}else
|
||||
syslog(LOG_ERR,"dimming Led [%s] don't exist", s);
|
||||
}
|
||||
}
|
||||
|
||||
DBG(1,"Dimming level %s", fn_actions[dimming_level]);
|
||||
DBG(1,"Dimming timeout %d", dimming_timeout);
|
||||
|
||||
{
|
||||
struct ucilist *node;
|
||||
/* read function buttons from section button_map */
|
||||
LIST_HEAD(press_indicator);
|
||||
|
||||
/* read in generic configuration. press indicator listdefault params..... */
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"led_map", "press_indicator", &press_indicator);
|
||||
list_for_each_entry(node, &press_indicator, list) {
|
||||
int ix;
|
||||
s = node->val;
|
||||
s +=4; /*remove 'led_' from string */
|
||||
DBG(1,"press indicator %s [%s]",node->val, s);
|
||||
ix = get_index_for_function(s);
|
||||
// DBG(1,"press indicator %s [%s]->%d",node->val, s, ix);
|
||||
leds[ix].press_indicator = 1;
|
||||
}
|
||||
}
|
||||
uloop_timeout_set(&flash_inform_timer, FLASH_TIMEOUT);
|
||||
|
||||
dump_led();
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
#include "server.h"
|
||||
|
||||
typedef enum {
|
||||
OFF,
|
||||
ON,
|
||||
FLASH_SLOW,
|
||||
FLASH_FAST,
|
||||
PULSING,
|
||||
FADEON,
|
||||
FADEOFF,
|
||||
NEED_INIT, /* set on loading config */
|
||||
LED_STATES_MAX,
|
||||
} led_state_t;
|
||||
|
||||
typedef enum {
|
||||
NONE,
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
YELLOW,
|
||||
WHITE,
|
||||
} led_color_t;
|
||||
|
||||
typedef enum {
|
||||
PRESS_NONE,
|
||||
PRESS_SHORT,
|
||||
PRESS_LONG,
|
||||
} press_t;
|
||||
|
||||
struct led_drv;
|
||||
|
||||
struct led_drv_func{
|
||||
int (*set_state)(struct led_drv *, led_state_t); /* Set led state, on,off,flash ... */
|
||||
led_state_t (*get_state)(struct led_drv *); /* Get led state, on,off,flash ... */
|
||||
int (*set_color)(struct led_drv *, led_color_t); /* Set led color */
|
||||
led_color_t (*get_color)(struct led_drv *); /* Get led color */
|
||||
int (*set_brightness)(struct led_drv *, int ); /* Set led brightness */
|
||||
int (*get_brightness)(struct led_drv *); /* Get led brightness */
|
||||
int (*support) (struct led_drv *, led_state_t); /* do driver has hardware support for state */
|
||||
};
|
||||
|
||||
struct led_drv {
|
||||
const char *name; /* name, set in the confg file,has to be uniq */
|
||||
void *priv; /* for use by the driver */
|
||||
struct led_drv_func *func; /* function pointers for controlling the led */
|
||||
};
|
||||
|
||||
void led_add( struct led_drv *);
|
||||
void led_init(struct server_ctx *);
|
||||
|
||||
void led_dimming(void);
|
||||
void led_pressindicator_set(press_t type);
|
||||
|
||||
#endif /* LED_H */
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
/* Use this */
|
||||
#include <syslog.h>
|
||||
|
||||
extern int debug_level;
|
||||
|
||||
#define DBG_RAW(...) fprintf( stderr, __VA_ARGS__ );
|
||||
#define DBG(level,fmt, args...) \
|
||||
do { \
|
||||
if (level <= debug_level) \
|
||||
syslog( LOG_DEBUG,"%-20s: " fmt , __func__, ##args); \
|
||||
} while(0)
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
#include <config.h>
|
||||
#include <getopt.h>
|
||||
#include "log.h"
|
||||
#include "ucix.h"
|
||||
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubus.h>
|
||||
|
||||
#include "server.h"
|
||||
|
||||
int debug_level = 0;
|
||||
|
||||
static const char *config_path = "/lib/db/config";
|
||||
static const char *config_file = "hw";
|
||||
|
||||
static char *ubus_socket;
|
||||
|
||||
void catv_monitor_set_socket(char *);
|
||||
|
||||
void print_usage(char *prg_name);
|
||||
|
||||
void print_usage(char *prg_name) {
|
||||
printf("Usage: %s -h -f\n", prg_name);
|
||||
printf(" Options: \n");
|
||||
printf(" -f, --foreground\tDon't fork off as a daemon.\n");
|
||||
printf(" -d, --debug=NUM\tSet debug level. Higher = more output\n");
|
||||
printf(" -c, --config=FILE\tConfig file to use. default = %s/%s\n", config_path, config_file);
|
||||
printf(" -s, --socket=FILE\tSet the unix domain socket to connect to for ubus\n");
|
||||
printf(" -h\t\tShow this help screen.\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
int daemonize = 1;
|
||||
pid_t pid, sid;
|
||||
struct uci_context *uci_ctx = NULL;
|
||||
static struct ubus_context *ubus_ctx = NULL;
|
||||
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"foreground", no_argument, 0, 'f'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"debug", required_argument, 0, 'd'},
|
||||
{"config",required_argument, 0, 'c'},
|
||||
{"socket",required_argument, 0, 's'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
ch = getopt_long(argc, argv, "hvfhd:c:s:",
|
||||
long_options, &option_index);
|
||||
|
||||
if (ch == -1)
|
||||
break;
|
||||
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
daemonize = 0;
|
||||
break;
|
||||
case 'd':
|
||||
debug_level = strtol(optarg, 0, 0);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
config_file = basename(optarg);
|
||||
config_path = dirname(optarg);
|
||||
break;
|
||||
case 's':
|
||||
ubus_socket = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
printf("Extra arguments discarded: ");
|
||||
while (optind < argc)
|
||||
printf("%s ", argv[optind++]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/* Setup logging */
|
||||
if (daemonize) {
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog(PACKAGE, LOG_CONS, LOG_USER);
|
||||
|
||||
syslog(LOG_INFO, "%s daemon starting up", PACKAGE);
|
||||
} else {
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog(PACKAGE, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||
|
||||
syslog(LOG_INFO, "%s program starting up", PACKAGE);
|
||||
}
|
||||
|
||||
/* daemonize */
|
||||
if (daemonize) {
|
||||
syslog(LOG_INFO, "starting the daemonizing process");
|
||||
|
||||
/* Fork off the parent process */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* If we got a good PID, then
|
||||
we can exit the parent process. */
|
||||
if (pid > 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Change the current working directory */
|
||||
if ((chdir("/")) < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Close out the standard file descriptors */
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
/* open configuration file */
|
||||
uci_ctx = ucix_init_path(config_path , config_file, 0 );
|
||||
if (! uci_ctx ) {
|
||||
syslog(LOG_ERR,"Failed to load config file \"%s/%s\"\n", config_path, config_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* connect to ubus */
|
||||
ubus_ctx = ubus_connect(ubus_socket);
|
||||
if (!ubus_ctx) {
|
||||
syslog(LOG_ERR,"Failed to connect to ubus. Can't continue.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* connect ubus handler to ubox evenet loop */
|
||||
if (uloop_init() != 0) {
|
||||
syslog(LOG_ERR,"Could not init event loop, Can't continue.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ubus_add_uloop(ubus_ctx);
|
||||
|
||||
catv_monitor_set_socket(ubus_socket);
|
||||
|
||||
server_start(uci_ctx, ubus_ctx);
|
||||
|
||||
ubus_free(ubus_ctx);
|
||||
|
||||
DBG(1,"testing\n");
|
||||
syslog(LOG_INFO, "%s exiting", PACKAGE);
|
||||
|
||||
uloop_done();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
#include <syslog.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "button.h"
|
||||
|
||||
#include "smbus.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "ucix.h"
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
/* register names, from page 29, */
|
||||
#define PX3220_SYSCONF 0x00
|
||||
#define PX3220_IRQ_STATUS 0x01
|
||||
#define PX3220_IRQ_CLEAR 0x02
|
||||
#define PX3220_IR_DATA_LOW 0x0A
|
||||
#define PX3220_IR_DATA_HIGH 0x0B
|
||||
#define PX3220_PS_DATA_LOW 0x0E
|
||||
#define PX3220_PS_DATA_HIGH 0x0F
|
||||
#define PX3220_PS_LOW_THRESH_L 0x2A
|
||||
#define PX3220_PS_LOW_THRESH_H 0x2B
|
||||
#define PX3220_PS_HIGH_THRESH_L 0x2C
|
||||
#define PX3220_PS_HIGH_THRESH_H 0x2D
|
||||
|
||||
#define IRQ_BUTTON 33
|
||||
|
||||
struct i2c_reg_tab {
|
||||
char addr;
|
||||
char value;
|
||||
char range; /* if set registers starting from addr to addr+range will be set to the same value */
|
||||
};
|
||||
|
||||
struct button_data {
|
||||
int addr;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
static const struct i2c_reg_tab i2c_init_tab_vox25[]={
|
||||
{PX3220_SYSCONF, 0x04, 0x00 }, /* Reset */
|
||||
{PX3220_SYSCONF, 0x02, 0x00 }, /* Power on IR */
|
||||
{PX3220_IRQ_STATUS, 0x01, 0x00 },
|
||||
{0x20, 0x17, 0x00 },
|
||||
{0x23, 0x03, 0x00 },
|
||||
{PX3220_PS_LOW_THRESH_L, 0x00, 0x00 },
|
||||
{PX3220_PS_LOW_THRESH_H, 0x18, 0x00 },
|
||||
{PX3220_PS_HIGH_THRESH_L, 0x00, 0x00 },
|
||||
{PX3220_PS_HIGH_THRESH_H, 0x14, 0x00 },
|
||||
};
|
||||
|
||||
int dev;
|
||||
int shadow_proximity;
|
||||
|
||||
void do_init_tab(const struct i2c_reg_tab *tab, int len );
|
||||
|
||||
|
||||
void do_init_tab(const struct i2c_reg_tab *tab, int len )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < len ; i++){
|
||||
int y;
|
||||
int ret;
|
||||
for ( y = 0 ; y <= tab[i].range; y++ ){
|
||||
DBG(3,"%s: addr %02X = %02X ",__func__,(unsigned char)tab[i].addr+y, (unsigned char)tab[i].value);
|
||||
ret = i2c_smbus_write_byte_data(dev, tab[i].addr+y, tab[i].value);
|
||||
if (ret < 0){
|
||||
perror("write to i2c dev\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void px3220_check(void)
|
||||
{
|
||||
int got_irq;
|
||||
unsigned short reg_low, reg_high, ps_val;
|
||||
|
||||
shadow_proximity = 0;
|
||||
if (dev){
|
||||
got_irq = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, IRQ_BUTTON, 0);
|
||||
|
||||
/* got_irq is active low */
|
||||
if (!got_irq) {
|
||||
reg_low = i2c_smbus_read_byte_data(dev, PX3220_PS_DATA_LOW);
|
||||
|
||||
reg_high = i2c_smbus_read_byte_data(dev, PX3220_PS_DATA_HIGH);
|
||||
|
||||
ps_val = ((reg_high & 0x3F) << 4) | (reg_low & 0xF);
|
||||
|
||||
if (ps_val > 0x58)
|
||||
shadow_proximity |= 0x1;
|
||||
else
|
||||
shadow_proximity |= 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
if (shadow_proximity)
|
||||
DBG(1,"shadow_proximity [%x]", shadow_proximity);
|
||||
}
|
||||
|
||||
static button_state_t px3220_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
struct button_data *p = (struct button_data *)drv->priv;
|
||||
|
||||
if (p->addr == 0 ){
|
||||
if (shadow_proximity & 1 ) {
|
||||
shadow_proximity &= ~0x1;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->addr == 1 ){
|
||||
if (shadow_proximity & 2 ) {
|
||||
shadow_proximity &= ~0x2;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
p->state = BUTTON_RELEASED;
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func button_func = {
|
||||
.get_state = px3220_button_get_state,
|
||||
};
|
||||
|
||||
void px3220_init(struct server_ctx *s_ctx) {
|
||||
|
||||
const char *p;
|
||||
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
p = ucix_get_option(s_ctx->uci_ctx, "hw", "board", "hardware");
|
||||
if (p == 0){
|
||||
syslog(LOG_INFO, "%s: Missing Hardware identifier in configuration. I2C is not started\n",__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Driver only existfor VOX25 board */
|
||||
if (strcmp("VOX25", p))
|
||||
return;
|
||||
|
||||
/* open i2c device */
|
||||
dev = i2c_open_dev("/dev/i2c-0", 0x1E,
|
||||
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE);
|
||||
if (dev < 0) {
|
||||
syslog(LOG_INFO,"%s: could not open i2c touch device\n",__func__);
|
||||
dev = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
do_init_tab(i2c_init_tab_vox25, sizeof(i2c_init_tab_vox25)/sizeof(struct i2c_reg_tab));
|
||||
|
||||
|
||||
/* read config file */
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"3220_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct button_data));
|
||||
memset(data,0,sizeof(struct button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
data->button.func = &button_func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef PROX_PX3220_H
|
||||
#define PROX_PX3220_H
|
||||
|
||||
#include "server.h"
|
||||
|
||||
void px3220_init(struct server_ctx *);
|
||||
void px3220_check(void);
|
||||
|
||||
#endif /* PROX_PX3220_H */
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#include "config.h"
|
||||
#include <syslog.h>
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "led.h"
|
||||
#include "button.h"
|
||||
#include "catv.h"
|
||||
#include "sfp.h"
|
||||
#include "touch_sx9512.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
struct server_ctx server;
|
||||
|
||||
void sim_led_init(struct server_ctx *);
|
||||
void sim_button_init(struct server_ctx *);
|
||||
|
||||
void gpio_led_init(struct server_ctx *);
|
||||
void gpio_button_init(struct server_ctx *);
|
||||
|
||||
void catv_monitor_init(struct server_ctx *);
|
||||
void vox_init(struct server_ctx *);
|
||||
|
||||
struct catv_handler *catv_h;
|
||||
struct sfp_handler *sfp_h;
|
||||
|
||||
void server_start(struct uci_context *uci_ctx, struct ubus_context *ubus_ctx)
|
||||
|
||||
{
|
||||
DBG(1, "init server context.");
|
||||
server.uci_ctx = uci_ctx;
|
||||
server.ubus_ctx = ubus_ctx;
|
||||
|
||||
DBG(1, "run init function for all hardware drivers.");
|
||||
|
||||
sim_led_init(&server);
|
||||
sim_button_init(&server);
|
||||
|
||||
#ifdef HAVE_BOARD_H
|
||||
gpio_led_init(&server);
|
||||
gpio_button_init(&server);
|
||||
|
||||
sx9512_handler_init(&server);
|
||||
|
||||
px3220_init(&server);
|
||||
|
||||
vox_init(&server);
|
||||
#endif
|
||||
|
||||
DBG(1, "connect generic buttons/leds to hardware drivers.");
|
||||
led_init(&server);
|
||||
button_init(&server);
|
||||
|
||||
sfp_h = sfp_init(uci_ctx);
|
||||
if (sfp_h) {
|
||||
sfp_ubus_populate(sfp_h, ubus_ctx);
|
||||
}
|
||||
|
||||
catv_h = catv_init(uci_ctx, "/dev/i2c-0", 0x50, 0x51);
|
||||
if (catv_h){
|
||||
catv_ubus_populate(catv_h, ubus_ctx);
|
||||
}
|
||||
|
||||
catv_monitor_init(&server);
|
||||
|
||||
DBG(1, "give control to uloop main loop.");
|
||||
uloop_run();
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
#include <libubus.h>
|
||||
#include "ucix.h"
|
||||
|
||||
struct server_ctx {
|
||||
struct uci_context *uci_ctx;
|
||||
struct ubus_context *ubus_ctx;
|
||||
};
|
||||
|
||||
void server_start( struct uci_context *uci_ctx, struct ubus_context *ubus_ctx);
|
||||
|
||||
#endif /* SERVER_H */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef SFP_H
|
||||
#include "libubus.h"
|
||||
#include "ucix.h"
|
||||
|
||||
struct sfp_handler;
|
||||
|
||||
struct sfp_handler * sfp_init(struct uci_context *uci_ctx);
|
||||
int sfp_ubus_populate(struct sfp_handler *h, struct ubus_context *ubus_ctx);
|
||||
void sfp_destroy(struct sfp_handler *h);
|
||||
|
||||
#endif /*SFP_H*/
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "button.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
|
||||
void sim_button_init(struct server_ctx *s_ctx);
|
||||
|
||||
struct sim_data {
|
||||
int addr;
|
||||
int active;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
struct drv_button_list{
|
||||
struct list_head list;
|
||||
struct button_drv *drv;
|
||||
};
|
||||
|
||||
static button_state_t sim_get_state(struct button_drv *drv)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
struct sim_data *p = (struct sim_data *)drv->priv;
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func func = {
|
||||
.get_state = sim_get_state,
|
||||
};
|
||||
|
||||
static LIST_HEAD(sim_buttons);
|
||||
|
||||
|
||||
enum {
|
||||
SIM_NAME,
|
||||
SIM_STATE,
|
||||
__SIM_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy sim_policy[] = {
|
||||
[SIM_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
|
||||
[SIM_STATE] = { .name = "state", .type = BLOBMSG_TYPE_STRING },
|
||||
};
|
||||
|
||||
static struct button_drv *get_drv_button(char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &sim_buttons) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
if (! strcmp(node->drv->name, name))
|
||||
return node->drv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sim_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__SIM_MAX];
|
||||
DBG(1, "");
|
||||
|
||||
blobmsg_parse(sim_policy, ARRAY_SIZE(sim_policy), tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
if ( tb[SIM_NAME] ) {
|
||||
if ( tb[SIM_STATE] ) {
|
||||
struct button_drv *bt = get_drv_button((char *)blobmsg_data(tb[SIM_NAME]));
|
||||
DBG(1," name = %s",(char *)blobmsg_data(tb[SIM_NAME]));
|
||||
DBG(1," state = %s",(char *)blobmsg_data(tb[SIM_STATE]));
|
||||
|
||||
if (bt) {
|
||||
struct sim_data *p = (struct sim_data *)bt->priv;
|
||||
|
||||
if(!strcasecmp("pressed", (char *)blobmsg_data(tb[SIM_STATE]))){
|
||||
p->state = BUTTON_PRESSED;
|
||||
}
|
||||
if(!strcasecmp("released", (char *)blobmsg_data(tb[SIM_STATE]))){
|
||||
p->state = BUTTON_RELEASED;
|
||||
}
|
||||
}else
|
||||
DBG(1," button = %s not found",(char *)blobmsg_data(tb[SIM_NAME]));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_status_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_buf blob;
|
||||
struct list_head *i;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
memset(&blob,0,sizeof(struct blob_buf));
|
||||
blob_buf_init(&blob, 0);
|
||||
|
||||
list_for_each(i, &sim_buttons) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
const char *state;
|
||||
struct sim_data *p = (struct sim_data *)node->drv->priv;
|
||||
|
||||
if(p->state == BUTTON_RELEASED)
|
||||
state = "Released";
|
||||
else
|
||||
state = "Pressed";
|
||||
|
||||
blobmsg_add_string(&blob, node->drv->name, state);
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, blob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct ubus_method sim_methods[] = {
|
||||
UBUS_METHOD("set", sim_set_method, sim_policy),
|
||||
{ .name = "status",
|
||||
.handler = sim_status_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type sim_object_type =
|
||||
UBUS_OBJECT_TYPE("sim", sim_methods);
|
||||
|
||||
#define SIM_OBJECTS 1
|
||||
static struct ubus_object sim_objects[SIM_OBJECTS] = {
|
||||
{ .name = "button",
|
||||
.type = &sim_object_type,
|
||||
.methods = sim_methods,
|
||||
.n_methods = ARRAY_SIZE(sim_methods),
|
||||
},
|
||||
};
|
||||
|
||||
void sim_button_init(struct server_ctx *s_ctx) {
|
||||
int i,ret;
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"sim_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct sim_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct sim_data));
|
||||
memset(data,0,sizeof(struct sim_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "active");
|
||||
data->active = -1;
|
||||
if (s){
|
||||
if (!strncasecmp("hi",s,2))
|
||||
data->active = 1;
|
||||
else if (!strncasecmp("low",s,3))
|
||||
data->active = 0;
|
||||
|
||||
}
|
||||
DBG(1, "active = %d", data->active);
|
||||
|
||||
data->button.func = &func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
|
||||
{ /* save button in internal list, we need this for ubus set/status */
|
||||
struct drv_button_list *bt = malloc(sizeof(struct drv_button_list));
|
||||
memset(bt, 0, sizeof(struct drv_button_list));
|
||||
bt->drv = &data->button;
|
||||
list_add(&bt->list, &sim_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<SIM_OBJECTS ; i++) {
|
||||
ret = ubus_add_object(s_ctx->ubus_ctx, &sim_objects[i]);
|
||||
if (ret)
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "led.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
void sim_led_init(struct server_ctx *s_ctx);
|
||||
|
||||
static int sim_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
DBG(1, "state %x on %s", state, drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static led_state_t sim_get_state(struct led_drv *drv)
|
||||
{
|
||||
DBG(1, "state for %s", drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_set_color(struct led_drv *drv, led_color_t color)
|
||||
{
|
||||
DBG(1, "color %d on %s", color, drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static led_color_t sim_get_color(struct led_drv *drv)
|
||||
{
|
||||
DBG(1, "color for %s", drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = sim_set_state,
|
||||
.get_state = sim_get_state,
|
||||
.set_color = sim_set_color,
|
||||
.get_color = sim_get_color,
|
||||
};
|
||||
|
||||
struct sim_data {
|
||||
int addr;
|
||||
led_color_t color;
|
||||
int state;
|
||||
int pulsing;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
void sim_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"sim_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct sim_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct sim_data));
|
||||
memset(data,0,sizeof(struct sim_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "color");
|
||||
if (s){
|
||||
if (!strncasecmp("red",s,3))
|
||||
data->color = RED;
|
||||
else if (!strncasecmp("green",s,5))
|
||||
data->color = GREEN;
|
||||
else if (!strncasecmp("blue",s,4))
|
||||
data->color = BLUE;
|
||||
else if (!strncasecmp("yellow",s,6))
|
||||
data->color = YELLOW;
|
||||
else if (!strncasecmp("white",s,5))
|
||||
data->color = WHITE;
|
||||
}
|
||||
DBG(1, "color = [%s]=(%d)", s,data->color);
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "pulsing");
|
||||
DBG(1, "pulsing = [%s]", s);
|
||||
if (s){
|
||||
if (!strncasecmp("yes",s,3))
|
||||
data->pulsing = 1;
|
||||
}
|
||||
data->led.func = &func;
|
||||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
smbus.c - SMBus level access helper functions
|
||||
|
||||
Copyright (C) 1995-1997 Simon G. Vogl
|
||||
Copyright (C) 1998-1999 Frodo Looijaard <frodol@dds.nl>
|
||||
Copyright (C) 2012-2013 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include "smbus.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
|
||||
/* Compatibility defines */
|
||||
#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN
|
||||
#define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA
|
||||
#endif
|
||||
#ifndef I2C_FUNC_SMBUS_PEC
|
||||
#define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC
|
||||
#endif
|
||||
|
||||
__s32 i2c_smbus_access(int file, char read_write, __u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_smbus_ioctl_data args;
|
||||
__s32 err;
|
||||
|
||||
args.read_write = read_write;
|
||||
args.command = command;
|
||||
args.size = size;
|
||||
args.data = data;
|
||||
|
||||
err = ioctl(file, I2C_SMBUS, &args);
|
||||
if (err == -1)
|
||||
err = -errno;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
__s32 i2c_smbus_write_quick(int file, __u8 value)
|
||||
{
|
||||
return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_read_byte(int file)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0x0FF & data.byte;
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_byte(int file, __u8 value)
|
||||
{
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, value,
|
||||
I2C_SMBUS_BYTE, NULL);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_read_byte_data(int file, __u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0x0FF & data.byte;
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.byte = value;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_read_word_data(int file, __u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0x0FFFF & data.word;
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.word = value;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.word = value;
|
||||
if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_PROC_CALL, &data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FFFF & data.word;
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i, err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data);
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
|
||||
ask for less than 32 bytes, your code will only work with kernels
|
||||
2.6.23 and later. */
|
||||
__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
__u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i, err;
|
||||
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
data.block[0] = length;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
|
||||
I2C_SMBUS_I2C_BLOCK_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
|
||||
__u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i, err;
|
||||
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_BLOCK_PROC_CALL, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
smbus.h - SMBus level access helper functions
|
||||
|
||||
Copyright (C) 1995-97 Simon G. Vogl
|
||||
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef LIB_I2C_SMBUS_H
|
||||
#define LIB_I2C_SMBUS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
extern __s32 i2c_smbus_access(int file, char read_write, __u8 command,
|
||||
int size, union i2c_smbus_data *data);
|
||||
|
||||
extern __s32 i2c_smbus_write_quick(int file, __u8 value);
|
||||
extern __s32 i2c_smbus_read_byte(int file);
|
||||
extern __s32 i2c_smbus_write_byte(int file, __u8 value);
|
||||
extern __s32 i2c_smbus_read_byte_data(int file, __u8 command);
|
||||
extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
|
||||
extern __s32 i2c_smbus_read_word_data(int file, __u8 command);
|
||||
extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
|
||||
extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
|
||||
extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values);
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
|
||||
ask for less than 32 bytes, your code will only work with kernels
|
||||
2.6.23 and later. */
|
||||
extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
__u8 *values);
|
||||
extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values);
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
|
||||
__u8 *values);
|
||||
|
||||
#endif /* LIB_I2C_SMBUS_H */
|
||||
|
|
@ -1,348 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "sx9512.h"
|
||||
#include "smbus.h"
|
||||
#include "i2c.h"
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
#define X(name, reserved, default) { #name, reserved, default },
|
||||
const struct sx9512_reg_data sx9512_reg_data[] = { SX9512_REGS };
|
||||
#undef X
|
||||
|
||||
|
||||
//! init the sx9512 and optionally program the registers
|
||||
|
||||
//! @param addr I2C address (0=0x2c)
|
||||
//! @param nvm compare and if different program the registers and flash the NVM with these contents
|
||||
//! @return file descriptor for SX9512 I2C device
|
||||
//! @retval -1 error
|
||||
int sx9512_init(const char *dev, int addr, struct sx9512_reg_nvm *nvm)
|
||||
{
|
||||
int fd, i;
|
||||
struct sx9512_reg_nvm nvm_read;
|
||||
if(!addr)
|
||||
addr=SX9512_I2C_ADDRESS;
|
||||
if((fd=i2c_open_dev(dev, addr, I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE))<0)
|
||||
return -1;
|
||||
/*fd = open(dev, O_RDWR);
|
||||
if(fd < 0) {
|
||||
error(0, errno, "could not open %s", dev);
|
||||
return -1;
|
||||
}
|
||||
if(ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
error(0, errno, "could not set address %x for i2c chip", SX9512_I2C_ADDRESS);
|
||||
close(fd);
|
||||
return -1;
|
||||
}*/
|
||||
if(nvm) {
|
||||
if(sx9512_reg_nvm_read(fd, &nvm_read)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
for(i=0;(unsigned int)i<sizeof(struct sx9512_reg_nvm);i++) {
|
||||
if(sx9512_reg_reserved(i+SX9512_REG_NVM_AREA_START))
|
||||
continue;
|
||||
if(((uint8_t *)nvm)[i] != ((uint8_t *)&nvm_read)[i]) {
|
||||
fprintf(stderr, "sx9512_init: register mismatch, setting default values and burning to NVM\n");
|
||||
if(sx9512_reg_nvm_write(fd, nvm)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
sx9512_reg_nvm_store(fd); //store to NVM
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
const char *sx9512_reg_name(sx9512_reg_t reg)
|
||||
{
|
||||
return sx9512_reg_data[reg].name;
|
||||
}
|
||||
|
||||
|
||||
//! SX9512 check if reg is reserved
|
||||
int sx9512_reg_reserved(sx9512_reg_t reg)
|
||||
{
|
||||
if(reg==SX9512_REG_I2C_SOFT_RESET)
|
||||
return 0;
|
||||
if(reg>=SX9512_REGS_AMOUNT)
|
||||
return 1;
|
||||
return sx9512_reg_data[reg].reserved;
|
||||
}
|
||||
|
||||
|
||||
//! send reset command
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reset(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_I2C_SOFT_RESET, 0xde)<0)
|
||||
return -1;
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_I2C_SOFT_RESET, 0x00)<0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send reset command but retain LED values
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reset_restore_led_state(int fd)
|
||||
{
|
||||
int r;
|
||||
uint8_t p[4];
|
||||
if((r=i2c_smbus_read_i2c_block_data(fd, SX9512_REG_LED1_ON, 4, (__u8 *)&p))<0)
|
||||
return r;
|
||||
if(sx9512_reset(fd))
|
||||
return -1;
|
||||
if((r=i2c_smbus_write_i2c_block_data(fd, SX9512_REG_LED1_ON, 4, (__u8 *)&p))<0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read interrupt reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_interrupt(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_IRQ_SRC))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read touch reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_buttons(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_TOUCH_STATUS))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read prox reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_proximity(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_PROX_STATUS))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read status regs
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_read_status(int fd, struct sx9512_reg_status *status)
|
||||
{
|
||||
//REG_IRQ_SRC not working if using block read for some reason.
|
||||
//if(i2c_smbus_read_i2c_block_data(fd, SX9512_REG_IRQ_SRC, sizeof(struct sx9512_reg_status), (uint8_t *)status)<0)
|
||||
//return -1;
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_IRQ_SRC))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[0]=r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_TOUCH_STATUS))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[1]=r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_PROX_STATUS))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[2]=r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read status cached
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_read_status_cached(int fd, struct sx9512_touch_state *touch_state)
|
||||
{
|
||||
static uint8_t last_state=0;
|
||||
struct sx9512_reg_status status;
|
||||
touch_state->touched=0;
|
||||
touch_state->released=0;
|
||||
if(sx9512_read_status(fd, &status))
|
||||
error(-1, errno, "I2C read error");
|
||||
touch_state->state=status.touch_status | !!((*(uint8_t *)&status.prox_status) & 0xc0);
|
||||
if(*(uint8_t *)&status.irq_src) {
|
||||
if(status.irq_src.touch || status.irq_src.prox_near)
|
||||
touch_state->touched = (last_state ^ touch_state->state) & touch_state->state;
|
||||
if(status.irq_src.release || status.irq_src.prox_far)
|
||||
touch_state->released = (last_state ^ touch_state->state) & last_state;
|
||||
}
|
||||
last_state=touch_state->state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send cmd to load values from NVM to RAM
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_load(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0x08)<0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send cmd to store RAM to NVM
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_store(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0x50)<0)
|
||||
return -1;
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0xa0)<0)
|
||||
return -1;
|
||||
//Wait 500ms then power off/on
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read whole NVM region
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_read(int fd, struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int r, s, i, rl;
|
||||
s=sizeof(struct sx9512_reg_nvm);
|
||||
for(i=0; i<s; i+=32) {
|
||||
rl=s-i;
|
||||
if(rl>32)
|
||||
rl=32;
|
||||
if((r=i2c_smbus_read_i2c_block_data(fd, SX9512_REG_NVM_AREA_START+i, rl, (uint8_t *)p+i))<0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! write whole NVM region
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_write(int fd, struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int r, s, i, rl;
|
||||
s=sizeof(struct sx9512_reg_nvm);
|
||||
for(i=0; i<s; i+=32) {
|
||||
rl=s-i;
|
||||
if(rl>32)
|
||||
rl=32;
|
||||
if((r=i2c_smbus_write_i2c_block_data(fd, SX9512_REG_NVM_AREA_START+i, rl, (uint8_t *)p+i))<0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! init NVM struct
|
||||
void sx9512_reg_nvm_init(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
memset(p, 0, sizeof(struct sx9512_reg_nvm));
|
||||
p->cap_sense_op.set_to_0x14=0x14;
|
||||
}
|
||||
|
||||
|
||||
//! init NVM struct to defaults
|
||||
void sx9512_reg_nvm_init_defaults(struct sx9512_reg_nvm *p, uint8_t capsense_channels, uint8_t led_channels)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init(p);
|
||||
p->irq_mask.touch=1;
|
||||
p->irq_mask.release=1;
|
||||
p->irq_mask.prox_near=1;
|
||||
p->irq_mask.prox_far=1;
|
||||
if(led_channels) {
|
||||
p->led_map[0]=0x00;
|
||||
//p->led_map[1]=led_channels;
|
||||
p->led_map[1]=0x00; //default all leds off
|
||||
p->led_pwm_freq=0x10;
|
||||
p->led_idle=0xff;
|
||||
p->led1_on=0xff;
|
||||
p->led2_on=0xff;
|
||||
p->led_pwr_idle=0xff;
|
||||
p->led_pwr_on=0xff;
|
||||
}
|
||||
p->cap_sense_enable=capsense_channels;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].ls_control=0x01;
|
||||
p->cap_sense_range[i].delta_cin_range=0x03;
|
||||
p->cap_sense_thresh[i]=0x04;
|
||||
}
|
||||
p->cap_sense_thresh[0]=0x02;
|
||||
p->cap_sense_op.auto_compensation=0;
|
||||
p->cap_sense_op.proximity_bl0=1;
|
||||
p->cap_sense_op.proximity_combined_channels=0;
|
||||
p->cap_sense_mode.raw_filter=0x03;
|
||||
p->cap_sense_mode.touch_reporting=1;
|
||||
p->cap_sense_mode.cap_sense_digital_gain=0;
|
||||
p->cap_sense_mode.cap_sense_report_mode=0;
|
||||
p->cap_sense_debounce.cap_sense_prox_near_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_prox_far_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_touch_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_release_debounce=1;
|
||||
p->cap_sense_neg_comp_thresh=0x80;
|
||||
p->cap_sense_pos_comp_thresh=0x80;
|
||||
p->cap_sense_pos_filt.cap_sense_prox_hyst=0;
|
||||
p->cap_sense_pos_filt.cap_sense_pos_comp_debounce=2;
|
||||
p->cap_sense_pos_filt.cap_sense_avg_pos_filt_coef=7;
|
||||
p->cap_sense_neg_filt.cap_sense_touch_hyst=0;
|
||||
p->cap_sense_neg_filt.cap_sense_neg_comp_debounce=2;
|
||||
p->cap_sense_neg_filt.cap_sense_avg_neg_filt_coef=5;
|
||||
p->spo_chan_map=0xff;
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_cg300(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init_defaults(p, 0x0f, 0x3c);
|
||||
p->led_map[0]=0x01;
|
||||
p->led_map[1]=0x3c;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].delta_cin_range=0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_cg301(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init_defaults(p, 0x3b, 0x7f);
|
||||
p->led_map[1]=0x7f;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].delta_cin_range=0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_eg300(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
sx9512_reg_nvm_init_defaults(p, 0x0f, 0xff);
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_dg400(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
sx9512_reg_nvm_init_defaults(p, 0x3f, 0x00);
|
||||
}
|
||||
|
|
@ -1,605 +0,0 @@
|
|||
#ifndef _SX9512_H
|
||||
#define _SX9512_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BIT_ORDER_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define SX9512_I2C_ADDRESS 0x2b
|
||||
#define SX9512B_I2C_ADDRESS 0x2d
|
||||
#define SX9512_CHANNELS 8
|
||||
|
||||
#define SX9512_REG_NVM_AREA_START 0x07
|
||||
#define SX9512_REG_NVM_AREA_END 0x62
|
||||
|
||||
#define SX9512_REG_I2C_SOFT_RESET 0xff
|
||||
|
||||
//Name, reserved, default value
|
||||
#define SX9512_REGS \
|
||||
X(IRQ_SRC, 0, 0x00) \
|
||||
X(TOUCH_STATUS, 0, 0x00) \
|
||||
X(PROX_STATUS, 0, 0x00) \
|
||||
X(COMP_STATUS, 0, 0x00) \
|
||||
X(NVM_CTRL, 0, 0x00) \
|
||||
X(R_05, 1, 0x00) \
|
||||
X(R_06, 1, 0x00) \
|
||||
X(SPO2_MODE, 0, 0x00) \
|
||||
X(PWR_KEY, 0, 0x00) \
|
||||
X(IRQ_MASK, 0, 0x00) \
|
||||
X(R_0A, 1, 0x00) \
|
||||
X(R_0B, 1, 0x00) \
|
||||
X(LED_MAP1, 0, 0x00) \
|
||||
X(LED_MAP2, 0, 0x00) \
|
||||
X(LED_PWM_FREQ, 0, 0x00) \
|
||||
X(LED_MODE, 0, 0x00) \
|
||||
X(LED_IDLE, 0, 0x00) \
|
||||
X(LED_OFF_DELAY, 0, 0x00) \
|
||||
X(LED1_ON, 0, 0x00) \
|
||||
X(LED1_FADE, 0, 0x00) \
|
||||
X(LED2_ON, 0, 0x00) \
|
||||
X(LED2_FADE, 0, 0x00) \
|
||||
X(LED_PWR_IDLE, 0, 0x00) \
|
||||
X(LED_PWR_ON, 0, 0x00) \
|
||||
X(LED_PWR_OFF, 0, 0x00) \
|
||||
X(LED_PWR_FADE, 0, 0x00) \
|
||||
X(LED_PWR_ON_PW, 0, 0x00) \
|
||||
X(LED_PWR_MODE, 0, 0x00) \
|
||||
X(R_1C, 1, 0x00) \
|
||||
X(R_1D, 1, 0x00) \
|
||||
X(CAP_SENSE_ENABLE, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE0, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE1, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE2, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE3, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE4, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE5, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE6, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE7, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE_ALL, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH0, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH1, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH2, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH3, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH4, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH5, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH6, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH7, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH_COMB, 0, 0x00) \
|
||||
X(CAP_SENSE_OP, 0, 0x00) \
|
||||
X(CAP_SENSE_MODE, 0, 0x00) \
|
||||
X(CAP_SENSE_DEBOUNCE, 0, 0x00) \
|
||||
X(CAP_SENSE_NEG_COMP_THRESH, 0, 0x00) \
|
||||
X(CAP_SENSE_POS_COMP_THRESH, 0, 0x00) \
|
||||
X(CAP_SENSE_POS_FILT, 0, 0x00) \
|
||||
X(CAP_SENSE_NEG_FILT, 0, 0x00) \
|
||||
X(CAP_SENSE_STUCK, 0, 0x00) \
|
||||
X(CAP_SENSE_FRAME_SKIP, 0, 0x00) \
|
||||
X(CAP_SENSE_MISC, 0, 0x00) \
|
||||
X(PROX_COMB_CHAN_MASK, 0, 0x00) \
|
||||
X(R_3C, 1, 0x00) \
|
||||
X(R_3D, 1, 0x00) \
|
||||
X(SPO_CHAN_MAP, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL0, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL1, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL2, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL3, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL4, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL5, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL6, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL7, 0, 0x00) \
|
||||
X(SPO_LEVEL_IDLE, 0, 0x00) \
|
||||
X(SPO_LEVEL_PROX, 0, 0x00) \
|
||||
X(R_49, 1, 0x00) \
|
||||
X(R_4A, 1, 0x00) \
|
||||
X(BUZZER_TRIGGER, 0, 0x00) \
|
||||
X(BUZZER_FREQ, 0, 0x00) \
|
||||
X(R_4D, 1, 0x00) \
|
||||
X(R_4E, 1, 0x00) \
|
||||
X(R_4F, 1, 0x00) \
|
||||
X(R_50, 1, 0x00) \
|
||||
X(R_51, 1, 0x00) \
|
||||
X(R_52, 1, 0x00) \
|
||||
X(R_53, 1, 0x00) \
|
||||
X(R_54, 1, 0x00) \
|
||||
X(R_55, 1, 0x00) \
|
||||
X(R_56, 1, 0x00) \
|
||||
X(R_57, 1, 0x00) \
|
||||
X(R_58, 1, 0x00) \
|
||||
X(R_59, 1, 0x00) \
|
||||
X(R_5A, 1, 0x00) \
|
||||
X(R_5B, 1, 0x00) \
|
||||
X(R_5C, 1, 0x00) \
|
||||
X(R_5D, 1, 0x00) \
|
||||
X(R_5E, 1, 0x00) \
|
||||
X(R_5F, 1, 0x00) \
|
||||
X(R_60, 1, 0x00) \
|
||||
X(R_61, 1, 0x00) \
|
||||
X(CAP_SENSE_CHAN_SELECT, 0, 0x00) \
|
||||
X(CAP_SENSE_USEFUL_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_USEFUL_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_AVERAGE_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_AVERAGE_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_DIFF_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_DIFF_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_COMP_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_COMP_LSB, 0, 0x00)
|
||||
|
||||
|
||||
#define X(name, reserved, default) SX9512_REG_##name,
|
||||
typedef enum { SX9512_REGS SX9512_REGS_AMOUNT } sx9512_reg_t;
|
||||
#undef X
|
||||
|
||||
|
||||
struct sx9512_reg_data {
|
||||
const char *name;
|
||||
uint8_t reserved, default_value;
|
||||
};
|
||||
|
||||
|
||||
//! Interrupt source
|
||||
|
||||
//! The Irq Source register will indicate that the specified event has occurred since the last read of this register. If the
|
||||
//! NIRQ function is selected for SPO2 then it will indicate the occurrence of any of these events that are not masked
|
||||
//! out in register 0x09.
|
||||
//! The Irq mask in register 0x09 will prevent an Irq from being indicated by the NIRQ pin but it will not prevent the
|
||||
//! IRQ from being noted in this register.
|
||||
struct sx9512_reg_irq_src {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t reset:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t release:1;
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t compensation_done:1; //!< write 1 to trigger compensation on all channels
|
||||
uint8_t conversion_done:1;
|
||||
uint8_t :1;
|
||||
#else
|
||||
uint8_t :1;
|
||||
uint8_t conversion_done:1;
|
||||
uint8_t compensation_done:1; //!< write 1 to trigger compensation on all channels
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t release:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t reset:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Proximity status
|
||||
struct sx9512_reg_prox_status {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t prox_bl0:1; //!< proximity detected on BL0
|
||||
uint8_t prox_multi:1; //!< proximity detected on combined channels
|
||||
uint8_t prox_multi_comp_pending:1; //!< compensation pending for combined channel prox sensing
|
||||
uint8_t :5;
|
||||
#else
|
||||
uint8_t :5;
|
||||
uint8_t prox_multi_comp_pending:1; //!< compensation pending for combined channel prox sensing
|
||||
uint8_t prox_multi:1; //!< proximity detected on combined channels
|
||||
uint8_t prox_bl0:1; //!< proximity detected on BL0
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! NVM Control
|
||||
|
||||
//! The NVM Area field indicates which of the user NVM areas are currently programmed and active (1, 2 or 3). The
|
||||
//! NVM Read bit gives the ability to manually request that the contents of the NVM be transferred to the registers
|
||||
//! and NVM Burn field gives the ability to burn the current registers to the next available NVM area.
|
||||
//! Normally, the transfer of data from the NVM to the registers is done automatically on power up and upon a reset
|
||||
//! but occasionally a user might want to force a read manually.
|
||||
//! Registers 0x07 through 0x62 are stored to NVM and loaded from NVM.
|
||||
//! After writing 0xA0 (ie NVM burn), wait for at least 500ms and then power off-on the IC for changes to be effective.
|
||||
//! Caution, there are only three user areas and attempts to burn values beyond user area 3 will be ignored.
|
||||
struct sx9512_reg_nvm_ctrl {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t nvm_burn:4; //!< write 0x50 followed by 0xA0 to initiate transfer of reg 0x07-0x62 to NVM
|
||||
uint8_t nvm_read:1; //!< trigger NVM read to registers
|
||||
uint8_t nvm_area:3; //!< indicates current active NVM area
|
||||
#else
|
||||
uint8_t nvm_area:3; //!< indicates current active NVM area
|
||||
uint8_t nvm_read:1; //!< trigger NVM read to registers
|
||||
uint8_t nvm_burn:4; //!< write 0x50 followed by 0xA0 to initiate transfer of reg 0x07-0x62 to NVM
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! SPO2 Mode Control
|
||||
|
||||
//! The SPO2 Config field will specify the functionality of the SPO pin. When selected as NIRQ, the open drain output
|
||||
//! will go low whenever a non-masked Irq occurs and the NIRQ will go back high after a register 0x00 is read over
|
||||
//! the I2C. When selected as Buzzer, the SPO2 pin will drive a 2 phase 2 frequency signal onto an external buzzer
|
||||
//! for each specified event (see Buzzer section). When selected as SPO2, pin operates as an analog output similar
|
||||
//! to SPO1 (see SPO section). If selected as TV power state, the pin is driven from the system PMIC with a high
|
||||
//! (SPO2 = SVDD) indicating that the system power is on and a low (SPO2 = GND) when the system power is off.
|
||||
//! The TV Power State bit reads back the current state of SPO2 if SPO2 is selected for TV power state, otherwise
|
||||
//! the system should write to this bit to indicate the current system power state. The SX9512/12B/13/13B needs to
|
||||
//! know the current state in able to correctly process some of the LED modes for the Power Button (see LED
|
||||
//! modes).
|
||||
struct sx9512_reg_spo2_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :1;
|
||||
uint8_t spo2_config:2; //!< set function of SPO2 pin
|
||||
uint8_t tv_power_state:1; //!< if SPO2 set to TV power state input then TV power state indicated by this bit.
|
||||
uint8_t :4;
|
||||
#else
|
||||
uint8_t :4;
|
||||
uint8_t tv_power_state:1; //!< if SPO2 set to TV power state input then TV power state indicated by this bit.
|
||||
uint8_t spo2_config:2; //!< set function of SPO2 pin
|
||||
uint8_t :1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Interrupt Request Mask
|
||||
|
||||
//! Set which Irqs will trigger an NIRQ (if enabled on SPO2) and report in reg 0x00
|
||||
//! 0=Disable IRQ
|
||||
//! 1=Enable IRQ
|
||||
struct sx9512_reg_irq_mask {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t reset:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t release:1;
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t compensation_done:1;
|
||||
uint8_t :2;
|
||||
#else
|
||||
uint8_t :2;
|
||||
uint8_t compensation_done:1;
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t release:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t reset:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED Mode
|
||||
struct sx9512_reg_led_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_fade_repeat:4;
|
||||
uint8_t :1;
|
||||
uint8_t led_fading:1;
|
||||
uint8_t led_mode:2;
|
||||
#else
|
||||
uint8_t led_mode:2;
|
||||
uint8_t led_fading:1;
|
||||
uint8_t :1;
|
||||
uint8_t led_fade_repeat:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED off delay
|
||||
struct sx9512_reg_led_off_delay {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_engine1_delay_off_time:4;
|
||||
uint8_t led_engine2_delay_off_time:4;
|
||||
#else
|
||||
uint8_t led_engine2_delay_off_time:4;
|
||||
uint8_t led_engine1_delay_off_time:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED Engine fade in/out timing
|
||||
struct sx9512_reg_led_fade {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_engine_fade_in_time:4;
|
||||
uint8_t led_engine_fade_out_time:4;
|
||||
#else
|
||||
uint8_t led_engine_fade_out_time:4;
|
||||
uint8_t led_engine_fade_in_time:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED power button mode
|
||||
struct sx9512_reg_led_pwr_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t power_led_off_mode:1;
|
||||
uint8_t power_led_max_level:1;
|
||||
uint8_t power_led_breath_max:1;
|
||||
uint8_t power_led_waveform:1;
|
||||
uint8_t :2;
|
||||
uint8_t power_button_enable:1;
|
||||
uint8_t led_touch_poarity_invert:1;
|
||||
#else
|
||||
uint8_t led_touch_poarity_invert:1;
|
||||
uint8_t power_button_enable:1;
|
||||
uint8_t :2;
|
||||
uint8_t power_led_waveform:1;
|
||||
uint8_t power_led_breath_max:1;
|
||||
uint8_t power_led_max_level:1;
|
||||
uint8_t power_led_off_mode:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense delta Cin range and LS control
|
||||
struct sx9512_reg_cap_sense_range {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t ls_control:2;
|
||||
uint8_t :4;
|
||||
uint8_t delta_cin_range:2;
|
||||
#else
|
||||
uint8_t delta_cin_range:2;
|
||||
uint8_t :4;
|
||||
uint8_t ls_control:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense auto compensation, proximity on BL0 and combined channel proximity
|
||||
struct sx9512_reg_cap_sense_op {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t auto_compensation:1;
|
||||
uint8_t proximity_bl0:1;
|
||||
uint8_t proximity_combined_channels:1;
|
||||
uint8_t set_to_0x14:5;
|
||||
#else
|
||||
uint8_t set_to_0x14:5;
|
||||
uint8_t proximity_combined_channels:1;
|
||||
uint8_t proximity_bl0:1;
|
||||
uint8_t auto_compensation:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense raw data filter coef, digital gain, I2C touch reporting and CapSense
|
||||
struct sx9512_reg_cap_sense_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t raw_filter:3;
|
||||
uint8_t touch_reporting:1;
|
||||
uint8_t cap_sense_digital_gain:2;
|
||||
uint8_t cap_sense_report_mode:2;
|
||||
#else
|
||||
uint8_t cap_sense_report_mode:2;
|
||||
uint8_t cap_sense_digital_gain:2;
|
||||
uint8_t touch_reporting:1;
|
||||
uint8_t raw_filter:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense debounce
|
||||
struct sx9512_reg_cap_sense_debounce {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_prox_near_debounce:2;
|
||||
uint8_t cap_sense_prox_far_debounce:2;
|
||||
uint8_t cap_sense_touch_debounce:2;
|
||||
uint8_t cap_sense_release_debounce:2;
|
||||
#else
|
||||
uint8_t cap_sense_release_debounce:2;
|
||||
uint8_t cap_sense_touch_debounce:2;
|
||||
uint8_t cap_sense_prox_far_debounce:2;
|
||||
uint8_t cap_sense_prox_near_debounce:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense positive filter coef, positive auto compensation debounce and proximity hyst
|
||||
struct sx9512_reg_cap_sense_pos_filt {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_prox_hyst:3;
|
||||
uint8_t cap_sense_pos_comp_debounce:2;
|
||||
uint8_t cap_sense_avg_pos_filt_coef:3;
|
||||
#else
|
||||
uint8_t cap_sense_avg_pos_filt_coef:3;
|
||||
uint8_t cap_sense_pos_comp_debounce:2;
|
||||
uint8_t cap_sense_prox_hyst:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense negative filter coef, negative auto compensation debounce and touch hyst
|
||||
struct sx9512_reg_cap_sense_neg_filt {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_touch_hyst:3;
|
||||
uint8_t cap_sense_neg_comp_debounce:2;
|
||||
uint8_t cap_sense_avg_neg_filt_coef:3;
|
||||
#else
|
||||
uint8_t cap_sense_avg_neg_filt_coef:3;
|
||||
uint8_t cap_sense_neg_comp_debounce:2;
|
||||
uint8_t cap_sense_touch_hyst:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense stuck-at timer and periodic compensation timer
|
||||
struct sx9512_reg_cap_sense_stuck {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_stuck_at_timer:4;
|
||||
uint8_t cap_sense_periodic_comp:4;
|
||||
#else
|
||||
uint8_t cap_sense_periodic_comp:4;
|
||||
uint8_t cap_sense_stuck_at_timer:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense frame skip setting from active and sleep
|
||||
struct sx9512_reg_cap_sense_frame_skip {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_active_frame_skip:4;
|
||||
uint8_t cap_sense_sleep_frame_skip:4;
|
||||
#else
|
||||
uint8_t cap_sense_sleep_frame_skip:4;
|
||||
uint8_t cap_sense_active_frame_skip:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense sleep enable, auto compensation channels threshold, inactive BL control
|
||||
struct sx9512_reg_cap_sense_misc {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :2;
|
||||
uint8_t comp_chan_num_thresh:2;
|
||||
uint8_t cap_sense_sleep_mode_enable:1;
|
||||
uint8_t :1;
|
||||
uint8_t cap_sense_inactive_bl_mode:2;
|
||||
#else
|
||||
uint8_t cap_sense_inactive_bl_mode:2;
|
||||
uint8_t :1;
|
||||
uint8_t cap_sense_sleep_mode_enable:1;
|
||||
uint8_t comp_chan_num_thresh:2;
|
||||
uint8_t :2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! SPO analog output for proximity
|
||||
struct sx9512_reg_spo_level_prox {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t spo_report_prox:1;
|
||||
uint8_t spo_prox_channel_mapping:1;
|
||||
uint8_t spo_level_prox:6;
|
||||
#else
|
||||
uint8_t spo_level_prox:6;
|
||||
uint8_t spo_prox_channel_mapping:1;
|
||||
uint8_t spo_report_prox:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Buzzer trigger event selection
|
||||
struct sx9512_reg_buzzer_trigger {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :3;
|
||||
uint8_t buzzer_near:1;
|
||||
uint8_t buzzer_far:1;
|
||||
uint8_t buzzer_touch:1;
|
||||
uint8_t buzzer_release:1;
|
||||
uint8_t buzzer_idle_level:1;
|
||||
#else
|
||||
uint8_t buzzer_idle_level:1;
|
||||
uint8_t buzzer_release:1;
|
||||
uint8_t buzzer_touch:1;
|
||||
uint8_t buzzer_far:1;
|
||||
uint8_t buzzer_near:1;
|
||||
uint8_t :3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Buzzer duration frequency
|
||||
struct sx9512_reg_buzzer_freq {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t buzzer_phase1_duration:2;
|
||||
uint8_t buzzer_phase1_freq:2;
|
||||
uint8_t buzzer_phase2_duration:2;
|
||||
uint8_t buzzer_phase2_freq:2;
|
||||
#else
|
||||
uint8_t buzzer_phase2_freq:2;
|
||||
uint8_t buzzer_phase2_duration:2;
|
||||
uint8_t buzzer_phase1_freq:2;
|
||||
uint8_t buzzer_phase1_duration:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg_nvm {
|
||||
struct sx9512_reg_spo2_mode spo2_mode; //!< SPO2 mode control
|
||||
uint8_t pwr_key; //!< Power key control
|
||||
struct sx9512_reg_irq_mask irq_mask; //!< Interrupt request mask
|
||||
uint8_t reserved_0a[2];
|
||||
uint8_t led_map[2]; //!< LED map for engine 1/2
|
||||
uint8_t led_pwm_freq; //!< LED PWM frequency
|
||||
struct sx9512_reg_led_mode led_mode; //!< LED mode
|
||||
uint8_t led_idle; //!< LED idle level
|
||||
struct sx9512_reg_led_off_delay led_off_delay; //!< LED off delay
|
||||
uint8_t led1_on; //!< LED engine 1 on level
|
||||
struct sx9512_reg_led_fade led1_fade; //!< LED engine 1 fade in/out time
|
||||
uint8_t led2_on; //!< LED engine 2 on level
|
||||
struct sx9512_reg_led_fade led2_fade; //!< LED engine 2 fade in/out time
|
||||
uint8_t led_pwr_idle; //!< LED power button idle level
|
||||
uint8_t led_pwr_on; //!< LED power button on level
|
||||
uint8_t led_pwr_off; //!< LED power button off level
|
||||
uint8_t led_pwr_fade; //!< LED power button fade in/out time
|
||||
uint8_t led_pwr_on_pw; //!< LED power on pulse width
|
||||
struct sx9512_reg_led_pwr_mode led_pwr_mode; //!< LED power button mode
|
||||
uint8_t reserved_1c[2];
|
||||
uint8_t cap_sense_enable; //!< CapSense enable
|
||||
struct sx9512_reg_cap_sense_range cap_sense_range[9]; //!< CapSense delta Cin range and LS control chan 0-7
|
||||
//struct sx9512_reg_cap_sense_range cap_sense_range_all; //!< CapSense delta Cin range and LS control for prox sensor (combined channels)
|
||||
uint8_t cap_sense_thresh[9]; //!< CapSense detection threshold for chan 0-7
|
||||
//uint8_t cap_sense_thesh_comb; //!< CapSense detection threshold for prox sensor (combined channels)
|
||||
struct sx9512_reg_cap_sense_op cap_sense_op; //!< CapSense auto compensation, proximity on BL0 and combined channel proximity enable
|
||||
struct sx9512_reg_cap_sense_mode cap_sense_mode; //!< CapSense raw data filter coef, digital gain, I2C touch reporting and CapSense reporting
|
||||
struct sx9512_reg_cap_sense_debounce cap_sense_debounce; //!< CapSense debounce
|
||||
uint8_t cap_sense_neg_comp_thresh; //!< CapSense negative auto compensation threshold
|
||||
uint8_t cap_sense_pos_comp_thresh; //!< CapSense positive auto compensation threshold
|
||||
struct sx9512_reg_cap_sense_pos_filt cap_sense_pos_filt; //!< CapSense positive filter coef, positive auto compensation debounce and proximity hyst
|
||||
struct sx9512_reg_cap_sense_neg_filt cap_sense_neg_filt; //!< CapSense negative filter coef, negative auto compensation debounce and touch hyst
|
||||
struct sx9512_reg_cap_sense_stuck cap_sense_stuck; //!< CapSense stuck-at timer and periodic compensation timer
|
||||
struct sx9512_reg_cap_sense_frame_skip cap_sense_frame_skip; //!< CapSense frame skip setting from active and sleep
|
||||
struct sx9512_reg_cap_sense_misc cap_sense_misc; //!< CapSense sleep enable, auto compensation channels threshold, inactive BL control
|
||||
uint8_t prox_comb_chan_mask; //!< Proximity combined channel mode channel mapping
|
||||
uint8_t reserved_3c[2];
|
||||
uint8_t spo_chan_map; //!< SPO channel mapping
|
||||
uint8_t spo_level_bl[8]; //!< SPO analog output levels
|
||||
uint8_t spo_level_idle; //!< SPO analog output level for idle
|
||||
struct sx9512_reg_spo_level_prox spo_level_prox; //!< SPO analog output for proximity
|
||||
uint8_t reserved_49[2];
|
||||
struct sx9512_reg_buzzer_trigger buzzer_trigger; //!< Buzzer trigger event selection
|
||||
struct sx9512_reg_buzzer_freq buzzer_freq; //!< Buzzer duration frequency
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg {
|
||||
struct sx9512_reg_irq_src irq_src; //!< Interrupt source
|
||||
uint8_t touch_status; //!< Touch status
|
||||
struct sx9512_reg_prox_status prox_status; //!< Proximity status
|
||||
uint8_t comp_status; //!< Compensation status
|
||||
struct sx9512_reg_nvm_ctrl nvm_ctrl; //!< NVM control
|
||||
struct sx9512_reg_nvm nvm; //!< Non-volatile memory
|
||||
uint8_t cap_sense_chan_select; //!< CapSense channel select for readback
|
||||
uint16_t cap_sense_useful_data; //!< CapSense useful data
|
||||
uint16_t cap_sense_average_data; //!< CapSense average data
|
||||
uint16_t cap_sense_diff_data; //!< CapSense diff data
|
||||
uint16_t cap_sense_comp; //!< CapSense compensation DAC value
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg_status {
|
||||
struct sx9512_reg_irq_src irq_src; //!< Interrupt source
|
||||
uint8_t touch_status; //!< Touch status
|
||||
struct sx9512_reg_prox_status prox_status; //!< Proximity status
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_touch_state {
|
||||
uint8_t state;
|
||||
uint8_t touched;
|
||||
uint8_t released;
|
||||
};
|
||||
|
||||
|
||||
int sx9512_init(const char *dev, int addr, struct sx9512_reg_nvm *nvm);
|
||||
const char *sx9512_reg_name(sx9512_reg_t reg);
|
||||
int sx9512_reg_reserved(sx9512_reg_t reg);
|
||||
int sx9512_reset(int fd);
|
||||
int sx9512_reset_restore_led_state(int fd);
|
||||
int sx9512_read_interrupt(int fd);
|
||||
int sx9512_read_buttons(int fd);
|
||||
int sx9512_read_proximity(int fd);
|
||||
int sx9512_read_status(int fd, struct sx9512_reg_status *status);
|
||||
int sx9512_read_status_cached(int fd, struct sx9512_touch_state *touch_state);
|
||||
int sx9512_reg_nvm_load(int fd);
|
||||
int sx9512_reg_nvm_store(int fd);
|
||||
int sx9512_reg_nvm_read(int fd, struct sx9512_reg_nvm *p);
|
||||
int sx9512_reg_nvm_write(int fd, struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_defaults(struct sx9512_reg_nvm *p, uint8_t capsense_channels, uint8_t led_channels);
|
||||
void sx9512_reg_nvm_init_cg300(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_cg301(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_eg300(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_dg400(struct sx9512_reg_nvm *p);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,447 +0,0 @@
|
|||
#include <syslog.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
#include "smbus.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "ucix.h"
|
||||
#include "i2c.h"
|
||||
|
||||
#include "touch_sx9512.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define SX9512_IRQ_RESET 1<<7
|
||||
#define SX9512_IRQ_TOUCH 1<<6
|
||||
#define SX9512_IRQ_RELEASE 1<<5
|
||||
#define SX9512_IRQ_NEAR 1<<4
|
||||
#define SX9512_IRQ_FAR 1<<3
|
||||
#define SX9512_IRQ_COM 1<<2
|
||||
#define SX9512_IRQ_CONV 1<<1
|
||||
|
||||
|
||||
struct i2c_reg_tab {
|
||||
char addr;
|
||||
char value;
|
||||
char range; /* if set registers starting from addr to addr+range will be set to the same value */
|
||||
};
|
||||
|
||||
struct i2c_touch{
|
||||
int dev;
|
||||
int shadow_irq;
|
||||
int shadow_touch;
|
||||
int shadow_proximity;
|
||||
int addr;
|
||||
int irq_button;
|
||||
};
|
||||
|
||||
struct led_data {
|
||||
int addr;
|
||||
led_state_t state;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
struct sx9512_list{
|
||||
struct list_head list;
|
||||
struct led_data *drv;
|
||||
};
|
||||
|
||||
/* holds all leds that is configured to be used. needed for reset */
|
||||
static LIST_HEAD(sx9512_leds);
|
||||
static struct i2c_touch i2c_touch_current; /* pointer to current active table */
|
||||
static int sx9512_led_set_state(struct led_drv *drv, led_state_t state);
|
||||
static led_state_t sx9512_led_get_state(struct led_drv *drv);
|
||||
static int sx9512_set_state(struct led_data *p, led_state_t state);
|
||||
extern struct uloop_timeout i2c_touch_reset_timer;
|
||||
|
||||
|
||||
/* sx9512 needs a reset every 30 minutes. to recalibrate the touch detection */
|
||||
#define I2C_RESET_TIME (1000 * 60 * 30) /* 30 min in ms */
|
||||
static void sx9512_reset_handler(struct uloop_timeout *timeout);
|
||||
struct uloop_timeout i2c_touch_reset_timer = { .cb = sx9512_reset_handler };
|
||||
|
||||
static void sx9512_reset_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct list_head *i;
|
||||
//do_init_tab(i2c_touch_current);
|
||||
sx9512_reset_restore_led_state(i2c_touch_current.dev);
|
||||
|
||||
list_for_each(i, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(i, struct sx9512_list, list);
|
||||
sx9512_set_state(node->drv, node->drv->state);
|
||||
}
|
||||
|
||||
uloop_timeout_set(&i2c_touch_reset_timer, I2C_RESET_TIME);
|
||||
}
|
||||
|
||||
/* set state regardless of previous state */
|
||||
static int sx9512_set_state(struct led_data *p, led_state_t state)
|
||||
{
|
||||
int ret;
|
||||
int bit = 1 << p->addr;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_LED_MAP2);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, LedMap2 register\n");
|
||||
|
||||
if (state == ON)
|
||||
ret = ret | bit;
|
||||
else if (state == OFF)
|
||||
ret = ret & ~bit;
|
||||
else{
|
||||
syslog(LOG_ERR,"%s: Led %s: Set to not supported state %d\n",__func__, p->led.name, state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->state = state;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(i2c_touch_current.dev, SX9512_REG_LED_MAP2, ret);
|
||||
if (ret < 0 ) {
|
||||
syslog(LOG_ERR, "Could not write to i2c device, LedMap2 register\n");
|
||||
return -1;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/* set state if not same as current state */
|
||||
static int sx9512_led_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct led_data *p = (struct led_data *)drv->priv;
|
||||
|
||||
if (!i2c_touch_current.dev)
|
||||
return -1;
|
||||
|
||||
if (p->addr > 7){
|
||||
DBG(1,"Led %s:with address %d outside range 0-7\n",drv->name, p->addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (state == p->state ) {
|
||||
DBG(3,"skipping set");
|
||||
return state;
|
||||
}
|
||||
|
||||
return sx9512_set_state(p, state);
|
||||
}
|
||||
|
||||
static led_state_t sx9512_led_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct led_data *p = (struct led_data *)drv->priv;
|
||||
DBG(1, "state for %s", drv->name);
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct led_drv_func led_func = {
|
||||
.set_state = sx9512_led_set_state,
|
||||
.get_state = sx9512_led_get_state,
|
||||
};
|
||||
|
||||
struct button_data {
|
||||
int addr;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
void sx9512_check(void)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
|
||||
int got_irq = 0;
|
||||
int ret;
|
||||
|
||||
if (!i2c_touch_current.dev)
|
||||
return;
|
||||
|
||||
if (i2c_touch_current.irq_button) {
|
||||
int button;
|
||||
button = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, i2c_touch_current.irq_button, 0);
|
||||
if (button == 0)
|
||||
got_irq = 1;
|
||||
}
|
||||
if ( got_irq ) {
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_IRQ_SRC);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, irq status register\n");
|
||||
i2c_touch_current.shadow_irq = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_TOUCH_STATUS);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, touch register\n");
|
||||
i2c_touch_current.shadow_touch = ret;
|
||||
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_PROX_STATUS);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, proximity register\n");
|
||||
i2c_touch_current.shadow_proximity = ret;
|
||||
}
|
||||
#if 0
|
||||
DEBUG_PRINT("%02x %02x %02x: irq ->",
|
||||
i2c_touch->shadow_irq ,
|
||||
i2c_touch->shadow_touch,
|
||||
i2c_touch->shadow_proximity);
|
||||
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_RESET )
|
||||
DEBUG_PRINT_RAW(" Reset ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_TOUCH )
|
||||
DEBUG_PRINT_RAW(" Touch ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_RELEASE )
|
||||
DEBUG_PRINT_RAW(" Release ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_NEAR )
|
||||
DEBUG_PRINT_RAW(" Near ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_FAR )
|
||||
DEBUG_PRINT_RAW(" Far ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_COM )
|
||||
DEBUG_PRINT_RAW(" Com ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_CONV )
|
||||
DEBUG_PRINT_RAW(" Conv ");
|
||||
|
||||
DEBUG_PRINT_RAW("\n");
|
||||
#endif
|
||||
|
||||
return ;
|
||||
}
|
||||
/*
|
||||
button address 0- 7 maps to touch event 0-7
|
||||
button address 8 proximity BL0 NEAR
|
||||
button address 9 proximity BL0 FAR
|
||||
|
||||
return BUTTON_RELEASED = no action on this button
|
||||
return BUTTON_PRESSED = button pressed
|
||||
return -1 = error
|
||||
*/
|
||||
|
||||
static button_state_t sx9512_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
struct button_data *p = (struct button_data *)drv->priv;
|
||||
int bit = 1 << p->addr;
|
||||
|
||||
if (!i2c_touch_current.dev)
|
||||
return -1;
|
||||
|
||||
if (p->addr < 8) {
|
||||
if ( bit & i2c_touch_current.shadow_touch ) {
|
||||
i2c_touch_current.shadow_touch = i2c_touch_current.shadow_touch & ~bit;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
|
||||
/* if the button was already pressed and we don't have a release irq report it as still pressed */
|
||||
if( p->state == BUTTON_PRESSED){
|
||||
if (! (i2c_touch_current.shadow_irq & SX9512_IRQ_RELEASE) ) {
|
||||
return BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
return p->state = BUTTON_RELEASED;
|
||||
|
||||
/* proximity NEAR */
|
||||
}else if (p->addr == 8 ) {
|
||||
bit = 1<<7;
|
||||
if( i2c_touch_current.shadow_irq & SX9512_IRQ_NEAR ) {
|
||||
i2c_touch_current.shadow_irq &= ~SX9512_IRQ_NEAR;
|
||||
if ( bit & i2c_touch_current.shadow_proximity ) {
|
||||
i2c_touch_current.shadow_proximity = i2c_touch_current.shadow_proximity & ~bit;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
return BUTTON_RELEASED;
|
||||
|
||||
/* proximity FAR */
|
||||
}else if (p->addr == 9) {
|
||||
if( i2c_touch_current.shadow_irq & SX9512_IRQ_FAR ) {
|
||||
i2c_touch_current.shadow_irq &= ~SX9512_IRQ_FAR;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
return BUTTON_RELEASED;
|
||||
}else {
|
||||
DBG(1,"Button address out of range %d\n",p->addr);
|
||||
return BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
static struct button_drv_func button_func = {
|
||||
.get_state = sx9512_button_get_state,
|
||||
};
|
||||
|
||||
|
||||
static void sx9512_button_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"9512_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct button_data));
|
||||
memset(data,0,sizeof(struct button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
data->button.func = &button_func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
}
|
||||
}
|
||||
|
||||
static void sx9512_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"9512_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct led_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct led_data));
|
||||
memset(data,0,sizeof(struct led_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s) {
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
data->led.func = &led_func;
|
||||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
|
||||
{ /* save leds in internal list, we need this for handling reset, we need to restore state */
|
||||
struct sx9512_list *ll = malloc(sizeof(struct sx9512_list));
|
||||
memset(ll, 0, sizeof( struct sx9512_list));
|
||||
ll->drv = data;
|
||||
list_add(&ll->list, &sx9512_leds);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void sx9512_handler_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
char *s, *sx9512_i2c_device;
|
||||
int i, fd, sx9512_i2c_address, sx9512_irq_pin, sx9512_active_capsense_channels, sx9512_active_led_channels;
|
||||
struct sx9512_reg_nvm nvm;
|
||||
struct list_head *il;
|
||||
|
||||
if(!(sx9512_i2c_device = ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_i2c_device"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_i2c_device");
|
||||
return;
|
||||
}
|
||||
DBG(1, "sx9512_i2c_device = [%s]", sx9512_i2c_device);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_i2c_address"))) {
|
||||
DBG(0, "Warning: option is missing: sx9512_i2c_address, setting to default (%02X)", SX9512_I2C_ADDRESS);
|
||||
sx9512_i2c_address = SX9512_I2C_ADDRESS;
|
||||
} else
|
||||
sx9512_i2c_address = strtol(s,0,16);
|
||||
DBG(1, "sx9512_i2c_address = [%02X]", sx9512_i2c_address);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_irq_pin"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_irq_pin");
|
||||
return;
|
||||
}
|
||||
sx9512_irq_pin = strtol(s,0,0);
|
||||
DBG(1, "sx9512_irq_pin = [%d]", sx9512_irq_pin);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_active_capsense_channels"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_active_capsense_channels");
|
||||
return;
|
||||
}
|
||||
sx9512_active_capsense_channels = strtol(s,0,16);
|
||||
DBG(1, "sx9512_active_capsense_channels = [%02X]", sx9512_active_capsense_channels);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_active_led_channels"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_active_led_channels");
|
||||
return;
|
||||
}
|
||||
sx9512_active_led_channels = strtol(s,0,16);
|
||||
DBG(1, "sx9512_active_led_channels = [%02X]", sx9512_active_led_channels);
|
||||
|
||||
sx9512_reg_nvm_init_defaults(&nvm, sx9512_active_capsense_channels, sx9512_active_led_channels);
|
||||
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_led_intensity"))) {
|
||||
nvm.led2_on = nvm.led1_on = strtol(s,0,16);
|
||||
DBG(1, "sx9512_led_intensity = [%02X]", nvm.led1_on);
|
||||
}
|
||||
|
||||
for(i=0;i<8;i++) {
|
||||
char tmpstr[22];
|
||||
sprintf(tmpstr, "sx9512_threshold_bl%d", i);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", tmpstr))) {
|
||||
nvm.cap_sense_thresh[i] = strtol(s,0,16);
|
||||
DBG(1, "sx9512_threshold_bl%d = [%02X]", i, nvm.cap_sense_thresh[i]);
|
||||
}
|
||||
}
|
||||
|
||||
LIST_HEAD(sx9512_init_regs);
|
||||
struct ucilist *node;
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw","sx9512_init_regs", "regs", &sx9512_init_regs);
|
||||
list_for_each_entry(node,&sx9512_init_regs,list) {
|
||||
sx9512_reg_t reg;
|
||||
uint8_t val;
|
||||
int repeat;
|
||||
reg = strtol(node->val,0,16);
|
||||
if(sx9512_reg_reserved(reg)) {
|
||||
DBG(0, "Error: invalid sx9512 reg [%02X]", reg);
|
||||
return;
|
||||
}
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw", node->val, "val");
|
||||
val = strtol(s,0,16);
|
||||
if(!(s = ucix_get_option(s_ctx->uci_ctx, "hw", node->val, "repeat")))
|
||||
repeat=1;
|
||||
else
|
||||
repeat=strtol(s,0,0);
|
||||
for(i=0;i<repeat;i++) {
|
||||
DBG(1, "sx9512_init_reg[%02X:%s=%02X]", reg, sx9512_reg_name(reg), val);
|
||||
((uint8_t *)&nvm)[reg-SX9512_REG_NVM_AREA_START] = val;
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
if((fd = sx9512_init(sx9512_i2c_device, sx9512_i2c_address, &nvm))<1)
|
||||
return;
|
||||
i2c_touch_current.dev=fd;
|
||||
i2c_touch_current.addr=sx9512_i2c_address;
|
||||
i2c_touch_current.irq_button=sx9512_irq_pin;
|
||||
|
||||
sx9512_button_init(s_ctx);
|
||||
sx9512_led_init(s_ctx);
|
||||
/* Force set of initial state for leds. */
|
||||
list_for_each(il, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(il, struct sx9512_list, list);
|
||||
sx9512_set_state(node->drv, node->drv->state);
|
||||
}
|
||||
/* start reset timer */
|
||||
uloop_timeout_set(&i2c_touch_reset_timer, I2C_RESET_TIME);
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef TOUCH_SX9512_H
|
||||
#define TOUCH_SX9512_H
|
||||
|
||||
#include "server.h"
|
||||
#include "sx9512.h"
|
||||
|
||||
void sx9512_handler_init(struct server_ctx *);
|
||||
void sx9512_check(void);
|
||||
|
||||
#endif /* TOUCH_SX9512_H */
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* ucix
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
* Copyright (C) 2010 Steven Barth <steven@midlink.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ucix.h"
|
||||
|
||||
struct uci_ptr uci_ptr;
|
||||
|
||||
int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
memset(&uci_ptr, 0, sizeof(uci_ptr));
|
||||
uci_ptr.package = p;
|
||||
uci_ptr.section = s;
|
||||
uci_ptr.option = o;
|
||||
uci_ptr.value = t;
|
||||
return uci_lookup_ptr(ctx, &uci_ptr, NULL, true);
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init(const char *config_file, int state)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
uci_set_confdir(ctx, "/etc/config");
|
||||
if(state)
|
||||
uci_set_savedir(ctx, "/var/state/");
|
||||
else
|
||||
uci_set_savedir(ctx, "/tmp/.uci/");
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->confdir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init_path(const char *vpath, const char *config_file, int state)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
char buf[256];
|
||||
if(!vpath)
|
||||
return ucix_init(config_file, state);
|
||||
ctx = uci_alloc_context();
|
||||
buf[255] = '\0';
|
||||
snprintf(buf, 255, "%s", vpath);
|
||||
uci_set_confdir(ctx, buf);
|
||||
// snprintf(buf, 255, "%s%s", vpath, (state)?("/var/state"):("/tmp/.uci"));
|
||||
// uci_add_delta_path(ctx, buf);
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->confdir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int ucix_get_option_list(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, struct list_head *l)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return 1;
|
||||
if (!(uci_ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return 1;
|
||||
e = uci_ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(uci_ptr.o->type) {
|
||||
case UCI_TYPE_LIST:
|
||||
uci_foreach_element(&uci_ptr.o->v.list, e)
|
||||
{
|
||||
struct ucilist *ul = malloc(sizeof(struct ucilist));
|
||||
ul->val = strdup((e->name)?(e->name):(""));
|
||||
list_add_tail(&ul->list, l);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
const char *value = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return NULL;
|
||||
if (!(uci_ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return NULL;
|
||||
e = uci_ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_SECTION:
|
||||
value = uci_to_section(e)->type;
|
||||
break;
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(uci_ptr.o->type) {
|
||||
case UCI_TYPE_STRING:
|
||||
value = uci_ptr.o->v.string;
|
||||
break;
|
||||
default:
|
||||
value = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (value) ? (strdup(value)):(NULL);
|
||||
}
|
||||
|
||||
void ucix_add_list(struct uci_context *ctx, const char *p, const char *s, const char *o, struct list_head *vals)
|
||||
{
|
||||
struct list_head *q;
|
||||
list_for_each(q, vals)
|
||||
{
|
||||
struct ucilist *ul = container_of(q, struct ucilist, list);
|
||||
if(ucix_get_ptr(ctx, p, s, o, (ul->val)?(ul->val):("")))
|
||||
return;
|
||||
uci_add_list(ctx, &uci_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&uci_ptr.p->sections, e)
|
||||
if (!strcmp(t, uci_to_section(e)->type))
|
||||
cb(e->name, priv);
|
||||
}
|
||||
|
||||
void ucix_for_each_section_option(struct uci_context *ctx,
|
||||
const char *p, const char *s,
|
||||
void (*cb)(const char*, const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&uci_ptr.s->options, e)
|
||||
{
|
||||
struct uci_option *o = uci_to_option(e);
|
||||
cb(o->e.name, o->v.string, priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* ucix
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
* Copyright (C) 2010 Steven Barth <steven@midlink.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UCI_H__
|
||||
#define _UCI_H__
|
||||
#include <uci.h>
|
||||
#include <libubox/list.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef uci_to_delta
|
||||
// Support older version of uci, where this function was named
|
||||
// differently
|
||||
#define uci_add_delta_path uci_add_history_path
|
||||
#endif
|
||||
|
||||
struct ucilist {
|
||||
struct list_head list;
|
||||
char *val;
|
||||
};
|
||||
|
||||
extern struct uci_ptr uci_ptr;
|
||||
|
||||
int ucix_get_ptr(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, const char *t);
|
||||
struct uci_context* ucix_init(const char *config_file, int state);
|
||||
struct uci_context* ucix_init_path(const char *vpath, const char *config_file, int state);
|
||||
int ucix_save_state(struct uci_context *ctx, const char *p);
|
||||
char* ucix_get_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
int ucix_get_option_list(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, struct list_head *l);
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(const char*, void*), void *priv);
|
||||
void ucix_for_each_section_option(struct uci_context *ctx,
|
||||
const char *p, const char *s,
|
||||
void (*cb)(const char*, const char*, void*), void *priv);
|
||||
void ucix_add_list(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, struct list_head *vals);
|
||||
|
||||
static inline void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if (!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_delete(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if (!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_revert(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_list_single(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if (ucix_get_ptr(ctx, p, s, o, t))
|
||||
return;
|
||||
uci_add_list(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if (ucix_get_ptr(ctx, p, s, o, t))
|
||||
return;
|
||||
uci_set(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, t))
|
||||
return;
|
||||
uci_set(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_option(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
static inline void ucix_add_list_single_int(struct uci_context *ctx, const char *p, const char *s, const char *o, const int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_list_single(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
static inline int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def)
|
||||
{
|
||||
char *tmp = ucix_get_option(ctx, p, s, o);
|
||||
int ret = def;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
ret = atoi(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int ucix_save(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
uci_save(ctx, uci_ptr.p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ucix_commit(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
return uci_commit(ctx, &uci_ptr.p, false);
|
||||
}
|
||||
|
||||
static inline void ucix_cleanup(struct uci_context *ctx)
|
||||
{
|
||||
uci_free_context(ctx);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "led.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define SPI_SLAVE_SELECT 1
|
||||
|
||||
struct vox_data {
|
||||
int addr;
|
||||
led_state_t state;
|
||||
int brightness;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
void vox_init(struct server_ctx *s_ctx);
|
||||
|
||||
static int vox_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
char spi_data[6] = {0,0,0,0,0,0};
|
||||
|
||||
if (p->state == state)
|
||||
return state;
|
||||
|
||||
memset(spi_data, 0, 6);
|
||||
|
||||
spi_data[0] = p->addr;
|
||||
|
||||
if (state == ON) {
|
||||
spi_data[1] = 1;
|
||||
spi_data[2] = 0x0;
|
||||
spi_data[3] = 0x0;
|
||||
spi_data[4] = 0x0;
|
||||
spi_data[4] = 0x0;
|
||||
} else if(state == PULSING) {
|
||||
spi_data[1] = 3;
|
||||
spi_data[2] = 0xa0;
|
||||
} else if(state == FLASH_SLOW) {
|
||||
spi_data[1] = 2;
|
||||
spi_data[3] = 0x95;
|
||||
} else if(state == FLASH_FAST) {
|
||||
spi_data[1] = 2;
|
||||
spi_data[3] = 0x20;
|
||||
}
|
||||
|
||||
DBG(2,"vox_set_state %x %x %x %x",spi_data[0],spi_data[1],spi_data[2],spi_data[3]);
|
||||
board_ioctl(BOARD_IOCTL_SPI_WRITE, SPI_SLAVE_SELECT, 0, spi_data, 6, 0);
|
||||
|
||||
p->state = state;
|
||||
return state;
|
||||
}
|
||||
|
||||
static led_state_t vox_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
return p->state;
|
||||
}
|
||||
|
||||
/* input brightness is in %. 0-100 */
|
||||
/* internal brightness is 5 steps. 0-4 */
|
||||
/*
|
||||
step, level percent mapping.
|
||||
0 0 -> 20
|
||||
1 21 -> 40
|
||||
2 41 -> 60
|
||||
3 61 -> 80
|
||||
4 81 -> 100
|
||||
|
||||
*/
|
||||
|
||||
static int vox_set_brightness(struct led_drv *drv, int level)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
int new = (level * 5)/101; /* really level/(101/5) */
|
||||
char spi_data[6] = {0,0,0,0,0,0};
|
||||
|
||||
if (new == p->brightness)
|
||||
return level;
|
||||
|
||||
p->brightness = new;
|
||||
|
||||
memset(spi_data, 0, 6);
|
||||
|
||||
spi_data[0] = p->addr;
|
||||
spi_data[1] = 6;
|
||||
spi_data[2] = p->brightness;
|
||||
|
||||
DBG(2,"vox_set_state %x %x %x %x",spi_data[0],spi_data[1],spi_data[2],spi_data[3]);
|
||||
board_ioctl(BOARD_IOCTL_SPI_WRITE, SPI_SLAVE_SELECT, 0, spi_data, 6, 0);
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static int vox_get_brightness(struct led_drv *drv)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
return p->brightness * (100/5);
|
||||
}
|
||||
|
||||
static int vox_support(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
|
||||
case OFF:
|
||||
case ON:
|
||||
case FLASH_SLOW:
|
||||
case FLASH_FAST:
|
||||
case PULSING:
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = vox_set_state,
|
||||
.get_state = vox_get_state,
|
||||
.set_brightness = vox_set_brightness,
|
||||
.get_brightness = vox_get_brightness,
|
||||
.support = vox_support,
|
||||
};
|
||||
|
||||
void vox_init(struct server_ctx *s_ctx) {
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
int register_spi = 0;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"vox_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct vox_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct vox_data));
|
||||
memset(data,0,sizeof(struct vox_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s) {
|
||||
data->addr = strtol(s,0,0);
|
||||
}else
|
||||
syslog(LOG_ERR,"vox_led config needs addr option\n");
|
||||
|
||||
data->led.func = &func;
|
||||
data->led.priv = data;
|
||||
data->state = NEED_INIT;
|
||||
data->brightness = 4;
|
||||
led_add(&data->led);
|
||||
register_spi = 1;
|
||||
}
|
||||
|
||||
/* if config entries for vox leds exist register the spi as used. */
|
||||
if(register_spi) {
|
||||
/* arg 4 is the spi mode encoded in a string pointer */
|
||||
/* mode is decribed i/bcm963xx/shared/opensource/include/bcm963xx/bcmSpiRes.h */
|
||||
board_ioctl(BOARD_IOCTL_SPI_INIT, SPI_SLAVE_SELECT, 0, (char*)0, 0, 391000);
|
||||
board_ioctl_init();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
int debug_level;
|
||||
struct termios orig_termios;
|
||||
|
||||
#define SPI_SLAVE_SELECT 1
|
||||
|
||||
void reset_terminal_mode(void);
|
||||
void set_conio_terminal_mode( void );
|
||||
int kbhit( void );
|
||||
int getch( void );
|
||||
void display(void);
|
||||
void inc(void);
|
||||
void dec(void);
|
||||
|
||||
void reset_terminal_mode( void)
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &orig_termios);
|
||||
}
|
||||
|
||||
void set_conio_terminal_mode( void )
|
||||
{
|
||||
struct termios new_termios;
|
||||
|
||||
/* take two copies - one for now, one for later */
|
||||
tcgetattr(0, &orig_termios);
|
||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
||||
|
||||
/* register cleanup handler, and set the new terminal mode */
|
||||
atexit(reset_terminal_mode);
|
||||
cfmakeraw(&new_termios);
|
||||
tcsetattr(0, TCSANOW, &new_termios);
|
||||
}
|
||||
|
||||
int kbhit( void )
|
||||
{
|
||||
struct timeval tv = { 0L, 0L };
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
return select(1, &fds, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
int getch( void )
|
||||
{
|
||||
int r = 0;
|
||||
int c = 0;
|
||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
||||
return r;
|
||||
} else {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
int ret = 0;
|
||||
ret |= (c >> 24) & 0x000000ff;
|
||||
ret |= (c >> 8) & 0x0000ff00;
|
||||
ret |= (c << 8) & 0x00ff0000;
|
||||
ret |= (c << 24) & 0xff000000;
|
||||
return ret;
|
||||
#else
|
||||
return c;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char spi_data [6] = {8,3,0,0,0,0};
|
||||
int pos;
|
||||
|
||||
void display(void){
|
||||
|
||||
printf("\r");
|
||||
printf("%02x %02x %02x %02x %02x %02x \r",
|
||||
spi_data[0],
|
||||
spi_data[1],
|
||||
spi_data[2],
|
||||
spi_data[3],
|
||||
spi_data[4],
|
||||
spi_data[5]
|
||||
);
|
||||
|
||||
|
||||
if (pos){
|
||||
int jump = pos/2;
|
||||
printf("\e[%dC",pos+jump);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void inc(void){
|
||||
|
||||
int byte = pos/2;
|
||||
int nibble = pos%2;
|
||||
|
||||
int val_hi = (spi_data[byte] >> 4 ) & 0xF;
|
||||
int val_lo = spi_data[byte] & 0xF;
|
||||
|
||||
if(!nibble) {
|
||||
val_hi++;
|
||||
if(val_hi > 0xF )
|
||||
val_hi = 0xf;
|
||||
}else{
|
||||
val_lo++;
|
||||
if(val_lo > 0xF )
|
||||
val_lo = 0xf;
|
||||
}
|
||||
|
||||
spi_data[byte] = val_hi << 4 | val_lo;
|
||||
}
|
||||
|
||||
void dec(void){
|
||||
int byte = pos/2;
|
||||
int nibble = pos%2;
|
||||
|
||||
int val_hi = (spi_data[byte] >> 4 ) & 0xF;
|
||||
int val_lo = spi_data[byte] & 0xF;
|
||||
|
||||
if(!nibble) {
|
||||
val_hi--;
|
||||
if(val_hi < 0 )
|
||||
val_hi = 0;
|
||||
}else{
|
||||
val_lo--;
|
||||
if(val_lo < 0 )
|
||||
val_lo = 0;
|
||||
}
|
||||
|
||||
spi_data[byte] = val_hi << 4 | val_lo;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
|
||||
board_ioctl_init();
|
||||
/* arg 4 is the spi mode encoded in a string pointer */
|
||||
/* mode is decribed i/bcm963xx/shared/opensource/include/bcm963xx/bcmSpiRes.h */
|
||||
board_ioctl(BOARD_IOCTL_SPI_INIT, SPI_SLAVE_SELECT, 0, (char *)0, 0, 391000);
|
||||
set_conio_terminal_mode();
|
||||
fflush(stdout);
|
||||
|
||||
display();
|
||||
|
||||
while ( 'q' != (char)(ch = getch())) {
|
||||
/* right */
|
||||
if (ch == 4414235) {
|
||||
pos++;
|
||||
if (pos > 11)
|
||||
pos = 11;
|
||||
}
|
||||
/* left */
|
||||
if (ch == 4479771) {
|
||||
pos--;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
}
|
||||
/* up */
|
||||
if (ch == 4283163) {
|
||||
inc();
|
||||
}
|
||||
/* down */
|
||||
if (ch == 4348699) {
|
||||
dec();
|
||||
}
|
||||
/* enter */
|
||||
if (ch == '\r') {
|
||||
board_ioctl(BOARD_IOCTL_SPI_WRITE, SPI_SLAVE_SELECT, 0, (char*)spi_data, 6, 0);
|
||||
}
|
||||
display();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -10,6 +10,18 @@ PKG_NAME:=qrencode
|
|||
PKG_VERSION:=3.0.3
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_VERSION:=2f575b43703c801f4f7bfac65e8845ce967c3d9e
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/qrencode
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:qrencode
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
TARGET_LDFLAGS+= \
|
||||
|
|
@ -32,11 +44,6 @@ define Package/qrencode/description
|
|||
digits or 4000 characters, and is highly robust.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
$(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
CC = gcc
|
||||
MAKEDEPEND = makedepend
|
||||
CDEBUG = -g
|
||||
CFLAGS = ${CDEBUG} ${INCL} -Wall
|
||||
LDFLAGS = ${CDEBUG}
|
||||
LIBDIR =
|
||||
LOCLIBS =
|
||||
LIBS = ${LOCLIBS} ${SYSLIBS}
|
||||
OBJS = bitstream.o mask.o qrenc.o qrencode.o qrinput.o qrspec.o rscode.o split.o
|
||||
SRCS = bitstream.c mask.c qrenc.c qrencode.c qrinput.c qrspec.c rscode.c split.c
|
||||
LIBSRCS =
|
||||
ISRCS = bitstream.h mask.h qrencode.h qrencode_inner.h qrinput.h qrspec.h rscode.h split.h config.h
|
||||
ALLSRCS = ${SRCS} ${ISRCS} ${LIBSRCS}
|
||||
|
||||
all: qrencode
|
||||
|
||||
qrencode: ${OBJS}
|
||||
${CC} ${LDFLAGS} -o qrencode ${OBJS} ${LIBDIR} ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f qrencode core *.o *.BAK *.bak *.CKP a.out
|
||||
|
||||
install:
|
||||
install -c -s -o bin -g bin -m 555 qrencode /usr/local/bin
|
||||
|
||||
depend:
|
||||
${MAKEDEPEND} ${INCL} ${SRCS} ${LIBSRCS}
|
||||
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Binary sequence class.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitstream.h"
|
||||
|
||||
BitStream *BitStream_new(void)
|
||||
{
|
||||
BitStream *bstream;
|
||||
|
||||
bstream = (BitStream *)malloc(sizeof(BitStream));
|
||||
bstream->data = NULL;
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
static BitStream *BitStream_newFromNum(int bits, unsigned int num)
|
||||
{
|
||||
unsigned int mask;
|
||||
int i;
|
||||
char *p;
|
||||
BitStream *bstream;
|
||||
|
||||
bstream = BitStream_new();
|
||||
bstream->data = (char *)malloc(bits + 1);
|
||||
|
||||
p = bstream->data;
|
||||
mask = 1 << (bits - 1);
|
||||
for(i=0; i<bits; i++) {
|
||||
if(num & mask) {
|
||||
*p = '1';
|
||||
} else {
|
||||
*p = '0';
|
||||
}
|
||||
p++;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
static BitStream *BitStream_newFromBytes(int size, unsigned char *data)
|
||||
{
|
||||
unsigned char mask;
|
||||
int i, j;
|
||||
char *p;
|
||||
BitStream *bstream;
|
||||
|
||||
bstream = BitStream_new();
|
||||
bstream->data = (char *)malloc(size * 8 + 1);
|
||||
|
||||
p = bstream->data;
|
||||
for(i=0; i<size; i++) {
|
||||
mask = 0x80;
|
||||
for(j=0; j<8; j++) {
|
||||
if(data[i] & mask) {
|
||||
*p = '1';
|
||||
} else {
|
||||
*p = '0';
|
||||
}
|
||||
p++;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
void BitStream_append(BitStream *bstream, BitStream *arg)
|
||||
{
|
||||
int l1, l2;
|
||||
char *data;
|
||||
|
||||
if(arg == NULL || arg->data == NULL) {
|
||||
return;
|
||||
}
|
||||
if(bstream->data == NULL) {
|
||||
bstream->data = strdup(arg->data);
|
||||
return;
|
||||
}
|
||||
|
||||
l1 = strlen(bstream->data);
|
||||
l2 = strlen(arg->data);
|
||||
data = (char *)malloc(l1 + l2 + 1);
|
||||
strcpy(data, bstream->data);
|
||||
strcat(data, arg->data);
|
||||
|
||||
free(bstream->data);
|
||||
bstream->data = data;
|
||||
}
|
||||
|
||||
void BitStream_appendNum(BitStream *bstream, int bits, unsigned int num)
|
||||
{
|
||||
BitStream *b;
|
||||
|
||||
b = BitStream_newFromNum(bits, num);
|
||||
BitStream_append(bstream, b);
|
||||
BitStream_free(b);
|
||||
}
|
||||
|
||||
void BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data)
|
||||
{
|
||||
BitStream *b;
|
||||
|
||||
b = BitStream_newFromBytes(size, data);
|
||||
BitStream_append(bstream, b);
|
||||
BitStream_free(b);
|
||||
}
|
||||
|
||||
unsigned int BitStream_size(BitStream *bstream)
|
||||
{
|
||||
if(bstream == NULL) return 0;
|
||||
if(bstream->data == NULL) return 0;
|
||||
|
||||
return strlen(bstream->data);
|
||||
}
|
||||
|
||||
unsigned char *BitStream_toByte(BitStream *bstream)
|
||||
{
|
||||
int i, j, size, bytes;
|
||||
unsigned char *data, v;
|
||||
char *p;
|
||||
|
||||
size = BitStream_size(bstream);
|
||||
data = (unsigned char *)malloc((size + 7) / 8);
|
||||
bytes = size / 8;
|
||||
|
||||
p = bstream->data;
|
||||
for(i=0; i<bytes; i++) {
|
||||
v = 0;
|
||||
for(j=0; j<8; j++) {
|
||||
v = v << 1;
|
||||
v |= *p == '1';
|
||||
p++;
|
||||
}
|
||||
data[i] = v;
|
||||
}
|
||||
if(size & 7) {
|
||||
v = 0;
|
||||
for(j=0; j<(size & 7); j++) {
|
||||
v = v << 1;
|
||||
v |= *p == '1';
|
||||
p++;
|
||||
}
|
||||
data[bytes] = v;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void BitStream_free(BitStream *bstream)
|
||||
{
|
||||
if(bstream->data != NULL) {
|
||||
free(bstream->data);
|
||||
}
|
||||
free(bstream);
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Binary sequence class.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __BITSTREAM_H__
|
||||
#define __BITSTREAM_H__
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
} BitStream;
|
||||
|
||||
extern BitStream *BitStream_new(void);
|
||||
extern void BitStream_append(BitStream *bstream, BitStream *arg);
|
||||
extern void BitStream_appendNum(BitStream *bstream, int bits, unsigned int num);
|
||||
extern void BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data);
|
||||
extern unsigned int BitStream_size(BitStream *bstream);
|
||||
extern unsigned char *BitStream_toByte(BitStream *bstream);
|
||||
extern void BitStream_free(BitStream *bstream);
|
||||
|
||||
#endif /* __BITSTREAM_H__ */
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Masking.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "qrencode.h"
|
||||
#include "qrencode_inner.h"
|
||||
#include "qrspec.h"
|
||||
#include "mask.h"
|
||||
|
||||
/**
|
||||
* Demerit coefficients.
|
||||
* See Section 8.8.2, pp.45, JIS X0510:2004.
|
||||
*/
|
||||
#define N1 (3)
|
||||
#define N2 (3)
|
||||
#define N3 (40)
|
||||
#define N4 (10)
|
||||
|
||||
#define MASKMAKER(__exp__) \
|
||||
int x, y;\
|
||||
unsigned int b = 0;\
|
||||
\
|
||||
for(y=0; y<width; y++) {\
|
||||
for(x=0; x<width; x++) {\
|
||||
if(*s & 0x80) {\
|
||||
*d = *s;\
|
||||
} else {\
|
||||
*d = *s ^ ((__exp__) == 0);\
|
||||
}\
|
||||
b += (*d & 1);\
|
||||
s++; d++;\
|
||||
}\
|
||||
}\
|
||||
return b;
|
||||
|
||||
static int Mask_mask0(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((x+y)&1)
|
||||
}
|
||||
|
||||
static int Mask_mask1(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(y&1)
|
||||
}
|
||||
|
||||
static int Mask_mask2(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(x%3)
|
||||
}
|
||||
|
||||
static int Mask_mask3(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((x+y)%3)
|
||||
}
|
||||
|
||||
static int Mask_mask4(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(((y/2)+(x/3))&1)
|
||||
}
|
||||
|
||||
static int Mask_mask5(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(((x*y)&1)+(x*y)%3)
|
||||
}
|
||||
|
||||
static int Mask_mask6(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((((x*y)&1)+(x*y)%3)&1)
|
||||
}
|
||||
|
||||
static int Mask_mask7(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((((x*y)%3)+((x+y)&1))&1)
|
||||
}
|
||||
|
||||
typedef int MaskMaker(int, const unsigned char *, unsigned char *);
|
||||
static MaskMaker *maskMakers[] = {
|
||||
Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3,
|
||||
Mask_mask4, Mask_mask5, Mask_mask6, Mask_mask7
|
||||
};
|
||||
|
||||
unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask)
|
||||
{
|
||||
unsigned char *masked;
|
||||
|
||||
masked = (unsigned char *)malloc(width * width);
|
||||
|
||||
maskMakers[mask](width, frame, masked);
|
||||
|
||||
return masked;
|
||||
}
|
||||
|
||||
static int runLength[QRSPEC_WIDTH_MAX + 1];
|
||||
|
||||
//static int n1;
|
||||
//static int n2;
|
||||
//static int n3;
|
||||
//static int n4;
|
||||
|
||||
static int Mask_calcN1N3(int length, int *runLength)
|
||||
{
|
||||
int i;
|
||||
int demerit = 0;
|
||||
int fact;
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
if(runLength[i] >= 5) {
|
||||
demerit += N1 + (runLength[i] - 5);
|
||||
//n1 += N1 + (runLength[i] - 5);
|
||||
}
|
||||
if((i & 1)) {
|
||||
if(i >= 3 && i < length-2 && (runLength[i] % 3) == 0) {
|
||||
fact = runLength[i] / 3;
|
||||
if(runLength[i-2] == fact &&
|
||||
runLength[i-1] == fact &&
|
||||
runLength[i+1] == fact &&
|
||||
runLength[i+2] == fact) {
|
||||
if(runLength[i-3] < 0 || runLength[i-3] >= 4 * fact) {
|
||||
demerit += N3;
|
||||
//n3 += N3;
|
||||
} else if(i+3 >= length || runLength[i+3] >= 4 * fact) {
|
||||
demerit += N3;
|
||||
//n3 += N3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
int Mask_evaluateSymbol(int width, unsigned char *frame)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char *p;
|
||||
unsigned char b22, w22;
|
||||
unsigned int i;
|
||||
int head;
|
||||
int demerit = 0;
|
||||
|
||||
p = frame;
|
||||
i = 0;
|
||||
for(y=0; y<width; y++) {
|
||||
head = 0;
|
||||
runLength[0] = 1;
|
||||
for(x=0; x<width; x++) {
|
||||
if(x > 0 && y > 0) {
|
||||
b22 = p[0] & p[-1] & p[-width] & p [-width-1];
|
||||
w22 = p[0] | p[-1] | p[-width] | p [-width-1];
|
||||
if((b22 | (w22 ^ 1))&1) {
|
||||
demerit += N2;
|
||||
}
|
||||
}
|
||||
if(x == 0 && (p[0] & 1)) {
|
||||
runLength[0] = -1;
|
||||
head = 1;
|
||||
runLength[head] = 1;
|
||||
} else if(x > 0) {
|
||||
if((p[0] ^ p[-1]) & 1) {
|
||||
head++;
|
||||
runLength[head] = 1;
|
||||
} else {
|
||||
runLength[head]++;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
demerit += Mask_calcN1N3(head+1, runLength);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for(x=0; x<width; x++) {
|
||||
head = 0;
|
||||
runLength[0] = 1;
|
||||
p = frame + x;
|
||||
for(y=0; y<width; y++) {
|
||||
if(y == 0 && (p[0] & 1)) {
|
||||
runLength[0] = -1;
|
||||
head = 1;
|
||||
runLength[head] = 1;
|
||||
} else if(y > 0) {
|
||||
if((p[0] ^ p[-width]) & 1) {
|
||||
head++;
|
||||
runLength[head] = 1;
|
||||
} else {
|
||||
runLength[head]++;
|
||||
}
|
||||
}
|
||||
p+=width;
|
||||
}
|
||||
demerit += Mask_calcN1N3(head+1, runLength);
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level)
|
||||
{
|
||||
int i;
|
||||
unsigned char *mask, *bestMask;
|
||||
int minDemerit = INT_MAX;
|
||||
int bestMaskNum = 0;
|
||||
int blacks;
|
||||
int demerit;
|
||||
|
||||
bestMask = NULL;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
// n1 = n2 = n3 = n4 = 0;
|
||||
demerit = 0;
|
||||
mask = (unsigned char *)malloc(width * width);
|
||||
blacks = maskMakers[i](width, frame, mask);
|
||||
blacks += QRcode_writeFormatInformation(width, mask, i, level);
|
||||
blacks = 100 * blacks / (width * width);
|
||||
demerit = (abs(blacks - 50) / 5) * N4;
|
||||
// n4 = demerit;
|
||||
demerit += Mask_evaluateSymbol(width, mask);
|
||||
// printf("(%d,%d,%d,%d)=%d\n", n1, n2, n3 ,n4, demerit);
|
||||
if(demerit < minDemerit) {
|
||||
minDemerit = demerit;
|
||||
bestMaskNum = i;
|
||||
if(bestMask != NULL) {
|
||||
free(bestMask);
|
||||
}
|
||||
bestMask = mask;
|
||||
} else {
|
||||
free(mask);
|
||||
}
|
||||
}
|
||||
|
||||
return bestMask;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Masking.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __MASK_H__
|
||||
#define __MASK_H__
|
||||
|
||||
#include "qrinput.h"
|
||||
|
||||
extern unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask);
|
||||
extern int Mask_evaluateSymbol(int width, unsigned char *frame);
|
||||
extern unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level);
|
||||
|
||||
#endif /* __MASK_H__ */
|
||||
|
|
@ -1,452 +0,0 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* QR Code encoding tool
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <png.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "qrencode.h"
|
||||
|
||||
static int casesensitive = 1;
|
||||
static int eightbit = 0;
|
||||
static int version = 0;
|
||||
static int size = 3;
|
||||
static int margin = 4;
|
||||
static int structured = 0;
|
||||
static QRecLevel level = QR_ECLEVEL_L;
|
||||
static QRencodeMode hint = QR_MODE_8;
|
||||
|
||||
static const struct option options[] = {
|
||||
{"help" , no_argument , NULL, 'h'},
|
||||
{"output" , required_argument, NULL, 'o'},
|
||||
{"level" , required_argument, NULL, 'l'},
|
||||
{"size" , required_argument, NULL, 's'},
|
||||
{"symversion" , required_argument, NULL, 'v'},
|
||||
{"margin" , required_argument, NULL, 'm'},
|
||||
{"structured" , no_argument , NULL, 'S'},
|
||||
{"kanji" , no_argument , NULL, 'k'},
|
||||
{"casesensitive", no_argument , NULL, 'c'},
|
||||
{"ignorecase" , no_argument , NULL, 'i'},
|
||||
{"8bit" , no_argument , NULL, '8'},
|
||||
{"version" , no_argument , NULL, 'V'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static char *optstring = "ho:l:s:v:m:Skci8V";
|
||||
|
||||
static void usage(int help, int longopt)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"qrencode version 3.0.3\n"
|
||||
"Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi\n");
|
||||
if(help) {
|
||||
if(longopt) {
|
||||
fprintf(stderr,
|
||||
"Usage: qrencode [OPTION]... [STRING]\n"
|
||||
"Encode input data in a QR Code and save as a PNG image.\n\n"
|
||||
" -h, --help display the help message. -h displays only the help of short\n"
|
||||
" options.\n\n"
|
||||
" -o FILENAME, --output=FILENAME\n"
|
||||
" write PNG image to FILENAME. If '-' is specified, the result\n"
|
||||
" will be output to standard output. If -S is given, structured\n"
|
||||
" symbols are written to FILENAME-01.png, FILENAME-02.png, ...;\n"
|
||||
" if specified, remove a trailing '.png' from FILENAME.\n\n"
|
||||
" -s NUMBER, --size=NUMBER\n"
|
||||
" specify the size of dot (pixel). (default=3)\n\n"
|
||||
" -l {LMQH}, --level={LMQH}\n"
|
||||
" specify error collectin level from L (lowest) to H (highest).\n"
|
||||
" (default=L)\n\n"
|
||||
" -v NUMBER, --symversion=NUMBER\n"
|
||||
" specify the version of the symbol. (default=auto)\n\n"
|
||||
" -m NUMBER, --margin=NUMBER\n"
|
||||
" specify the width of margin. (default=4)\n\n"
|
||||
" -S, --structured\n"
|
||||
" make structured symbols. Version must be specified.\n\n"
|
||||
" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n"
|
||||
" -c, --casesensitive\n"
|
||||
" encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
|
||||
" -i, --ignorecase\n"
|
||||
" ignore case distinctions and use only upper-case characters.\n\n"
|
||||
" -8, -8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
|
||||
" -V, --version\n"
|
||||
" display the version number and copyrights of the qrencode.\n\n"
|
||||
" [STRING] input data. If it is not specified, data will be taken from\n"
|
||||
" standard input.\n"
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Usage: qrencode [OPTION]... [STRING]\n"
|
||||
"Encode input data in a QR Code and save as a PNG image.\n\n"
|
||||
" -h display this message.\n"
|
||||
" --help display the usage of long options.\n"
|
||||
" -o FILENAME write PNG image to FILENAME. If '-' is specified, the result\n"
|
||||
" will be output to standard output. If -S is given, structured\n"
|
||||
" symbols are written to FILENAME-01.png, FILENAME-02.png, ...;\n"
|
||||
" if specified, remove a trailing '.png' from FILENAME.\n"
|
||||
" -s NUMBER specify the size of dot (pixel). (default=3)\n"
|
||||
" -l {LMQH} specify error collectin level from L (lowest) to H (highest).\n"
|
||||
" (default=L)\n"
|
||||
" -v NUMBER specify the version of the symbol. (default=auto)\n"
|
||||
" -m NUMBER specify the width of margin. (default=4)\n"
|
||||
" -S make structured symbols. Version must be specified.\n"
|
||||
" -k assume that the input text contains kanji (shift-jis).\n"
|
||||
" -c encode lower-case alphabet characters in 8-bit mode. (default)\n"
|
||||
" -i ignore case distinctions and use only upper-case characters.\n"
|
||||
" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
|
||||
" -V display the version number and copyrights of the qrencode.\n"
|
||||
" [STRING] input data. If it is not specified, data will be taken from\n"
|
||||
" standard input.\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_DATA_SIZE (7090 * 16) /* from the specification */
|
||||
static char *readStdin(void)
|
||||
{
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = (char *)malloc(MAX_DATA_SIZE);
|
||||
ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
|
||||
if(ret == 0) {
|
||||
fprintf(stderr, "No input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(!feof(stdin)) {
|
||||
fprintf(stderr, "Input data is too large.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
buffer[ret] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int writePNG(QRcode *qrcode, const char *outfile)
|
||||
{
|
||||
FILE *fp;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
unsigned char *row, *p, *q;
|
||||
int x, y, xx, yy, bit;
|
||||
int realwidth;
|
||||
|
||||
realwidth = (qrcode->width + margin * 2) * size;
|
||||
row = (unsigned char *)malloc((realwidth + 7) / 8);
|
||||
if(row == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(outfile[0] == '-' && outfile[1] == '\0') {
|
||||
fp = stdout;
|
||||
} else {
|
||||
fp = fopen(outfile, "wb");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "Failed to create file: %s\n", outfile);
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if(png_ptr == NULL) {
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Failed to initialize PNG writer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if(info_ptr == NULL) {
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Failed to initialize PNG write.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Failed to write PNG image.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_set_IHDR(png_ptr, info_ptr,
|
||||
realwidth, realwidth,
|
||||
1,
|
||||
PNG_COLOR_TYPE_GRAY,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
/* top margin */
|
||||
memset(row, 0xff, (realwidth + 7) / 8);
|
||||
for(y=0; y<margin * size; y++) {
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
|
||||
/* data */
|
||||
p = qrcode->data;
|
||||
for(y=0; y<qrcode->width; y++) {
|
||||
bit = 7;
|
||||
memset(row, 0xff, (realwidth + 7) / 8);
|
||||
q = row;
|
||||
q += margin * size / 8;
|
||||
bit = 7 - (margin * size % 8);
|
||||
for(x=0; x<qrcode->width; x++) {
|
||||
for(xx=0; xx<size; xx++) {
|
||||
*q ^= (*p & 1) << bit;
|
||||
bit--;
|
||||
if(bit < 0) {
|
||||
q++;
|
||||
bit = 7;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
for(yy=0; yy<size; yy++) {
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
}
|
||||
/* bottom margin */
|
||||
memset(row, 0xff, (realwidth + 7) / 8);
|
||||
for(y=0; y<margin * size; y++) {
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(fp);
|
||||
free(row);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QRcode *encode(const char *intext)
|
||||
{
|
||||
QRcode *code;
|
||||
|
||||
if(eightbit) {
|
||||
code = QRcode_encodeString8bit(intext, version, level);
|
||||
} else {
|
||||
code = QRcode_encodeString(intext, version, level, hint, casesensitive);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static void qrencode(const char *intext, const char *outfile)
|
||||
{
|
||||
QRcode *qrcode;
|
||||
|
||||
qrcode = encode(intext);
|
||||
if(qrcode == NULL) {
|
||||
fprintf(stderr, "Failed to encode the input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
writePNG(qrcode, outfile);
|
||||
QRcode_free(qrcode);
|
||||
}
|
||||
|
||||
static QRcode_List *encodeStructured(const char *intext)
|
||||
{
|
||||
QRcode_List *list;
|
||||
|
||||
if(eightbit) {
|
||||
list = QRcode_encodeString8bitStructured(intext, version, level);
|
||||
} else {
|
||||
list = QRcode_encodeStringStructured(intext, version, level, hint, casesensitive);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void qrencodeStructured(const char *intext, const char *outfile)
|
||||
{
|
||||
QRcode_List *qrlist, *p;
|
||||
char filename[FILENAME_MAX];
|
||||
char *base, *q, *suffix = NULL;
|
||||
int i = 1;
|
||||
|
||||
base = strdup(outfile);
|
||||
if(base == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(strlen(base) > 4) {
|
||||
q = base + strlen(base) - 4;
|
||||
if(strcasecmp(".png", q) == 0) {
|
||||
suffix = strdup(q);
|
||||
*q = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
qrlist = encodeStructured(intext);
|
||||
if(qrlist == NULL) {
|
||||
fprintf(stderr, "Failed to encode the input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(p = qrlist; p != NULL; p = p->next) {
|
||||
if(p->code == NULL) {
|
||||
fprintf(stderr, "Failed to encode the input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(suffix) {
|
||||
snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix);
|
||||
} else {
|
||||
snprintf(filename, FILENAME_MAX, "%s-%02d", base, i);
|
||||
}
|
||||
writePNG(p->code, filename);
|
||||
i++;
|
||||
}
|
||||
|
||||
free(base);
|
||||
if(suffix) {
|
||||
free(suffix);
|
||||
}
|
||||
|
||||
QRcode_List_free(qrlist);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt, lindex = -1;
|
||||
char *outfile = NULL;
|
||||
char *intext = NULL;
|
||||
|
||||
while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
|
||||
switch(opt) {
|
||||
case 'h':
|
||||
if(lindex == 0) {
|
||||
usage(1, 1);
|
||||
} else {
|
||||
usage(1, 0);
|
||||
}
|
||||
exit(0);
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case 's':
|
||||
size = atoi(optarg);
|
||||
if(size <= 0) {
|
||||
fprintf(stderr, "Invalid size: %d\n", size);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
version = atoi(optarg);
|
||||
if(version < 0) {
|
||||
fprintf(stderr, "Invalid version: %d\n", version);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
switch(*optarg) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
level = QR_ECLEVEL_L;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
level = QR_ECLEVEL_M;
|
||||
break;
|
||||
case 'q':
|
||||
case 'Q':
|
||||
level = QR_ECLEVEL_Q;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
level = QR_ECLEVEL_H;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid level: %s\n", optarg);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
margin = atoi(optarg);
|
||||
if(margin < 0) {
|
||||
fprintf(stderr, "Invalid margin: %d\n", margin);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
structured = 1;
|
||||
case 'k':
|
||||
hint = QR_MODE_KANJI;
|
||||
break;
|
||||
case 'c':
|
||||
casesensitive = 1;
|
||||
break;
|
||||
case 'i':
|
||||
casesensitive = 0;
|
||||
break;
|
||||
case '8':
|
||||
eightbit = 1;
|
||||
break;
|
||||
case 'V':
|
||||
usage(0, 0);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Try `qrencode --help' for more information.\n");
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(argc == 1) {
|
||||
usage(1, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(outfile == NULL) {
|
||||
fprintf(stderr, "No output filename is given.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(optind < argc) {
|
||||
intext = argv[optind];
|
||||
}
|
||||
if(intext == NULL) {
|
||||
intext = readStdin();
|
||||
}
|
||||
|
||||
if(structured) {
|
||||
if(version == 0) {
|
||||
fprintf(stderr, "Version must be specified to encode structured symbols.\n");
|
||||
exit(1);
|
||||
}
|
||||
qrencodeStructured(intext, outfile);
|
||||
} else {
|
||||
qrencode(intext, outfile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,591 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "qrencode.h"
|
||||
#include "qrencode_inner.h"
|
||||
#include "qrspec.h"
|
||||
#include "bitstream.h"
|
||||
#include "qrinput.h"
|
||||
#include "rscode.h"
|
||||
#include "split.h"
|
||||
#include "mask.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Raw code
|
||||
*****************************************************************************/
|
||||
|
||||
static void RSblock_init(RSblock *block, int dl, unsigned char *data, int el)
|
||||
{
|
||||
RS *rs;
|
||||
|
||||
block->dataLength = dl;
|
||||
block->data = data;
|
||||
block->eccLength = el;
|
||||
block->ecc = (unsigned char *)malloc(el);
|
||||
|
||||
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
|
||||
encode_rs_char(rs, data, block->ecc);
|
||||
}
|
||||
|
||||
QRRawCode *QRraw_new(QRinput *input)
|
||||
{
|
||||
QRRawCode *raw;
|
||||
int *spec;
|
||||
int i;
|
||||
RSblock *rsblock;
|
||||
unsigned char *p;
|
||||
|
||||
p = QRinput_getByteStream(input);
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
raw = (QRRawCode *)malloc(sizeof(QRRawCode));
|
||||
raw->datacode = p;
|
||||
spec = QRspec_getEccSpec(input->version, input->level);
|
||||
if(spec == NULL) {
|
||||
free(raw);
|
||||
return NULL;
|
||||
}
|
||||
raw->version = input->version;
|
||||
raw->blocks = QRspec_rsBlockNum(spec);
|
||||
raw->rsblock = (RSblock *)malloc(sizeof(RSblock) * raw->blocks);
|
||||
|
||||
rsblock = raw->rsblock;
|
||||
p = raw->datacode;
|
||||
for(i=0; i<QRspec_rsBlockNum1(spec); i++) {
|
||||
RSblock_init(rsblock, QRspec_rsDataCodes1(spec), p,
|
||||
QRspec_rsEccCodes1(spec));
|
||||
p += QRspec_rsDataCodes1(spec);
|
||||
rsblock++;
|
||||
}
|
||||
for(i=0; i<QRspec_rsBlockNum2(spec); i++) {
|
||||
RSblock_init(rsblock, QRspec_rsDataCodes2(spec), p,
|
||||
QRspec_rsEccCodes2(spec));
|
||||
p += QRspec_rsDataCodes2(spec);
|
||||
rsblock++;
|
||||
}
|
||||
|
||||
raw->b1 = QRspec_rsBlockNum1(spec);
|
||||
raw->dataLength = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec)
|
||||
+ QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec);
|
||||
raw->eccLength = QRspec_rsBlockNum(spec) * QRspec_rsEccCodes1(spec);
|
||||
raw->count = 0;
|
||||
|
||||
free(spec);
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a code (byte).
|
||||
* This function can be called iteratively.
|
||||
* @param raw raw code.
|
||||
* @return code
|
||||
*/
|
||||
unsigned char QRraw_getCode(QRRawCode *raw)
|
||||
{
|
||||
int col, row;
|
||||
unsigned char ret;
|
||||
|
||||
if(raw->count < raw->dataLength) {
|
||||
row = raw->count % raw->blocks;
|
||||
col = raw->count / raw->blocks;
|
||||
if(col >= raw->rsblock[row].dataLength) {
|
||||
row += raw->b1;
|
||||
}
|
||||
ret = raw->rsblock[row].data[col];
|
||||
} else if(raw->count < raw->dataLength + raw->eccLength) {
|
||||
row = (raw->count - raw->dataLength) % raw->blocks;
|
||||
col = (raw->count - raw->dataLength) / raw->blocks;
|
||||
ret = raw->rsblock[row].ecc[col];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
raw->count++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void QRraw_free(QRRawCode *raw)
|
||||
{
|
||||
int i;
|
||||
|
||||
free(raw->datacode);
|
||||
for(i=0; i<raw->blocks; i++) {
|
||||
free(raw->rsblock[i].ecc);
|
||||
}
|
||||
free(raw->rsblock);
|
||||
free(raw);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Frame filling
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
unsigned char *frame;
|
||||
int x, y;
|
||||
int dir;
|
||||
int bit;
|
||||
} FrameFiller;
|
||||
|
||||
static FrameFiller *FrameFiller_new(int width, unsigned char *frame)
|
||||
{
|
||||
FrameFiller *filler;
|
||||
|
||||
filler = (FrameFiller *)malloc(sizeof(FrameFiller));
|
||||
filler->width = width;
|
||||
filler->frame = frame;
|
||||
filler->x = width - 1;
|
||||
filler->y = width - 1;
|
||||
filler->dir = -1;
|
||||
filler->bit = -1;
|
||||
|
||||
return filler;
|
||||
}
|
||||
|
||||
static unsigned char *FrameFiller_next(FrameFiller *filler)
|
||||
{
|
||||
unsigned char *p;
|
||||
int x, y, w;
|
||||
|
||||
if(filler->bit == -1) {
|
||||
filler->bit = 0;
|
||||
return filler->frame + filler->y * filler->width + filler->x;
|
||||
}
|
||||
|
||||
x = filler->x;
|
||||
y = filler->y;
|
||||
p = filler->frame;
|
||||
w = filler->width;
|
||||
|
||||
if(filler->bit == 0) {
|
||||
x--;
|
||||
filler->bit++;
|
||||
} else {
|
||||
x++;
|
||||
y += filler->dir;
|
||||
filler->bit--;
|
||||
}
|
||||
|
||||
if(filler->dir < 0) {
|
||||
if(y < 0) {
|
||||
y = 0;
|
||||
x -= 2;
|
||||
filler->dir = 1;
|
||||
if(x == 6) {
|
||||
x--;
|
||||
y = 9;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(y == w) {
|
||||
y = w - 1;
|
||||
x -= 2;
|
||||
filler->dir = -1;
|
||||
if(x == 6) {
|
||||
x--;
|
||||
y -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(x < 0 || y < 0) return NULL;
|
||||
|
||||
filler->x = x;
|
||||
filler->y = y;
|
||||
|
||||
if(p[y * w + x] & 0x80) {
|
||||
// This tail recursion could be optimized.
|
||||
return FrameFiller_next(filler);
|
||||
}
|
||||
return &p[y * w + x];
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned char *FrameFiller_fillerTest(int version)
|
||||
{
|
||||
int width, length;
|
||||
unsigned char *frame, *p;
|
||||
FrameFiller *filler;
|
||||
int i, j;
|
||||
unsigned char cl = 1;
|
||||
unsigned char ch = 0;
|
||||
|
||||
width = QRspec_getWidth(version);
|
||||
frame = QRspec_newFrame(version);
|
||||
filler = FrameFiller_new(width, frame);
|
||||
length = QRspec_getDataLength(version, QR_ECLEVEL_L)
|
||||
+ QRspec_getECCLength(version, QR_ECLEVEL_L);
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
for(j=0; j<8; j++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = ch | cl;
|
||||
cl++;
|
||||
if(cl == 9) {
|
||||
cl = 1;
|
||||
ch += 0x10;
|
||||
}
|
||||
}
|
||||
}
|
||||
length = QRspec_getRemainder(version);
|
||||
for(i=0; i<length; i++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = 0xa0;
|
||||
}
|
||||
p = FrameFiller_next(filler);
|
||||
free(filler);
|
||||
if(p != NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
|
||||
int QRcode_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level)
|
||||
{
|
||||
unsigned int format;
|
||||
unsigned char v;
|
||||
int i;
|
||||
int blacks = 0;
|
||||
|
||||
format = QRspec_getFormatInfo(mask, level);
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
if(format & 1) {
|
||||
blacks += 2;
|
||||
v = 0x85;
|
||||
} else {
|
||||
v = 0x84;
|
||||
}
|
||||
frame[width * 8 + width - 1 - i] = v;
|
||||
if(i < 6) {
|
||||
frame[width * i + 8] = v;
|
||||
} else {
|
||||
frame[width * (i + 1) + 8] = v;
|
||||
}
|
||||
format= format >> 1;
|
||||
}
|
||||
for(i=0; i<7; i++) {
|
||||
if(format & 1) {
|
||||
blacks += 2;
|
||||
v = 0x85;
|
||||
} else {
|
||||
v = 0x84;
|
||||
}
|
||||
frame[width * (width - 7 + i) + 8] = v;
|
||||
if(i == 0) {
|
||||
frame[width * 8 + 7] = v;
|
||||
} else {
|
||||
frame[width * 8 + 6 - i] = v;
|
||||
}
|
||||
format= format >> 1;
|
||||
}
|
||||
|
||||
return blacks;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* QR-code encoding
|
||||
*****************************************************************************/
|
||||
|
||||
static QRcode *QRcode_new(int version, int width, unsigned char *data)
|
||||
{
|
||||
QRcode *qrcode;
|
||||
|
||||
qrcode = (QRcode *)malloc(sizeof(QRcode));
|
||||
qrcode->version = version;
|
||||
qrcode->width = width;
|
||||
qrcode->data = data;
|
||||
|
||||
return qrcode;
|
||||
}
|
||||
|
||||
void QRcode_free(QRcode *qrcode)
|
||||
{
|
||||
if(qrcode == NULL) return;
|
||||
|
||||
if(qrcode->data != NULL) {
|
||||
free(qrcode->data);
|
||||
}
|
||||
free(qrcode);
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeMask(QRinput *input, int mask)
|
||||
{
|
||||
int width, version;
|
||||
QRRawCode *raw;
|
||||
unsigned char *frame, *masked, *p, code, bit;
|
||||
FrameFiller *filler;
|
||||
int i, j;
|
||||
QRcode *qrcode;
|
||||
|
||||
if(input->version < 0 || input->version > QRSPEC_VERSION_MAX) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if(input->level < QR_ECLEVEL_L || input->level > QR_ECLEVEL_H) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
raw = QRraw_new(input);
|
||||
if(raw == NULL) return NULL;
|
||||
|
||||
version = raw->version;
|
||||
width = QRspec_getWidth(version);
|
||||
frame = QRspec_newFrame(version);
|
||||
filler = FrameFiller_new(width, frame);
|
||||
|
||||
/* inteleaved data and ecc codes */
|
||||
for(i=0; i<raw->dataLength + raw->eccLength; i++) {
|
||||
code = QRraw_getCode(raw);
|
||||
bit = 0x80;
|
||||
for(j=0; j<8; j++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = 0x02 | ((bit & code) != 0);
|
||||
bit = bit >> 1;
|
||||
}
|
||||
}
|
||||
QRraw_free(raw);
|
||||
/* remainder bits */
|
||||
j = QRspec_getRemainder(version);
|
||||
for(i=0; i<j; i++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = 0x02;
|
||||
}
|
||||
free(filler);
|
||||
/* masking */
|
||||
if(mask < 0) {
|
||||
masked = Mask_mask(width, frame, input->level);
|
||||
} else {
|
||||
masked = Mask_makeMask(width, frame, mask);
|
||||
QRcode_writeFormatInformation(width, masked, mask, input->level);
|
||||
}
|
||||
qrcode = QRcode_new(version, width, masked);
|
||||
|
||||
free(frame);
|
||||
|
||||
return qrcode;
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeInput(QRinput *input)
|
||||
{
|
||||
return QRcode_encodeMask(input, -1);
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode *code;
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
QRinput_append(input, QR_MODE_8, strlen(string), (unsigned char *)string);
|
||||
code = QRcode_encodeInput(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode *code;
|
||||
int ret;
|
||||
|
||||
if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
ret = Split_splitStringToQRinput(string, input, hint, casesensitive);
|
||||
if(ret < 0) {
|
||||
QRinput_free(input);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
code = QRcode_encodeInput(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Structured QR-code encoding
|
||||
*****************************************************************************/
|
||||
|
||||
static QRcode_List *QRcode_List_newEntry(void)
|
||||
{
|
||||
QRcode_List *entry;
|
||||
|
||||
entry = (QRcode_List *)malloc(sizeof(QRcode_List));
|
||||
if(entry == NULL) return NULL;
|
||||
|
||||
entry->next = NULL;
|
||||
entry->code = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void QRcode_List_freeEntry(QRcode_List *entry)
|
||||
{
|
||||
if(entry->code != NULL) QRcode_free(entry->code);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
void QRcode_List_free(QRcode_List *qrlist)
|
||||
{
|
||||
QRcode_List *list = qrlist, *next;
|
||||
|
||||
while(list != NULL) {
|
||||
next = list->next;
|
||||
QRcode_List_freeEntry(list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
int QRcode_List_size(QRcode_List *qrlist)
|
||||
{
|
||||
QRcode_List *list = qrlist;
|
||||
int size = 0;
|
||||
|
||||
while(list != NULL) {
|
||||
size++;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned char QRcode_parity(const char *str, int size)
|
||||
{
|
||||
unsigned char parity = 0;
|
||||
int i;
|
||||
|
||||
for(i=0; i<size; i++) {
|
||||
parity ^= str[i];
|
||||
}
|
||||
|
||||
return parity;
|
||||
}
|
||||
#endif
|
||||
|
||||
QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s)
|
||||
{
|
||||
QRcode_List *head = NULL;
|
||||
QRcode_List *tail = NULL;
|
||||
QRinput_InputList *list = s->head;
|
||||
|
||||
while(list != NULL) {
|
||||
if(head == NULL) {
|
||||
head = QRcode_List_newEntry();
|
||||
tail = head;
|
||||
} else {
|
||||
tail->next = QRcode_List_newEntry();
|
||||
tail = tail->next;
|
||||
}
|
||||
tail->code = QRcode_encodeInput(list->input);
|
||||
if(tail->code == NULL) {
|
||||
QRcode_List_free(head);
|
||||
return NULL;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static QRcode_List *QRcode_encodeInputToStructured(QRinput *input)
|
||||
{
|
||||
QRinput_Struct *s;
|
||||
QRcode_List *codes;
|
||||
|
||||
s = QRinput_splitQRinputToStruct(input);
|
||||
if(s == NULL) return NULL;
|
||||
|
||||
codes = QRcode_encodeInputStructured(s);
|
||||
QRinput_Struct_free(s);
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode_List *codes;
|
||||
int ret;
|
||||
|
||||
if(version <= 0) return NULL;
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
ret = QRinput_append(input, QR_MODE_8, strlen(string), (unsigned char *)string);
|
||||
if(ret < 0) {
|
||||
QRinput_free(input);
|
||||
return NULL;
|
||||
}
|
||||
codes = QRcode_encodeInputToStructured(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode_List *codes;
|
||||
int ret;
|
||||
|
||||
if(version <= 0) return NULL;
|
||||
if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
ret = Split_splitStringToQRinput(string, input, hint, casesensitive);
|
||||
if(ret < 0) {
|
||||
QRinput_free(input);
|
||||
return NULL;
|
||||
}
|
||||
codes = QRcode_encodeInputToStructured(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
|
@ -1,423 +0,0 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/** \mainpage
|
||||
* Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D
|
||||
* symbology.
|
||||
*
|
||||
* \section encoding Encoding
|
||||
*
|
||||
* There are two ways to encode data: <b>encoding a string</b> or
|
||||
* <b>encoding a structured data</b>.
|
||||
*
|
||||
* \subsection encoding-string Encoding a string
|
||||
* You can encode a string by calling QRcode_encodeString().
|
||||
* The given string is parsed automatically and encoded. If you want to encode
|
||||
* data that can be represented as a C string style (NUL terminated), you can
|
||||
* simply use this way.
|
||||
*
|
||||
* If the input data contains Kanji (Shift-JIS) characters and you want to
|
||||
* encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint.
|
||||
* Otherwise, all of non-alphanumeric characters are encoded as 8 bit data.
|
||||
* If you want to encode a whole string in 8 bit mode, use
|
||||
* QRcode_encodeString8bit() instead.
|
||||
*
|
||||
* Please note that a C string can not contain NUL character. If your data
|
||||
* contains NUL, you should chose the second way.
|
||||
*
|
||||
* \subsection encoding-input Encoding a structured data
|
||||
* You can construct a structured input data manually. If the structure of the
|
||||
* input data is known, you can use this way.
|
||||
* At first, you must create a ::QRinput object by QRinput_new(). Then, you can
|
||||
* add input data to the QRinput object by QRinput_append().
|
||||
* Finally you can call QRcode_encodeInput() to encode the QRinput data.
|
||||
* You can reuse the QRinput data again to encode it in other symbols with
|
||||
* different parameters.
|
||||
*
|
||||
* \section result Result
|
||||
* The encoded symbol is resulted as a ::QRcode object. It will contain
|
||||
* its version number, width of the symbol and an array represents the symbol.
|
||||
* See ::QRcode for the details. You can free the object by QRcode_free().
|
||||
*
|
||||
* Please note that the version of the result may be larger than specified.
|
||||
* In such cases, the input data would be too large to be encoded in the
|
||||
* symbol of the specified version.
|
||||
*
|
||||
* \section structured Structured append
|
||||
* Libqrencode can generate "Structured-appended" symbols that enables to split
|
||||
* a large data set into mulitple QR codes. A QR code reader concatenates
|
||||
* multiple QR code symbols into a string.
|
||||
* Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured()
|
||||
* to generate structured-appended symbols. This functions returns an instance
|
||||
* of ::QRcode_List. The returned list is a singly-linked list of QRcode: you
|
||||
* can retrieve each QR code in this way:
|
||||
*
|
||||
* \code
|
||||
* QRcode_List *qrcodes;
|
||||
* QRcode_List *entry;
|
||||
* QRcode *qrcode;
|
||||
*
|
||||
* qrcodes = QRcode_encodeStringStructured(...);
|
||||
* entry = qrcodes;
|
||||
* while(entry != NULL) {
|
||||
* qrcode = entry->code;
|
||||
* // do something
|
||||
* entry = entry->next;
|
||||
* }
|
||||
* QRcode_List_free(entry);
|
||||
* \endcode
|
||||
*
|
||||
* Instead of using auto-parsing functions, you can construct your own
|
||||
* structured input. At first, instantiate an object of ::QRinput_Struct
|
||||
* by calling QRinput_Struct_new(). This object can hold multiple ::QRinput,
|
||||
* and one QR code is generated for a ::QRinput.
|
||||
* QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct
|
||||
* object. In order to generate structured-appended symbols, it is required to
|
||||
* embed headers to each symbol. You can use
|
||||
* QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate
|
||||
* headers to each symbol. You should call this function just once before
|
||||
* encoding symbols.
|
||||
*/
|
||||
|
||||
#ifndef __QRENCODE_H__
|
||||
#define __QRENCODE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Encoding mode.
|
||||
*/
|
||||
typedef enum {
|
||||
QR_MODE_NUL = -1, ///< Terminator (NUL character)
|
||||
QR_MODE_NUM = 0, ///< Numeric mode
|
||||
QR_MODE_AN, ///< Alphabet-numeric mode
|
||||
QR_MODE_8, ///< 8-bit data mode
|
||||
QR_MODE_KANJI, ///< Kanji (shift-jis) mode
|
||||
QR_MODE_STRUCTURE, ///< Internal use only
|
||||
} QRencodeMode;
|
||||
|
||||
/**
|
||||
* Level of error correction.
|
||||
*/
|
||||
typedef enum {
|
||||
QR_ECLEVEL_L = 0, ///< lowest
|
||||
QR_ECLEVEL_M,
|
||||
QR_ECLEVEL_Q,
|
||||
QR_ECLEVEL_H ///< highest
|
||||
} QRecLevel;
|
||||
|
||||
/******************************************************************************
|
||||
* Input data (qrinput.c)
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Singly linked list to contain input strings. An instance of this class
|
||||
* contains its version and error correction level too. It is required to
|
||||
* set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(),
|
||||
* or use QRinput_new2() to instantiate an object.
|
||||
*/
|
||||
typedef struct _QRinput QRinput;
|
||||
|
||||
/**
|
||||
* Instantiate an input data object. The version is set to 0 (auto-select)
|
||||
* and the error correction level is set to QR_ECLEVEL_L.
|
||||
* @return an input object (initialized). On error, NULL is returned and errno
|
||||
* is set to indicate the error.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern QRinput *QRinput_new(void);
|
||||
|
||||
/**
|
||||
* Instantiate an input data object.
|
||||
* @param version version number.
|
||||
* @param level Error correction level.
|
||||
* @return an input object (initialized). On error, NULL is returned and errno
|
||||
* is set to indicate the error.
|
||||
* @throw ENOMEM unable to allocate memory for input objects.
|
||||
* @throw EINVAL invalid arguments.
|
||||
*/
|
||||
extern QRinput *QRinput_new2(int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Append data to an input object.
|
||||
* The data is copied and appended to the input object.
|
||||
* @param input input object.
|
||||
* @param mode encoding mode.
|
||||
* @param size size of data (byte).
|
||||
* @param data a pointer to the memory area of the input data.
|
||||
* @retval 0 success.
|
||||
* @retval -1 an error occurred and errno is set to indeicate the error.
|
||||
* See Execptions for the details.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
* @throw EINVAL input data is invalid.
|
||||
*
|
||||
*/
|
||||
extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data);
|
||||
|
||||
/**
|
||||
* Get current version.
|
||||
* @param input input object.
|
||||
* @return current version.
|
||||
*/
|
||||
extern int QRinput_getVersion(QRinput *input);
|
||||
|
||||
/**
|
||||
* Set version of the QR-code that is to be encoded.
|
||||
* @param input input object.
|
||||
* @param version version number (0 = auto)
|
||||
* @retval 0 success.
|
||||
* @retval -1 invalid argument.
|
||||
*/
|
||||
extern int QRinput_setVersion(QRinput *input, int version);
|
||||
|
||||
/**
|
||||
* Get current error correction level.
|
||||
* @param input input object.
|
||||
* @return Current error correcntion level.
|
||||
*/
|
||||
extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input);
|
||||
|
||||
/**
|
||||
* Set error correction level of the QR-code that is to be encoded.
|
||||
* @param input input object.
|
||||
* @param level Error correction level.
|
||||
* @retval 0 success.
|
||||
* @retval -1 invalid argument.
|
||||
*/
|
||||
extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Free the input object.
|
||||
* All of data chunks in the input object are freed too.
|
||||
* @param input input object.
|
||||
*/
|
||||
extern void QRinput_free(QRinput *input);
|
||||
|
||||
/**
|
||||
* Validate the input data.
|
||||
* @param mode encoding mode.
|
||||
* @param size size of data (byte).
|
||||
* @param data a pointer to the memory area of the input data.
|
||||
* @retval 0 success.
|
||||
* @retval -1 invalid arguments.
|
||||
*/
|
||||
extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data);
|
||||
|
||||
/**
|
||||
* Set of QRinput for structured symbols.
|
||||
*/
|
||||
typedef struct _QRinput_Struct QRinput_Struct;
|
||||
|
||||
/**
|
||||
* Instantiate a set of input data object.
|
||||
* @return an instance of QRinput_Struct. On error, NULL is returned and errno
|
||||
* is set to indicate the error.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern QRinput_Struct *QRinput_Struct_new(void);
|
||||
|
||||
/**
|
||||
* Set parity of structured symbols.
|
||||
* @param s structured input object.
|
||||
* @param parity parity of s.
|
||||
*/
|
||||
extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity);
|
||||
|
||||
/**
|
||||
* Append a QRinput object to the set.
|
||||
* @warning never append the same QRinput object twice.
|
||||
* @param s structured input object.
|
||||
* @param input an input object.
|
||||
* @retval >0 number of input objects in the structure.
|
||||
* @retval -1 an error occurred. See Exceptions for the details.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input);
|
||||
|
||||
/**
|
||||
* Free all of QRinput in the set.
|
||||
* @param s a structured input object.
|
||||
*/
|
||||
extern void QRinput_Struct_free(QRinput_Struct *s);
|
||||
|
||||
/**
|
||||
* Split a QRinput to QRinput_Struct. It calculates a parity, set it, then
|
||||
* insert structured-append headers.
|
||||
* @param input input object. Version number and error correction level must be
|
||||
* set.
|
||||
* @return a set of input data. On error, NULL is returned, and errno is set
|
||||
* to indicate the error. See Exceptions for the details.
|
||||
* @throw ERANGE input data is too large.
|
||||
* @throw EINVAL invalid input data.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input);
|
||||
|
||||
/**
|
||||
* Insert structured-append headers to the input structure. It calculates
|
||||
* a parity and set it if the parity is not set yet.
|
||||
* @param s input structure
|
||||
* @retval 0 success.
|
||||
* @retval -1 an error occurred and errno is set to indeicate the error.
|
||||
* See Execptions for the details.
|
||||
* @throw EINVAL invalid input object.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s);
|
||||
|
||||
/******************************************************************************
|
||||
* QRcode output (qrencode.c)
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* QRcode class.
|
||||
* Symbol data is represented as an array contains width*width uchars.
|
||||
* Each uchar represents a module (dot). If the less significant bit of
|
||||
* the uchar is 1, the corresponding module is black. The other bits are
|
||||
* meaningless for usual applications, but here its specification is described.
|
||||
*
|
||||
* <pre>
|
||||
* MSB 76543210 LSB
|
||||
* |||||||`- 1=black/0=white
|
||||
* ||||||`-- data and ecc code area
|
||||
* |||||`--- format information
|
||||
* ||||`---- version information
|
||||
* |||`----- timing pattern
|
||||
* ||`------ alignment pattern
|
||||
* |`------- finder pattern and separator
|
||||
* `-------- non-data modules (format, timing, etc.)
|
||||
* </pre>
|
||||
*/
|
||||
typedef struct {
|
||||
int version; ///< version of the symbol
|
||||
int width; ///< width of the symbol
|
||||
unsigned char *data; ///< symbol data
|
||||
} QRcode;
|
||||
|
||||
/**
|
||||
* Singly-linked list of QRcode. Used to represent a structured symbols.
|
||||
* A list is terminated with NULL.
|
||||
*/
|
||||
typedef struct _QRcode_List QRcode_List;
|
||||
|
||||
struct _QRcode_List {
|
||||
QRcode *code;
|
||||
QRcode_List *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a symbol from the input data.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param input input data.
|
||||
* @return an instance of QRcode class. The version of the result QRcode may
|
||||
* be larger than the designated version. On error, NULL is returned,
|
||||
* and errno is set to indicate the error. See Exceptions for the
|
||||
* details.
|
||||
* @throw EINVAL invalid input object.
|
||||
* @throw ENOMEM unable to allocate memory for input objects.
|
||||
*/
|
||||
extern QRcode *QRcode_encodeInput(QRinput *input);
|
||||
|
||||
/**
|
||||
* Create a symbol from the string. The library automatically parses the input
|
||||
* string and encodes in a QR Code symbol.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param string input string. It must be NULL terminated.
|
||||
* @param version version of the symbol. If 0, the library chooses the minimum
|
||||
* version for the given input data.
|
||||
* @param level error correction level.
|
||||
* @param hint tell the library how non-alphanumerical characters should be
|
||||
* encoded. If QR_MODE_KANJI is given, kanji characters will be
|
||||
* encoded as Shif-JIS characters. If QR_MODE_8 is given, all of
|
||||
* non-alphanumerical characters will be encoded as is. If you want
|
||||
* to embed UTF-8 string, choose this.
|
||||
* @param casesensitive case-sensitive(1) or not(0).
|
||||
* @return an instance of QRcode class. The version of the result QRcode may
|
||||
* be larger than the designated version. On error, NULL is returned,
|
||||
* and errno is set to indicate the error. See Exceptions for the
|
||||
* details.
|
||||
* @throw EINVAL invalid input object.
|
||||
* @throw ENOMEM unable to allocate memory for input objects.
|
||||
*/
|
||||
extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
|
||||
/**
|
||||
* Same to ::QRcode_qncodeString, but encode whole data in 8-bit mode.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
*/
|
||||
extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Free the instance of QRcode class.
|
||||
* @param qrcode an instance of QRcode class.
|
||||
*/
|
||||
extern void QRcode_free(QRcode *qrcode);
|
||||
|
||||
/**
|
||||
* Create structured symbols from the input data.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param s
|
||||
* @return a singly-linked list of QRcode.
|
||||
*/
|
||||
extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s);
|
||||
|
||||
/**
|
||||
* Create structured symbols from the string. The library automatically parses
|
||||
* the input string and encodes in a QR Code symbol.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param string input string. It should be NULL terminated.
|
||||
* @param version version of the symbol.
|
||||
* @param level error correction level.
|
||||
* @param hint tell the library how non-alphanumerical characters should be
|
||||
* encoded. If QR_MODE_KANJI is given, kanji characters will be
|
||||
* encoded as Shif-JIS characters. If QR_MODE_8 is given, all of
|
||||
* non-alphanumerical characters will be encoded as is. If you want
|
||||
* to embed UTF-8 string, choose this.
|
||||
* @param casesensitive case-sensitive(1) or not(0).
|
||||
* @return a singly-linked list of QRcode.
|
||||
*/
|
||||
extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
|
||||
/**
|
||||
* Same to QRcode_qncodeStringStructured, but encode whole data in 8-bit mode.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
*/
|
||||
extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return the number of symbols included in a QRcode_List.
|
||||
* @param qrlist a head entry of a QRcode_List.
|
||||
* @return number of symbols in the list.
|
||||
*/
|
||||
extern int QRcode_List_size(QRcode_List *qrlist);
|
||||
|
||||
/**
|
||||
* Free the QRcode_List.
|
||||
* @param qrlist a head entry of a QRcode_List.
|
||||
*/
|
||||
extern void QRcode_List_free(QRcode_List *qrlist);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __QRENCODE_H__ */
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Header for internal use
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __QRENCODE_INNER_H__
|
||||
#define __QRENCODE_INNER_H__
|
||||
|
||||
/**
|
||||
* This header file includes definitions for inner use.
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* Raw code
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int dataLength;
|
||||
unsigned char *data;
|
||||
int eccLength;
|
||||
unsigned char *ecc;
|
||||
} RSblock;
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
unsigned char *datacode;
|
||||
int blocks;
|
||||
RSblock *rsblock;
|
||||
int count;
|
||||
int dataLength;
|
||||
int eccLength;
|
||||
int b1;
|
||||
} QRRawCode;
|
||||
|
||||
extern QRRawCode *QRraw_new(QRinput *input);
|
||||
extern unsigned char QRraw_getCode(QRRawCode *raw);
|
||||
extern void QRraw_free(QRRawCode *raw);
|
||||
|
||||
/******************************************************************************
|
||||
* Frame filling
|
||||
*****************************************************************************/
|
||||
extern unsigned char *FrameFiller_fillerTest(int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
extern int QRcode_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level);
|
||||
|
||||
extern QRcode *QRcode_encodeMask(QRinput *input, int mask);
|
||||
#endif /* __QRENCODE_INNER_H__ */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Input data chunk class
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __QRINPUT_H__
|
||||
#define __QRINPUT_H__
|
||||
|
||||
#include "qrencode.h"
|
||||
#include "bitstream.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Entry of input data
|
||||
*****************************************************************************/
|
||||
typedef struct _QRinput_List QRinput_List;
|
||||
|
||||
struct _QRinput_List {
|
||||
QRencodeMode mode;
|
||||
int size; ///< Size of data chunk (byte).
|
||||
unsigned char *data; ///< Data chunk.
|
||||
BitStream *bstream;
|
||||
QRinput_List *next;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Input Data
|
||||
*****************************************************************************/
|
||||
struct _QRinput {
|
||||
int version;
|
||||
QRecLevel level;
|
||||
QRinput_List *head;
|
||||
QRinput_List *tail;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Structured append input data
|
||||
*****************************************************************************/
|
||||
typedef struct _QRinput_InputList QRinput_InputList;
|
||||
|
||||
struct _QRinput_InputList {
|
||||
QRinput *input;
|
||||
QRinput_InputList *next;
|
||||
};
|
||||
|
||||
struct _QRinput_Struct {
|
||||
int size; ///< number of structured symbols
|
||||
int parity;
|
||||
QRinput_InputList *head;
|
||||
QRinput_InputList *tail;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert a structured-append header to the head of the input data.
|
||||
* @param input input data.
|
||||
* @param size number of structured symbols.
|
||||
* @param index index number of the symbol. (1 <= index <= size)
|
||||
* @param parity parity among input data. (NOTE: each symbol of a set of structured symbols has the same parity data)
|
||||
* @retval 0 success.
|
||||
* @retval -1 error occurred and errno is set to indeicate the error. See Execptions for the details.
|
||||
* @throw EINVAL invalid parameter.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, unsigned char parity);
|
||||
|
||||
/**
|
||||
* Pack all bit streams padding bits into a byte array.
|
||||
* @param input input data.
|
||||
* @return padded merged byte stream
|
||||
*/
|
||||
extern unsigned char *QRinput_getByteStream(QRinput *input);
|
||||
|
||||
|
||||
extern int QRinput_estimateBitsModeNum(int size);
|
||||
extern int QRinput_estimateBitsModeAn(int size);
|
||||
extern int QRinput_estimateBitsMode8(int size);
|
||||
extern int QRinput_estimateBitsModeKanji(int size);
|
||||
|
||||
extern int QRinput_estimateBitStreamSize(QRinput *input, int version);
|
||||
extern BitStream *QRinput_mergeBitStream(QRinput *input);
|
||||
extern BitStream *QRinput_getBitStream(QRinput *input);
|
||||
extern int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits);
|
||||
extern QRinput *QRinput_dup(QRinput *input);
|
||||
extern int QRinput_splitEntry(QRinput_List *entry, int bytes);
|
||||
|
||||
extern const signed char QRinput_anTable[];
|
||||
|
||||
/**
|
||||
* Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
|
||||
* @param __c__ character
|
||||
* @return value
|
||||
*/
|
||||
#define QRinput_lookAnTable(__c__) \
|
||||
((__c__ & 0x80)?-1:QRinput_anTable[(int)__c__])
|
||||
|
||||
/**
|
||||
* Length of a segment of structured-append header.
|
||||
*/
|
||||
#define STRUCTURE_HEADER_BITS 20
|
||||
|
||||
/**
|
||||
* Maximum number of symbols in a set of structured-appended symbols.
|
||||
*/
|
||||
#define MAX_STRUCTURED_SYMBOLS 16
|
||||
|
||||
#endif /* __QRINPUT_H__ */
|
||||
|
|
@ -1,587 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* QR Code specification in convenient format.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "qrspec.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Version and capacity
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int width; //< Edge length of the symbol
|
||||
int words; //< Data capacity (bytes)
|
||||
int remainder; //< Remainder bit (bits)
|
||||
int ec[4]; //< Number of ECC code (bytes)
|
||||
} QRspec_Capacity;
|
||||
|
||||
/**
|
||||
* Table of the capacity of symbols
|
||||
* See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
|
||||
*/
|
||||
static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = {
|
||||
{ 0, 0, 0, { 0, 0, 0, 0}},
|
||||
{ 21, 26, 0, { 7, 10, 13, 17}}, // 1
|
||||
{ 25, 44, 7, { 10, 16, 22, 28}},
|
||||
{ 29, 70, 7, { 15, 26, 36, 44}},
|
||||
{ 33, 100, 7, { 20, 36, 52, 64}},
|
||||
{ 37, 134, 7, { 26, 48, 72, 88}}, // 5
|
||||
{ 41, 172, 7, { 36, 64, 96, 112}},
|
||||
{ 45, 196, 0, { 40, 72, 108, 130}},
|
||||
{ 49, 242, 0, { 48, 88, 132, 156}},
|
||||
{ 53, 292, 0, { 60, 110, 160, 192}},
|
||||
{ 57, 346, 0, { 72, 130, 192, 224}}, //10
|
||||
{ 61, 404, 0, { 80, 150, 224, 264}},
|
||||
{ 65, 466, 0, { 96, 176, 260, 308}},
|
||||
{ 69, 532, 0, { 104, 198, 288, 352}},
|
||||
{ 73, 581, 3, { 120, 216, 320, 384}},
|
||||
{ 77, 655, 3, { 132, 240, 360, 432}}, //15
|
||||
{ 81, 733, 3, { 144, 280, 408, 480}},
|
||||
{ 85, 815, 3, { 168, 308, 448, 532}},
|
||||
{ 89, 901, 3, { 180, 338, 504, 588}},
|
||||
{ 93, 991, 3, { 196, 364, 546, 650}},
|
||||
{ 97, 1085, 3, { 224, 416, 600, 700}}, //20
|
||||
{101, 1156, 4, { 224, 442, 644, 750}},
|
||||
{105, 1258, 4, { 252, 476, 690, 816}},
|
||||
{109, 1364, 4, { 270, 504, 750, 900}},
|
||||
{113, 1474, 4, { 300, 560, 810, 960}},
|
||||
{117, 1588, 4, { 312, 588, 870, 1050}}, //25
|
||||
{121, 1706, 4, { 336, 644, 952, 1110}},
|
||||
{125, 1828, 4, { 360, 700, 1020, 1200}},
|
||||
{129, 1921, 3, { 390, 728, 1050, 1260}},
|
||||
{133, 2051, 3, { 420, 784, 1140, 1350}},
|
||||
{137, 2185, 3, { 450, 812, 1200, 1440}}, //30
|
||||
{141, 2323, 3, { 480, 868, 1290, 1530}},
|
||||
{145, 2465, 3, { 510, 924, 1350, 1620}},
|
||||
{149, 2611, 3, { 540, 980, 1440, 1710}},
|
||||
{153, 2761, 3, { 570, 1036, 1530, 1800}},
|
||||
{157, 2876, 0, { 570, 1064, 1590, 1890}}, //35
|
||||
{161, 3034, 0, { 600, 1120, 1680, 1980}},
|
||||
{165, 3196, 0, { 630, 1204, 1770, 2100}},
|
||||
{169, 3362, 0, { 660, 1260, 1860, 2220}},
|
||||
{173, 3532, 0, { 720, 1316, 1950, 2310}},
|
||||
{177, 3706, 0, { 750, 1372, 2040, 2430}} //40
|
||||
};
|
||||
|
||||
int QRspec_getDataLength(int version, QRecLevel level)
|
||||
{
|
||||
return qrspecCapacity[version].words - qrspecCapacity[version].ec[level];
|
||||
}
|
||||
|
||||
int QRspec_getECCLength(int version, QRecLevel level)
|
||||
{
|
||||
return qrspecCapacity[version].ec[level];
|
||||
}
|
||||
|
||||
int QRspec_getMinimumVersion(int size, QRecLevel level)
|
||||
{
|
||||
int i;
|
||||
int words;
|
||||
|
||||
for(i=1; i<= QRSPEC_VERSION_MAX; i++) {
|
||||
words = qrspecCapacity[i].words - qrspecCapacity[i].ec[level];
|
||||
if(words >= size) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int QRspec_getWidth(int version)
|
||||
{
|
||||
return qrspecCapacity[version].width;
|
||||
}
|
||||
|
||||
int QRspec_getRemainder(int version)
|
||||
{
|
||||
return qrspecCapacity[version].remainder;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Length indicator
|
||||
*****************************************************************************/
|
||||
|
||||
static const int lengthTableBits[4][3] = {
|
||||
{10, 12, 14},
|
||||
{ 9, 11, 13},
|
||||
{ 8, 16, 16},
|
||||
{ 8, 10, 12}
|
||||
};
|
||||
|
||||
int QRspec_lengthIndicator(QRencodeMode mode, int version)
|
||||
{
|
||||
int l;
|
||||
|
||||
if(mode == QR_MODE_STRUCTURE) return 0;
|
||||
if(version <= 9) {
|
||||
l = 0;
|
||||
} else if(version <= 26) {
|
||||
l = 1;
|
||||
} else {
|
||||
l = 2;
|
||||
}
|
||||
|
||||
return lengthTableBits[mode][l];
|
||||
}
|
||||
|
||||
int QRspec_maximumWords(QRencodeMode mode, int version)
|
||||
{
|
||||
int l;
|
||||
int bits;
|
||||
int words;
|
||||
|
||||
if(mode == QR_MODE_STRUCTURE) return 3;
|
||||
if(version <= 9) {
|
||||
l = 0;
|
||||
} else if(version <= 26) {
|
||||
l = 1;
|
||||
} else {
|
||||
l = 2;
|
||||
}
|
||||
|
||||
bits = lengthTableBits[mode][l];
|
||||
words = (1 << bits) - 1;
|
||||
if(mode == QR_MODE_KANJI) {
|
||||
words *= 2; // the number of bytes is required
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Error correction code
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Table of the error correction code (Reed-Solomon block)
|
||||
* See Table 12-16 (pp.30-36), JIS X0510:2004.
|
||||
*/
|
||||
static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = {
|
||||
{{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}},
|
||||
{{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, // 1
|
||||
{{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}},
|
||||
{{ 1, 0}, { 1, 0}, { 2, 0}, { 2, 0}},
|
||||
{{ 1, 0}, { 2, 0}, { 2, 0}, { 4, 0}},
|
||||
{{ 1, 0}, { 2, 0}, { 2, 2}, { 2, 2}}, // 5
|
||||
{{ 2, 0}, { 4, 0}, { 4, 0}, { 4, 0}},
|
||||
{{ 2, 0}, { 4, 0}, { 2, 4}, { 4, 1}},
|
||||
{{ 2, 0}, { 2, 2}, { 4, 2}, { 4, 2}},
|
||||
{{ 2, 0}, { 3, 2}, { 4, 4}, { 4, 4}},
|
||||
{{ 2, 2}, { 4, 1}, { 6, 2}, { 6, 2}}, //10
|
||||
{{ 4, 0}, { 1, 4}, { 4, 4}, { 3, 8}},
|
||||
{{ 2, 2}, { 6, 2}, { 4, 6}, { 7, 4}},
|
||||
{{ 4, 0}, { 8, 1}, { 8, 4}, {12, 4}},
|
||||
{{ 3, 1}, { 4, 5}, {11, 5}, {11, 5}},
|
||||
{{ 5, 1}, { 5, 5}, { 5, 7}, {11, 7}}, //15
|
||||
{{ 5, 1}, { 7, 3}, {15, 2}, { 3, 13}},
|
||||
{{ 1, 5}, {10, 1}, { 1, 15}, { 2, 17}},
|
||||
{{ 5, 1}, { 9, 4}, {17, 1}, { 2, 19}},
|
||||
{{ 3, 4}, { 3, 11}, {17, 4}, { 9, 16}},
|
||||
{{ 3, 5}, { 3, 13}, {15, 5}, {15, 10}}, //20
|
||||
{{ 4, 4}, {17, 0}, {17, 6}, {19, 6}},
|
||||
{{ 2, 7}, {17, 0}, { 7, 16}, {34, 0}},
|
||||
{{ 4, 5}, { 4, 14}, {11, 14}, {16, 14}},
|
||||
{{ 6, 4}, { 6, 14}, {11, 16}, {30, 2}},
|
||||
{{ 8, 4}, { 8, 13}, { 7, 22}, {22, 13}}, //25
|
||||
{{10, 2}, {19, 4}, {28, 6}, {33, 4}},
|
||||
{{ 8, 4}, {22, 3}, { 8, 26}, {12, 28}},
|
||||
{{ 3, 10}, { 3, 23}, { 4, 31}, {11, 31}},
|
||||
{{ 7, 7}, {21, 7}, { 1, 37}, {19, 26}},
|
||||
{{ 5, 10}, {19, 10}, {15, 25}, {23, 25}}, //30
|
||||
{{13, 3}, { 2, 29}, {42, 1}, {23, 28}},
|
||||
{{17, 0}, {10, 23}, {10, 35}, {19, 35}},
|
||||
{{17, 1}, {14, 21}, {29, 19}, {11, 46}},
|
||||
{{13, 6}, {14, 23}, {44, 7}, {59, 1}},
|
||||
{{12, 7}, {12, 26}, {39, 14}, {22, 41}}, //35
|
||||
{{ 6, 14}, { 6, 34}, {46, 10}, { 2, 64}},
|
||||
{{17, 4}, {29, 14}, {49, 10}, {24, 46}},
|
||||
{{ 4, 18}, {13, 32}, {48, 14}, {42, 32}},
|
||||
{{20, 4}, {40, 7}, {43, 22}, {10, 67}},
|
||||
{{19, 6}, {18, 31}, {34, 34}, {20, 61}},//40
|
||||
};
|
||||
|
||||
int *QRspec_getEccSpec(int version, QRecLevel level)
|
||||
{
|
||||
int b1, b2;
|
||||
int data, ecc;
|
||||
int *array;
|
||||
|
||||
b1 = eccTable[version][level][0];
|
||||
b2 = eccTable[version][level][1];
|
||||
data = QRspec_getDataLength(version, level);
|
||||
ecc = QRspec_getECCLength(version, level);
|
||||
|
||||
array = (int *)malloc(sizeof(int) * 6);
|
||||
if(array == NULL) return NULL;
|
||||
|
||||
if(b2 == 0) {
|
||||
array[0] = b1;
|
||||
array[1] = data / b1;
|
||||
array[2] = ecc / b1;
|
||||
array[3] = array[4] = array[5] = 0;
|
||||
} else {
|
||||
array[0] = b1;
|
||||
array[1] = data / (b1 + b2);
|
||||
array[2] = ecc / (b1 + b2);
|
||||
array[3] = b2;
|
||||
array[4] = array[1] + 1;
|
||||
array[5] = (ecc - (array[2] * b1)) / b2;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Alignment pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Positions of alignment patterns.
|
||||
* This array includes only the second and the third position of the alignment
|
||||
* patterns. Rest of them can be calculated from the distance between them.
|
||||
*
|
||||
* See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
|
||||
*/
|
||||
static const int alignmentPattern[QRSPEC_VERSION_MAX+1][2] = {
|
||||
{ 0, 0},
|
||||
{ 0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, // 1- 5
|
||||
{34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, // 6-10
|
||||
{30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, //11-15
|
||||
{26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, //16-20
|
||||
{28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, //21-25
|
||||
{30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, //26-30
|
||||
{30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, //31-35
|
||||
{24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, //35-40
|
||||
};
|
||||
|
||||
QRspec_Alignment *QRspec_getAlignmentPattern(int version)
|
||||
{
|
||||
int width;
|
||||
int d, w, x, y, cx, cy;
|
||||
QRspec_Alignment *al;
|
||||
int *p;
|
||||
|
||||
if(version < 2) return NULL;
|
||||
|
||||
al = (QRspec_Alignment *)malloc(sizeof(QRspec_Alignment));
|
||||
|
||||
width = qrspecCapacity[version].width;
|
||||
d = alignmentPattern[version][1] - alignmentPattern[version][0];
|
||||
if(d < 0) {
|
||||
w = 2;
|
||||
} else {
|
||||
w = (width - alignmentPattern[version][0]) / d + 2;
|
||||
}
|
||||
|
||||
al->n = w * w - 3;
|
||||
al->pos = (int *)malloc(sizeof(int) * al->n * 2);
|
||||
|
||||
if(al->n == 1) {
|
||||
al->pos[0] = alignmentPattern[version][0];
|
||||
al->pos[1] = alignmentPattern[version][0];
|
||||
|
||||
return al;
|
||||
}
|
||||
#if 0
|
||||
/* Just for debug purpose */
|
||||
printf("%d ", version);
|
||||
cx = alignmentPattern[version][0];
|
||||
for(x=0; x<w-1; x++) {
|
||||
printf(" %3d", cx);
|
||||
cx += d;
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
p = al->pos;
|
||||
|
||||
cx = alignmentPattern[version][0];
|
||||
for(x=1; x<w - 1; x++) {
|
||||
p[0] = 6;
|
||||
p[1] = cx;
|
||||
p[2] = cx;
|
||||
p[3] = 6;
|
||||
cx += d;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
cy = alignmentPattern[version][0];
|
||||
for(y=0; y<w-1; y++) {
|
||||
cx = alignmentPattern[version][0];
|
||||
for(x=0; x<w-1; x++) {
|
||||
p[0] = cx;
|
||||
p[1] = cy;
|
||||
cx += d;
|
||||
p += 2;
|
||||
}
|
||||
cy += d;
|
||||
}
|
||||
|
||||
return al;
|
||||
}
|
||||
|
||||
void QRspec_freeAlignment(QRspec_Alignment *al)
|
||||
{
|
||||
if(al != NULL) {
|
||||
if(al->pos != NULL) {
|
||||
free(al->pos);
|
||||
}
|
||||
free(al);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Version information pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Version information pattern (BCH coded).
|
||||
* See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
|
||||
*/
|
||||
static const unsigned int versionPattern[QRSPEC_VERSION_MAX - 6] = {
|
||||
0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
|
||||
0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
|
||||
0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
|
||||
0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
|
||||
0x27541, 0x28c69
|
||||
};
|
||||
|
||||
unsigned int QRspec_getVersionPattern(int version)
|
||||
{
|
||||
if(version < 7 || version > QRSPEC_VERSION_MAX) return 0;
|
||||
|
||||
return versionPattern[version -7];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
|
||||
/* See calcFormatInfo in tests/test_qrspec.c */
|
||||
static const unsigned int formatInfo[4][8] = {
|
||||
{0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976},
|
||||
{0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0},
|
||||
{0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed},
|
||||
{0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b}
|
||||
};
|
||||
|
||||
unsigned int QRspec_getFormatInfo(int mask, QRecLevel level)
|
||||
{
|
||||
if(mask < 0 || mask > 7) return 0;
|
||||
|
||||
return formatInfo[level][mask];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Frame
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Cache of initial frames.
|
||||
*/
|
||||
/* C99 says that static storage shall be initialized to a null pointer
|
||||
* by compiler. */
|
||||
static unsigned char *frames[QRSPEC_VERSION_MAX + 1];
|
||||
|
||||
/**
|
||||
* Put a finder pattern.
|
||||
* @param frame
|
||||
* @param width
|
||||
* @param ox,oy upper-left coordinate of the pattern
|
||||
*/
|
||||
static void putFinderPattern(unsigned char *frame, int width, int ox, int oy)
|
||||
{
|
||||
static const unsigned char finder[] = {
|
||||
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
|
||||
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
|
||||
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
|
||||
};
|
||||
int x, y;
|
||||
const unsigned char *s;
|
||||
|
||||
frame += oy * width + ox;
|
||||
s = finder;
|
||||
for(y=0; y<7; y++) {
|
||||
for(x=0; x<7; x++) {
|
||||
frame[x] = s[x];
|
||||
}
|
||||
frame += width;
|
||||
s += 7;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an alignment pattern.
|
||||
* @param frame
|
||||
* @param width
|
||||
* @param ox,oy center coordinate of the pattern
|
||||
*/
|
||||
static void putAlignmentPattern(unsigned char *frame, int width, int ox, int oy)
|
||||
{
|
||||
static const unsigned char finder[] = {
|
||||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||||
0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
|
||||
0xa1, 0xa0, 0xa1, 0xa0, 0xa1,
|
||||
0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
|
||||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||||
};
|
||||
int x, y;
|
||||
const unsigned char *s;
|
||||
|
||||
frame += (oy - 2) * width + ox - 2;
|
||||
s = finder;
|
||||
for(y=0; y<5; y++) {
|
||||
for(x=0; x<5; x++) {
|
||||
frame[x] = s[x];
|
||||
}
|
||||
frame += width;
|
||||
s += 5;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *QRspec_createFrame(int version)
|
||||
{
|
||||
unsigned char *frame, *p, *q;
|
||||
int width;
|
||||
int x, y;
|
||||
unsigned int verinfo, v;
|
||||
QRspec_Alignment *alignment;
|
||||
|
||||
width = qrspecCapacity[version].width;
|
||||
frame = (unsigned char *)malloc(width * width);
|
||||
memset(frame, 0, width * width);
|
||||
/* Finder pattern */
|
||||
putFinderPattern(frame, width, 0, 0);
|
||||
putFinderPattern(frame, width, width - 7, 0);
|
||||
putFinderPattern(frame, width, 0, width - 7);
|
||||
/* Separator */
|
||||
p = frame;
|
||||
q = frame + width * (width - 7);
|
||||
for(y=0; y<7; y++) {
|
||||
p[7] = 0xc0;
|
||||
p[width - 8] = 0xc0;
|
||||
q[7] = 0xc0;
|
||||
p += width;
|
||||
q += width;
|
||||
}
|
||||
memset(frame + width * 7, 0xc0, 8);
|
||||
memset(frame + width * 8 - 8, 0xc0, 8);
|
||||
memset(frame + width * (width - 8), 0xc0, 8);
|
||||
/* Mask format information area */
|
||||
memset(frame + width * 8, 0x84, 9);
|
||||
memset(frame + width * 9 - 8, 0x84, 8);
|
||||
p = frame + 8;
|
||||
for(y=0; y<8; y++) {
|
||||
*p = 0x84;
|
||||
p += width;
|
||||
}
|
||||
p = frame + width * (width - 7) + 8;
|
||||
for(y=0; y<7; y++) {
|
||||
*p = 0x84;
|
||||
p += width;
|
||||
}
|
||||
/* Timing pattern */
|
||||
p = frame + width * 6 + 8;
|
||||
q = frame + width * 8 + 6;
|
||||
for(x=1; x<width-15; x++) {
|
||||
*p = 0x90 | (x & 1);
|
||||
*q = 0x90 | (x & 1);
|
||||
p++;
|
||||
q += width;
|
||||
}
|
||||
/* Alignment pattern */
|
||||
alignment = QRspec_getAlignmentPattern(version);
|
||||
if(alignment != NULL) {
|
||||
for(x=0; x<alignment->n; x++) {
|
||||
putAlignmentPattern(frame, width,
|
||||
alignment->pos[x*2], alignment->pos[x*2+1]);
|
||||
}
|
||||
QRspec_freeAlignment(alignment);
|
||||
}
|
||||
/* Version information */
|
||||
if(version >= 7) {
|
||||
verinfo = QRspec_getVersionPattern(version);
|
||||
|
||||
p = frame + width * (width - 11);
|
||||
v = verinfo;
|
||||
for(x=0; x<6; x++) {
|
||||
for(y=0; y<3; y++) {
|
||||
p[width * y + x] = 0x88 | (v & 1);
|
||||
v = v >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
p = frame + width - 11;
|
||||
v = verinfo;
|
||||
for(y=0; y<6; y++) {
|
||||
for(x=0; x<3; x++) {
|
||||
p[x] = 0x88 | (v & 1);
|
||||
v = v >> 1;
|
||||
}
|
||||
p += width;
|
||||
}
|
||||
}
|
||||
/* and a little bit... */
|
||||
frame[width * (width - 8) + 8] = 0x81;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
unsigned char *QRspec_newFrame(int version)
|
||||
{
|
||||
unsigned char *frame;
|
||||
int width;
|
||||
|
||||
if(version < 1 || version > QRSPEC_VERSION_MAX) return NULL;
|
||||
|
||||
if(frames[version] == NULL) {
|
||||
frames[version] = QRspec_createFrame(version);
|
||||
}
|
||||
width = qrspecCapacity[version].width;
|
||||
frame = (unsigned char *)malloc(width * width);
|
||||
memcpy(frame, frames[version], width * width);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void QRspec_clearCache(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
|
||||
if(frames[i] != NULL) {
|
||||
free(frames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* QR Code specification in convenient format.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __QRSPEC_H__
|
||||
#define __QRSPEC_H__
|
||||
|
||||
#include "qrencode.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Version and capacity
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Maximum version (size) of QR-code symbol.
|
||||
*/
|
||||
#define QRSPEC_VERSION_MAX 40
|
||||
|
||||
/**
|
||||
* Maximum width of a symbol
|
||||
*/
|
||||
#define QRSPEC_WIDTH_MAX 177
|
||||
|
||||
/**
|
||||
* Return maximum data code length (bytes) for the version.
|
||||
* @param version
|
||||
* @param level
|
||||
* @return maximum size (bytes)
|
||||
*/
|
||||
extern int QRspec_getDataLength(int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return maximum error correction code length (bytes) for the version.
|
||||
* @param version
|
||||
* @param level
|
||||
* @return ECC size (bytes)
|
||||
*/
|
||||
extern int QRspec_getECCLength(int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return a version number that satisfies the input code length.
|
||||
* @param size input code length (byte)
|
||||
* @param level
|
||||
* @return version number
|
||||
*/
|
||||
extern int QRspec_getMinimumVersion(int size, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return the width of the symbol for the version.
|
||||
* @param version
|
||||
* @return width
|
||||
*/
|
||||
extern int QRspec_getWidth(int version);
|
||||
|
||||
/**
|
||||
* Return the numer of remainder bits.
|
||||
* @param version
|
||||
* @return number of remainder bits
|
||||
*/
|
||||
extern int QRspec_getRemainder(int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Length indicator
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return the size of lenght indicator for the mode and version.
|
||||
* @param mode
|
||||
* @param version
|
||||
* @return the size of the appropriate length indicator (bits).
|
||||
*/
|
||||
extern int QRspec_lengthIndicator(QRencodeMode mode, int version);
|
||||
|
||||
/**
|
||||
* Return the maximum length for the mode and version.
|
||||
* @param mode
|
||||
* @param version
|
||||
* @return the maximum length (bytes)
|
||||
*/
|
||||
extern int QRspec_maximumWords(QRencodeMode mode, int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Error correction code
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return an array of ECC specification.
|
||||
* @param version
|
||||
* @param level
|
||||
* @return an array of ECC specification contains as following:
|
||||
* {# of type1 blocks, # of data code, # of ecc code,
|
||||
* # of type2 blocks, # of data code, # of ecc code}
|
||||
* It can be freed by calling free().
|
||||
*/
|
||||
int *QRspec_getEccSpec(int version, QRecLevel level);
|
||||
|
||||
#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3])
|
||||
#define QRspec_rsBlockNum1(__spec__) (__spec__[0])
|
||||
#define QRspec_rsDataCodes1(__spec__) (__spec__[1])
|
||||
#define QRspec_rsEccCodes1(__spec__) (__spec__[2])
|
||||
#define QRspec_rsBlockNum2(__spec__) (__spec__[3])
|
||||
#define QRspec_rsDataCodes2(__spec__) (__spec__[4])
|
||||
#define QRspec_rsEccCodes2(__spec__) (__spec__[5])
|
||||
|
||||
/******************************************************************************
|
||||
* Alignment pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Array of positions of alignment patterns.
|
||||
* X and Y coordinates are interleaved into 'pos'.
|
||||
*/
|
||||
typedef struct {
|
||||
int n; //< Number of patterns
|
||||
int *pos;
|
||||
} QRspec_Alignment;
|
||||
|
||||
/**
|
||||
* Return positions of alignment patterns.
|
||||
* @param version
|
||||
* @return a QRspec_Alignment object that contains all of positions of alignment
|
||||
* patterns.
|
||||
*/
|
||||
extern QRspec_Alignment *QRspec_getAlignmentPattern(int version);
|
||||
|
||||
/**
|
||||
* Free QRspec_Alignment instance.
|
||||
* @param al QRspec_Alignment instance.
|
||||
*/
|
||||
extern void QRspec_freeAlignment(QRspec_Alignment *al);
|
||||
|
||||
/******************************************************************************
|
||||
* Version information pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return BCH encoded version information pattern that is used for the symbol
|
||||
* of version 7 or greater. Use lower 18 bits.
|
||||
* @param version
|
||||
* @return BCH encoded version information pattern
|
||||
*/
|
||||
extern unsigned int QRspec_getVersionPattern(int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return BCH encoded format information pattern.
|
||||
* @param mask
|
||||
* @param level
|
||||
* @return BCH encoded format information pattern
|
||||
*/
|
||||
extern unsigned int QRspec_getFormatInfo(int mask, QRecLevel level);
|
||||
|
||||
/******************************************************************************
|
||||
* Frame
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return a copy of initialized frame.
|
||||
* When the same version is requested twice or more, a copy of cached frame
|
||||
* is returned.
|
||||
* WARNING: Thread unsafe!!!
|
||||
* @param version
|
||||
* @return Array of unsigned char. You can free it by free().
|
||||
*/
|
||||
extern unsigned char *QRspec_newFrame(int version);
|
||||
|
||||
/**
|
||||
* Clear the frame cache. Typically for debug.
|
||||
* WARNING: Thread unsafe!!!
|
||||
*/
|
||||
extern void QRspec_clearCache(void);
|
||||
|
||||
#endif /* __QRSPEC_H__ */
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
|
||||
* editted and packed into a pair of .c and .h files.
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
* (libfec is released under the GNU Lesser General Public License.)
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "rscode.h"
|
||||
|
||||
/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs
|
||||
*
|
||||
*/
|
||||
typedef unsigned char data_t;
|
||||
|
||||
|
||||
/**
|
||||
* Reed-Solomon codec control block
|
||||
*/
|
||||
struct _RS {
|
||||
int mm; /* Bits per symbol */
|
||||
int nn; /* Symbols per block (= (1<<mm)-1) */
|
||||
data_t *alpha_to; /* log lookup table */
|
||||
data_t *index_of; /* Antilog lookup table */
|
||||
data_t *genpoly; /* Generator polynomial */
|
||||
int nroots; /* Number of generator roots = number of parity symbols */
|
||||
int fcr; /* First consecutive root, index form */
|
||||
int prim; /* Primitive element, index form */
|
||||
int iprim; /* prim-th root of 1, index form */
|
||||
int pad; /* Padding bytes in shortened block */
|
||||
int gfpoly;
|
||||
struct _RS *next;
|
||||
};
|
||||
|
||||
RS *rslist = NULL;
|
||||
|
||||
static inline int modnn(RS *rs, int x){
|
||||
while (x >= rs->nn) {
|
||||
x -= rs->nn;
|
||||
x = (x >> rs->mm) + (x & rs->nn);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
#define MODNN(x) modnn(rs,x)
|
||||
|
||||
#define MM (rs->mm)
|
||||
#define NN (rs->nn)
|
||||
#define ALPHA_TO (rs->alpha_to)
|
||||
#define INDEX_OF (rs->index_of)
|
||||
#define GENPOLY (rs->genpoly)
|
||||
#define NROOTS (rs->nroots)
|
||||
#define FCR (rs->fcr)
|
||||
#define PRIM (rs->prim)
|
||||
#define IPRIM (rs->iprim)
|
||||
#define PAD (rs->pad)
|
||||
#define A0 (NN)
|
||||
|
||||
|
||||
/* Initialize a Reed-Solomon codec
|
||||
* symsize = symbol size, bits
|
||||
* gfpoly = Field generator polynomial coefficients
|
||||
* fcr = first root of RS code generator polynomial, index form
|
||||
* prim = primitive element to generate polynomial roots
|
||||
* nroots = RS code generator polynomial degree (number of roots)
|
||||
* pad = padding bytes at front of shortened block
|
||||
*/
|
||||
static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
|
||||
{
|
||||
RS *rs;
|
||||
|
||||
|
||||
/* Common code for intializing a Reed-Solomon control block (char or int symbols)
|
||||
* Copyright 2004 Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
//#undef NULL
|
||||
//#define NULL ((void *)0)
|
||||
|
||||
int i, j, sr,root,iprim;
|
||||
|
||||
rs = NULL;
|
||||
/* Check parameter ranges */
|
||||
if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(fcr < 0 || fcr >= (1<<symsize))
|
||||
goto done;
|
||||
if(prim <= 0 || prim >= (1<<symsize))
|
||||
goto done;
|
||||
if(nroots < 0 || nroots >= (1<<symsize))
|
||||
goto done; /* Can't have more roots than symbol values! */
|
||||
if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
|
||||
goto done; /* Too much padding */
|
||||
|
||||
rs = (RS *)calloc(1,sizeof(RS));
|
||||
if(rs == NULL)
|
||||
goto done;
|
||||
|
||||
rs->mm = symsize;
|
||||
rs->nn = (1<<symsize)-1;
|
||||
rs->pad = pad;
|
||||
|
||||
rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
|
||||
if(rs->alpha_to == NULL){
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
|
||||
if(rs->index_of == NULL){
|
||||
free(rs->alpha_to);
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Generate Galois field lookup tables */
|
||||
rs->index_of[0] = A0; /* log(zero) = -inf */
|
||||
rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */
|
||||
sr = 1;
|
||||
for(i=0;i<rs->nn;i++){
|
||||
rs->index_of[sr] = i;
|
||||
rs->alpha_to[i] = sr;
|
||||
sr <<= 1;
|
||||
if(sr & (1<<symsize))
|
||||
sr ^= gfpoly;
|
||||
sr &= rs->nn;
|
||||
}
|
||||
if(sr != 1){
|
||||
/* field generator polynomial is not primitive! */
|
||||
free(rs->alpha_to);
|
||||
free(rs->index_of);
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Form RS code generator polynomial from its roots */
|
||||
rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1));
|
||||
if(rs->genpoly == NULL){
|
||||
free(rs->alpha_to);
|
||||
free(rs->index_of);
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
rs->fcr = fcr;
|
||||
rs->prim = prim;
|
||||
rs->nroots = nroots;
|
||||
rs->gfpoly = gfpoly;
|
||||
|
||||
/* Find prim-th root of 1, used in decoding */
|
||||
for(iprim=1;(iprim % prim) != 0;iprim += rs->nn)
|
||||
;
|
||||
rs->iprim = iprim / prim;
|
||||
|
||||
rs->genpoly[0] = 1;
|
||||
for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) {
|
||||
rs->genpoly[i+1] = 1;
|
||||
|
||||
/* Multiply rs->genpoly[] by @**(root + x) */
|
||||
for (j = i; j > 0; j--){
|
||||
if (rs->genpoly[j] != 0)
|
||||
rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)];
|
||||
else
|
||||
rs->genpoly[j] = rs->genpoly[j-1];
|
||||
}
|
||||
/* rs->genpoly[0] can never be zero */
|
||||
rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)];
|
||||
}
|
||||
/* convert rs->genpoly[] to index form for quicker encoding */
|
||||
for (i = 0; i <= nroots; i++)
|
||||
rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
|
||||
done:;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
|
||||
{
|
||||
RS *rs;
|
||||
|
||||
for(rs = rslist; rs != NULL; rs = rs->next) {
|
||||
if(rs->nroots != nroots) continue;
|
||||
if(rs->pad != pad) continue;
|
||||
if(rs->mm != symsize) continue;
|
||||
if(rs->gfpoly != gfpoly) continue;
|
||||
if(rs->fcr != fcr) continue;
|
||||
if(rs->prim != prim) continue;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
rs = init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad);
|
||||
rs->next = rslist;
|
||||
rslist = rs;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
void free_rs_char(RS *rs)
|
||||
{
|
||||
free(rs->alpha_to);
|
||||
free(rs->index_of);
|
||||
free(rs->genpoly);
|
||||
free(rs);
|
||||
}
|
||||
|
||||
/* The guts of the Reed-Solomon encoder, meant to be #included
|
||||
* into a function body with the following typedefs, macros and variables supplied
|
||||
* according to the code parameters:
|
||||
|
||||
* data_t - a typedef for the data symbol
|
||||
* data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded
|
||||
* data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols
|
||||
* NROOTS - the number of roots in the RS code generator polynomial,
|
||||
* which is the same as the number of parity symbols in a block.
|
||||
Integer variable or literal.
|
||||
*
|
||||
* NN - the total number of symbols in a RS block. Integer variable or literal.
|
||||
* PAD - the number of pad symbols in a block. Integer variable or literal.
|
||||
* ALPHA_TO - The address of an array of NN elements to convert Galois field
|
||||
* elements in index (log) form to polynomial form. Read only.
|
||||
* INDEX_OF - The address of an array of NN elements to convert Galois field
|
||||
* elements in polynomial form to index (log) form. Read only.
|
||||
* MODNN - a function to reduce its argument modulo NN. May be inline or a macro.
|
||||
* GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form
|
||||
|
||||
* The memset() and memmove() functions are used. The appropriate header
|
||||
* file declaring these functions (usually <string.h>) must be included by the calling
|
||||
* program.
|
||||
|
||||
* Copyright 2004, Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
|
||||
#undef A0
|
||||
#define A0 (NN) /* Special reserved value encoding zero in index form */
|
||||
|
||||
void encode_rs_char(RS *rs, const data_t *data, data_t *parity)
|
||||
{
|
||||
int i, j;
|
||||
data_t feedback;
|
||||
|
||||
memset(parity,0,NROOTS*sizeof(data_t));
|
||||
|
||||
for(i=0;i<NN-NROOTS-PAD;i++){
|
||||
feedback = INDEX_OF[data[i] ^ parity[0]];
|
||||
if(feedback != A0){ /* feedback term is non-zero */
|
||||
#ifdef UNNORMALIZED
|
||||
/* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
|
||||
* always be for the polynomials constructed by init_rs()
|
||||
*/
|
||||
feedback = MODNN(NN - GENPOLY[NROOTS] + feedback);
|
||||
#endif
|
||||
for(j=1;j<NROOTS;j++)
|
||||
parity[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS-j])];
|
||||
}
|
||||
/* Shift */
|
||||
memmove(&parity[0],&parity[1],sizeof(data_t)*(NROOTS-1));
|
||||
if(feedback != A0)
|
||||
parity[NROOTS-1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])];
|
||||
else
|
||||
parity[NROOTS-1] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
|
||||
* editted and packed into a pair of .c and .h files.
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
* (libfec is released under the GNU Lesser General Public License.)
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __RSCODE_H__
|
||||
#define __RSCODE_H__
|
||||
|
||||
/*
|
||||
* General purpose RS codec, 8-bit symbols.
|
||||
*/
|
||||
|
||||
typedef struct _RS RS;
|
||||
|
||||
/* WARNING: Thread unsafe!!! */
|
||||
extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
|
||||
extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity);
|
||||
extern void free_rs_char(RS *rs);
|
||||
|
||||
#endif /* __RSCODE_H__ */
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Input data splitter.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "qrencode.h"
|
||||
#include "qrinput.h"
|
||||
#include "qrspec.h"
|
||||
#include "split.h"
|
||||
|
||||
#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10)
|
||||
#define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0)
|
||||
|
||||
static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint)
|
||||
{
|
||||
unsigned char c, d;
|
||||
unsigned int word;
|
||||
|
||||
c = string[0];
|
||||
|
||||
if(c == '\0') return QR_MODE_NUL;
|
||||
if(isdigit(c)) {
|
||||
return QR_MODE_NUM;
|
||||
} else if(isalnum(c)) {
|
||||
return QR_MODE_AN;
|
||||
} else if(hint == QR_MODE_KANJI) {
|
||||
d = string[1];
|
||||
if(d != '\0') {
|
||||
word = ((unsigned int)c << 8) | d;
|
||||
if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) {
|
||||
return QR_MODE_KANJI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QR_MODE_8;
|
||||
}
|
||||
|
||||
static int Split_eatNum(const char *string, QRinput *input, QRencodeMode hint);
|
||||
static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint);
|
||||
static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint);
|
||||
static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint);
|
||||
|
||||
static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint)
|
||||
{
|
||||
const char *p;
|
||||
int ret;
|
||||
int run;
|
||||
int dif;
|
||||
int ln;
|
||||
QRencodeMode mode;
|
||||
|
||||
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
|
||||
|
||||
p = string;
|
||||
while(isdigit(*p)) {
|
||||
p++;
|
||||
}
|
||||
run = p - string;
|
||||
mode = Split_identifyMode(p, hint);
|
||||
if(mode == QR_MODE_8) {
|
||||
dif = QRinput_estimateBitsModeNum(run) + 4 + ln
|
||||
+ QRinput_estimateBitsMode8(1) /* + 4 + l8 */
|
||||
- QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
|
||||
if(dif > 0) {
|
||||
return Split_eat8(string, input, hint);
|
||||
}
|
||||
}
|
||||
if(mode == QR_MODE_AN) {
|
||||
dif = QRinput_estimateBitsModeNum(run) + 4 + ln
|
||||
+ QRinput_estimateBitsModeAn(1) /* + 4 + la */
|
||||
- QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */;
|
||||
if(dif > 0) {
|
||||
return Split_eatAn(string, input, hint);
|
||||
}
|
||||
}
|
||||
|
||||
ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint)
|
||||
{
|
||||
const char *p, *q;
|
||||
int ret;
|
||||
int run;
|
||||
int dif;
|
||||
int la, ln;
|
||||
|
||||
la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
|
||||
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
|
||||
|
||||
p = string;
|
||||
while(isalnum(*p)) {
|
||||
if(isdigit(*p)) {
|
||||
q = p;
|
||||
while(isdigit(*q)) {
|
||||
q++;
|
||||
}
|
||||
dif = QRinput_estimateBitsModeAn(p - string) /* + 4 + la */
|
||||
+ QRinput_estimateBitsModeNum(q - p) + 4 + ln
|
||||
- QRinput_estimateBitsModeAn(q - string) /* - 4 - la */;
|
||||
if(dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
p = q;
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
run = p - string;
|
||||
|
||||
if(*p && !isalnum(*p)) {
|
||||
dif = QRinput_estimateBitsModeAn(run) + 4 + la
|
||||
+ QRinput_estimateBitsMode8(1) /* + 4 + l8 */
|
||||
- QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
|
||||
if(dif > 0) {
|
||||
return Split_eat8(string, input, hint);
|
||||
}
|
||||
}
|
||||
|
||||
ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint)
|
||||
{
|
||||
const char *p;
|
||||
int ret;
|
||||
int run;
|
||||
|
||||
p = string;
|
||||
while(Split_identifyMode(p, hint) == QR_MODE_KANJI) {
|
||||
p += 2;
|
||||
}
|
||||
run = p - string;
|
||||
ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint)
|
||||
{
|
||||
const char *p, *q;
|
||||
QRencodeMode mode;
|
||||
int ret;
|
||||
int run;
|
||||
int dif;
|
||||
int la, ln;
|
||||
|
||||
la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
|
||||
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
|
||||
|
||||
p = string + 1;
|
||||
while(*p != '\0') {
|
||||
mode = Split_identifyMode(p, hint);
|
||||
if(mode == QR_MODE_KANJI) {
|
||||
break;
|
||||
}
|
||||
if(mode == QR_MODE_NUM) {
|
||||
q = p;
|
||||
while(isdigit(*q)) {
|
||||
q++;
|
||||
}
|
||||
dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
|
||||
+ QRinput_estimateBitsModeNum(q - p) + 4 + ln
|
||||
- QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
|
||||
if(dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
p = q;
|
||||
}
|
||||
} else if(mode == QR_MODE_AN) {
|
||||
q = p;
|
||||
while(isalnum(*q)) {
|
||||
q++;
|
||||
}
|
||||
dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
|
||||
+ QRinput_estimateBitsModeAn(q - p) + 4 + la
|
||||
- QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
|
||||
if(dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
p = q;
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
run = p - string;
|
||||
ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_splitString(const char *string, QRinput *input,
|
||||
QRencodeMode hint)
|
||||
{
|
||||
int length;
|
||||
QRencodeMode mode;
|
||||
|
||||
if(*string == '\0') return 0;
|
||||
|
||||
mode = Split_identifyMode(string, hint);
|
||||
if(mode == QR_MODE_NUM) {
|
||||
length = Split_eatNum(string, input, hint);
|
||||
} else if(mode == QR_MODE_AN) {
|
||||
length = Split_eatAn(string, input, hint);
|
||||
} else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) {
|
||||
length = Split_eatKanji(string, input, hint);
|
||||
} else {
|
||||
length = Split_eat8(string, input, hint);
|
||||
}
|
||||
if(length == 0) return 0;
|
||||
if(length < 0) return -1;
|
||||
return Split_splitString(&string[length], input, hint);
|
||||
}
|
||||
|
||||
static char *dupAndToUpper(const char *str, QRencodeMode hint)
|
||||
{
|
||||
char *newstr, *p;
|
||||
QRencodeMode mode;
|
||||
|
||||
newstr = strdup(str);
|
||||
if(newstr == NULL) return NULL;
|
||||
|
||||
p = newstr;
|
||||
while(*p != '\0') {
|
||||
mode = Split_identifyMode(p, hint);
|
||||
if(mode == QR_MODE_KANJI) {
|
||||
p += 2;
|
||||
} else {
|
||||
if (*p >= 'a' && *p <= 'z') {
|
||||
*p = (char)((int)*p - 32);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return newstr;
|
||||
}
|
||||
|
||||
int Split_splitStringToQRinput(const char *string, QRinput *input,
|
||||
QRencodeMode hint, int casesensitive)
|
||||
{
|
||||
char *newstr;
|
||||
int ret;
|
||||
|
||||
if(!casesensitive) {
|
||||
newstr = dupAndToUpper(string, hint);
|
||||
if(newstr == NULL) return -1;
|
||||
ret = Split_splitString(newstr, input, hint);
|
||||
free(newstr);
|
||||
} else {
|
||||
ret = Split_splitString(string, input, hint);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Input data splitter.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __SPLIT_H__
|
||||
#define __SPLIT_H__
|
||||
|
||||
#include "qrencode.h"
|
||||
|
||||
/**
|
||||
* Split the input string (null terminated) into QRinput.
|
||||
* @param string input string
|
||||
* @param hint give QR_MODE_KANJI if the input string contains Kanji character encoded in Shift-JIS. If not, give QR_MODE_8.
|
||||
* @param casesensitive 0 for case-insensitive encoding (all alphabet characters are replaced to UPPER-CASE CHARACTERS.
|
||||
* @retval 0 success.
|
||||
* @retval -1 an error occurred.
|
||||
*/
|
||||
extern int Split_splitStringToQRinput(const char *string, QRinput *input,
|
||||
QRencodeMode hint, int casesensitive);
|
||||
|
||||
#endif /* __SPLIT_H__ */
|
||||
|
|
@ -8,7 +8,18 @@ include $(INCLUDE_DIR)/kernel.mk
|
|||
PKG_NAME:=questd
|
||||
PKG_VERSION:=2.0.3
|
||||
PKG_RELEASE:=3
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_SOURCE_VERSION:=550f09040af42a62a53544aa31866c93048f7d2f
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/questd
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:questd
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
|
@ -34,11 +45,6 @@ define Package/questd/description
|
|||
this information via ubus
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Package/questd/install
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_DIR) $(1)/tmp
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
CC = gcc
|
||||
CFLAGS = -g -Wall
|
||||
LOCLIBS =
|
||||
LIBS = -luci -lubus -lubox -lpthread
|
||||
OBJS = questd.o dumper.o port.o arping.o usb.o ndisc.o dslstats.o tools.o igmp.o
|
||||
SRCS = questd.c dumper.c port.c arping.c usb.c ndisc.c dslstats.c tools.c igmp.c
|
||||
LIBSRCS =
|
||||
ISRCS = questd.h
|
||||
|
||||
all: questd
|
||||
|
||||
questd: ${OBJS}
|
||||
${CC} ${LDFLAGS} ${LIBSRCS} -o questd ${OBJS} ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f questd *.o
|
||||
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* arping -- arping tool for questd
|
||||
*
|
||||
* Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
|
||||
* Author: Sukru Senli sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
|
||||
struct in_addr src;
|
||||
struct in_addr dst;
|
||||
struct sockaddr_ll me;
|
||||
struct sockaddr_ll he;
|
||||
int sock_fd;
|
||||
|
||||
//void *mempcpy(void *dst, const void *src, size_t n);
|
||||
|
||||
static int
|
||||
send_pack(struct in_addr *src_addr, struct in_addr *dst_addr, struct sockaddr_ll *ME, struct sockaddr_ll *HE)
|
||||
{
|
||||
int err;
|
||||
unsigned char buf[256];
|
||||
struct arphdr *ah = (struct arphdr *) buf;
|
||||
unsigned char *p = (unsigned char *) (ah + 1);
|
||||
|
||||
ah->ar_hrd = htons(ARPHRD_ETHER);
|
||||
ah->ar_pro = htons(ETH_P_IP);
|
||||
ah->ar_hln = ME->sll_halen;
|
||||
ah->ar_pln = 4;
|
||||
ah->ar_op = htons(ARPOP_REQUEST);
|
||||
|
||||
p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
|
||||
p = mempcpy(p, src_addr, 4);
|
||||
|
||||
p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
|
||||
p = mempcpy(p, dst_addr, 4);
|
||||
|
||||
err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool
|
||||
recv_pack(char *buf, int len, struct sockaddr_ll *FROM)
|
||||
{
|
||||
struct arphdr *ah = (struct arphdr *) buf;
|
||||
unsigned char *p = (unsigned char *) (ah + 1);
|
||||
struct in_addr src_ip, dst_ip;
|
||||
|
||||
/* Filter out wild packets */
|
||||
if (FROM->sll_pkttype != PACKET_HOST
|
||||
&& FROM->sll_pkttype != PACKET_BROADCAST
|
||||
&& FROM->sll_pkttype != PACKET_MULTICAST)
|
||||
return false;
|
||||
|
||||
/* Only these types are recognized */
|
||||
if (ah->ar_op != htons(ARPOP_REPLY))
|
||||
return false;
|
||||
|
||||
/* ARPHRD check and this darned FDDI hack here :-( */
|
||||
if (ah->ar_hrd != htons(FROM->sll_hatype)
|
||||
&& (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
|
||||
return false;
|
||||
|
||||
/* Protocol must be IP. */
|
||||
if (ah->ar_pro != htons(ETH_P_IP)
|
||||
|| (ah->ar_pln != 4)
|
||||
|| (ah->ar_hln != me.sll_halen)
|
||||
|| (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
|
||||
return false;
|
||||
|
||||
(src_ip.s_addr) = *(uint32_t*)(p + ah->ar_hln);
|
||||
(dst_ip.s_addr) = *(uint32_t*)(p + ah->ar_hln + 4 + ah->ar_hln);
|
||||
|
||||
if (dst.s_addr != src_ip.s_addr)
|
||||
return false;
|
||||
|
||||
if ((src.s_addr != dst_ip.s_addr) || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
arping(char *targetIP, char *device, int toms)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
struct ifreq ifr;
|
||||
int probe_fd;
|
||||
|
||||
sock_fd = socket(AF_PACKET, SOCK_DGRAM, 0);
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, device, IF_NAMESIZE);
|
||||
|
||||
if (ioctl(sock_fd, SIOCGIFINDEX, &ifr, sizeof(ifr)) < 0) {
|
||||
close(sock_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
me.sll_family = AF_PACKET;
|
||||
me.sll_ifindex = ifr.ifr_ifindex;
|
||||
me.sll_protocol = htons(ETH_P_ARP);
|
||||
bind(sock_fd, (struct sockaddr *) &me, sizeof(me));
|
||||
|
||||
socklen_t mlen = sizeof(me);
|
||||
getsockname(sock_fd, (struct sockaddr *) &me, &mlen);
|
||||
|
||||
he = me;
|
||||
memset(he.sll_addr, -1, he.sll_halen);
|
||||
|
||||
inet_pton(AF_INET, targetIP, &(dst.s_addr));
|
||||
|
||||
/* Get the sender IP address */
|
||||
probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
saddr.sin_port = htons(1025);
|
||||
saddr.sin_addr = dst;
|
||||
connect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
|
||||
getsockname(probe_fd, (struct sockaddr *) &saddr, &slen);
|
||||
src = saddr.sin_addr;
|
||||
close(probe_fd);
|
||||
|
||||
send_pack(&src, &dst, &me, &he);
|
||||
|
||||
char packet[64];
|
||||
struct sockaddr_ll from;
|
||||
socklen_t alen = sizeof(from);
|
||||
bool connected = false;
|
||||
int cc = -1;
|
||||
|
||||
fd_set read_fds, write_fds, except_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_ZERO(&write_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(sock_fd, &read_fds);
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = toms * 1000;
|
||||
|
||||
if (select(sock_fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1)
|
||||
{
|
||||
cc = recvfrom(sock_fd, packet, sizeof(packet), 0, (struct sockaddr *) &from, &alen);
|
||||
}
|
||||
|
||||
if (cc >= 0)
|
||||
connected = recv_pack(packet, cc, &from);
|
||||
|
||||
close(sock_fd);
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* dslstats -- collects adsl information for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: martin.schroder@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
#define DSLDEBUG(...) {} //printf(__VA_ARGS__)
|
||||
|
||||
void dslstats_init(struct dsl_stats *self){
|
||||
*self = (struct dsl_stats){0};
|
||||
}
|
||||
|
||||
void dslstats_load(struct dsl_stats *self){
|
||||
FILE *fp;
|
||||
char line[128];
|
||||
char name[64];
|
||||
char sep[64];
|
||||
char arg1[64];
|
||||
char arg2[64];
|
||||
|
||||
// start with default bearer 0 (we can support more later)
|
||||
DSLBearer *bearer = &self->bearers[0];
|
||||
DSLCounters *counters = &self->counters[0];
|
||||
int done = 0;
|
||||
|
||||
if(!(fp = popen("xdslctl info --stats", "r"))) return;
|
||||
|
||||
while(!done && fgets(line, sizeof(line), fp) != NULL) {
|
||||
DSLDEBUG("LINE: %d, %s, args:%d\n", strlen(line), line, narg);
|
||||
name[0] = 0; arg1[0] = 0; arg2[0] = 0;
|
||||
remove_newline(line);
|
||||
int narg = sscanf(line, "%[^\t]%[\t ]%[^\t]%[\t]%[^\t]", name, sep, arg1, sep, arg2);
|
||||
switch(narg){
|
||||
case 0: { // sections
|
||||
if(strstr(line, "Bearer")){
|
||||
int id = 0;
|
||||
if(sscanf(strstr(line, "Bearer"), "Bearer %d", &id) > 0){
|
||||
if(id < DSLSTATS_BEARER_COUNT){
|
||||
bearer = &self->bearers[id];
|
||||
DSLDEBUG("Switching bearer: %d\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// it is possible to add more stats like this though
|
||||
/*
|
||||
else if(strstr(name, "Latest 15 minutes time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_CURRENT_15];
|
||||
else if(strstr(name, "Previous 15 minutes time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_PREVIOUS_15];
|
||||
else if(strstr(name, "Latest 1 day time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_CURRENT_DAY];
|
||||
else if(strstr(name, "Previous 1 day time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_PREVIOUS_DAY];
|
||||
else if(strstr(name, "Since Link time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_SINCE_LINK]; */
|
||||
} break;
|
||||
case 1: { // various one liners
|
||||
if(strstr(line, "Total time =") == line) counters = &self->counters[DSLSTATS_COUNTER_TOTALS];
|
||||
else if(strstr(line, "Latest 15 minutes time =") == line) done = 1; // we stop parsing at this right now
|
||||
else if(strstr(line, "Status") == line && strlen(line) > 9) strncpy(self->status, line + 8, sizeof(self->status));
|
||||
} break;
|
||||
case 3: {
|
||||
if(strstr(name, "Link Power State") == name) strncpy(self->link_power_state, arg1, sizeof(self->link_power_state));
|
||||
else if(strstr(name, "Mode") == name) strncpy(self->mode, arg1, sizeof(self->mode));
|
||||
else if(strstr(name, "VDSL2 Profile") == name) strncpy(self->vdsl2_profile, arg1, sizeof(self->vdsl2_profile));
|
||||
else if(strstr(name, "TPS") == name) strncpy(self->traffic, arg1, sizeof(self->traffic));
|
||||
else if(strstr(name, "Trellis") == name){
|
||||
char tmp[2][64];
|
||||
if(sscanf(arg1, "U:%s /D:%s", tmp[0], tmp[1])){
|
||||
DSLDEBUG("TRELLIS: %s %s\n", tmp[0], tmp[1]);
|
||||
if(strcmp(tmp[0], "ON") == 0) self->trellis.down = 1;
|
||||
else self->trellis.down = 0;
|
||||
if(strcmp(tmp[1], "ON") == 0) self->trellis.up = 1;
|
||||
else self->trellis.up = 0;
|
||||
}
|
||||
}
|
||||
else if(strstr(name, "Line Status") == name) strncpy(self->line_status, arg1, sizeof(self->line_status));
|
||||
else if(strstr(name, "Bearer") == name){
|
||||
unsigned long id, up, down, ret;
|
||||
if((ret = sscanf(arg1, "%lu, Upstream rate = %lu Kbps, Downstream rate = %lu Kbps", &id, &up, &down)) == 3){
|
||||
if(id < DSLSTATS_BEARER_COUNT){
|
||||
bearer = &self->bearers[id];
|
||||
bearer->rate.up = up;
|
||||
bearer->rate.down = down;
|
||||
DSLDEBUG("Switching bearer: %d\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strstr(name, "Max") == name) {
|
||||
sscanf(arg1, "Upstream rate = %lf Kbps, Downstream rate = %lf Kbps", &bearer->max_rate.up, &bearer->max_rate.down);
|
||||
}
|
||||
DSLDEBUG("PARSED: name:%s, arg1:%s\n", name, arg1);
|
||||
} break;
|
||||
case 5: {
|
||||
if(strstr(name, "SNR") == name) {
|
||||
self->snr.down = atof(arg1);
|
||||
self->snr.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "Attn") == name){
|
||||
self->attn.down = atof(arg1);
|
||||
self->attn.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "Pwr") == name){
|
||||
self->pwr.down = atof(arg1);
|
||||
self->pwr.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "MSGc") == name){
|
||||
bearer->msgc.down = atof(arg1);
|
||||
bearer->msgc.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "B:") == name){
|
||||
bearer->b.down = atof(arg1);
|
||||
bearer->b.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "M:") == name){
|
||||
bearer->m.down = atof(arg1);
|
||||
bearer->m.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "T:") == name){
|
||||
bearer->t.down = atof(arg1);
|
||||
bearer->t.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "R:") == name){
|
||||
bearer->r.down = atof(arg1);
|
||||
bearer->r.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "S:") == name){
|
||||
bearer->s.down = atof(arg1);
|
||||
bearer->s.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "L:") == name){
|
||||
bearer->l.down = atof(arg1);
|
||||
bearer->l.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "D:") == name){
|
||||
bearer->d.down = atof(arg1);
|
||||
bearer->d.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "delay:") == name){
|
||||
bearer->delay.down = atof(arg1);
|
||||
bearer->delay.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "INP:") == name){
|
||||
bearer->inp.down = atof(arg1);
|
||||
bearer->inp.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "SF:") == name){
|
||||
bearer->sf.down = atoll(arg1);
|
||||
bearer->sf.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "SFErr:") == name){
|
||||
bearer->sf_err.down = atoll(arg1);
|
||||
bearer->sf_err.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "RS:") == name){
|
||||
bearer->rs.down = atoll(arg1);
|
||||
bearer->rs.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "RSCorr:") == name){
|
||||
bearer->rs_corr.down = atoll(arg1);
|
||||
bearer->rs_corr.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "RSUnCorr:") == name){
|
||||
bearer->rs_uncorr.down = atoll(arg1);
|
||||
bearer->rs_uncorr.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "HEC:") == name){
|
||||
bearer->hec.down = atoll(arg1);
|
||||
bearer->hec.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "OCD:") == name){
|
||||
bearer->ocd.down = atoll(arg1);
|
||||
bearer->ocd.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "LCD:") == name){
|
||||
bearer->lcd.down = atoll(arg1);
|
||||
bearer->lcd.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "Total Cells:") == name){
|
||||
bearer->total_cells.down = atoll(arg1);
|
||||
bearer->total_cells.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "Data Cells:") == name){
|
||||
bearer->data_cells.down = atoll(arg1);
|
||||
bearer->data_cells.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "Bit Errors:") == name){
|
||||
bearer->bit_errors.down = atoll(arg1);
|
||||
bearer->bit_errors.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "ES:") == name){
|
||||
counters->es.down = atoll(arg1);
|
||||
counters->es.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "SES:") == name){
|
||||
counters->ses.down = atoll(arg1);
|
||||
counters->ses.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "UAS:") == name){
|
||||
counters->uas.down = atoll(arg1);
|
||||
counters->uas.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "FEC:") == name){
|
||||
counters->fec.down = atoll(arg1);
|
||||
counters->fec.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "CRC:") == name){
|
||||
counters->crc.down = atoll(arg1);
|
||||
counters->crc.up = atoll(arg2);
|
||||
}
|
||||
DSLDEBUG("PARSED: name:%s, arg1:%s, arg2:%s\n", name, arg1, arg2);
|
||||
} break;
|
||||
default: {
|
||||
DSLDEBUG("ERROR: line:%s, fcnt:%d, name:%s, arg1:%s, arg2:%s\n", line, narg, name, arg1, arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
}
|
||||
|
||||
void dslstats_free(struct dsl_stats *self){
|
||||
|
||||
}
|
||||
|
||||
void dslstats_to_blob_buffer(struct dsl_stats *self, struct blob_buf *b){
|
||||
void *t, *array, *obj;
|
||||
DSLBearer *bearer = &self->bearers[0];
|
||||
DSLCounters *counter = &self->counters[DSLSTATS_COUNTER_TOTALS];
|
||||
//dslstats_load(self);
|
||||
|
||||
t = blobmsg_open_table(b, "dslstats");
|
||||
blobmsg_add_string(b, "mode", self->mode);
|
||||
blobmsg_add_string(b, "traffic", self->traffic);
|
||||
blobmsg_add_string(b, "status", self->status);
|
||||
blobmsg_add_string(b, "link_power_state", self->link_power_state);
|
||||
blobmsg_add_string(b, "line_status", self->line_status);
|
||||
blobmsg_add_u8(b, "trellis_up", self->trellis.up);
|
||||
blobmsg_add_u8(b, "trellis_down", self->trellis.down);
|
||||
blobmsg_add_u32(b, "snr_up_x100", self->snr.up * 100);
|
||||
blobmsg_add_u32(b, "snr_down_x100", self->snr.down * 100);
|
||||
blobmsg_add_u32(b, "pwr_up_x100", self->pwr.up * 100);
|
||||
blobmsg_add_u32(b, "pwr_down_x100", self->pwr.down * 100);
|
||||
blobmsg_add_u32(b, "attn_up_x100", self->attn.up * 100);
|
||||
blobmsg_add_u32(b, "attn_down_x100", self->attn.down * 100);
|
||||
|
||||
// add bearer data (currently only one bearer)
|
||||
array = blobmsg_open_array(b, "bearers");
|
||||
obj = blobmsg_open_table(b, NULL);
|
||||
blobmsg_add_u32(b, "max_rate_up", bearer->max_rate.up);
|
||||
blobmsg_add_u32(b, "max_rate_down", bearer->max_rate.down);
|
||||
blobmsg_add_u32(b, "rate_up", bearer->rate.up);
|
||||
blobmsg_add_u32(b, "rate_down", bearer->rate.down);
|
||||
blobmsg_add_u32(b, "msgc_up", bearer->msgc.up);
|
||||
blobmsg_add_u32(b, "msgc_down", bearer->msgc.down);
|
||||
blobmsg_add_u32(b, "b_down", bearer->b.down);
|
||||
blobmsg_add_u32(b, "b_up", bearer->b.up);
|
||||
blobmsg_add_u32(b, "m_down", bearer->m.down);
|
||||
blobmsg_add_u32(b, "m_up", bearer->m.up);
|
||||
blobmsg_add_u32(b, "t_down", bearer->t.down);
|
||||
blobmsg_add_u32(b, "t_up", bearer->t.up);
|
||||
blobmsg_add_u32(b, "r_down", bearer->r.down);
|
||||
blobmsg_add_u32(b, "r_up", bearer->r.up);
|
||||
blobmsg_add_u32(b, "s_down_x10000", bearer->s.down * 10000);
|
||||
blobmsg_add_u32(b, "s_up_x10000", bearer->s.up * 10000);
|
||||
blobmsg_add_u32(b, "l_down", bearer->l.down);
|
||||
blobmsg_add_u32(b, "l_up", bearer->l.up);
|
||||
blobmsg_add_u32(b, "d_down", bearer->d.down);
|
||||
blobmsg_add_u32(b, "d_up", bearer->d.up);
|
||||
blobmsg_add_u32(b, "delay_down", bearer->delay.down);
|
||||
blobmsg_add_u32(b, "delay_up", bearer->delay.up);
|
||||
blobmsg_add_u32(b, "inp_down_x100", bearer->inp.down * 100);
|
||||
blobmsg_add_u32(b, "inp_up_x100", bearer->inp.up * 100);
|
||||
blobmsg_add_u64(b, "sf_down", bearer->sf.down);
|
||||
blobmsg_add_u64(b, "sf_up", bearer->sf.up);
|
||||
blobmsg_add_u64(b, "sf_err_down", bearer->sf_err.down);
|
||||
blobmsg_add_u64(b, "sf_err_up", bearer->sf_err.up);
|
||||
blobmsg_add_u64(b, "rs_down", bearer->rs.down);
|
||||
blobmsg_add_u64(b, "rs_up", bearer->rs.up);
|
||||
blobmsg_add_u64(b, "rs_corr_down", bearer->rs_corr.down);
|
||||
blobmsg_add_u64(b, "rs_corr_up", bearer->rs_corr.up);
|
||||
blobmsg_add_u64(b, "rs_uncorr_down", bearer->rs_uncorr.down);
|
||||
blobmsg_add_u64(b, "rs_uncorr_up", bearer->rs_uncorr.up);
|
||||
blobmsg_add_u64(b, "hec_down", bearer->hec.down);
|
||||
blobmsg_add_u64(b, "hec_up", bearer->hec.up);
|
||||
blobmsg_add_u64(b, "ocd_down", bearer->ocd.down);
|
||||
blobmsg_add_u64(b, "ocd_up", bearer->ocd.up);
|
||||
blobmsg_add_u64(b, "lcd_down", bearer->lcd.down);
|
||||
blobmsg_add_u64(b, "lcd_up", bearer->lcd.up);
|
||||
blobmsg_add_u64(b, "total_cells_down", bearer->total_cells.down);
|
||||
blobmsg_add_u64(b, "total_cells_up", bearer->total_cells.up);
|
||||
blobmsg_add_u64(b, "data_cells_down", bearer->data_cells.down);
|
||||
blobmsg_add_u64(b, "data_cells_up", bearer->data_cells.up);
|
||||
blobmsg_add_u64(b, "bit_errors_down", bearer->bit_errors.down);
|
||||
blobmsg_add_u64(b, "bit_errors_up", bearer->bit_errors.up);
|
||||
blobmsg_close_table(b, obj);
|
||||
blobmsg_close_array(b, array);
|
||||
|
||||
// add counter data (currently only totals)
|
||||
//counter = &self->counters[DSLSTATS_COUNTER_TOTALS];
|
||||
array = blobmsg_open_table(b, "counters");
|
||||
obj = blobmsg_open_table(b, "totals");
|
||||
blobmsg_add_u64(b, "fec_down", counter->fec.down);
|
||||
blobmsg_add_u64(b, "fec_up", counter->fec.up);
|
||||
blobmsg_add_u64(b, "crc_down", counter->crc.down);
|
||||
blobmsg_add_u64(b, "crc_up", counter->crc.up);
|
||||
blobmsg_add_u64(b, "es_down", counter->es.down);
|
||||
blobmsg_add_u64(b, "es_up", counter->es.up);
|
||||
blobmsg_add_u64(b, "ses_down", counter->ses.down);
|
||||
blobmsg_add_u64(b, "ses_up", counter->ses.up);
|
||||
blobmsg_add_u64(b, "uas_down", counter->uas.down);
|
||||
blobmsg_add_u64(b, "uas_up", counter->uas.up);
|
||||
blobmsg_close_table(b, obj);
|
||||
blobmsg_close_array(b, array);
|
||||
|
||||
blobmsg_close_table(b, t);
|
||||
}
|
||||
|
||||
|
||||
int dslstats_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg){
|
||||
static struct blob_buf bb;
|
||||
static struct dsl_stats dslstats;
|
||||
|
||||
dslstats_init(&dslstats);
|
||||
blob_buf_init(&bb, 0);
|
||||
|
||||
dslstats_load(&dslstats);
|
||||
dslstats_to_blob_buffer(&dslstats, &bb);
|
||||
|
||||
ubus_send_reply(ctx, req, bb.head);
|
||||
|
||||
dslstats_free(&dslstats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* dslstats -- collects adsl information for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: martin.schroder@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum {
|
||||
DSLSTATS_BEARER_0 = 0,
|
||||
DSLSTATS_BEARER_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
DSLSTATS_COUNTER_TOTALS,
|
||||
DSLSTATS_COUNTER_CURRENT_15,
|
||||
DSLSTATS_COUNTER_PREVIOUS_15,
|
||||
DSLSTATS_COUNTER_CURRENT_DAY,
|
||||
DSLSTATS_COUNTER_PREVIOUS_DAY,
|
||||
DSLSTATS_COUNTER_SINCE_LINK,
|
||||
DSLSTATS_COUNTER_COUNT
|
||||
};
|
||||
|
||||
typedef struct { double up; double down; } UpDown;
|
||||
typedef struct dsl_bearer {
|
||||
|
||||
UpDown max_rate;
|
||||
UpDown rate;
|
||||
UpDown msgc;
|
||||
UpDown b,m,t,r,s,l,d;
|
||||
UpDown delay;
|
||||
UpDown inp;
|
||||
UpDown sf, sf_err;
|
||||
UpDown rs, rs_corr, rs_uncorr;
|
||||
UpDown hec, ocd, lcd;
|
||||
UpDown total_cells, data_cells, bit_errors;
|
||||
|
||||
} DSLBearer;
|
||||
|
||||
typedef struct dsl_counters {
|
||||
UpDown es, ses, uas;
|
||||
UpDown fec, crc;
|
||||
} DSLCounters;
|
||||
|
||||
typedef struct dsl_stats {
|
||||
char mode[64];
|
||||
char traffic[64];
|
||||
char status[64];
|
||||
char link_power_state[64];
|
||||
char line_status[64];
|
||||
char vdsl2_profile[64];
|
||||
UpDown trellis;
|
||||
UpDown snr;
|
||||
UpDown pwr;
|
||||
UpDown attn;
|
||||
DSLBearer bearers[DSLSTATS_BEARER_COUNT];
|
||||
DSLCounters counters[DSLSTATS_COUNTER_COUNT];
|
||||
} DSLStats;
|
||||
|
||||
void dslstats_init(struct dsl_stats *self);
|
||||
void dslstats_load(struct dsl_stats *self);
|
||||
void dslstats_to_blob_buffer(struct dsl_stats *self, struct blob_buf *b);
|
||||
int dslstats_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* dumper -- collects router device and system info for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
struct uci_context *db_ctx;
|
||||
static bool dbLoaded = false;
|
||||
static struct uci_ptr ptr;
|
||||
|
||||
void
|
||||
init_db_hw_config(void)
|
||||
{
|
||||
db_ctx = uci_alloc_context();
|
||||
uci_set_confdir(db_ctx, "/lib/db/config/");
|
||||
if(uci_load(db_ctx, "hw", NULL) == UCI_OK)
|
||||
dbLoaded = true;
|
||||
}
|
||||
|
||||
static void
|
||||
get_db_hw_value(char *opt, char **val)
|
||||
{
|
||||
memset(&ptr, 0, sizeof(ptr));
|
||||
ptr.package = "hw";
|
||||
ptr.section = "board";
|
||||
ptr.value = NULL;
|
||||
|
||||
*val = "";
|
||||
|
||||
if (!dbLoaded)
|
||||
return;
|
||||
|
||||
ptr.option = opt;
|
||||
if (uci_lookup_ptr(db_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return;
|
||||
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return;
|
||||
|
||||
if(!ptr.o->v.string)
|
||||
return;
|
||||
|
||||
*val = ptr.o->v.string;
|
||||
}
|
||||
|
||||
void
|
||||
get_jif_val(jiffy_counts_t *p_jif)
|
||||
{
|
||||
FILE *file;
|
||||
char line[128];
|
||||
int ret;
|
||||
|
||||
if ((file = fopen("/proc/stat", "r"))) {
|
||||
while(fgets(line, sizeof(line), file) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
ret = sscanf(line, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle,
|
||||
&p_jif->iowait, &p_jif->irq, &p_jif->softirq, &p_jif->steal);
|
||||
|
||||
if (ret >= 4) {
|
||||
p_jif->total = p_jif->usr + p_jif->nic + p_jif->sys + p_jif->idle
|
||||
+ p_jif->iowait + p_jif->irq + p_jif->softirq + p_jif->steal;
|
||||
|
||||
p_jif->busy = p_jif->total - p_jif->idle - p_jif->iowait;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_specs(Spec *spec)
|
||||
{
|
||||
char *val;
|
||||
|
||||
spec->wifi = false;
|
||||
spec->adsl = false;
|
||||
spec->vdsl = false;
|
||||
spec->voice = false;
|
||||
spec->dect = false;
|
||||
spec->vports = 0;
|
||||
spec->eports = 0;
|
||||
|
||||
get_db_hw_value("hasWifi", &val);
|
||||
if (!strcmp(val, "1")) spec->wifi = true;
|
||||
|
||||
get_db_hw_value("hasAdsl", &val);
|
||||
if (!strcmp(val, "1")) spec->adsl = true;
|
||||
|
||||
get_db_hw_value("hasVdsl", &val);
|
||||
if (!strcmp(val, "1")) spec->vdsl = true;
|
||||
|
||||
get_db_hw_value("hasVoice", &val);
|
||||
if (!strcmp(val, "1")) spec->voice = true;
|
||||
|
||||
get_db_hw_value("hasDect", &val);
|
||||
if (!strcmp(val, "1")) spec->dect = true;
|
||||
|
||||
get_db_hw_value("VoicePorts", &val);
|
||||
if (spec->voice) spec->vports = atoi(val);
|
||||
|
||||
get_db_hw_value("ethernetPorts", &val);
|
||||
spec->eports = atoi(val);
|
||||
}
|
||||
|
||||
void
|
||||
dump_keys(Key *keys)
|
||||
{
|
||||
get_db_hw_value("authKey", &keys->auth);
|
||||
get_db_hw_value("desKey", &keys->des);
|
||||
get_db_hw_value("wpaKey", &keys->wpa);
|
||||
}
|
||||
|
||||
void
|
||||
dump_static_router_info(Router *router)
|
||||
{
|
||||
get_db_hw_value("boardId", &router->boardid);
|
||||
get_db_hw_value("hardwareVersion", &router->hardware);
|
||||
get_db_hw_value("routerModel", &router->model);
|
||||
get_db_hw_value("iopVersion", &router->firmware);
|
||||
get_db_hw_value("brcmVersion", &router->brcmver);
|
||||
get_db_hw_value("filesystem", &router->filesystem);
|
||||
get_db_hw_value("socModel", &router->socmod);
|
||||
get_db_hw_value("socRevision", &router->socrev);
|
||||
get_db_hw_value("cfeVersion", &router->cfever);
|
||||
get_db_hw_value("kernelVersion", &router->kernel);
|
||||
get_db_hw_value("BaseMacAddr", &router->basemac);
|
||||
get_db_hw_value("serialNumber", &router->serialno);
|
||||
}
|
||||
|
||||
void
|
||||
dump_hostname(Router *router)
|
||||
{
|
||||
FILE *file;
|
||||
char line[64];
|
||||
char name[64];
|
||||
|
||||
strcpy(router->name, "");
|
||||
if ((file = fopen("/proc/sys/kernel/hostname", "r"))) {
|
||||
while(fgets(line, sizeof(line), file) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
if (sscanf(line, "%s", name) == 1)
|
||||
break;
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
strcpy(router->name, name);
|
||||
}
|
||||
|
||||
void
|
||||
dump_sysinfo(Router *router, Memory *memory)
|
||||
{
|
||||
struct sysinfo sinfo;
|
||||
long int seconds;
|
||||
int days, hours, minutes;
|
||||
|
||||
if (sysinfo(&sinfo) == 0) {
|
||||
seconds = sinfo.uptime;
|
||||
days = seconds / (60 * 60 * 24);
|
||||
seconds -= days * (60 * 60 * 24);
|
||||
hours = seconds / (60 * 60);
|
||||
seconds -= hours * (60 * 60);
|
||||
minutes = seconds / 60;
|
||||
seconds -= minutes * 60;
|
||||
sprintf(router->uptime, "%dd %dh %dm %lds", days, hours, minutes, seconds);
|
||||
|
||||
router->procs = sinfo.procs;
|
||||
|
||||
memory->total = (sinfo.totalram / 1024);
|
||||
memory->free = (sinfo.freeram / 1024);
|
||||
memory->used = ((sinfo.totalram - sinfo.freeram) / 1024);
|
||||
memory->shared = (sinfo.sharedram / 1024);
|
||||
memory->buffers = (sinfo.bufferram / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_cpuinfo(Router *router, jiffy_counts_t *prev_jif, jiffy_counts_t *cur_jif)
|
||||
{
|
||||
unsigned total_diff, cpu;
|
||||
|
||||
total_diff = (unsigned)(cur_jif->total - prev_jif->total);
|
||||
|
||||
if (total_diff == 0) total_diff = 1;
|
||||
|
||||
cpu = 100 * (unsigned)(cur_jif->usr - prev_jif->usr) / total_diff;
|
||||
|
||||
router->cpu = cpu;
|
||||
}
|
||||
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
#include "igmp.h"
|
||||
|
||||
char* convert_to_ipaddr(int ip)
|
||||
{
|
||||
struct in_addr ip_addr;
|
||||
ip_addr.s_addr = ip;
|
||||
return inet_ntoa(ip_addr);
|
||||
}
|
||||
|
||||
char* single_space(char* str){
|
||||
char *from, *to;
|
||||
int space = 0;
|
||||
from = to = str;
|
||||
while(1) {
|
||||
if(space && *from == ' ' && to[-1] == ' ') {
|
||||
++from;
|
||||
} else {
|
||||
space = (*from == ' ') ? 1 : 0;
|
||||
*to++ = *from++;
|
||||
if(!to[-1])
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int igmp_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg) {
|
||||
|
||||
struct blob_buf bb;
|
||||
IGMPtable table[MAX_IGMP_ENTRY];
|
||||
FILE *snptable;
|
||||
char line[256];
|
||||
int idx = 0;
|
||||
void *t, *a;
|
||||
|
||||
if ((snptable = fopen("/proc/net/igmp_snooping", "r"))) {
|
||||
while(fgets(line, sizeof(line), snptable) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
table[idx].exists = false;
|
||||
if(sscanf(single_space(line),"%s %s %s %s %x %x %x %s %x %x %x %d %x %d",
|
||||
table[idx].bridge, table[idx].device, table[idx].srcdev, table[idx].tags, &(table[idx].lantci), &(table[idx].wantci),
|
||||
&(table[idx].group), table[idx].mode, &(table[idx].RxGroup), &(table[idx].source), &(table[idx].reporter),
|
||||
&(table[idx].timeout), &(table[idx].Index), &(table[idx].ExcludPt)) == 14)
|
||||
{
|
||||
table[idx].exists = true;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
fclose(snptable);
|
||||
} else
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
blob_buf_init(&bb, 0);
|
||||
|
||||
a = blobmsg_open_array(&bb, "table");
|
||||
for (idx = 0; idx < MAX_IGMP_ENTRY; idx++) {
|
||||
if (!table[idx].exists)
|
||||
break;
|
||||
t = blobmsg_open_table(&bb, NULL);
|
||||
blobmsg_add_string(&bb,"bridge", table[idx].bridge);
|
||||
blobmsg_add_string(&bb,"device", table[idx].device);
|
||||
blobmsg_add_string(&bb,"srcdev", table[idx].srcdev);
|
||||
blobmsg_add_string(&bb,"tags", table[idx].tags);
|
||||
blobmsg_add_u32(&bb,"lantci", table[idx].lantci);
|
||||
blobmsg_add_u32(&bb,"wantci", table[idx].wantci);
|
||||
blobmsg_add_string(&bb,"group", convert_to_ipaddr(table[idx].group));
|
||||
blobmsg_add_string(&bb,"mode", table[idx].mode);
|
||||
blobmsg_add_string(&bb,"rxgroup", convert_to_ipaddr(table[idx].RxGroup));
|
||||
blobmsg_add_string(&bb,"source", convert_to_ipaddr(table[idx].source));
|
||||
blobmsg_add_string(&bb,"reporter", convert_to_ipaddr(table[idx].reporter));
|
||||
blobmsg_add_u32(&bb,"timeout", table[idx].timeout);
|
||||
blobmsg_add_u32(&bb,"index", table[idx].Index);
|
||||
blobmsg_add_u32(&bb,"excludpt", table[idx].ExcludPt);
|
||||
blobmsg_close_table(&bb, t);
|
||||
}
|
||||
blobmsg_close_array(&bb, a);
|
||||
|
||||
ubus_send_reply(ctx, req, bb.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* igmp.h
|
||||
*
|
||||
* Created on: May 5, 2015
|
||||
* Author: stefan
|
||||
*/
|
||||
|
||||
#ifndef IGMP_H_
|
||||
#define IGMP_H_
|
||||
#ifndef NULL
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
|
||||
#define MAX_IGMP_ENTRY 128
|
||||
|
||||
int igmp_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
|
||||
|
||||
typedef struct igmp_table {
|
||||
bool exists;
|
||||
char bridge[32];
|
||||
char device[32];
|
||||
char srcdev[32];
|
||||
char tags[32];
|
||||
int lantci;
|
||||
int wantci;
|
||||
int group;
|
||||
char mode[32];
|
||||
int RxGroup;
|
||||
int source;
|
||||
int reporter;
|
||||
int timeout;
|
||||
int Index;
|
||||
int ExcludPt;
|
||||
|
||||
}IGMPtable;
|
||||
#endif /* IGMP_H_ */
|
||||
|
|
@ -1,507 +0,0 @@
|
|||
/*
|
||||
* ndisc.c - ICMPv6 neighbour discovery command line tool
|
||||
*
|
||||
* Author: Rémi Denis-Courmont
|
||||
* questd port: Sukru Senli sukru.senli@inteno.se
|
||||
*
|
||||
* Copyright © 2004-2007 Rémi Denis-Courmont.
|
||||
* This program is free software: you can redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, versions 2 of the license.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* div() */
|
||||
#include <inttypes.h> /* uint8_t */
|
||||
#include <limits.h> /* UINT_MAX */
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <errno.h> /* EMFILE */
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h> /* close() */
|
||||
#include <time.h> /* clock_gettime() */
|
||||
#include <poll.h> /* poll() */
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/times.h> /* times() fallback */
|
||||
|
||||
#include <netdb.h> /* getaddrinfo() */
|
||||
#include <arpa/inet.h> /* inet_ntop() */
|
||||
#include <net/if.h> /* if_nametoindex() */
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#ifndef IPV6_RECVHOPLIMIT
|
||||
/* Using obsolete RFC 2292 instead of RFC 3542 */
|
||||
# define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
|
||||
#endif
|
||||
|
||||
#ifndef AI_IDN
|
||||
# define AI_IDN 0
|
||||
#endif
|
||||
|
||||
enum ndisc_flags
|
||||
{
|
||||
NDISC_VERBOSE1=0x1,
|
||||
NDISC_VERBOSE2=0x2,
|
||||
NDISC_VERBOSE3=0x3,
|
||||
NDISC_VERBOSE =0x3,
|
||||
NDISC_NUMERIC =0x4,
|
||||
NDISC_SINGLE =0x8,
|
||||
};
|
||||
|
||||
#if defined (CLOCK_HIGHRES) && !defined (CLOCK_MONOTONIC)
|
||||
# define CLOCK_MONOTONIC CLOCK_HIGHRES
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
mono_gettime (struct timespec *ts)
|
||||
{
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
if (clock_gettime (CLOCK_MONOTONIC, ts))
|
||||
#endif
|
||||
{
|
||||
static long freq = 0;
|
||||
if (freq == 0)
|
||||
freq = sysconf (_SC_CLK_TCK);
|
||||
|
||||
struct tms dummy;
|
||||
clock_t t = times (&dummy);
|
||||
ts->tv_sec = t / freq;
|
||||
ts->tv_nsec = (t % freq) * (1000000000 / freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getipv6byname (const char *name, const char *ifname, int numeric, struct sockaddr_in6 *addr)
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
hints.ai_family = PF_INET6;
|
||||
hints.ai_socktype = SOCK_DGRAM; /* dummy */
|
||||
hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
|
||||
|
||||
int val = getaddrinfo (name, NULL, &hints, &res);
|
||||
if (val)
|
||||
{
|
||||
fprintf (stderr, "%s: %s\n", name, gai_strerror (val));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (addr, res->ai_addr, sizeof (struct sockaddr_in6));
|
||||
freeaddrinfo (res);
|
||||
|
||||
val = if_nametoindex (ifname);
|
||||
if (val == 0)
|
||||
{
|
||||
perror (ifname);
|
||||
return -1;
|
||||
}
|
||||
addr->sin6_scope_id = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
sethoplimit (int fd, int value)
|
||||
{
|
||||
return (setsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&value, sizeof (value))
|
||||
|| setsockopt (fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
&value, sizeof (value))) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static char MACADDR[24];
|
||||
|
||||
void
|
||||
clear_macaddr() {
|
||||
memset(MACADDR, '\0', sizeof(MACADDR));
|
||||
}
|
||||
|
||||
char *
|
||||
get_macaddr()
|
||||
{
|
||||
return MACADDR;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
printmacaddress (const uint8_t *ptr, size_t len)
|
||||
{
|
||||
char mac[4];
|
||||
while (len > 1)
|
||||
{
|
||||
sprintf(mac, "%02X:", *ptr);
|
||||
strcat(MACADDR, mac);
|
||||
ptr++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len == 1) {
|
||||
sprintf(mac, "%02X", *ptr);
|
||||
strcat(MACADDR, mac);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# ifdef __linux__
|
||||
# include <sys/ioctl.h>
|
||||
# endif
|
||||
|
||||
static int
|
||||
getmacaddress (const char *ifname, uint8_t *addr)
|
||||
{
|
||||
# ifdef SIOCGIFHWADDR
|
||||
struct ifreq req;
|
||||
memset (&req, 0, sizeof (req));
|
||||
|
||||
if (((unsigned)strlen (ifname)) >= (unsigned)IFNAMSIZ)
|
||||
return -1; /* buffer overflow = local root */
|
||||
strcpy (req.ifr_name, ifname);
|
||||
|
||||
int fd = socket (AF_INET6, SOCK_DGRAM, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
if (ioctl (fd, SIOCGIFHWADDR, &req))
|
||||
{
|
||||
perror (ifname);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
close (fd);
|
||||
|
||||
memcpy (addr, req.ifr_hwaddr.sa_data, 6);
|
||||
return 0;
|
||||
# else
|
||||
(void)ifname;
|
||||
(void)addr;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t nd_type_advert = ND_NEIGHBOR_ADVERT;
|
||||
static const unsigned nd_delay_ms = 1000;
|
||||
static const unsigned ndisc_default = NDISC_VERBOSE1 | NDISC_SINGLE;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct nd_neighbor_solicit hdr;
|
||||
struct nd_opt_hdr opt;
|
||||
uint8_t hw_addr[6];
|
||||
} solicit_packet;
|
||||
|
||||
|
||||
static ssize_t
|
||||
buildsol (solicit_packet *ns, struct sockaddr_in6 *tgt, const char *ifname)
|
||||
{
|
||||
/* builds ICMPv6 Neighbor Solicitation packet */
|
||||
ns->hdr.nd_ns_type = ND_NEIGHBOR_SOLICIT;
|
||||
ns->hdr.nd_ns_code = 0;
|
||||
ns->hdr.nd_ns_cksum = 0; /* computed by the kernel */
|
||||
ns->hdr.nd_ns_reserved = 0;
|
||||
memcpy (&ns->hdr.nd_ns_target, &tgt->sin6_addr, 16);
|
||||
|
||||
/* determines actual multicast destination address */
|
||||
memcpy (tgt->sin6_addr.s6_addr, "\xff\x02\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x01\xff", 13);
|
||||
|
||||
/* gets our own interface's link-layer address (MAC) */
|
||||
if (getmacaddress (ifname, ns->hw_addr))
|
||||
return sizeof (ns->hdr);
|
||||
|
||||
ns->opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
ns->opt.nd_opt_len = 1; /* 8 bytes */
|
||||
return sizeof (*ns);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parseadv (const uint8_t *buf, size_t len, const struct sockaddr_in6 *tgt, bool verbose)
|
||||
{
|
||||
const struct nd_neighbor_advert *na =
|
||||
(const struct nd_neighbor_advert *)buf;
|
||||
const uint8_t *ptr;
|
||||
|
||||
/* checks if the packet is a Neighbor Advertisement, and
|
||||
* if the target IPv6 address is the right one */
|
||||
if ((len < sizeof (struct nd_neighbor_advert))
|
||||
|| (na->nd_na_type != ND_NEIGHBOR_ADVERT)
|
||||
|| (na->nd_na_code != 0)
|
||||
|| memcmp (&na->nd_na_target, &tgt->sin6_addr, 16))
|
||||
return -1;
|
||||
|
||||
len -= sizeof (struct nd_neighbor_advert);
|
||||
|
||||
/* looks for Target Link-layer address option */
|
||||
ptr = buf + sizeof (struct nd_neighbor_advert);
|
||||
|
||||
while (len >= 8)
|
||||
{
|
||||
uint16_t optlen;
|
||||
|
||||
optlen = ((uint16_t)(ptr[1])) << 3;
|
||||
if (optlen == 0)
|
||||
break; /* invalid length */
|
||||
|
||||
if (len < optlen) /* length > remaining bytes */
|
||||
break;
|
||||
len -= optlen;
|
||||
|
||||
|
||||
/* skips unrecognized option */
|
||||
if (ptr[0] != ND_OPT_TARGET_LINKADDR)
|
||||
{
|
||||
ptr += optlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Found! displays link-layer address */
|
||||
ptr += 2;
|
||||
optlen -= 2;
|
||||
if (verbose)
|
||||
fputs ("Target link-layer address: ", stdout);
|
||||
|
||||
printmacaddress (ptr, optlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
static ssize_t
|
||||
recvfromLL (int fd, void *buf, size_t len, int flags, struct sockaddr_in6 *addr)
|
||||
{
|
||||
char cbuf[CMSG_SPACE (sizeof (int))];
|
||||
struct iovec iov =
|
||||
{
|
||||
.iov_base = buf,
|
||||
.iov_len = len
|
||||
};
|
||||
struct msghdr hdr =
|
||||
{
|
||||
.msg_name = addr,
|
||||
.msg_namelen = sizeof (*addr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cbuf,
|
||||
.msg_controllen = sizeof (cbuf)
|
||||
};
|
||||
|
||||
ssize_t val = recvmsg (fd, &hdr, flags);
|
||||
if (val == -1)
|
||||
return val;
|
||||
|
||||
/* ensures the hop limit is 255 */
|
||||
struct cmsghdr *cmsg;
|
||||
for (cmsg = CMSG_FIRSTHDR (&hdr);
|
||||
cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR (&hdr, cmsg))
|
||||
{
|
||||
if ((cmsg->cmsg_level == IPPROTO_IPV6)
|
||||
&& (cmsg->cmsg_type == IPV6_HOPLIMIT))
|
||||
{
|
||||
if (255 != *(int *)CMSG_DATA (cmsg))
|
||||
{
|
||||
// pretend to be a spurious wake-up
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
recvadv (int fd, const struct sockaddr_in6 *tgt, unsigned wait_ms, unsigned flags)
|
||||
{
|
||||
struct timespec now, end;
|
||||
unsigned responses = 0;
|
||||
|
||||
/* computes deadline time */
|
||||
mono_gettime (&now);
|
||||
{
|
||||
div_t d;
|
||||
|
||||
d = div (wait_ms, 1000);
|
||||
end.tv_sec = now.tv_sec + d.quot;
|
||||
end.tv_nsec = now.tv_nsec + (d.rem * 1000000);
|
||||
}
|
||||
|
||||
/* receive loop */
|
||||
for (;;)
|
||||
{
|
||||
/* waits for reply until deadline */
|
||||
ssize_t val = 0;
|
||||
if (end.tv_sec >= now.tv_sec)
|
||||
{
|
||||
val = (end.tv_sec - now.tv_sec) * 1000
|
||||
+ (int)((end.tv_nsec - now.tv_nsec) / 1000000);
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
}
|
||||
|
||||
val = poll (&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, val);
|
||||
if (val < 0)
|
||||
break;
|
||||
|
||||
if (val == 0)
|
||||
return responses;
|
||||
|
||||
/* receives an ICMPv6 packet */
|
||||
// TODO: use interface MTU as buffer size
|
||||
union
|
||||
{
|
||||
uint8_t b[1460];
|
||||
uint64_t align;
|
||||
} buf;
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
val = recvfromLL (fd, &buf, sizeof (buf), MSG_DONTWAIT, &addr);
|
||||
if (val == -1)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
perror ("Receiving ICMPv6 packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ensures the response came through the right interface */
|
||||
if (addr.sin6_scope_id
|
||||
&& (addr.sin6_scope_id != tgt->sin6_scope_id))
|
||||
continue;
|
||||
|
||||
if (parseadv (buf.b, val, tgt, (flags & NDISC_VERBOSE) != 0) == 0)
|
||||
{
|
||||
if (flags & NDISC_VERBOSE)
|
||||
{
|
||||
char str[INET6_ADDRSTRLEN];
|
||||
|
||||
if (inet_ntop (AF_INET6, &addr.sin6_addr, str,
|
||||
sizeof (str)) != NULL)
|
||||
printf (" from %s\n", str);
|
||||
}
|
||||
|
||||
if (responses < INT_MAX)
|
||||
responses++;
|
||||
|
||||
if (flags & NDISC_SINGLE)
|
||||
return 1 /* = responses */;
|
||||
}
|
||||
mono_gettime (&now);
|
||||
}
|
||||
|
||||
return -1; /* error */
|
||||
}
|
||||
|
||||
bool
|
||||
ndisc (const char *name, const char *ifname, unsigned flags, unsigned retry, unsigned wait_ms)
|
||||
{
|
||||
struct sockaddr_in6 tgt;
|
||||
|
||||
int fd = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
perror ("Raw IPv6 socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* set ICMPv6 filter */
|
||||
{
|
||||
struct icmp6_filter f;
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL (&f);
|
||||
ICMP6_FILTER_SETPASS (nd_type_advert, &f);
|
||||
setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER, &f, sizeof (f));
|
||||
}
|
||||
|
||||
setsockopt (fd, SOL_SOCKET, SO_DONTROUTE, &(int){ 1 }, sizeof (int));
|
||||
|
||||
/* sets Hop-by-hop limit to 255 */
|
||||
sethoplimit (fd, 255);
|
||||
setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
|
||||
&(int){ 1 }, sizeof (int));
|
||||
|
||||
/* resolves target's IPv6 address */
|
||||
if (getipv6byname (name, ifname, (flags & NDISC_NUMERIC) ? 1 : 0, &tgt))
|
||||
goto error;
|
||||
else
|
||||
{
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop (AF_INET6, &tgt.sin6_addr, s, sizeof (s));
|
||||
if (flags & NDISC_VERBOSE)
|
||||
printf ("Soliciting %s (%s) on %s...\n", name, s, ifname);
|
||||
}
|
||||
|
||||
{
|
||||
solicit_packet packet;
|
||||
struct sockaddr_in6 dst;
|
||||
ssize_t plen;
|
||||
|
||||
memcpy (&dst, &tgt, sizeof (dst));
|
||||
plen = buildsol (&packet, &dst, ifname);
|
||||
if (plen == -1)
|
||||
goto error;
|
||||
|
||||
while (retry > 0)
|
||||
{
|
||||
/* sends a Solitication */
|
||||
if (sendto (fd, &packet, plen, 0,
|
||||
(const struct sockaddr *)&dst,
|
||||
sizeof (dst)) != plen)
|
||||
{
|
||||
//perror ("Sending ICMPv6 packet");
|
||||
goto error;
|
||||
}
|
||||
retry--;
|
||||
|
||||
/* receives an Advertisement */
|
||||
ssize_t val = recvadv (fd, &tgt, wait_ms, flags);
|
||||
if (val > 0)
|
||||
{
|
||||
close (fd);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (val == 0)
|
||||
{
|
||||
if (flags & NDISC_VERBOSE)
|
||||
puts ("Timed out.");
|
||||
}
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
close (fd);
|
||||
if (flags & NDISC_VERBOSE)
|
||||
puts ("No response.");
|
||||
return false;
|
||||
|
||||
error:
|
||||
close (fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
* port -- collects port info for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
#include <linux/if_bridge.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define CHUNK 128
|
||||
|
||||
static long
|
||||
get_port_stat(char *dev, char *stat)
|
||||
{
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
sprintf(cmnd, "/sys/class/net/%s/statistics/%s", dev, stat);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
return atoi(result);
|
||||
}
|
||||
|
||||
void
|
||||
get_port_stats(Port *port)
|
||||
{
|
||||
port->stat.rx_bytes = get_port_stat(port->device, "rx_bytes");
|
||||
port->stat.rx_packets = get_port_stat(port->device, "rx_packets");
|
||||
port->stat.rx_errors = get_port_stat(port->device, "rx_errors");
|
||||
port->stat.tx_bytes = get_port_stat(port->device, "tx_bytes");
|
||||
port->stat.tx_packets =get_port_stat(port->device, "tx_packets");
|
||||
port->stat.tx_errors = get_port_stat(port->device, "tx_errors");
|
||||
}
|
||||
|
||||
void
|
||||
get_port_name(Port *port)
|
||||
{
|
||||
FILE *in;
|
||||
char buf[32];
|
||||
char cmnd[80];
|
||||
|
||||
sprintf(cmnd, ". /lib/network/config.sh && interfacename %s 2>/dev/null", port->device);
|
||||
if (!(in = popen(cmnd, "r")))
|
||||
exit(1);
|
||||
|
||||
fgets(buf, sizeof(buf), in);
|
||||
pclose(in);
|
||||
remove_newline(buf);
|
||||
strcpy(port->name, buf);
|
||||
|
||||
memset(cmnd, '\0', sizeof(cmnd));
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
|
||||
if(!strncmp(port->device, "wl", 2)) {
|
||||
sprintf(cmnd, "wlctl -i %s ssid | awk '{print$3}' | sed 's/\"//g' 2>/dev/null", port->device);
|
||||
if (!(in = popen(cmnd, "r")))
|
||||
exit(1);
|
||||
|
||||
fgets(buf, sizeof(buf), in);
|
||||
pclose(in);
|
||||
remove_newline(buf);
|
||||
strcpy(port->ssid, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
get_bridge_ports(char *bridge, char **ports)
|
||||
{
|
||||
FILE *in;
|
||||
char buf[64];
|
||||
char cmnd[128];
|
||||
|
||||
*ports = "";
|
||||
|
||||
sprintf(cmnd, "brctl showbr %s | awk '{print$NF}' | grep -v interfaces | tr '\n' ' '", bridge);
|
||||
if (!(in = popen(cmnd, "r")))
|
||||
exit(1);
|
||||
|
||||
fgets(buf, sizeof(buf), in);
|
||||
pclose(in);
|
||||
*ports = strdup(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_fdbs(const void *_f0, const void *_f1)
|
||||
{
|
||||
const struct fdb_entry *f0 = _f0;
|
||||
const struct fdb_entry *f1 = _f1;
|
||||
|
||||
return memcmp(f0->mac_addr, f1->mac_addr, 6);
|
||||
}
|
||||
|
||||
static inline void
|
||||
copy_fdb(struct fdb_entry *ent, const struct __fdb_entry *f)
|
||||
{
|
||||
memcpy(ent->mac_addr, f->mac_addr, 6);
|
||||
ent->port_no = f->port_no;
|
||||
ent->is_local = f->is_local;
|
||||
}
|
||||
|
||||
static int
|
||||
bridge_read_fdb(const char *bridge, struct fdb_entry *fdbs, unsigned long offset, int num)
|
||||
{
|
||||
FILE *f;
|
||||
int i, n;
|
||||
struct __fdb_entry fe[num];
|
||||
char path[256];
|
||||
|
||||
snprintf(path, 256, "/sys/class/net/%s/brforward", bridge);
|
||||
f = fopen(path, "r");
|
||||
if (f) {
|
||||
fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
|
||||
n = fread(fe, sizeof(struct __fdb_entry), num, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
copy_fdb(fdbs+i, fe+i);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
get_clients_onport(char *bridge, int portno, char **macaddr)
|
||||
{
|
||||
int i, n;
|
||||
struct fdb_entry *fdb = NULL;
|
||||
int offset = 0;
|
||||
char tmpmac[2400];
|
||||
char mac[24];
|
||||
|
||||
*macaddr = "";
|
||||
|
||||
for(;;) {
|
||||
fdb = realloc(fdb, (offset + CHUNK) * sizeof(struct fdb_entry));
|
||||
if (!fdb) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
n = bridge_read_fdb(bridge, fdb+offset, offset, CHUNK);
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "read of forward table failed: %s\n",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
}
|
||||
|
||||
qsort(fdb, offset, sizeof(struct fdb_entry), compare_fdbs);
|
||||
|
||||
for (i = 0; i < offset; i++) {
|
||||
const struct fdb_entry *f = fdb + i;
|
||||
if (f->port_no == portno && !f->is_local) {
|
||||
sprintf(mac, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]);
|
||||
strcat(tmpmac, " ");
|
||||
strcat(tmpmac, mac);
|
||||
}
|
||||
}
|
||||
*macaddr = strdup(tmpmac);
|
||||
|
||||
free(fdb);
|
||||
memset(tmpmac, '\0', sizeof(tmpmac));
|
||||
}
|
||||
2164
questd/src/questd.c
2164
questd/src/questd.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,219 +0,0 @@
|
|||
//#define _GNU_SOURCE
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <uci.h>
|
||||
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/ustream.h>
|
||||
#include <libubox/utils.h>
|
||||
|
||||
#include <libubus.h>
|
||||
|
||||
#include "dslstats.h"
|
||||
#include "igmp.h"
|
||||
|
||||
#define MAX_RADIO 4
|
||||
#define MAX_VIF 8
|
||||
#define MAX_NETWORK 16
|
||||
#define MAX_CLIENT 128
|
||||
#define MAX_PORT 8
|
||||
#define MAX_USB 18
|
||||
|
||||
typedef struct {
|
||||
const char *vif;
|
||||
const char *device;
|
||||
const char *ssid;
|
||||
const char *network;
|
||||
int noise;
|
||||
} Wireless;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *band;
|
||||
int frequency;
|
||||
const char *hwmodes[6];
|
||||
int channels[16];
|
||||
const char *pcid;
|
||||
int bwcaps[4];
|
||||
bool is_ac;
|
||||
} Radio;
|
||||
|
||||
typedef struct {
|
||||
int connum;
|
||||
int idle;
|
||||
int in_network;
|
||||
long tx_bytes;
|
||||
long rx_bytes;
|
||||
int tx_rate;
|
||||
int rx_rate;
|
||||
int snr;
|
||||
} Detail;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
bool local;
|
||||
bool dhcp;
|
||||
char leaseno[24];
|
||||
char macaddr[24];
|
||||
char ipaddr[24];
|
||||
char hostname[64];
|
||||
char network[32];
|
||||
char device[32];
|
||||
bool wireless;
|
||||
char wdev[8];
|
||||
bool connected;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
char macaddr[24];
|
||||
char wdev[8];
|
||||
int snr;
|
||||
} Sta;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
char ip6addr[128];
|
||||
char macaddr[24];
|
||||
char hostname[64];
|
||||
char duid[64];
|
||||
char device[32];
|
||||
bool wireless;
|
||||
char wdev[8];
|
||||
bool connected;
|
||||
} Client6;
|
||||
|
||||
typedef struct {
|
||||
unsigned long rx_bytes;
|
||||
unsigned long rx_packets;
|
||||
unsigned long rx_errors;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_packets;
|
||||
unsigned long tx_errors;
|
||||
} Statistic;
|
||||
|
||||
typedef struct {
|
||||
char name[16];
|
||||
char ssid[32];
|
||||
char device[32];
|
||||
Statistic stat;
|
||||
Client client[MAX_CLIENT];
|
||||
} Port;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
bool is_lan;
|
||||
const char *name;
|
||||
const char *type;
|
||||
const char *proto;
|
||||
const char *ipaddr;
|
||||
const char *netmask;
|
||||
char ifname[128];
|
||||
Port port[MAX_PORT];
|
||||
bool ports_populated;
|
||||
} Network;
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
char *hardware;
|
||||
char *model;
|
||||
char *boardid;
|
||||
char *firmware;
|
||||
char *brcmver;
|
||||
char *filesystem;
|
||||
char *socmod;
|
||||
char *socrev;
|
||||
char *cfever;
|
||||
char *kernel;
|
||||
char *basemac;
|
||||
char *serialno;
|
||||
char uptime[64];
|
||||
unsigned int procs;
|
||||
unsigned int cpu;
|
||||
} Router;
|
||||
|
||||
typedef struct {
|
||||
unsigned long total;
|
||||
unsigned long used;
|
||||
unsigned long free;
|
||||
unsigned long shared;
|
||||
unsigned long buffers;
|
||||
} Memory;
|
||||
|
||||
typedef struct {
|
||||
char *auth;
|
||||
char *des;
|
||||
char *wpa;
|
||||
} Key;
|
||||
|
||||
typedef struct {
|
||||
bool wifi;
|
||||
bool adsl;
|
||||
bool vdsl;
|
||||
bool voice;
|
||||
bool dect;
|
||||
int vports;
|
||||
int eports;
|
||||
} Spec;
|
||||
|
||||
typedef struct {
|
||||
char mount[64];
|
||||
char product[64];
|
||||
char no[8];
|
||||
char name[8];
|
||||
unsigned long size;
|
||||
char *device;
|
||||
char *vendor;
|
||||
char *serial;
|
||||
char *speed;
|
||||
char *maxchild;
|
||||
} USB;
|
||||
|
||||
typedef struct jiffy_counts_t {
|
||||
unsigned long long usr, nic, sys, idle;
|
||||
unsigned long long iowait, irq, softirq, steal;
|
||||
unsigned long long total;
|
||||
unsigned long long busy;
|
||||
} jiffy_counts_t;
|
||||
|
||||
struct fdb_entry
|
||||
{
|
||||
u_int8_t mac_addr[6];
|
||||
u_int16_t port_no;
|
||||
unsigned char is_local;
|
||||
};
|
||||
|
||||
void recalc_sleep_time(bool calc, int toms);
|
||||
void init_db_hw_config(void);
|
||||
bool arping(char *target, char *device, int toms);
|
||||
void remove_newline(char *buf);
|
||||
void replace_char(char *buf, char a, char b);
|
||||
void runCmd(const char *pFmt, ...);
|
||||
const char *chrCmd(const char *pFmt, ...);
|
||||
void get_jif_val(jiffy_counts_t *p_jif);
|
||||
void dump_keys(Key *keys);
|
||||
void dump_specs(Spec *spec);
|
||||
void dump_static_router_info(Router *router);
|
||||
void dump_hostname(Router *router);
|
||||
void dump_sysinfo(Router *router, Memory *memory);
|
||||
void dump_cpuinfo(Router *router, jiffy_counts_t *prev_jif, jiffy_counts_t *cur_jif);
|
||||
void get_port_name(Port *port);
|
||||
void get_port_stats(Port *port);
|
||||
void get_bridge_ports(char *network, char **ifname);
|
||||
void get_clients_onport(char *bridge, int portno, char **macaddr);
|
||||
void dump_usb_info(USB *usb, char *usbno);
|
||||
void clear_macaddr(void);
|
||||
char *get_macaddr(void);
|
||||
bool ndisc (const char *name, const char *ifname, unsigned flags, unsigned retry, unsigned wait_ms);
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
void
|
||||
remove_newline(char *buf)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf) - 1;
|
||||
if (buf[len] == '\n')
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
replace_char(char *buf, char a, char b)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (buf[i]) {
|
||||
if (buf[i] == a)
|
||||
buf[i] = b;
|
||||
i++;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
runCmd(const char *pFmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char cmd[256] = {0};
|
||||
int len=0, maxLen;
|
||||
|
||||
maxLen = sizeof(cmd);
|
||||
|
||||
va_start(ap, pFmt);
|
||||
|
||||
if (len < maxLen)
|
||||
{
|
||||
maxLen -= len;
|
||||
vsnprintf(&cmd[len], maxLen, pFmt, ap);
|
||||
}
|
||||
|
||||
system(cmd);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
const char*
|
||||
chrCmd(const char *pFmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char cmd[256] = {0};
|
||||
int len=0, maxLen;
|
||||
|
||||
maxLen = sizeof(cmd);
|
||||
|
||||
va_start(ap, pFmt);
|
||||
|
||||
if (len < maxLen)
|
||||
{
|
||||
maxLen -= len;
|
||||
vsnprintf(&cmd[len], maxLen, pFmt, ap);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
FILE *pipe = 0;
|
||||
static char buffer[128] = {0};
|
||||
if ((pipe = popen(cmd, "r"))){
|
||||
fgets(buffer, sizeof(buffer), pipe);
|
||||
pclose(pipe);
|
||||
|
||||
remove_newline(buffer);
|
||||
if (strlen(buffer))
|
||||
return (const char*)buffer;
|
||||
else
|
||||
return "";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
131
questd/src/usb.c
131
questd/src/usb.c
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* usb -- collects usb info for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
#include <string.h>
|
||||
|
||||
static void
|
||||
remove_space(char *buf)
|
||||
{
|
||||
char *newbuf = malloc(strlen(buf)+1);
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
while (buf[i]) {
|
||||
newbuf[j] = buf[i];
|
||||
if (buf[i] != ' ')
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
newbuf[j] = '\0';
|
||||
strcpy(buf, newbuf);
|
||||
free(newbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
get_usb_infos(char **val, char *usbno, char *info) {
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
*val = "";
|
||||
|
||||
sprintf(cmnd, "/sys/bus/usb/devices/%s/%s", usbno, info);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
remove_newline(result);
|
||||
fclose(in);
|
||||
*val = strdup(result);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_usb_device(char **val, char *mount) {
|
||||
FILE *mounts;
|
||||
char line[128];
|
||||
char dev[16];
|
||||
char mnt[64];
|
||||
|
||||
*val = NULL;
|
||||
|
||||
if ((mounts = fopen("/var/usbmounts", "r"))) {
|
||||
while(fgets(line, sizeof(line), mounts) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
if (sscanf(line, "/dev/%s /mnt/%s", dev, mnt) == 2) {
|
||||
if (!strcmp(mnt, mount) || strstr(mount, mnt)) {
|
||||
*val = strdup(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(mounts);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_usb_size(unsigned long *val, char *device) {
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
*val = 0;
|
||||
|
||||
sprintf(cmnd, "/sys/class/block/%s/size", device);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
remove_newline(result);
|
||||
fclose(in);
|
||||
*val = (long)(atoi(result) / 2048);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_usb_info(USB *usb, char *usbno)
|
||||
{
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
sprintf(cmnd, "/sys/bus/usb/devices/%s/product", usbno);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
remove_newline(result);
|
||||
fclose(in);
|
||||
|
||||
strcpy(usb->product, result);
|
||||
sprintf(usb->no, "%s", usbno);
|
||||
sprintf(usb->name, "USB%s", strndup(usbno+2, strlen(usbno)));
|
||||
get_usb_infos(&usb->vendor, usb->no, "manufacturer");
|
||||
get_usb_infos(&usb->serial, usb->no, "serial");
|
||||
//get_usb_infos(&usb->speed, usb->no, "speed");
|
||||
get_usb_infos(&usb->maxchild, usb->no, "maxchild");
|
||||
sprintf(usb->mount, "%s%s", usb->vendor, usb->serial);
|
||||
remove_space(usb->mount);
|
||||
if(!strcmp(usb->mount, usb->serial)) {
|
||||
sprintf(usb->mount, "%s%s", usb->product, usb->serial);
|
||||
remove_space(usb->mount);
|
||||
}
|
||||
get_usb_device(&usb->device, usb->mount);
|
||||
get_usb_size(&usb->size, usb->device);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,18 @@ PKG_NAME:=statd
|
|||
PKG_VERSION:=0.0.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_VERSION:=54125a06399b378a27db31f722d891a5b23baf2d
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/statd
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:statd
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
target=$(firstword $(subst -, ,$(BOARD)))
|
||||
|
|
@ -29,11 +41,6 @@ define Package/statd/description
|
|||
Application that listen on ubus events to be sent on syslog or snmp
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
$(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
# Makefile for statd application
|
||||
|
||||
CC = gcc
|
||||
MAKEDEPEND = makedepend
|
||||
CDEBUG = -g
|
||||
CFLAGS = ${CDEBUG} ${INCL} -Wall
|
||||
LDFLAGS = ${CDEBUG}
|
||||
LIBDIR =
|
||||
LOCLIBS =
|
||||
LIBS = ${LOCLIBS} ${SYSLIBS}
|
||||
OBJS = statd.o statd_rules.o
|
||||
SRCS = statd.c statd_rules.c
|
||||
LIBSRCS =
|
||||
ISRCS = statd.h statd_rules.h
|
||||
ALLSRCS = ${SRCS} ${ISRCS} ${LIBSRCS}
|
||||
|
||||
all: statd
|
||||
|
||||
statd: ${OBJS}
|
||||
${CC} ${LDFLAGS} -o statd ${OBJS} ${LIBDIR} ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f statd ${OBJS}
|
||||
|
||||
depend:
|
||||
${MAKEDEPEND} ${INCL} ${SRCS} ${LIBSRCS}
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/ustream.h>
|
||||
#include <libubox/utils.h>
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubus.h>
|
||||
|
||||
#include <uci.h>
|
||||
|
||||
#include "statd_rules.h"
|
||||
|
||||
#define CFG_PATH "/etc/config/"
|
||||
#define CFG_FILE "statd"
|
||||
|
||||
static struct ubus_event_handler ubus_listener_syslog;
|
||||
|
||||
static bool ubus_connected = false;
|
||||
static struct ubus_context *ubus_ctx = NULL;
|
||||
|
||||
static void system_fd_set_cloexec(int fd)
|
||||
{
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ubus_receive_event_syslog_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
|
||||
const char *type, struct blob_attr *msg)
|
||||
{
|
||||
char *tmp;
|
||||
char *str;
|
||||
|
||||
tmp = blobmsg_format_json(msg, true);
|
||||
str = (char *) malloc(strlen(type) + strlen(tmp) + /* Curly braces, null terminator etc... */ 9);
|
||||
sprintf(str, "{ \"%s\": %s }", type, tmp);
|
||||
printf("Sending to syslog: %s\n", str);
|
||||
syslog(LOG_INFO, str);
|
||||
|
||||
free(str);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void ubus_connection_lost_cb(struct ubus_context *ctx)
|
||||
{
|
||||
fprintf(stderr, "UBUS connection lost\n");
|
||||
ubus_connected = false;
|
||||
}
|
||||
|
||||
static struct ubus_event_handler *get_ubus_event_handler(const struct statd_rule *rule)
|
||||
{
|
||||
static struct ubus_event_handler *ubus_listener = NULL;
|
||||
switch (statd_rule_get_destination(rule)) {
|
||||
case DEST_SYSLOG:
|
||||
ubus_listener = &ubus_listener_syslog;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown destination, can't register\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return ubus_listener;
|
||||
}
|
||||
|
||||
static int load_rules()
|
||||
{
|
||||
struct uci_context *uci_ctx = uci_alloc_context();
|
||||
if (!uci_ctx) {
|
||||
fprintf(stderr, "Failed to initialize uci\n");
|
||||
return 1;
|
||||
}
|
||||
uci_set_confdir(uci_ctx, CFG_PATH);
|
||||
if (uci_load(uci_ctx, CFG_FILE, NULL) != UCI_OK) {
|
||||
fprintf(stderr, "Configuration missing or corrupt (%s/%s)\n", CFG_PATH, CFG_FILE);
|
||||
uci_free_context(uci_ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct uci_element *package_element;
|
||||
uci_foreach_element(&uci_ctx->root, package_element) {
|
||||
struct uci_package *package = uci_to_package(package_element);
|
||||
|
||||
struct uci_element *section_element;
|
||||
uci_foreach_element(&package->sections, section_element)
|
||||
{
|
||||
struct uci_section *section = uci_to_section(section_element);
|
||||
if (strcmp(section->type, "rule")) {
|
||||
fprintf(stderr, "Ignoring unknown uci section type %s\n", section->type);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct uci_element *option_element;
|
||||
const char *filter = NULL;
|
||||
enum statd_destination destination = DEST_UNKNOWN;
|
||||
uci_foreach_element(§ion->options, option_element)
|
||||
{
|
||||
struct uci_option *option = uci_to_option(option_element);
|
||||
if (option->type != UCI_TYPE_STRING) {
|
||||
fprintf(stderr, "Ignoring uci option, type is not string\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(option_element->name, "filter")) {
|
||||
filter = option->v.string;
|
||||
} else if (!strcmp(option_element->name, "destination")) {
|
||||
if (strcmp(option->v.string, "syslog")) {
|
||||
fprintf(stderr, "Ignoring unknown uci option destination %s\n", option->v.string);
|
||||
continue;
|
||||
}
|
||||
destination = DEST_SYSLOG;
|
||||
} else {
|
||||
fprintf(stderr, "Ignoring unknown uci option %s\n", option_element->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (filter && destination != DEST_UNKNOWN) {
|
||||
statd_rule_add(filter, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uci_free_context(uci_ctx);
|
||||
|
||||
if (!statd_rule_get_head()) {
|
||||
fprintf(stderr, "No valid rules found in configuration\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
fd_set fdset;
|
||||
struct timeval timeout;
|
||||
|
||||
/* Read configuration */
|
||||
if (load_rules()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Listener for events to be sent on syslog */
|
||||
memset(&ubus_listener_syslog, 0, sizeof(ubus_listener_syslog));
|
||||
ubus_listener_syslog.cb = ubus_receive_event_syslog_cb;
|
||||
openlog(NULL, LOG_NDELAY, LOG_LOCAL0);
|
||||
|
||||
/* TODO: Listener for events to be sent using snmp trap */
|
||||
|
||||
/* Initialize ubus connection */
|
||||
ubus_ctx = ubus_connect(NULL);
|
||||
if (!ubus_ctx) {
|
||||
fprintf(stderr, "Failed to connect to UBUS\n");
|
||||
} else {
|
||||
ubus_ctx->connection_lost = ubus_connection_lost_cb;
|
||||
system_fd_set_cloexec(ubus_ctx->sock.fd);
|
||||
printf("Connected to UBUS, id: %08x\n", ubus_ctx->local_id);
|
||||
|
||||
/* Register ubus event listeners */
|
||||
ret = 0;
|
||||
struct statd_rule *current_rule = statd_rule_get_head();
|
||||
while (current_rule) {
|
||||
printf("Registering for event: %s\n", statd_rule_get_filter(current_rule));
|
||||
struct ubus_event_handler *ubus_listener = get_ubus_event_handler(current_rule);
|
||||
if (ubus_listener) {
|
||||
ret |= ubus_register_event_handler(ubus_ctx, ubus_listener, statd_rule_get_filter(current_rule));
|
||||
}
|
||||
current_rule = statd_rule_get_next(current_rule);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ubus_connected = true;
|
||||
} else {
|
||||
fprintf(stderr, "Error while registering for events: %s\n", ubus_strerror(ret));
|
||||
ubus_free(ubus_ctx);
|
||||
ubus_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Main application loop */
|
||||
while(1) {
|
||||
FD_ZERO(&fdset);
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
if (ubus_connected) {
|
||||
FD_SET(ubus_ctx->sock.fd, &fdset);
|
||||
}
|
||||
|
||||
/* Wait for events from ubus (or in the future SNMP requests) */
|
||||
ret = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: %s\n", strerror(errno));
|
||||
if (errno == EINTR) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ubus_connected) {
|
||||
if (FD_ISSET(ubus_ctx->sock.fd, &fdset)) {
|
||||
ubus_handle_event(ubus_ctx);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ubus_ctx) {
|
||||
if (ubus_reconnect(ubus_ctx, NULL) == 0) {
|
||||
printf("UBUS reconnected\n");
|
||||
ubus_connected = true;
|
||||
system_fd_set_cloexec(ubus_ctx->sock.fd);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ubus_ctx = ubus_connect(NULL);
|
||||
if (ubus_ctx) {
|
||||
ubus_ctx->connection_lost = ubus_connection_lost_cb;
|
||||
system_fd_set_cloexec(ubus_ctx->sock.fd);
|
||||
|
||||
ret = 0;
|
||||
struct statd_rule *current_rule = statd_rule_get_head();
|
||||
while (current_rule) {
|
||||
struct ubus_event_handler *ubus_listener = get_ubus_event_handler(current_rule);
|
||||
if (ubus_listener) {
|
||||
ret |= ubus_register_event_handler(ubus_ctx, ubus_listener, statd_rule_get_filter(current_rule));
|
||||
}
|
||||
current_rule = statd_rule_get_next(current_rule);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ubus_connected = true;
|
||||
printf("Connected to UBUS, id: %08x\n", ubus_ctx->local_id);
|
||||
} else {
|
||||
ubus_free(ubus_ctx);
|
||||
ubus_ctx = NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ubus_free(ubus_ctx); //Shut down UBUS connection
|
||||
printf("UBUS connection closed\n");
|
||||
|
||||
statd_rule_destroy_all();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#include "statd_rules.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct statd_rule *head = NULL;
|
||||
static struct statd_rule *tail = NULL;
|
||||
|
||||
struct statd_rule *statd_rule_add(const char* filter, enum statd_destination destination)
|
||||
{
|
||||
struct statd_rule *rule = NULL;
|
||||
|
||||
rule = malloc(sizeof(*rule));
|
||||
rule->filter = strdup(filter);
|
||||
rule->destination = destination;
|
||||
rule->next = NULL;
|
||||
|
||||
if (!head) {
|
||||
head = rule;
|
||||
}
|
||||
|
||||
if (tail) {
|
||||
tail->next = rule;
|
||||
}
|
||||
tail = rule;
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
static void statd_rule_destroy(struct statd_rule *rule)
|
||||
{
|
||||
free(rule->filter);
|
||||
free(rule);
|
||||
}
|
||||
|
||||
void statd_rule_destroy_all()
|
||||
{
|
||||
struct statd_rule *current_rule = head;
|
||||
while (current_rule) {
|
||||
struct statd_rule *next = statd_rule_get_next(current_rule);
|
||||
statd_rule_destroy(current_rule);
|
||||
current_rule = next;
|
||||
}
|
||||
|
||||
head = NULL;
|
||||
tail = NULL;
|
||||
}
|
||||
|
||||
struct statd_rule *statd_rule_get_head()
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
struct statd_rule *statd_rule_get_next(const struct statd_rule *rule)
|
||||
{
|
||||
return rule->next;
|
||||
}
|
||||
|
||||
const char *statd_rule_get_filter(const struct statd_rule *rule)
|
||||
{
|
||||
return rule->filter;
|
||||
}
|
||||
|
||||
enum statd_destination statd_rule_get_destination(const struct statd_rule *rule)
|
||||
{
|
||||
return rule->destination;
|
||||
}
|
||||
|
||||
int statd_rule_has_next(const struct statd_rule *rule)
|
||||
{
|
||||
return rule->next != NULL;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef _RULES_H_
|
||||
#define _RULES_H_
|
||||
|
||||
enum statd_destination
|
||||
{
|
||||
DEST_SYSLOG,
|
||||
DEST_UNKNOWN
|
||||
};
|
||||
|
||||
struct statd_rule
|
||||
{
|
||||
char *filter;
|
||||
enum statd_destination destination;
|
||||
struct statd_rule *next;
|
||||
};
|
||||
|
||||
/* Create rule and add to internal list */
|
||||
struct statd_rule *statd_rule_add(const char* filter, enum statd_destination destination);
|
||||
|
||||
/* Destroy all rules */
|
||||
void statd_rule_destroy_all();
|
||||
|
||||
/* Get first rule. Useful for looping over all rules */
|
||||
struct statd_rule *statd_rule_get_head();
|
||||
|
||||
/* Get ubus filter for rule */
|
||||
const char *statd_rule_get_filter(const struct statd_rule *rule);
|
||||
|
||||
/* Get log destination for rule */
|
||||
enum statd_destination statd_rule_get_destination(const struct statd_rule *rule);
|
||||
|
||||
/* Get next rule in list */
|
||||
struct statd_rule *statd_rule_get_next(const struct statd_rule *rule);
|
||||
|
||||
/* Returns true if current rule has a next */
|
||||
int statd_rule_has_next(const struct statd_rule *rule);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,8 +1,20 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=tptest
|
||||
PKG_RELEASE:=0
|
||||
PKG_VERSION:=1.3
|
||||
PKG_RELEASE:=0
|
||||
|
||||
PKG_SOURCE_VERSION:=4dfab45a92328226c8182347df50e86a5d72ca5f
|
||||
PKG_SOURCE_PROTO:=git
|
||||
ifeq ($(CONFIG_BCM_OPEN),y)
|
||||
PKG_SOURCE_URL:=http://public.inteno.se/tptest
|
||||
else
|
||||
PKG_SOURCE_URL:=git@public.inteno.se:tptest
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
|
@ -27,11 +39,6 @@ define Package/tptest/description
|
|||
TPTEST speed test utility
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
$(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) MAKE_OPTS=$(MAKE_OPTS) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
TPTEST engine changelog
|
||||
-----------------------
|
||||
|
||||
|
||||
Version 3.15:
|
||||
|
||||
- Modified TPEngine struct to include "UINT32 start_tcpsend_bytes" and
|
||||
"UINT32 start_tcprecv_bytes", which are used by tpclient.c:AdvanceTest()
|
||||
as start values for tcpBytes when doing TCP send and receive tests.
|
||||
Previously, the values were a #define (START_TCP_BYTES).
|
||||
|
||||
This modification allows a (TPTEST/Statistik) client program to perform
|
||||
auto-TCP tests more effectively.
|
||||
|
||||
- Added "char email[101]" and "char pwd[101]" to TPEngine struct.
|
||||
(more TPTEST/Statistik support).
|
||||
|
||||
- Stat reports now include "email=x;pwd=y" also, no matter if email or
|
||||
pwd exists/is used or not.
|
||||
|
||||
- New test modes supported by AdvanceTest():
|
||||
M_TCP_AUTO, M_TCP_AUTO_SEND, M_TCP_AUTO_RECV
|
||||
|
||||
|
||||
Version 3.16:
|
||||
|
||||
- Added "int socket_sndbuf, socket_rcvbuf, cur_socket_sndbuf, cur_socket_rcvbuf"
|
||||
to TPEngine struct. socket_sndbuf/socket_rcvbuf are used by the application
|
||||
to tell the IO module that it would like certain SO_SNDBUF/SO_RCVBUF values
|
||||
set for data sockets (only. The control socket will use default values for
|
||||
SO_SNDBUF/SO_RCVBUF). If the IO module sees that these variables are non-zero
|
||||
it should try to set the send- and receive buffers for new data sockets
|
||||
accordingly. The IO module should also do a getsockopt() or similar, asking
|
||||
for the actual SO_SNDBUF/SO_RCVBUF values used (after trying to set them) and
|
||||
store the results in cur_socket_rcvbuf/cur_socket_sndbuf. The application may
|
||||
then determine what buffer settings were actually used for the test.
|
||||
|
||||
Note that data sockets aren't created by the engine until a test has been
|
||||
initiated and test parameters have been negotiated between client and server.
|
||||
This means that an application has to e.g. wait until the engine state is
|
||||
"engp->state == CLSM_TESTLOOP" before checking what actual values for
|
||||
SO_SNDBUF/SO_RCVBUF are used.
|
||||
|
||||
Also worth knowing is that SO_SNDBUF and SO_RCVBUF are used by most Unix-like
|
||||
OS's to determine TCP window size. Setting both values to e.g. 65536 on both
|
||||
the client and server side will cause the machines to negotiate that value
|
||||
for the TCP window size when the data connection is set up in a TCP test.
|
||||
|
||||
|
||||
|
|
@ -1,459 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
CC = gcc
|
||||
MAKEDEPEND = makedepend
|
||||
CDEBUG = -g
|
||||
EXTRADEFINES = -DUNIX -DLINUX
|
||||
CFLAGS = ${CDEBUG} ${EXTRADEFINES} ${INCL} -Wall
|
||||
LDFLAGS = ${CDEBUG}
|
||||
LIBDIR =
|
||||
LOCLIBS =
|
||||
LIBS = ${LOCLIBS} ${SYSLIBS}
|
||||
OBJS = tpio_unix.o tpengine.o tpcommon.o client.o tpclient.o getopt.o
|
||||
SRCS = tpio_unix.c tpengine.c tpcommon.c client.c tpclient.c getopt.c
|
||||
LIBSRCS =
|
||||
ISRCS = tpengine.h tpio.h tpio_unix.h server.h tpclient.h
|
||||
ALLSRCS = ${SRCS} ${ISRCS} ${LIBSRCS}
|
||||
|
||||
all: tptest
|
||||
|
||||
tptest: ${OBJS}
|
||||
${CC} ${LDFLAGS} -o tptest ${OBJS} ${LIBDIR} ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f tptest core *.o *.BAK *.bak *.CKP a.out
|
||||
|
||||
depend:
|
||||
${MAKEDEPEND} ${INCL} ${SRCS} ${LIBSRCS}
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
$Id: README,v 1.1 2002/09/12 19:28:38 rlonn Exp $
|
||||
$Source: /cvsroot/tptest/os-dep/unix/README,v $
|
||||
|
||||
tpio_unix is the platform-dependent communications module for Unix.
|
||||
It has been compiled and tested on Solaris 2.8, Redhat Linux 7.0,
|
||||
OpenBSD 2.7 and NetBSD 1.5.
|
||||
|
||||
To build tpio_unix.o
|
||||
|
||||
Do:
|
||||
|
||||
On Solaris: gcc -c tpio_unix.c -DUNIX -DSOLARIS
|
||||
On *BSD: gcc -c tpio_unix.c -DUNIX -DOPENBSD
|
||||
On Linux: gcc -c tpio_unix.c -DUNIX -DLINUX
|
||||
|
||||
The resulting tpio_unix.o is used together with the test engine files
|
||||
(tpengine.o, tpcommon.o, tpclient.o) to create clients and servers.
|
||||
|
||||
|
||||
|
|
@ -1,578 +0,0 @@
|
|||
/*
|
||||
* $Id: client.c,v 1.6 2004/05/17 15:11:55 rlonn Exp $
|
||||
* $Source: /cvsroot/tptest/apps/unix/client/client.c,v $
|
||||
*
|
||||
* TPTEST 3.0 (C) Copyright II-Stiftelsen 2002
|
||||
*
|
||||
* client.c - TPTEST 3.0 client
|
||||
*
|
||||
* Written by
|
||||
* Ragnar Lönn <prl@gatorhole.com>
|
||||
*
|
||||
* This file is part of the TPTEST system.
|
||||
* See the file LICENSE for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "tpengine.h"
|
||||
#include "tpcommon.h"
|
||||
#include "tpclient.h"
|
||||
#include "tpio.h"
|
||||
|
||||
/* globals */
|
||||
int verbosity = 0;
|
||||
int syslog_verbosity = 0;
|
||||
int no_output = 0;
|
||||
int is_v4 = 0;
|
||||
int use_delay = 0;
|
||||
int repeat = 1;
|
||||
char output_text[400];
|
||||
|
||||
/* prototypes */
|
||||
void usage(char *);
|
||||
void log_error(char *);
|
||||
void log_text(int);
|
||||
LONG_LONG timediff(struct timeval *, struct timeval *);
|
||||
void ReportResults(int, TPEngine *, time_t *, time_t *);
|
||||
|
||||
void usage(char *s) {
|
||||
printf("Usage: tptestclient [options] <-m mode> <parameters> <address> <port>\n");
|
||||
printf("\n");
|
||||
printf("options: <> = required argument, [] = optional argument\n");
|
||||
printf(" -b <local address> Bind to local address/interface\n");
|
||||
printf(" -n <repetitions> Repeat test n number of times (0 = infinite)\n");
|
||||
printf(" -v <verbosity> Set verbosity level\n");
|
||||
printf(" -s <verbosity> Set syslog verbosity level\n");
|
||||
printf(" -e <email> Set email for TPTEST/Statistik\n");
|
||||
printf(" -p <password> Set password for TPTEST/Statistik\n");
|
||||
printf(" -d <delaytime> Set delaytime between repeated tests\n");
|
||||
printf(" -S <sendbuf size> Set size of socket send buffer\n");
|
||||
printf(" -R <recvbuf size> Set size of socket receive buffer\n");
|
||||
printf(" -t No text output\n");
|
||||
printf("\n");
|
||||
printf("test modes & parameters:\n");
|
||||
printf(" udp-send | us UDP send to server\n");
|
||||
printf(" parameters: <testtime> <bitrate>\n");
|
||||
printf(" parameters: <testtime> <packetsize> <packets/sec>\n");
|
||||
printf(" udp-receive | ur UDP receive from server\n");
|
||||
printf(" parameters: <testtime> <bitrate>\n");
|
||||
printf(" parameters: <testtime> <packetsize> <packets/sec>\n");
|
||||
printf(" udp-fdx | uf UDP full duplex\n");
|
||||
printf(" parameters: <testtime> <bitrate>\n");
|
||||
printf(" parameters: <testtime> <packetsize> <packets/sec>\n");
|
||||
printf(" tcp-send | ts TCP send to server\n");
|
||||
printf(" parameters: <max testtime> <bytes to send>\n");
|
||||
printf(" tcp-receive | tr TCP receive from server\n");
|
||||
printf(" parameters: <max testtime> <bytes to receive>\n");
|
||||
printf(" tcp-send-auto | tsa TCP auto send to server\n");
|
||||
printf(" tcp-receive-auto | tra TCP auto receive from server\n");
|
||||
printf(" tcp-auto | ta TCP auto (auto send + auto receive)\n");
|
||||
printf("\n");
|
||||
if (strlen(s)) {
|
||||
printf("%s\n", s);
|
||||
}
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
TPEngine *engp;
|
||||
int selectedMode, ch;
|
||||
int succeeds = 0;
|
||||
int fails = 0;
|
||||
int not_checked = 1;
|
||||
int delay = 30;
|
||||
double tmp;
|
||||
struct timespec sleeptime;
|
||||
time_t starttime, stoptime;
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/* 0.5 sec wait between automatic tests */
|
||||
sleeptime.tv_sec = 0;
|
||||
sleeptime.tv_nsec = 500000000;
|
||||
|
||||
/* create engine context */
|
||||
engp = CreateContext();
|
||||
|
||||
/* check command line arguments */
|
||||
while ((ch = getopt(argc, argv, "m:b:v:s:n:e:p:d:S:R:t")) != -1) {
|
||||
switch (ch) {
|
||||
case 'm':
|
||||
if (strcasecmp(optarg, "udp-send")==0 || strcasecmp(optarg, "us")==0)
|
||||
selectedMode = CLM_UDP_SEND;
|
||||
else if (strcasecmp(optarg, "udp-receive")==0 || strcasecmp(optarg, "ur")==0)
|
||||
selectedMode = CLM_UDP_RECV;
|
||||
else if (strcasecmp(optarg, "udp-full-duplex")==0 || strcasecmp(optarg, "uf")==0)
|
||||
selectedMode = CLM_UDP_FDX;
|
||||
else if (strcasecmp(optarg, "tcp-send")==0 || strcasecmp(optarg, "ts")==0)
|
||||
selectedMode = CLM_TCP_SEND;
|
||||
else if (strcasecmp(optarg, "tcp-receive")==0 || strcasecmp(optarg, "tr")==0)
|
||||
selectedMode = CLM_TCP_RECV;
|
||||
else if (strcasecmp(optarg, "tcp-send-auto")==0 || strcasecmp(optarg, "tsa")==0)
|
||||
selectedMode = CLM_AUTO_TCP_SEND;
|
||||
else if (strcasecmp(optarg, "tcp-receive-auto")==0 || strcasecmp(optarg, "tra")==0)
|
||||
selectedMode = CLM_AUTO_TCP_RECV;
|
||||
else if (strcasecmp(optarg, "tcp-auto")==0 || strcasecmp(optarg, "ta")==0)
|
||||
selectedMode = CLM_AUTO_TCP;
|
||||
else {
|
||||
/* error, no mode supplied */
|
||||
usage("Error: no test mode supplied");
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (inet_addr(optarg) != INADDR_NONE)
|
||||
engp->myLocalAddress.s_addr = inet_addr(optarg);
|
||||
else {
|
||||
/* error - invalid IP address */
|
||||
usage("Error: invalid IP address argument for -b option");
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
engp->socket_sndbuf = atoi(optarg);
|
||||
if (engp->socket_sndbuf == 0) {
|
||||
usage("Error: invalid socket send buffer size\n");
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
engp->socket_rcvbuf = atoi(optarg);
|
||||
if (engp->socket_rcvbuf == 0) {
|
||||
usage("Error: invalid socket receive buffer size\n");
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
no_output = 1;
|
||||
break;
|
||||
case 'e':
|
||||
strncpy(engp->stats.email, optarg, 99);
|
||||
engp->stats.email[99] = '\0';
|
||||
is_v4 = 1;
|
||||
break;
|
||||
case 'd':
|
||||
delay = atoi(optarg);
|
||||
use_delay = 1;
|
||||
break;
|
||||
case 'p':
|
||||
strncpy(engp->stats.pwd, optarg, 99);
|
||||
engp->stats.pwd[99] = '\0';
|
||||
is_v4 = 1;
|
||||
break;
|
||||
case 'n':
|
||||
repeat = atoi(optarg);
|
||||
if (repeat == 0 && optarg[0] != '0') {
|
||||
/* error. non-number argument */
|
||||
usage("Error: invalid argument to -n option");
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
verbosity = atoi(optarg);
|
||||
if (verbosity == 0 && optarg[0] != '0') {
|
||||
/* error - missing argument */
|
||||
usage("Error: invalid argument to -v option");
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
syslog_verbosity = atoi(optarg);
|
||||
if (syslog_verbosity == 0 && optarg[0] != '0') {
|
||||
/* error - missing argument */
|
||||
usage("Error: invalid argument to -s option");
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage("Error: command line syntax error");
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* check test params for individual tests */
|
||||
switch (selectedMode) {
|
||||
case CLM_UDP_SEND:
|
||||
case CLM_UDP_RECV:
|
||||
case CLM_UDP_FDX:
|
||||
/* determine test params */
|
||||
if (argc == 4) {
|
||||
engp->sessionTime = atoi(argv[0]);
|
||||
engp->bitsPerSecond = atoi(argv[1]);
|
||||
strncpy(engp->hostName, argv[2], TP_HOST_NAME_SIZE);
|
||||
engp->hostCtrlPort = atoi(argv[3]);
|
||||
RecalculatePPSSZ(engp);
|
||||
}
|
||||
else if (argc == 5) {
|
||||
engp->sessionTime = atoi(argv[0]);
|
||||
engp->packetSize = atoi(argv[1]);
|
||||
engp->packetsPerSecond = atoi(argv[2]);
|
||||
strncpy(engp->hostName, argv[3], TP_HOST_NAME_SIZE);
|
||||
engp->hostCtrlPort = atoi(argv[4]);
|
||||
}
|
||||
/* check that we have necessary values */
|
||||
if (engp->sessionTime == 0)
|
||||
usage("Error: no test session time set");
|
||||
if (engp->bitsPerSecond == 0) {
|
||||
if (engp->packetsPerSecond == 0 || engp->packetSize == 0)
|
||||
usage("Error: no bitrate (or packet size + packet rate) set");
|
||||
}
|
||||
break;
|
||||
case CLM_TCP_SEND:
|
||||
case CLM_TCP_RECV:
|
||||
if (argc == 4) {
|
||||
engp->sessionMaxTime = atoi(argv[0]);
|
||||
engp->tcpBytes = atoi(argv[1]);
|
||||
strncpy(engp->hostName, argv[2], TP_HOST_NAME_SIZE);
|
||||
engp->hostCtrlPort = atoi(argv[3]);
|
||||
}
|
||||
if (engp->sessionMaxTime == 0)
|
||||
usage("Error: no max time set for test session");
|
||||
if (engp->tcpBytes == 0)
|
||||
usage("Error: number of TCP bytes to transfer not set");
|
||||
break;
|
||||
case CLM_AUTO_TCP_SEND:
|
||||
case CLM_AUTO_TCP_RECV:
|
||||
case CLM_AUTO_TCP:
|
||||
if (argc == 2) {
|
||||
strncpy(engp->hostName, argv[0], TP_HOST_NAME_SIZE);
|
||||
engp->hostCtrlPort = atoi(argv[1]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
usage("Error: unknown test mode");
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
/* error - need server and server port as commandline args */
|
||||
usage("Error: need server address and control port");
|
||||
}
|
||||
|
||||
if (engp->hostCtrlPort == 0) {
|
||||
/* error - invalid server port argument */
|
||||
usage("Error: invalid server control port argument");
|
||||
}
|
||||
|
||||
/* check server address argument */
|
||||
if (inet_addr(engp->hostName) == INADDR_NONE) {
|
||||
struct hostent * hent;
|
||||
hent = gethostbyname(engp->hostName);
|
||||
if (hent == NULL) {
|
||||
log_error("Error: hostname lookup failed");
|
||||
exit(1);
|
||||
}
|
||||
engp->hostIP.s_addr = ((struct in_addr *)(hent->h_addr))->s_addr;
|
||||
}
|
||||
else
|
||||
engp->hostIP.s_addr = inet_addr(engp->hostName);
|
||||
|
||||
engp->tpMode = CLM_NONE;
|
||||
|
||||
/* init syslog, if we want that facility */
|
||||
if (syslog_verbosity) {
|
||||
openlog("tptestclient", LOG_CONS | LOG_PID, LOG_USER);
|
||||
}
|
||||
|
||||
engp->stats.MajorVersion = MAJORVERSION;
|
||||
engp->stats.MinorVersion = MINORVERSION;
|
||||
|
||||
if (is_v4) {
|
||||
delay = 30;
|
||||
use_delay = 1;
|
||||
}
|
||||
|
||||
/* ********************************* */
|
||||
/* Main loop. May run multiple tests */
|
||||
/* ********************************* */
|
||||
|
||||
while (1) {
|
||||
|
||||
time(&starttime);
|
||||
|
||||
/* Inner main loop. This loop runs individual tests or auto-tests */
|
||||
|
||||
while (1) {
|
||||
|
||||
/* use AdvanceTest() to set test params and new test mode */
|
||||
engp->tpMode = AdvanceTest(engp, selectedMode, engp->tpMode, 0);
|
||||
if (engp->tpMode == CLM_NONE)
|
||||
break;
|
||||
|
||||
/* initiate new test */
|
||||
if (StartClientContext(engp) != 0) {
|
||||
log_error("Error: StartClientContext() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
not_checked = 1;
|
||||
|
||||
if (engp->tpMode == CLM_TCP_SEND || engp->tpMode == CLM_TCP_RECV) {
|
||||
sprintf(output_text, "Server: %s:%u Test:%d Time:%u Maxtime:%u Bytes: %u\n",
|
||||
inet_ntoa(engp->hostIP), engp->hostCtrlPort,
|
||||
(int)engp->tpMode, (unsigned int)engp->sessionTime,
|
||||
(unsigned int)engp->sessionMaxTime, (unsigned int)engp->tcpBytes);
|
||||
}
|
||||
else {
|
||||
sprintf(output_text, "Server: %s:%u Test:%d Time:%u Maxtime:%u Bitrate: %s\n",
|
||||
inet_ntoa(engp->hostIP), engp->hostCtrlPort,
|
||||
(int)engp->tpMode, (unsigned int)engp->sessionTime,
|
||||
(unsigned int)engp->sessionMaxTime, Int32ToString(engp->bitsPerSecond));
|
||||
}
|
||||
log_text(2);
|
||||
|
||||
/* run test until finished or an error occurs */
|
||||
while (1) {
|
||||
if (engp->state == CLSM_FAILED) {
|
||||
/* Backoff algorithm to avoid overloading the servers. */
|
||||
/* If we fail more than 2 consecutive times, we increase */
|
||||
/* the delay between tests. If we succeed more than two */
|
||||
/* consecutive times, we decrease the delay between tests */
|
||||
/* (down to a minimum of 30 seconds) */
|
||||
if (is_v4) {
|
||||
succeeds = 0;
|
||||
if (++fails > 2) {
|
||||
delay += 30;
|
||||
fails = 0;
|
||||
}
|
||||
}
|
||||
sprintf(output_text, "Test failed. Failcode:%d Ioerror:%d\n",
|
||||
(int)engp->failCode, (int)engp->ioError);
|
||||
log_text(0);
|
||||
break;
|
||||
}
|
||||
else if (engp->state == CLSM_COMPLETE) {
|
||||
/* more backoff stuff */
|
||||
if (is_v4) {
|
||||
fails = 0;
|
||||
if (++succeeds > 2) {
|
||||
delay -= 30;
|
||||
if (delay < 30)
|
||||
delay = 30;
|
||||
succeeds = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (engp->state == CLSM_TESTLOOP && not_checked) {
|
||||
not_checked = 0;
|
||||
if (engp->socket_sndbuf != 0) {
|
||||
sprintf(output_text, "Wanted SO_SNDBUF: %d Actual SO_SNDBUF: %d\n",
|
||||
engp->socket_sndbuf, engp->cur_socket_sndbuf); log_text(2);
|
||||
}
|
||||
if (engp->socket_rcvbuf != 0) {
|
||||
sprintf(output_text, "Wanted SO_RCVBUF: %d Actual SO_RCVBUF: %d\n",
|
||||
engp->socket_rcvbuf, engp->cur_socket_rcvbuf); log_text(2);
|
||||
}
|
||||
}
|
||||
RunClientContext(engp);
|
||||
}
|
||||
|
||||
if (engp->state == CLSM_COMPLETE &&
|
||||
(selectedMode != CLM_UDP_SEND &&
|
||||
selectedMode != CLM_UDP_RECV &&
|
||||
selectedMode != CLM_UDP_FDX) ) {
|
||||
tmp = (engp->stats.BytesRecvd * 8.0) /
|
||||
timediff(&engp->stats.StartRecv, &engp->stats.StopRecv);
|
||||
sprintf(output_text, "Received %u/%u bytes in %0.2f seconds.\n",
|
||||
(unsigned int)engp->stats.BytesRecvd, (unsigned int)engp->tcpBytes,
|
||||
(double)timediff(&engp->stats.StartRecv, &engp->stats.StopRecv) / 1000000.0);
|
||||
log_text(2);
|
||||
}
|
||||
|
||||
/* sleep 0.5 seconds before starting next test, if any */
|
||||
nanosleep(&sleeptime, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* note when this test stopped */
|
||||
|
||||
time(&stoptime);
|
||||
|
||||
/* Update starting values for TCP tests so future tests will find */
|
||||
/* optimal value for tcpBytes quicker */
|
||||
|
||||
if (engp->bestTCPRecvRate > 0.0)
|
||||
engp->start_tcprecv_bytes = engp->bestTCPRecvRate * 20;
|
||||
if (engp->bestTCPSendRate > 0.0)
|
||||
engp->start_tcpsend_bytes = engp->bestTCPSendRate * 20;
|
||||
|
||||
/* report results */
|
||||
ReportResults(selectedMode, engp, &starttime, &stoptime);
|
||||
|
||||
/* perform more tests or quit? */
|
||||
if (repeat != 0) {
|
||||
if (--repeat <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* perform more tests */
|
||||
engp->tpMode = CLM_NONE;
|
||||
engp->bestTCPRecvRate = 0.0f;
|
||||
engp->bestTCPSendRate = 0.0f;
|
||||
engp->bestUDPRecvRate = 0.0f;
|
||||
engp->bestUDPSendRate = 0.0f;
|
||||
|
||||
if (use_delay) {
|
||||
sprintf(output_text, "Sleeping %d seconds until next test...\n", delay); log_text(2);
|
||||
sleep(delay);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void log_text(int level) {
|
||||
if (no_output) return;
|
||||
if (syslog_verbosity >= level)
|
||||
syslog(LOG_NOTICE, output_text);
|
||||
if (verbosity >= level)
|
||||
printf(output_text);
|
||||
}
|
||||
|
||||
|
||||
void ReportResults(int selectedMode, TPEngine *engp, time_t * starttime, time_t * stoptime) {
|
||||
int throughput;
|
||||
LONG_LONG recvtime;
|
||||
struct tm *tmPnt;
|
||||
|
||||
sprintf(output_text, "Test results:\n"); log_text(1);
|
||||
sprintf(output_text, "-------------\n"); log_text(1);
|
||||
sprintf(output_text, "Server: %s:%d\n", inet_ntoa(engp->hostIP), engp->hostCtrlPort); log_text(1);
|
||||
sprintf(output_text, "Test: %d\n", selectedMode); log_text(1);
|
||||
|
||||
if (selectedMode == CLM_UDP_SEND || selectedMode == CLM_UDP_RECV ||
|
||||
selectedMode == CLM_TCP_SEND || selectedMode == CLM_TCP_RECV ||
|
||||
selectedMode == CLM_UDP_FDX) {
|
||||
sprintf(output_text, "Time: %lu Timelimit: %lu\n",
|
||||
engp->sessionTime, engp->sessionMaxTime); log_text(1);
|
||||
}
|
||||
|
||||
sprintf(output_text, "Test started: %s", ctime(starttime)); log_text(1);
|
||||
sprintf(output_text, "Test ended: %s", ctime(stoptime)); log_text(1);
|
||||
|
||||
/* report results from an auto test (series of tests) */
|
||||
|
||||
if (selectedMode == CLM_AUTO_TCP || selectedMode == CLM_AUTO_TCP_SEND) {
|
||||
/* report best TCP SEND results */
|
||||
sprintf(output_text, "TCP Send: %d bps (%s)\n",
|
||||
(int)(engp->bestTCPSendRate * 8.0), Int32ToString((int)(engp->bestTCPSendRate * 8.0)));
|
||||
log_text(0);
|
||||
}
|
||||
if (selectedMode == CLM_AUTO_TCP || selectedMode == CLM_AUTO_TCP_RECV) {
|
||||
/* report best TCP RECV results */
|
||||
sprintf(output_text, "TCP Recv: %d bps (%s)\n",
|
||||
(int)(engp->bestTCPRecvRate * 8.0), Int32ToString((int)(engp->bestTCPRecvRate * 8.0)));
|
||||
log_text(0);
|
||||
}
|
||||
if (selectedMode == CLM_AUTO_TCP_SEND || selectedMode == CLM_AUTO_TCP_RECV ||
|
||||
selectedMode == CLM_AUTO_TCP) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* report results from an individual test */
|
||||
|
||||
if (selectedMode == CLM_TCP_SEND || selectedMode == CLM_TCP_RECV) {
|
||||
sprintf(output_text, "TCP Bytes: %lu\n", engp->tcpBytes); log_text(1);
|
||||
}
|
||||
else {
|
||||
sprintf(output_text, "# of packets: %lu\n", engp->nPackets); log_text(1);
|
||||
sprintf(output_text, "Packetsize: %lu\n", engp->packetSize); log_text(1);
|
||||
}
|
||||
|
||||
tmPnt = localtime( (time_t *)(&engp->stats.StartSend.tv_sec) );
|
||||
sprintf(output_text, "Send start: %04d-%02d-%02d %02d:%02d:%02d.%03ld\n",
|
||||
tmPnt->tm_year + 1900, tmPnt->tm_mon + 1, tmPnt->tm_mday,
|
||||
tmPnt->tm_hour, tmPnt->tm_min, tmPnt->tm_sec,
|
||||
engp->stats.StartSend.tv_usec / 1000L ); log_text(1);
|
||||
|
||||
tmPnt = localtime( (time_t *)(&engp->stats.StopSend.tv_sec) );
|
||||
sprintf(output_text, "Send stop : %04d-%02d-%02d %02d:%02d:%02d.%03ld\n",
|
||||
tmPnt->tm_year + 1900, tmPnt->tm_mon + 1, tmPnt->tm_mday,
|
||||
tmPnt->tm_hour, tmPnt->tm_min, tmPnt->tm_sec,
|
||||
engp->stats.StopSend.tv_usec / 1000L ); log_text(1);
|
||||
|
||||
tmPnt = localtime( (time_t *)(&engp->stats.StartRecv.tv_sec) );
|
||||
sprintf(output_text, "Recv start: %04d-%02d-%02d %02d:%02d:%02d.%03ld\n",
|
||||
tmPnt->tm_year + 1900, tmPnt->tm_mon + 1, tmPnt->tm_mday,
|
||||
tmPnt->tm_hour, tmPnt->tm_min, tmPnt->tm_sec,
|
||||
engp->stats.StartRecv.tv_usec / 1000L ); log_text(1);
|
||||
|
||||
tmPnt = localtime( (time_t *)(&engp->stats.StopRecv.tv_sec) );
|
||||
sprintf(output_text, "Recv stop : %04d-%02d-%02d %02d:%02d:%02d.%03ld\n",
|
||||
tmPnt->tm_year + 1900, tmPnt->tm_mon + 1, tmPnt->tm_mday,
|
||||
tmPnt->tm_hour, tmPnt->tm_min, tmPnt->tm_sec,
|
||||
engp->stats.StopRecv.tv_usec / 1000L ); log_text(1);
|
||||
|
||||
if (selectedMode == CLM_UDP_SEND || selectedMode == CLM_UDP_RECV || selectedMode == CLM_UDP_FDX) {
|
||||
sprintf(output_text, "Packets sent: %lu\n", engp->stats.PktsSent); log_text(1);
|
||||
sprintf(output_text, "Packets received: %lu\n", engp->stats.PktsRecvd); log_text(1);
|
||||
sprintf(output_text, "Packets lost: %lu (%0.2f%%)\n", engp->stats.PktsSent - engp->stats.PktsRecvd,
|
||||
((float)(engp->stats.PktsSent - engp->stats.PktsRecvd) / (float)engp->stats.PktsSent) * 100.0);
|
||||
log_text(1);
|
||||
sprintf(output_text, "Packets unsent: %lu\n", engp->stats.PktsUnSent); log_text(1);
|
||||
sprintf(output_text, "OO Packets: %lu\n", engp->stats.ooCount); log_text(1);
|
||||
if (selectedMode == CLM_UDP_FDX) {
|
||||
if (engp->stats.nRoundtrips > 0) {
|
||||
sprintf(output_text, "Max roundtrip: %0.3fms\n",
|
||||
(double)engp->stats.MaxRoundtrip / 1000.0); log_text(1);
|
||||
sprintf(output_text, "Min roundtrip: %0.3fms\n",
|
||||
(double)engp->stats.MinRoundtrip / 1000.0); log_text(1);
|
||||
sprintf(output_text, "Avg roundtrip: %0.3fms\n",
|
||||
((double)engp->stats.TotalRoundtrip / (double)engp->stats.nRoundtrips) / 1000.0); log_text(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
sprintf(output_text, "Bytes sent: %" LONG_LONG_PREFIX "d\n", engp->stats.BytesSent); log_text(1);
|
||||
sprintf(output_text, "Bytes rcvd: %" LONG_LONG_PREFIX "d\n", engp->stats.BytesRecvd); log_text(1);
|
||||
recvtime = timediff(&engp->stats.StartRecv, &engp->stats.StopRecv);
|
||||
if (recvtime > 0)
|
||||
throughput = (int)((double)(engp->stats.BytesRecvd * 8)/((double)recvtime / 1000000.0));
|
||||
else
|
||||
throughput = 0;
|
||||
sprintf(output_text, "Throughput: %d bps (%s)\n", (int)throughput, Int32ToString((int)throughput));
|
||||
log_text(0);
|
||||
}
|
||||
|
||||
LONG_LONG timediff(struct timeval * tv1, struct timeval * tv2) {
|
||||
LONG_LONG t1, t2;
|
||||
t1 = (LONG_LONG)tv1->tv_sec * (LONG_LONG)1000000 +
|
||||
(LONG_LONG)tv1->tv_usec;
|
||||
t2 = (LONG_LONG)tv2->tv_sec * (LONG_LONG)1000000 +
|
||||
(LONG_LONG)tv2->tv_usec;
|
||||
return t1 > t2 ? t1 - t2 : t2 - t1;
|
||||
}
|
||||
|
||||
void log_error(char *str) {
|
||||
fprintf(stderr, "%s\n", str);
|
||||
if (syslog_verbosity)
|
||||
syslog(LOG_ERR, "%s\n", str);
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
#ifndef UNIX
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
/*
|
||||
* static char sccsid[] = "from: @(#)getopt.c 8.2 (Berkeley) 4/2/94";
|
||||
*/
|
||||
static char *rcsid =
|
||||
"$Id: getopt.c,v 1.1 2004/04/07 13:23:00 rlonn Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _BSD
|
||||
extern char *__progname;
|
||||
#else
|
||||
#define __progname "getopt"
|
||||
#endif
|
||||
|
||||
int opterr = 1, /* if error message should be printed */
|
||||
optind = 1, /* index into parent argv vector */
|
||||
optopt, /* character checked for validity */
|
||||
optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
char EMSG[] = "";
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt(int nargc, char *const *nargv, const char *ostr)
|
||||
{
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-') { /* found "--" */
|
||||
++optind;
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int) *place++) == (int) ':' ||
|
||||
!(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int) '-')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void) fprintf(stderr,
|
||||
"%s: illegal option -- %c\n", __progname,
|
||||
optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
} else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if (*ostr == ':')
|
||||
return (BADARG);
|
||||
if (opterr)
|
||||
(void) fprintf(stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
__progname, optopt);
|
||||
return (BADCH);
|
||||
} else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* dump back option letter */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,552 +0,0 @@
|
|||
/*
|
||||
* $Id: tpclient.c,v 1.9 2004/03/22 20:49:12 rlonn Exp $
|
||||
* $Source: /cvsroot/tptest/engine/tpclient.c,v $
|
||||
*
|
||||
* TPTEST 3.0 (C) Copyright II-Stiftelsen 2002
|
||||
*
|
||||
* tpclient.c - test client support functions
|
||||
*
|
||||
* Written by
|
||||
* Ragnar Lönn <prl@gatorhole.com>
|
||||
*
|
||||
* This file is part of the TPTEST system.
|
||||
* See the file LICENSE for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "tpclient.h"
|
||||
#include "tpengine.h"
|
||||
|
||||
void RecalculatePPSSZ(TPEngine *);
|
||||
int AdvanceTest(TPEngine *, int, int, int);
|
||||
|
||||
#ifdef UNIX
|
||||
double min(double a, double b) { return a < b ? a : b; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
// Recalculate good PPS and Packetsize values after the user has changed
|
||||
// the desired data rate. Most modern PCs can output several thousand UDP packets
|
||||
// per second without stalling due to CPU shortage so I have changed the old
|
||||
// behaviour somewhat: this program increases the packetsize up to 1400
|
||||
// bytes then starts increasing the packet rate until it reaches 3000 pps.
|
||||
// It doesn't continue increasing the packet size before reaching 3000 pps.
|
||||
// This function also decreases packet rate and size until the data rate
|
||||
// matches the desired data rate as closely as possible.
|
||||
//
|
||||
*/
|
||||
|
||||
void RecalculatePPSSZ(TPEngine *engp)
|
||||
{
|
||||
if (engp->bitsPerSecond >
|
||||
(engp->packetsPerSecond * engp->packetSize * 8)) {
|
||||
while (engp->bitsPerSecond > (engp->packetsPerSecond * engp->packetSize * 8)) {
|
||||
while (engp->packetsPerSecond < 20) {
|
||||
engp->packetsPerSecond++;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetSize < 1400) {
|
||||
engp->packetSize++;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetsPerSecond < 3000) {
|
||||
engp->packetsPerSecond++;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetSize < 32000) {
|
||||
engp->packetSize++;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetsPerSecond < 6000) {
|
||||
engp->packetsPerSecond++;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetSize < 65000) {
|
||||
engp->packetSize++;
|
||||
continue;
|
||||
}
|
||||
engp->packetsPerSecond++;
|
||||
}
|
||||
}
|
||||
else if (engp->bitsPerSecond < (engp->packetsPerSecond * engp->packetSize * 8)) {
|
||||
while (engp->bitsPerSecond < (engp->packetsPerSecond * engp->packetSize * 8)) {
|
||||
if (engp->packetsPerSecond > 6000) {
|
||||
engp->packetsPerSecond--;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetSize > 32000) {
|
||||
engp->packetSize--;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetsPerSecond > 3000) {
|
||||
engp->packetsPerSecond--;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetSize > 1400) {
|
||||
engp->packetSize--;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetsPerSecond > 20) {
|
||||
engp->packetsPerSecond--;
|
||||
continue;
|
||||
}
|
||||
if (engp->packetSize > MIN_PKT_SIZE) {
|
||||
engp->packetSize--;
|
||||
continue;
|
||||
}
|
||||
engp->packetsPerSecond--;
|
||||
}
|
||||
}
|
||||
// Lower value so we don't *exceed* selected datarate
|
||||
while ((engp->packetsPerSecond * engp->packetSize * 8) > engp->bitsPerSecond)
|
||||
{
|
||||
if (engp->packetsPerSecond > 10 || engp->packetSize == 60)
|
||||
engp->packetsPerSecond--;
|
||||
else
|
||||
engp->packetSize--;
|
||||
}
|
||||
|
||||
engp->nPackets = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int AdvanceTest(TPEngine * engp, int SelMode, int Cur, int LastRet)
|
||||
{
|
||||
double BytesPerSecondRecv;
|
||||
|
||||
static double LastBytesPerSecondRecv = 0;
|
||||
static double bestTCPSendRate = 0;
|
||||
static double bestTCPRecvRate = 0;
|
||||
static double bestUDPSendRate = 0;
|
||||
static double bestUDPRecvRate = 0;
|
||||
|
||||
int msRecv;
|
||||
|
||||
if (Cur != CLM_NONE) {
|
||||
msRecv = ( engp->stats.StopRecv.tv_sec - engp->stats.StartRecv.tv_sec ) * 1000;
|
||||
msRecv += ( engp->stats.StopRecv.tv_usec - engp->stats.StartRecv.tv_usec ) / 1000;
|
||||
|
||||
if( msRecv != 0 )
|
||||
BytesPerSecondRecv = ( (double)(engp->stats.BytesRecvd) * 1000.0 )
|
||||
/ (double)(msRecv);
|
||||
else
|
||||
BytesPerSecondRecv = 0.0;
|
||||
}
|
||||
else {
|
||||
LastBytesPerSecondRecv = 0;
|
||||
bestTCPSendRate = bestTCPRecvRate = bestUDPSendRate = bestUDPRecvRate = 0.0;
|
||||
}
|
||||
|
||||
switch (SelMode) {
|
||||
|
||||
case CLM_AUTO:
|
||||
switch (Cur) {
|
||||
case CLM_NONE:
|
||||
engp->tcpBytes = engp->start_tcpsend_bytes;
|
||||
engp->sessionMaxTime = 60;
|
||||
LastBytesPerSecondRecv = 0.0;
|
||||
return CLM_TCP_SEND;
|
||||
case CLM_TCP_SEND:
|
||||
if (msRecv < 18000 && LastRet == 0) {
|
||||
// aim for 20 secs if last receive time was > 1 sec
|
||||
// The *5 multiplication can work badly for connections
|
||||
// with high, but very fluctuating bandwidth
|
||||
if (msRecv > 1000)
|
||||
engp->tcpBytes = (UINT32)
|
||||
min( (float)(engp->tcpBytes) * 5.0,
|
||||
((float)(engp->tcpBytes) * (20000.0 / (float)msRecv))
|
||||
);
|
||||
else
|
||||
engp->tcpBytes = (UINT32)(engp->tcpBytes * 1.8);
|
||||
return Cur;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPSendRate) {
|
||||
bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > engp->bestTCPSendRate) {
|
||||
engp->bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
LastBytesPerSecondRecv = 0.0;
|
||||
engp->tcpBytes = engp->start_tcprecv_bytes;
|
||||
engp->sessionMaxTime = 60;
|
||||
return CLM_TCP_RECV;
|
||||
case CLM_TCP_RECV:
|
||||
if (msRecv < 18000 && LastRet == 0) {
|
||||
// aim for 20 secs if last receive time was > 1 sec
|
||||
// The *5 multiplication can work badly for connections
|
||||
// with high, but very fluctuating bandwidth
|
||||
if (msRecv > 1000)
|
||||
engp->tcpBytes = (UINT32)
|
||||
min( (float)(engp->tcpBytes) * 5.0,
|
||||
((float)(engp->tcpBytes) * (20000.0 / (float)msRecv))
|
||||
);
|
||||
else
|
||||
engp->tcpBytes = (UINT32)(engp->tcpBytes * 1.8);
|
||||
return Cur;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPRecvRate) {
|
||||
bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > engp->bestTCPRecvRate) {
|
||||
engp->bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
LastBytesPerSecondRecv = 0.0;
|
||||
if ((bestTCPSendRate * 8) < 20000.0)
|
||||
engp->bitsPerSecond = 20000;
|
||||
else
|
||||
engp->bitsPerSecond = (UINT32)((bestTCPSendRate*8)*0.75);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
return CLM_UDP_SEND;
|
||||
case CLM_UDP_SEND:
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) && LastRet == 0) {
|
||||
if (BytesPerSecondRecv > bestUDPSendRate) {
|
||||
bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > engp->bestUDPSendRate) {
|
||||
engp->bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > (LastBytesPerSecondRecv * 1.1)) {
|
||||
engp->bitsPerSecond = (int)((double)(engp->bitsPerSecond) * 1.5);
|
||||
RecalculatePPSSZ(engp);
|
||||
LastBytesPerSecondRecv = BytesPerSecondRecv;
|
||||
return Cur;
|
||||
}
|
||||
}
|
||||
LastBytesPerSecondRecv = 0.0;
|
||||
if ((bestTCPRecvRate * 8) < 20000.0)
|
||||
engp->bitsPerSecond = 20000;
|
||||
else
|
||||
engp->bitsPerSecond = (UINT32)((bestTCPRecvRate*8)*0.75);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
return CLM_UDP_RECV;
|
||||
case CLM_UDP_RECV: /// ***
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) && LastRet == 0) {
|
||||
if (BytesPerSecondRecv > bestUDPRecvRate) {
|
||||
bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > engp->bestUDPRecvRate) {
|
||||
engp->bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > (LastBytesPerSecondRecv * 1.1)) {
|
||||
engp->bitsPerSecond = (int)((double)(engp->bitsPerSecond) * 1.5);
|
||||
RecalculatePPSSZ(engp);
|
||||
LastBytesPerSecondRecv = BytesPerSecondRecv;
|
||||
return Cur;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
default: // not reached
|
||||
return CLM_NONE;
|
||||
}
|
||||
// not reached
|
||||
|
||||
case CLM_AUTO_TCP:
|
||||
if (Cur == M_NONE) {
|
||||
engp->tcpBytes = engp->start_tcpsend_bytes;
|
||||
engp->sessionMaxTime = 60;
|
||||
return CLM_TCP_SEND;
|
||||
}
|
||||
if (msRecv < 18000 && LastRet == 0) {
|
||||
// aim for 20 secs if last receive time was > 1 sec
|
||||
// The *5 multiplication can work badly for connections
|
||||
// with high, but very fluctuating bandwidth
|
||||
if (msRecv > 1000)
|
||||
engp->tcpBytes = (UINT32)
|
||||
min( (float)(engp->tcpBytes) * 5.0,
|
||||
((float)(engp->tcpBytes) * (20000.0 / (float)msRecv))
|
||||
);
|
||||
else
|
||||
engp->tcpBytes = (UINT32)(engp->tcpBytes * 1.8);
|
||||
return Cur;
|
||||
}
|
||||
if (Cur == M_TCP_SEND) {
|
||||
if (BytesPerSecondRecv > engp->bestTCPSendRate) {
|
||||
engp->bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPSendRate) {
|
||||
bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
engp->tcpBytes = engp->start_tcprecv_bytes;
|
||||
engp->sessionMaxTime = 60;
|
||||
return CLM_TCP_RECV;
|
||||
}
|
||||
else {
|
||||
if (BytesPerSecondRecv > engp->bestTCPRecvRate) {
|
||||
engp->bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPRecvRate) {
|
||||
bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_AUTO_TCP_SEND:
|
||||
case CLM_AUTO_TCP_RECV:
|
||||
if (Cur == M_NONE) {
|
||||
engp->sessionMaxTime = 60;
|
||||
if (SelMode == CLM_AUTO_TCP_SEND) {
|
||||
engp->tcpBytes = engp->start_tcpsend_bytes;
|
||||
return CLM_TCP_SEND;
|
||||
}
|
||||
else {
|
||||
engp->tcpBytes = engp->start_tcprecv_bytes;
|
||||
return CLM_TCP_RECV;
|
||||
}
|
||||
}
|
||||
if (msRecv < 18000 && LastRet == 0) {
|
||||
// aim for 20 secs if last receive time was > 1 sec
|
||||
// The *5 multiplication can work badly for connections
|
||||
// with high, but very fluctuating bandwidth
|
||||
if (msRecv > 1000)
|
||||
engp->tcpBytes = (UINT32)
|
||||
min( (float)(engp->tcpBytes) * 5.0,
|
||||
((float)(engp->tcpBytes) * (20000.0 / (float)msRecv))
|
||||
);
|
||||
else
|
||||
engp->tcpBytes = (UINT32)(engp->tcpBytes * 1.8);
|
||||
return Cur;
|
||||
}
|
||||
if (Cur == M_TCP_SEND) {
|
||||
if (BytesPerSecondRecv > engp->bestTCPSendRate) {
|
||||
engp->bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPSendRate) {
|
||||
bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BytesPerSecondRecv > engp->bestTCPRecvRate) {
|
||||
engp->bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPRecvRate) {
|
||||
bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_AUTO_UDP_SEND:
|
||||
case CLM_AUTO_UDP_RECV:
|
||||
if (Cur == M_NONE) {
|
||||
engp->bitsPerSecond = 30000;
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
if (SelMode == CLM_AUTO_UDP_SEND)
|
||||
return CLM_UDP_SEND;
|
||||
else
|
||||
return CLM_UDP_RECV;
|
||||
}
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) && LastRet == 0) {
|
||||
if (Cur == M_UDP_SEND) {
|
||||
if (BytesPerSecondRecv > engp->bestUDPSendRate) {
|
||||
engp->bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestUDPSendRate) {
|
||||
bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BytesPerSecondRecv > engp->bestUDPRecvRate) {
|
||||
engp->bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestUDPRecvRate) {
|
||||
bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
if (BytesPerSecondRecv > (LastBytesPerSecondRecv * 1.1)) {
|
||||
engp->bitsPerSecond = (int)((double)(engp->bitsPerSecond) * 1.5);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
LastBytesPerSecondRecv = BytesPerSecondRecv;
|
||||
return Cur;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_AUTO_SEND:
|
||||
switch (Cur) {
|
||||
case CLM_NONE:
|
||||
engp->tcpBytes = engp->start_tcpsend_bytes;
|
||||
engp->sessionMaxTime = 60;
|
||||
return CLM_TCP_SEND;
|
||||
case CLM_TCP_SEND:
|
||||
if (msRecv < 18000 && LastRet == 0) {
|
||||
// aim for 20 secs if last receive time was > 1 sec
|
||||
// The *5 multiplication can work badly for connections
|
||||
// with high, but very fluctuating bandwidth
|
||||
if (msRecv > 1000)
|
||||
engp->tcpBytes = (UINT32)
|
||||
min( (float)(engp->tcpBytes) * 5.0,
|
||||
((float)(engp->tcpBytes) * (20000.0 / (float)msRecv))
|
||||
);
|
||||
else
|
||||
engp->tcpBytes = (UINT32)(engp->tcpBytes * 1.8);
|
||||
return Cur;
|
||||
}
|
||||
if (BytesPerSecondRecv > engp->bestTCPSendRate) {
|
||||
engp->bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPSendRate) {
|
||||
bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
LastBytesPerSecondRecv = 0.0;
|
||||
if ((engp->bestTCPSendRate * 8) < 20000.0)
|
||||
engp->bitsPerSecond = 20000;
|
||||
else
|
||||
engp->bitsPerSecond = (UINT32)((bestTCPSendRate * 8)*0.75);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
return CLM_UDP_SEND;
|
||||
case CLM_UDP_SEND:
|
||||
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) && LastRet == 0) {
|
||||
if (BytesPerSecondRecv > engp->bestUDPSendRate) {
|
||||
engp->bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestUDPSendRate) {
|
||||
bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > (LastBytesPerSecondRecv * 1.1)) {
|
||||
engp->bitsPerSecond = (int)((double)(engp->bitsPerSecond) * 1.5);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
LastBytesPerSecondRecv = BytesPerSecondRecv;
|
||||
return Cur;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_AUTO_RECV:
|
||||
switch (Cur) {
|
||||
case CLM_NONE:
|
||||
engp->tcpBytes = engp->start_tcprecv_bytes;
|
||||
engp->sessionMaxTime = 60;
|
||||
return CLM_TCP_RECV;
|
||||
|
||||
case CLM_TCP_RECV:
|
||||
if (msRecv < 18000 && LastRet == 0) {
|
||||
// aim for 20 secs if last receive time was > 1 sec
|
||||
// The *5 multiplication can work badly for connections
|
||||
// with high, but very fluctuating bandwidth
|
||||
if (msRecv > 1000)
|
||||
engp->tcpBytes = (UINT32)
|
||||
min( (float)(engp->tcpBytes) * 5.0,
|
||||
((float)(engp->tcpBytes) * (20000.0 / (float)msRecv))
|
||||
);
|
||||
else
|
||||
engp->tcpBytes = (UINT32)(engp->tcpBytes * 1.8);
|
||||
return Cur;
|
||||
}
|
||||
if (BytesPerSecondRecv > engp->bestTCPRecvRate) {
|
||||
engp->bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestTCPRecvRate) {
|
||||
bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
LastBytesPerSecondRecv = 0.0;
|
||||
if ((engp->bestTCPRecvRate * 8) < 20000.0)
|
||||
engp->bitsPerSecond = 20000;
|
||||
else
|
||||
engp->bitsPerSecond = (UINT32)((bestTCPRecvRate * 8)*0.75);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
return CLM_UDP_RECV;
|
||||
|
||||
case CLM_UDP_RECV:
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) && LastRet == 0) {
|
||||
if (BytesPerSecondRecv > engp->bestUDPRecvRate) {
|
||||
engp->bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > bestUDPRecvRate) {
|
||||
bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
if (BytesPerSecondRecv > (LastBytesPerSecondRecv * 1.1)) {
|
||||
engp->bitsPerSecond = (int)((double)(engp->bitsPerSecond) * 1.5);
|
||||
engp->sessionTime = 5;
|
||||
RecalculatePPSSZ(engp);
|
||||
LastBytesPerSecondRecv = BytesPerSecondRecv;
|
||||
return Cur;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
|
||||
case CLM_TCP_SEND:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
if (msRecv >= 18000 && LastRet == 0) {
|
||||
if (BytesPerSecondRecv > engp->bestTCPSendRate) {
|
||||
engp->bestTCPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_TCP_RECV:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
if (msRecv >= 18000 && LastRet == 0) {
|
||||
if (BytesPerSecondRecv > engp->bestTCPRecvRate) {
|
||||
engp->bestTCPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_UDP_SEND:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) &&
|
||||
LastRet == 0) {
|
||||
if (BytesPerSecondRecv > engp->bestUDPSendRate) {
|
||||
engp->bestUDPSendRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_UDP_RECV:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
if (engp->stats.PktsRecvd > ((engp->nPackets / 2) + 1) &&
|
||||
LastRet == 0) {
|
||||
if (BytesPerSecondRecv > engp->bestUDPRecvRate) {
|
||||
engp->bestUDPRecvRate = BytesPerSecondRecv;
|
||||
}
|
||||
}
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_UDP_FDX:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_QUERY_MASTER:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
return CLM_NONE;
|
||||
|
||||
case CLM_NAME_LOOKUP:
|
||||
if (Cur == CLM_NONE) return SelMode;
|
||||
return CLM_NONE;
|
||||
|
||||
// not reached
|
||||
}
|
||||
// not reached
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* $Id: tpclient.h,v 1.4 2004/03/22 20:49:12 rlonn Exp $
|
||||
* $Source: /cvsroot/tptest/engine/tpclient.h,v $
|
||||
*
|
||||
* TPTEST 3.0 (C) Copyright II-Stiftelsen 2002
|
||||
*
|
||||
* tpclient.h - header file
|
||||
*
|
||||
* Written by
|
||||
* Ragnar Lönn <prl@gatorhole.com>
|
||||
*
|
||||
* This file is part of the TPTEST system.
|
||||
* See the file LICENSE for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TPCLIENT_H_
|
||||
#define _TPCLIENT_H_
|
||||
|
||||
#include "tpengine.h"
|
||||
|
||||
/*
|
||||
* Modes recognized by tpengine.c and tpclient.c
|
||||
*/
|
||||
#define CLM_NONE M_NONE
|
||||
#define CLM_UDP_FDX M_UDP_FDX
|
||||
#define CLM_UDP_SEND M_UDP_SEND
|
||||
#define CLM_UDP_RECV M_UDP_RECV
|
||||
#define CLM_TCP_SEND M_TCP_SEND
|
||||
#define CLM_TCP_RECV M_TCP_RECV
|
||||
#define CLM_QUERY_MASTER M_QUERY_MASTER
|
||||
#define CLM_NAME_LOOKUP M_NAME_LOOKUP
|
||||
|
||||
/*
|
||||
* Modes used exclusively by tpclient.c
|
||||
*/
|
||||
#define CLM_SERVER_MODE 301
|
||||
#define CLM_AUTO 302
|
||||
#define CLM_AUTO_TCP_SEND 303
|
||||
#define CLM_AUTO_TCP_RECV 304
|
||||
#define CLM_AUTO_UDP_SEND 305
|
||||
#define CLM_AUTO_UDP_RECV 306
|
||||
#define CLM_AUTO_SEND 307
|
||||
#define CLM_AUTO_RECV 308
|
||||
#define CLM_AUTO_TCP 309
|
||||
|
||||
// Client defaults
|
||||
|
||||
#define DEFAULT_TCPBYTES (START_TCP_BYTES * 2)
|
||||
#define DEFAULT_TESTTIME 10
|
||||
#define MIN_PKT_SIZE ( sizeof( struct tpHeader ) + IP_UDP_SIZE )
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RecalculatePPSSZ(TPEngine *);
|
||||
int AdvanceTest(TPEngine *, int, int, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif // _TPCLIENT_H_
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue