Merge remote-tracking branch 'origin/from-iop-3.4' into v3.5

Conflicts:
	brcm_fw_tool/Makefile
	brcminfo/Makefile
	peripheral_manager/Makefile
	questd/src/questd.c
	wifimngr/Makefile
This commit is contained in:
Martin Schröder 2016-01-21 15:28:48 +01:00
commit 009d2b613c
131 changed files with 283 additions and 30367 deletions

View file

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

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

@ -1,53 +0,0 @@
#
# Copyright (C) 2006-2009 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
export BUILD_DIR
PKG_NAME:=brcm_fw_tool
PKG_RELEASE:=1
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
include $(INCLUDE_DIR)/package.mk
define Package/brcm_fw_tool
SECTION:=utils
CATEGORY:=Base system
TITLE:=Update utility for Broadcom nand firmware images
DEPENDS:=bcmkernel
endef
define Package/brcm_fw_tool/description
This package contains an utility useful to upgrade from other firmware or
older OpenWrt releases.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
target=$(firstword $(subst -, ,$(BOARD)))
MAKE_FLAGS += TARGET="$(target)"
TARGET_CFLAGS += -Dtarget_$(target)=1 -Wall
ifdef CONFIG_MTD_REDBOOT_PARTS
MAKE_FLAGS += FIS_SUPPORT=1
TARGET_CFLAGS += -DFIS_SUPPORT=1
endif
define Package/brcm_fw_tool/install
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/brcm_fw_tool $(1)/sbin/
endef
$(eval $(call BuildPackage,brcm_fw_tool))

View file

@ -1,16 +0,0 @@
CC = gcc
CFLAGS += -Wall
CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/shared/opensource/include/bcm963xx/
CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx/
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
obj = brcm_fw_tool.o jffs2.o crc32.o
obj.brcm47xx = $(obj.brcm)
brcm_fw_tool: $(obj) $(obj.$(TARGET))
clean:
rm -f *.o jffs2

File diff suppressed because it is too large Load diff

View file

@ -1,11 +0,0 @@
#ifndef __mtd_h
#define __mtd_h
#include <stdbool.h>
#define JFFS2_EOF "\xde\xad\xc0\xde"
extern int quiet;
extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename, int nand_erasesize);
#endif /* __mtd_h */

View file

@ -1,95 +0,0 @@
/*
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*
* First, the polynomial itself and its table of feedback terms. The
* polynomial is
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
* Note that we take it "backwards" and put the highest-order term in
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
* the MSB being 1
*
* Note that the usual hardware shift register implementation, which
* is what we're using (we're merely optimizing it by doing eight-bit
* chunks at a time) shifts bits into the lowest-order term. In our
* implementation, that means shifting towards the right. Why do we
* do it this way? Because the calculated CRC must be transmitted in
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly
*
* The feedback terms table consists of 256, 32-bit entries. Notes
*
* The table can be generated at runtime if desired; code to do so
* is shown later. It might not be obvious, but the feedback
* terms simply represent the results of eight shift/xor opera
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
*/
#include <stdint.h>
const uint32_t crc32_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};

View file

@ -1,26 +0,0 @@
#ifndef CRC32_H
#define CRC32_H
#include <stdint.h>
extern const uint32_t crc32_table[256];
/* Return a 32-bit CRC of the contents of the buffer. */
static inline uint32_t
crc32(uint32_t val, const void *ss, int len)
{
const unsigned char *s = ss;
while (--len >= 0)
val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
return val;
}
static inline unsigned int crc32buf(char *buf, size_t len)
{
return crc32(0xFFFFFFFF, buf, len);
}
#endif

View file

@ -1,350 +0,0 @@
/*
* jffs2 on-disk structure generator for mtd
*
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* 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.
* Based on:
* JFFS2 -- Journalling Flash File System, Version 2.
* Copyright © 2001-2007 Red Hat, Inc.
* Created by David Woodhouse <dwmw2@infradead.org>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <endian.h>
#include "jffs2.h"
#include "crc32.h"
#include "brcm_fw_tool.h"
#define PAD(x) (((x)+3)&~3)
#if BYTE_ORDER == BIG_ENDIAN
# define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"
#else
# define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"
#endif
static int last_ino = 0;
static int last_version = 0;
static char *buf = NULL;
static int ofs = 0;
static int outfd = -1;
static int mtdofs = 0;
static int target_ino = 0;
static int erasesize = 128*1024;
static void prep_eraseblock(void);
static void pad(int size)
{
if ((ofs % size == 0) && (ofs < erasesize))
return;
if (ofs < erasesize) {
memset(buf + ofs, 0xff, (size - (ofs % size)));
ofs += (size - (ofs % size));
}
ofs = ofs % erasesize;
if (ofs == 0) {
write(outfd, buf, erasesize);
mtdofs += erasesize;
}
}
static inline int rbytes(void)
{
return erasesize - (ofs % erasesize);
}
static inline void add_data(char *ptr, int len)
{
if (ofs + len > erasesize) {
pad(erasesize);
prep_eraseblock();
}
memcpy(buf + ofs, ptr, len);
ofs += len;
}
static void prep_eraseblock(void)
{
if (ofs > 0)
return;
add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1);
}
static int add_dirent(const char *name, const char type, int parent)
{
struct jffs2_raw_dirent *de;
if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name))
pad(erasesize);
prep_eraseblock();
last_ino++;
memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent));
de = (struct jffs2_raw_dirent *) (buf + ofs);
de->magic = JFFS2_MAGIC_BITMASK;
de->nodetype = JFFS2_NODETYPE_DIRENT;
de->type = type;
de->name_crc = crc32(0, name, strlen(name));
de->ino = last_ino++;
de->pino = parent;
de->totlen = sizeof(*de) + strlen(name);
de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4);
de->version = last_version++;
de->mctime = 0;
de->nsize = strlen(name);
de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8);
memcpy(de->name, name, strlen(name));
ofs += sizeof(struct jffs2_raw_dirent) + de->nsize;
pad(4);
return de->ino;
}
static int add_dir(const char *name, int parent)
{
struct jffs2_raw_inode ri;
int inode;
inode = add_dirent(name, IFTODT(S_IFDIR), parent);
if (rbytes() < sizeof(ri))
pad(erasesize);
prep_eraseblock();
memset(&ri, 0, sizeof(ri));
ri.magic = JFFS2_MAGIC_BITMASK;
ri.nodetype = JFFS2_NODETYPE_INODE;
ri.totlen = sizeof(ri);
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
ri.ino = inode;
ri.mode = S_IFDIR | 0755;
ri.uid = ri.gid = 0;
ri.atime = ri.ctime = ri.mtime = 0;
ri.isize = ri.csize = ri.dsize = 0;
ri.version = 1;
ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
ri.data_crc = 0;
add_data((char *) &ri, sizeof(ri));
pad(4);
return inode;
}
static void add_file(const char *name, int parent)
{
int inode, f_offset = 0, fd;
struct jffs2_raw_inode ri;
struct stat st;
char wbuf[4096];
const char *fname;
if (stat(name, &st)) {
fprintf(stderr, "File %s does not exist\n", name);
return;
}
fname = strrchr(name, '/');
if (fname)
fname++;
else
fname = name;
inode = add_dirent(fname, IFTODT(S_IFREG), parent);
memset(&ri, 0, sizeof(ri));
ri.magic = JFFS2_MAGIC_BITMASK;
ri.nodetype = JFFS2_NODETYPE_INODE;
ri.ino = inode;
ri.mode = st.st_mode;
ri.uid = ri.gid = 0;
ri.atime = st.st_atime;
ri.ctime = st.st_ctime;
ri.mtime = st.st_mtime;
ri.isize = st.st_size;
ri.compr = 0;
ri.usercompr = 0;
fd = open(name, 0);
if (fd < 0) {
fprintf(stderr, "File %s does not exist\n", name);
return;
}
for (;;) {
int len = 0;
for (;;) {
len = rbytes() - sizeof(ri);
if (len > 128)
break;
pad(erasesize);
prep_eraseblock();
}
if (len > sizeof(wbuf))
len = sizeof(wbuf);
len = read(fd, wbuf, len);
if (len <= 0)
break;
ri.totlen = sizeof(ri) + len;
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
ri.version = ++last_version;
ri.offset = f_offset;
ri.csize = ri.dsize = len;
ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
ri.data_crc = crc32(0, wbuf, len);
f_offset += len;
add_data((char *) &ri, sizeof(ri));
add_data(wbuf, len);
pad(4);
prep_eraseblock();
}
close(fd);
}
int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename, int nand_erasesize)
{
outfd = fd;
mtdofs = ofs;
erasesize = nand_erasesize;
buf = malloc(erasesize);
target_ino = 1;
if (!last_ino)
last_ino = 1;
add_file(filename, target_ino);
pad(erasesize);
/* add eof marker, pad to eraseblock size and write the data */
add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
pad(erasesize);
free(buf);
return 0;
}
void mtd_parse_jffs2data(const char *buf, const char *dir)
{
struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
unsigned int ofs = 0;
while (ofs < erasesize) {
node = (struct jffs2_unknown_node *) (buf + ofs);
if (node->magic != 0x1985)
break;
ofs += PAD(node->totlen);
if (node->nodetype == JFFS2_NODETYPE_DIRENT) {
struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node;
/* is this the right directory name and is it a subdirectory of / */
if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize))
target_ino = de->ino;
/* store the last inode and version numbers for adding extra files */
if (last_ino < de->ino)
last_ino = de->ino;
if (last_version < de->version)
last_version = de->version;
}
}
}
int quiet = 0;
int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
{
int err = -1, fdeof = 0;
if (quiet < 2)
fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
buf = malloc(erasesize);
if (!buf) {
fprintf(stderr, "Out of memory!\n");
goto done;
}
if (!*dir)
target_ino = 1;
/* parse the structure of the jffs2 first
* locate the directory that the file is going to be placed in */
for(;;) {
struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
if (read(outfd, buf, erasesize) != erasesize) {
fdeof = 1;
break;
}
mtdofs += erasesize;
if (node->magic == 0x8519) {
fprintf(stderr, "Error: wrong endianness filesystem\n");
goto done;
}
/* assume no magic == end of filesystem
* the filesystem will probably end with be32(0xdeadc0de) */
if (node->magic != 0x1985)
break;
mtd_parse_jffs2data(buf, dir);
}
if (fdeof) {
fprintf(stderr, "Error: No room for additional data\n");
goto done;
}
/* jump back one eraseblock */
mtdofs -= erasesize;
lseek(outfd, mtdofs, SEEK_SET);
ofs = 0;
if (!last_ino)
last_ino = 1;
if (!target_ino)
target_ino = add_dir(dir, 1);
add_file(filename, target_ino);
pad(erasesize);
/* add eof marker, pad to eraseblock size and write the data */
add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
pad(erasesize);
err = 0;
done:
close(outfd);
if (buf)
free(buf);
return err;
}

View file

@ -1,216 +0,0 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*
*
*/
#ifndef __LINUX_JFFS2_H__
#define __LINUX_JFFS2_H__
#define JFFS2_SUPER_MAGIC 0x72b6
/* You must include something which defines the C99 uintXX_t types.
We don't do it from here because this file is used in too many
different environments. */
/* Values we may expect to find in the 'magic' field */
#define JFFS2_OLD_MAGIC_BITMASK 0x1984
#define JFFS2_MAGIC_BITMASK 0x1985
#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
#define JFFS2_EMPTY_BITMASK 0xffff
#define JFFS2_DIRTY_BITMASK 0x0000
/* Summary node MAGIC marker */
#define JFFS2_SUM_MAGIC 0x02851885
/* We only allow a single char for length, and 0xFF is empty flash so
we don't want it confused with a real length. Hence max 254.
*/
#define JFFS2_MAX_NAME_LEN 254
/* How small can we sensibly write nodes? */
#define JFFS2_MIN_DATA_LEN 128
#define JFFS2_COMPR_NONE 0x00
#define JFFS2_COMPR_ZERO 0x01
#define JFFS2_COMPR_RTIME 0x02
#define JFFS2_COMPR_RUBINMIPS 0x03
#define JFFS2_COMPR_COPY 0x04
#define JFFS2_COMPR_DYNRUBIN 0x05
#define JFFS2_COMPR_ZLIB 0x06
/* Compatibility flags. */
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
#define JFFS2_NODE_ACCURATE 0x2000
/* INCOMPAT: Fail to mount the filesystem */
#define JFFS2_FEATURE_INCOMPAT 0xc000
/* ROCOMPAT: Mount read-only */
#define JFFS2_FEATURE_ROCOMPAT 0x8000
/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
/* XATTR Related */
#define JFFS2_XPREFIX_USER 1 /* for "user." */
#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
#define JFFS2_ACL_VERSION 0x0001
// Maybe later...
//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
mount time, don't wait for it to
happen later */
#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
compression type */
/* These can go once we've made sure we've caught all uses without
byteswapping */
typedef uint32_t jint32_t;
typedef uint32_t jmode_t;
typedef uint16_t jint16_t;
struct jffs2_unknown_node
{
/* All start like this */
jint16_t magic;
jint16_t nodetype;
jint32_t totlen; /* So we can skip over nodes we don't grok */
jint32_t hdr_crc;
};
struct jffs2_raw_dirent
{
jint16_t magic;
jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t pino;
jint32_t version;
jint32_t ino; /* == zero for unlink */
jint32_t mctime;
uint8_t nsize;
uint8_t type;
uint8_t unused[2];
jint32_t node_crc;
jint32_t name_crc;
uint8_t name[0];
};
/* The JFFS2 raw inode structure: Used for storage on physical media. */
/* The uid, gid, atime, mtime and ctime members could be longer, but
are left like this for space efficiency. If and when people decide
they really need them extended, it's simple enough to add support for
a new type of raw node.
*/
struct jffs2_raw_inode
{
jint16_t magic; /* A constant magic number. */
jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
jint32_t totlen; /* Total length of this node (inc data, etc.) */
jint32_t hdr_crc;
jint32_t ino; /* Inode number. */
jint32_t version; /* Version number. */
jmode_t mode; /* The file's type or mode. */
jint16_t uid; /* The file's owner. */
jint16_t gid; /* The file's group. */
jint32_t isize; /* Total resultant size of this inode (used for truncations) */
jint32_t atime; /* Last access time. */
jint32_t mtime; /* Last modification time. */
jint32_t ctime; /* Change time. */
jint32_t offset; /* Where to begin to write. */
jint32_t csize; /* (Compressed) data size */
jint32_t dsize; /* Size of the node's data. (after decompression) */
uint8_t compr; /* Compression algorithm used */
uint8_t usercompr; /* Compression algorithm requested by the user */
jint16_t flags; /* See JFFS2_INO_FLAG_* */
jint32_t data_crc; /* CRC for the (compressed) data. */
jint32_t node_crc; /* CRC for the raw inode (excluding data) */
uint8_t data[0];
};
struct jffs2_raw_xattr {
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t xid; /* XATTR identifier number */
jint32_t version;
uint8_t xprefix;
uint8_t name_len;
jint16_t value_len;
jint32_t data_crc;
jint32_t node_crc;
uint8_t data[0];
} __attribute__((packed));
struct jffs2_raw_xref
{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t ino; /* inode number */
jint32_t xid; /* XATTR identifier number */
jint32_t xseqno; /* xref sequencial number */
jint32_t node_crc;
} __attribute__((packed));
struct jffs2_raw_summary
{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t sum_num; /* number of sum entries*/
jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
jint32_t padded; /* sum of the size of padding nodes */
jint32_t sum_crc; /* summary information crc */
jint32_t node_crc; /* node crc */
jint32_t sum[0]; /* inode summary info */
};
union jffs2_node_union
{
struct jffs2_raw_inode i;
struct jffs2_raw_dirent d;
struct jffs2_raw_xattr x;
struct jffs2_raw_xref r;
struct jffs2_raw_summary s;
struct jffs2_unknown_node u;
};
/* Data payload for device nodes. */
union jffs2_device_node {
jint16_t old;
jint32_t new;
};
#endif /* __LINUX_JFFS2_H__ */

View file

@ -1,58 +0,0 @@
#
# Copyright (C) 2006-2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=brcminfo
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
include $(INCLUDE_DIR)/package.mk
define Package/brcminfo
CATEGORY:=Utilities
TITLE:=Broadcom voice driver info utility
URL:=
DEPENDS:= bcmkernel
endef
define Package/brcminfo/description
Utility that prints information regarding voice configuration
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
target=$(firstword $(subst -, ,$(BOARD)))
MAKE_FLAGS += TARGET="$(target)"
EXTRA_CFLAGS += -DBOS_OS_LINUXUSER
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/broadcom/include/bcm963xx/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/endpt/inc/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/inc
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/codec
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/xchg_common/bos/publicInc/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/casCtl/inc/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/xchg_drivers/inc
TARGET_CFLAGS += -D$(CONFIG_TARGET_IBOARDID) -Dtarget_$(target)=1 -Wall
define Package/brcminfo/install
$(INSTALL_DIR) $(1)/usr/bin
cp $(PKG_BUILD_DIR)/brcminfo $(1)/usr/bin/
endef
$(eval $(call BuildPackage,brcminfo))

View file

@ -1,15 +0,0 @@
# Makefile for brcminfo utility
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
OBJS = brcminfo.o
all: main
dynamic: all
main: brcminfo.o
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o brcminfo brcminfo.o -lm
clean:
rm -f brcminfo ${OBJS}

View file

@ -1,92 +0,0 @@
/*
* brcminfo.c
* Minor utility that will attempt to read the number of available
* endpoints from the brcm voice driver
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <endpointdrv.h>
static int endpoint_fd = -1;
static int num_fxs_endpoints = -1;
static int num_fxo_endpoints = -1;
static int num_dect_endpoints = -1;
static int num_endpoints = -1;
int vrgEndptDriverOpen(void)
{
endpoint_fd = open("/dev/bcmendpoint0", O_RDWR);
if (endpoint_fd == -1) {
return -1;
} else {
return 0;
}
}
int vrgEndptDriverClose(void)
{
int result = close(endpoint_fd);
endpoint_fd = -1;
return result;
}
static int brcm_get_endpoints_count(void)
{
ENDPOINTDRV_ENDPOINTCOUNT_PARM endpointCount;
endpointCount.size = sizeof(ENDPOINTDRV_ENDPOINTCOUNT_PARM);
if ( ioctl( endpoint_fd, ENDPOINTIOCTL_FXSENDPOINTCOUNT, &endpointCount ) != IOCTL_STATUS_SUCCESS ) {
return -1;
} else {
num_fxs_endpoints = endpointCount.endpointNum;
}
if ( ioctl( endpoint_fd, ENDPOINTIOCTL_FXOENDPOINTCOUNT, &endpointCount ) != IOCTL_STATUS_SUCCESS ) {
return -1;
} else {
num_fxo_endpoints = endpointCount.endpointNum;
}
if ( ioctl( endpoint_fd, ENDPOINTIOCTL_DECTENDPOINTCOUNT, &endpointCount ) != IOCTL_STATUS_SUCCESS ) {
return -1;
} else {
num_dect_endpoints = endpointCount.endpointNum;
}
num_endpoints = num_fxs_endpoints + num_fxo_endpoints + num_dect_endpoints;
return 0;
}
int main(int argc, char **argv)
{
int result;
result = vrgEndptDriverOpen();
if (result != 0) {
printf("Could not open endpoint driver\n");
return result;
}
result = brcm_get_endpoints_count();
if (result == 0) {
printf("DECT Endpoints:\t%d\n", num_dect_endpoints);
printf("FXS Endpoints:\t%d\n", num_fxs_endpoints);
printf("FXO Endpoints:\t%d\n", num_fxo_endpoints);
printf("All Endpoints:\t%d\n", num_endpoints);
}
else {
printf("Endpoint counting failed, maybe driver is not initialized?\n");
}
result = vrgEndptDriverClose();
if (result != 0) {
printf("Could not close endpoint driver\n");
return result;
}
return 0;
}

View file

@ -9,35 +9,42 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=broadcom-nvram
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
PKG_SOURCE_VERSION:=8b6018d9ce5e292f0a4a3e86f8fa7d8bc003c3fb
PKG_SOURCE_PROTO:=git
ifeq ($(CONFIG_BCM_OPEN),y)
PKG_SOURCE_URL:=http://public.inteno.se/broadcom-nvram
else
PKG_SOURCE_URL:=git@public.inteno.se:broadcom-nvram
endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
STAMP_PREPARED:=$(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
include $(INCLUDE_DIR)/package.mk
LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib
RSTRIP:=true
define Package/bcmnvram
CATEGORY:=Libraries
TITLE:=Broadcom nvram emulator library
URL:=
DEPENDS:=PACKAGE_libuci:libuci
CATEGORY:=Libraries
TITLE:=Broadcom nvram emulator library
URL:=
DEPENDS:=PACKAGE_libuci:libuci
endef
define Package/bcmnvram/description
Broadcom nvram to uci wrapper
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
target=$(firstword $(subst -, ,$(BOARD)))
MAKE_FLAGS += TARGET="$(target)"

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

115
broadcom-utils/Makefile Normal file
View file

@ -0,0 +1,115 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=broadcom-utils
PKG_VERSION:=0
PKG_RELEASE:=1
PKG_SOURCE_VERSION:=2d83316221fe1e3be7d86c1d44d99b00b62f2373
PKG_SOURCE_PROTO:=git
ifeq ($(CONFIG_BCM_OPEN),y)
PKG_SOURCE_URL:=http://public.inteno.se/broadcom-utils
else
PKG_SOURCE_URL:=git@public.inteno.se:broadcom-utils
endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
############################################################################## #
include $(INCLUDE_DIR)/package.mk
define Package/broadcom-utils/Default
SECTION:=utils
CATEGORY:=Broadcom utilities
TITLE:=Broadcom utilities
DEPENDS:=bcmkernel
endef
define Package/broadcom-utils/description
This package contains useful broadcom related utilities.
endef
target=$(firstword $(subst -, ,$(BOARD)))
_make_flags := $(MAKE_FLAGS)
_target_cflags := $(TARGET_CFLAGS)
############################################################################## #
# brcm_fw_tool #
############################################################################## #
MAKE_FLAGS := $(_make_flags)
TARGET_CFLAGS := $(_target_cflags) -Dtarget_$(target)=1 -Wall
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
ifdef CONFIG_MTD_REDBOOT_PARTS
MAKE_FLAGS += FIS_SUPPORT=1
TARGET_CFLAGS += -DFIS_SUPPORT=1
endif
define Package/brcm_fw_tool
$(call Package/broadcom-utils/Default)
TITLE:=Update utility for Broadcom nand firmware images
endef
define Package/brcm_fw_tool/description
This package contains an utility useful to upgrade from other firmware or
older OpenWrt releases.
endef
define Build/brcm_fw_tool/prepare
mkdir -p $(PKG_BUILD_DIR)/brcm_fw_tool
$(CP) $(PKG_SOURCE_SUBDIR)/brcm_fw_tool/* $(PKG_BUILD_DIR)/brcm_fw_tool/
endef
define Package/brcm_fw_tool/install
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/brcm_fw_tool/brcm_fw_tool $(1)/sbin/
endef
############################################################################## #
# brcminfo #
############################################################################## #
MAKE_FLAGS := $(_make_flags)
TARGET_CFLAGS := $(_target_cflags) -D$(CONFIG_TARGET_IBOARDID) -Dtarget_$(target)=1 -Wall
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
EXTRA_CFLAGS += -DBOS_OS_LINUXUSER
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/broadcom/include/bcm963xx/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/endpt/inc/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/inc
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/codec
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/xchg_common/bos/publicInc/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/voice_res_gw/casCtl/inc/
EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/bcm963xx/xChange/dslx_common/xchg_drivers/inc
define Package/brcminfo
$(call Package/broadcom-utils/Default)
TITLE:=Broadcom voice driver info utility
endef
define Package/brcminfo/description
Utility that prints information regarding voice configuration
endef
define Build/brcminfo/prepare
mkdir -p $(PKG_BUILD_DIR)/brcminfo
$(CP) $(PKG_SOURCE_SUBDIR)/brcminfo/* $(PKG_BUILD_DIR)/brcminfo/
endef
define Package/brcminfo/install
$(INSTALL_DIR) $(1)/usr/bin
cp $(PKG_BUILD_DIR)/brcminfo/brcminfo $(1)/usr/bin/
endef
############################################################################## #
$(eval $(call BuildPackage,brcminfo))
$(eval $(call BuildPackage,brcm_fw_tool))

View file

@ -9,8 +9,21 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=peripheral_manager
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_SOURCE_VERSION:=9c3e0825db6a5e8c4ecd950ebf850a6d3c87a556
PKG_SOURCE_PROTO:=git
ifeq ($(CONFIG_BCM_OPEN),y)
PKG_SOURCE_URL:=http://public.inteno.se/peripheral_manager
else
PKG_SOURCE_URL:=git@public.inteno.se:peripheral_manager
endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
# support parallel build
PKG_BUILD_PARALLEL:=1
@ -24,10 +37,10 @@ PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
define Package/peripheral_manager
CATEGORY:=Utilities
TITLE:=Application deamon for handling of peripheral
URL:=
DEPENDS:=+libuci +libubus +libblobmsg-json bcmkernel
CATEGORY:=Utilities
TITLE:=Application deamon for handling of peripheral
URL:=
DEPENDS:=+libuci +libubus +libblobmsg-json bcmkernel
endef
define Package/peripheral_manager/description
@ -36,26 +49,16 @@ endef
TARGET_CPPFLAGS := \
-I$(STAGING_DIR)/usr/include/bcm963xx/shared/opensource/include/bcm963xx \
-I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx \
$(TARGET_CPPFLAGS)
# In future get the git. unpack it in src.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
$(CP) ./files/* $(PKG_BUILD_DIR)/
endef
-I$(STAGING_DIR)/usr/include/bcm963xx/bcmdrivers/opensource/include/bcm963xx \
$(TARGET_CPPFLAGS)
define Package/peripheral_manager/install
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/etc/
$(INSTALL_DIR) $(1)/etc/init.d/
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/peripheral_manager $(1)/sbin/
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gpio_test $(1)/sbin/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/etc/init.d/* $(1)/etc/init.d/
endef
$(eval $(call BuildPackage,peripheral_manager))

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_RELEASE:=1
PKG_SOURCE_VERSION:=2f575b43703c801f4f7bfac65e8845ce967c3d9e
PKG_SOURCE_PROTO:=git
ifeq ($(CONFIG_BCM_OPEN),y)
PKG_SOURCE_URL:=http://public.inteno.se/qrencode
else
PKG_SOURCE_URL:=git@public.inteno.se:qrencode
endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
TARGET_LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -lpng
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -lpng
TARGET_CFLAGS += $(FPIC)
define Package/qrencode
CATEGORY:=Utilities
DEPENDS:=+libpng
TITLE:=QRcode encoder library
URL:=http://megaui.net/fukuchi/works/qrencode/index.en.html
CATEGORY:=Utilities
DEPENDS:=+libpng
TITLE:=QRcode encoder library
URL:=http://megaui.net/fukuchi/works/qrencode/index.en.html
endef
define Package/qrencode/description
@ -32,11 +44,6 @@ define Package/qrencode/description
digits or 4000 characters, and is highly robust.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"

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_VERSION:=2.0.3
PKG_RELEASE:=3
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_VERSION:=550f09040af42a62a53544aa31866c93048f7d2f
PKG_SOURCE_PROTO:=git
ifeq ($(CONFIG_BCM_OPEN),y)
PKG_SOURCE_URL:=http://public.inteno.se/questd
else
PKG_SOURCE_URL:=git@public.inteno.se:questd
endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib
ifeq ($(CONFIG_PACKAGE_bcmkernel),y)
BCMKERNEL_DIR:=$(BUILD_DIR)/bcmkernel/bcm963xx
@ -24,9 +35,9 @@ endif
export BCMKERNEL_DIR
define Package/questd
CATEGORY:=Utilities
DEPENDS:=+libuci +libubox +ubus +libpthread
TITLE:=router info daemon
CATEGORY:=Utilities
DEPENDS:=+libuci +libubox +ubus +libpthread
TITLE:=router info daemon
endef
define Package/questd/description
@ -34,16 +45,11 @@ define Package/questd/description
this information via ubus
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/questd/install
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_DIR) $(1)/tmp
$(INSTALL_BIN) $(PKG_BUILD_DIR)/questd $(1)/sbin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,questd))

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,40 +8,47 @@ PKG_NAME:=statd
PKG_VERSION:=0.0.1
PKG_RELEASE:=1
PKG_SOURCE_VERSION:=54125a06399b378a27db31f722d891a5b23baf2d
PKG_SOURCE_PROTO:=git
ifeq ($(CONFIG_BCM_OPEN),y)
PKG_SOURCE_URL:=http://public.inteno.se/statd
else
PKG_SOURCE_URL:=git@public.inteno.se:statd
endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
target=$(firstword $(subst -, ,$(BOARD)))
TARGET_LDFLAGS+= \
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -luci -lubus -lblobmsg_json
-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
-Wl,-rpath-link=$(STAGING_DIR)/lib -luci -lubus -lblobmsg_json
TARGET_CFLAGS += $(FPIC) -Dtarget_$(target)=1 -Wall
MAKE_FLAGS += TARGET="$(target)"
define Package/statd
CATEGORY:=Utilities
TITLE:=Statistics manager
DEPENDS:=+libuci +ubus +libblobmsg-json
CATEGORY:=Utilities
TITLE:=Statistics manager
DEPENDS:=+libuci +ubus +libblobmsg-json
endef
define Package/statd/description
Application that listen on ubus events to be sent on syslog or snmp
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) LINUX_DIR=$(LINUX_DIR) LDFLAGS="$(TARGET_LDFLAGS)" CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include -I$(STAGING_DIR)/usr/include"
endef
define Package/statd/install
$(INSTALL_DIR) $(1)/sbin
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/statd $(1)/sbin/
endef

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}

Some files were not shown because too many files have changed in this diff Show more