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:
Fredrik Åsberg 2016-01-18 17:52:14 +01:00
parent 416807ec6d
commit a88e8ca92a
118 changed files with 146 additions and 28349 deletions

View file

@ -9,41 +9,45 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=bcmhotproxy PKG_NAME:=bcmhotproxy
PKG_VERSION:=1.0.0
PKG_RELEASE:=13 PKG_RELEASE:=13
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME) PKG_SOURCE_VERSION:=63a265031b870a0aa6b45352cf28224518a31638
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS) 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 include $(INCLUDE_DIR)/package.mk
define Package/bcmhotproxy define Package/bcmhotproxy
SECTION:=utils SECTION:=utils
CATEGORY:=Base system CATEGORY:=Base system
TITLE:=Daemon That feeds broadcom driver calls to hotplug2 TITLE:=Daemon That feeds broadcom driver calls to hotplug2
endef endef
define Package/bcmhotproxy/description 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 This package contains a Daemon that will listen to link events from broadcoms adsl driver and etherent driver and proxy them to hotplug
endef endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
$(CP) ./files/* $(PKG_BUILD_DIR)/
endef
target=$(firstword $(subst -, ,$(BOARD))) target=$(firstword $(subst -, ,$(BOARD)))
MAKE_FLAGS += TARGET="$(target)" MAKE_FLAGS += TARGET="$(target)"
TARGET_CFLAGS += -Dtarget_$(target)=1 -Wall TARGET_CFLAGS += -Dtarget_$(target)=1 -Wall
define Package/bcmhotproxy/install define Package/bcmhotproxy/install
$(INSTALL_DIR) $(1)/sbin $(INSTALL_DIR) $(1)/sbin
$(INSTALL_DIR) $(1)/etc/ $(INSTALL_DIR) $(1)/etc/
$(INSTALL_DIR) $(1)/etc/init.d/ $(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/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/bcmhotproxy $(1)/sbin/
endef endef

View file

@ -1,8 +0,0 @@
CC = gcc
CFLAGS += -Wall
obj = bcmhotproxy.o brcmdaemon.o
bcmhotproxy: $(obj) $(obj.$(TARGET))
clean:
rm -f *.o

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -9,35 +9,42 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=broadcom-nvram PKG_NAME:=broadcom-nvram
PKG_VERSION:=1.0.0
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME) PKG_SOURCE_VERSION:=8b6018d9ce5e292f0a4a3e86f8fa7d8bc003c3fb
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS) 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 include $(INCLUDE_DIR)/package.mk
LDFLAGS+= \ LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \ -Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -Wl,-rpath-link=$(STAGING_DIR)/lib
RSTRIP:=true RSTRIP:=true
define Package/bcmnvram define Package/bcmnvram
CATEGORY:=Libraries CATEGORY:=Libraries
TITLE:=Broadcom nvram emulator library TITLE:=Broadcom nvram emulator library
URL:= URL:=
DEPENDS:=PACKAGE_libuci:libuci DEPENDS:=PACKAGE_libuci:libuci
endef endef
define Package/bcmnvram/description define Package/bcmnvram/description
Broadcom nvram to uci wrapper Broadcom nvram to uci wrapper
endef endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
target=$(firstword $(subst -, ,$(BOARD))) target=$(firstword $(subst -, ,$(BOARD)))
MAKE_FLAGS += TARGET="$(target)" MAKE_FLAGS += TARGET="$(target)"

View file

@ -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}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View file

@ -9,8 +9,21 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=peripheral_manager PKG_NAME:=peripheral_manager
PKG_VERSION:=1.0.0
PKG_RELEASE:=1 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 # support parallel build
PKG_BUILD_PARALLEL:=1 PKG_BUILD_PARALLEL:=1
@ -24,10 +37,10 @@ PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
define Package/peripheral_manager define Package/peripheral_manager
CATEGORY:=Utilities CATEGORY:=Utilities
TITLE:=Application deamon for handling of peripheral TITLE:=Application deamon for handling of peripheral
URL:= URL:=
DEPENDS:=+libuci +libubus +libblobmsg-json +bcmkernel DEPENDS:=+libuci +libubus +libblobmsg-json bcmkernel
endef endef
define Package/peripheral_manager/description define Package/peripheral_manager/description
@ -36,26 +49,16 @@ endef
TARGET_CPPFLAGS := \ TARGET_CPPFLAGS := \
-I$(STAGING_DIR)/usr/include/bcm963xx/shared/opensource/include/bcm963xx \ -I$(STAGING_DIR)/usr/include/bcm963xx/shared/opensource/include/bcm963xx \
-I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx \ -I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx \
$(TARGET_CPPFLAGS) $(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 define Package/peripheral_manager/install
$(INSTALL_DIR) $(1)/etc/ $(INSTALL_DIR) $(1)/etc/
$(INSTALL_DIR) $(1)/etc/init.d/ $(INSTALL_DIR) $(1)/etc/init.d/
$(INSTALL_DIR) $(1)/sbin $(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/peripheral_manager $(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_INSTALL_DIR)/usr/bin/gpio_test $(1)/sbin/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/etc/init.d/* $(1)/etc/init.d/
endef endef
$(eval $(call BuildPackage,peripheral_manager)) $(eval $(call BuildPackage,peripheral_manager))

View file

@ -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)\"

View file

@ -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'

View file

@ -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}
])

View file

@ -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
])

View file

@ -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();
}

View file

@ -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

View file

@ -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 */

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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 */

View file

@ -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();
}

View file

@ -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

View file

@ -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*/

View file

@ -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));
}
}

View file

@ -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);
}
}

View file

@ -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];
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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 */

View file

@ -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);
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -10,19 +10,31 @@ PKG_NAME:=qrencode
PKG_VERSION:=3.0.3 PKG_VERSION:=3.0.3
PKG_RELEASE:=1 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 include $(INCLUDE_DIR)/package.mk
TARGET_LDFLAGS+= \ TARGET_LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \ -Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -lpng -Wl,-rpath-link=$(STAGING_DIR)/lib -lpng
TARGET_CFLAGS += $(FPIC) TARGET_CFLAGS += $(FPIC)
define Package/qrencode define Package/qrencode
CATEGORY:=Utilities CATEGORY:=Utilities
DEPENDS:=+libpng DEPENDS:=+libpng
TITLE:=QRcode encoder library TITLE:=QRcode encoder library
URL:=http://megaui.net/fukuchi/works/qrencode/index.en.html URL:=http://megaui.net/fukuchi/works/qrencode/index.en.html
endef endef
define Package/qrencode/description define Package/qrencode/description
@ -32,11 +44,6 @@ define Package/qrencode/description
digits or 4000 characters, and is highly robust. digits or 4000 characters, and is highly robust.
endef endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \ $(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" $(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"

View file

@ -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}

View file

@ -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);
}

View file

@ -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__ */

View file

@ -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

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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

View file

@ -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__ */

View file

@ -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]);
}
}
}

View file

@ -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__ */

View file

@ -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;
}
}

View file

@ -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__ */

View file

@ -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;
}

View file

@ -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__ */

View file

@ -8,13 +8,24 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=questd PKG_NAME:=questd
PKG_VERSION:=2.0.3 PKG_VERSION:=2.0.3
PKG_RELEASE:=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 include $(INCLUDE_DIR)/package.mk
LDFLAGS+= \ LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \ -Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -Wl,-rpath-link=$(STAGING_DIR)/lib
ifeq ($(CONFIG_PACKAGE_bcmkernel),y) ifeq ($(CONFIG_PACKAGE_bcmkernel),y)
BCMKERNEL_DIR:=$(BUILD_DIR)/bcmkernel/bcm963xx BCMKERNEL_DIR:=$(BUILD_DIR)/bcmkernel/bcm963xx
@ -24,9 +35,9 @@ endif
export BCMKERNEL_DIR export BCMKERNEL_DIR
define Package/questd define Package/questd
CATEGORY:=Utilities CATEGORY:=Utilities
DEPENDS:=+libuci +libubox +ubus +libpthread DEPENDS:=+libuci +libubox +ubus +libpthread
TITLE:=router info daemon TITLE:=router info daemon
endef endef
define Package/questd/description define Package/questd/description
@ -34,11 +45,6 @@ define Package/questd/description
this information via ubus this information via ubus
endef endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/questd/install define Package/questd/install
$(INSTALL_DIR) $(1)/sbin $(INSTALL_DIR) $(1)/sbin
$(INSTALL_DIR) $(1)/tmp $(INSTALL_DIR) $(1)/tmp

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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;
}

View file

@ -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));
}

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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 "";
}
}

View file

@ -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);
}
}

View file

@ -8,32 +8,39 @@ PKG_NAME:=statd
PKG_VERSION:=0.0.1 PKG_VERSION:=0.0.1
PKG_RELEASE:=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 include $(INCLUDE_DIR)/package.mk
target=$(firstword $(subst -, ,$(BOARD))) target=$(firstword $(subst -, ,$(BOARD)))
TARGET_LDFLAGS+= \ TARGET_LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \ -Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -luci -lubus -lblobmsg_json -Wl,-rpath-link=$(STAGING_DIR)/lib -luci -lubus -lblobmsg_json
TARGET_CFLAGS += $(FPIC) -Dtarget_$(target)=1 -Wall TARGET_CFLAGS += $(FPIC) -Dtarget_$(target)=1 -Wall
MAKE_FLAGS += TARGET="$(target)" MAKE_FLAGS += TARGET="$(target)"
define Package/statd define Package/statd
CATEGORY:=Utilities CATEGORY:=Utilities
TITLE:=Statistics manager TITLE:=Statistics manager
DEPENDS:=+libuci +ubus +libblobmsg-json DEPENDS:=+libuci +ubus +libblobmsg-json
endef endef
define Package/statd/description define Package/statd/description
Application that listen on ubus events to be sent on syslog or snmp Application that listen on ubus events to be sent on syslog or snmp
endef endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \ $(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" $(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"

View file

@ -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}

View file

@ -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(&section->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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -1,37 +1,44 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=tptest PKG_NAME:=tptest
PKG_RELEASE:=0
PKG_VERSION:=1.3 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 include $(INCLUDE_DIR)/package.mk
TARGET_LDFLAGS+= \ TARGET_LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \ -Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -Wl,-rpath-link=$(STAGING_DIR)/lib
TARGET_CFLAGS+= \ TARGET_CFLAGS+= \
-DUNIX -DLINUX -DUNIX -DLINUX
MAKE_OPTS:= \ MAKE_OPTS:= \
ARCH="$(LINUX_KARCH)" \ ARCH="$(LINUX_KARCH)" \
CROSS_COMPILE="$(TARGET_CROSS)" \ CROSS_COMPILE="$(TARGET_CROSS)" \
SUBDIRS="$(PKG_BUILD_DIR)" \ SUBDIRS="$(PKG_BUILD_DIR)" \
define Package/tptest define Package/tptest
CATEGORY:=Utilities CATEGORY:=Utilities
TITLE:=TPTEST speed test utility TITLE:=TPTEST speed test utility
endef endef
define Package/tptest/description define Package/tptest/description
TPTEST speed test utility TPTEST speed test utility
endef endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \ $(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" $(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"

View file

@ -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.

View file

@ -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

View file

@ -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}

View file

@ -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.

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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