mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
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:
commit
009d2b613c
131 changed files with 283 additions and 30367 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
CC = gcc
|
||||
CFLAGS += -Wall
|
||||
|
||||
obj = bcmhotproxy.o brcmdaemon.o
|
||||
|
||||
bcmhotproxy: $(obj) $(obj.$(TARGET))
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* bcmhotproxy -- a proxy to send messages from broadcom drivers to userspace
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: Strhuan Blomquist
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
#include "bcmhotproxy.h"
|
||||
|
||||
int netlink_init() {
|
||||
int sock_fd;
|
||||
sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_BRCM_MONITOR);
|
||||
if(sock_fd<0)
|
||||
return -1;
|
||||
return sock_fd;
|
||||
}
|
||||
int hotplug_call(struct hotplug_arg arg)
|
||||
{
|
||||
char str[512];
|
||||
int ret;
|
||||
memset(str, '\0', sizeof(512));
|
||||
syslog(LOG_INFO, "ACTION=%s INTERFACE=%s /sbin/hotplug-call %s", arg.action,arg.inteface,arg.subsystem);
|
||||
sprintf(str, "ACTION=%s INTERFACE=%s /sbin/hotplug-call %s",arg.action,arg.inteface,arg.subsystem);
|
||||
ret=system(str);
|
||||
return ret;
|
||||
}
|
||||
hotplug_arg createargumetstruct(char *hotplugmsg)
|
||||
{
|
||||
hotplug_arg arg;
|
||||
char argumets[3][20];
|
||||
char * pch;
|
||||
int x=0;
|
||||
pch = strtok (hotplugmsg," ");
|
||||
while (pch != NULL){
|
||||
strcpy(argumets[x],pch);
|
||||
pch = strtok (NULL, " ");
|
||||
x++;
|
||||
}
|
||||
strncpy(arg.action,argumets[0],sizeof(arg.action));
|
||||
strncpy(arg.inteface,argumets[1],sizeof(arg.action));
|
||||
strncpy(arg.subsystem,argumets[2],sizeof(arg.action));
|
||||
|
||||
return arg;
|
||||
|
||||
}
|
||||
|
||||
int netlink_bind(int sock_fd) {
|
||||
|
||||
struct sockaddr_nl src_addr;
|
||||
memset(&src_addr, 0, sizeof(src_addr));
|
||||
src_addr.nl_family = AF_NETLINK;
|
||||
src_addr.nl_pid = getpid(); /* self pid */
|
||||
src_addr.nl_groups = 1; //multicast Group
|
||||
|
||||
bind(sock_fd, (struct sockaddr*)&src_addr,sizeof(src_addr));
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&src_addr,sizeof(src_addr))) {
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
int dispatcher() {
|
||||
struct sockaddr_nl dest_addr;
|
||||
struct nlmsghdr *nlh = NULL;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
hotplug_arg arg;
|
||||
int sock_fd;
|
||||
/* Initlize the netlink socket */
|
||||
sock_fd=netlink_init();
|
||||
if (sock_fd == -1) {
|
||||
fprintf(stderr, "Unable to Intitlize netlink socket.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Bind the netlink socket */
|
||||
sock_fd=netlink_bind(sock_fd);
|
||||
if (sock_fd == -1) {
|
||||
fprintf(stderr, "Unable to Listen to netlink socket.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* destination address to listen to */
|
||||
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
|
||||
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
|
||||
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
|
||||
nlh->nlmsg_pid = getpid();
|
||||
nlh->nlmsg_flags = 0;
|
||||
|
||||
/* Fill the netlink message header */
|
||||
iov.iov_base = (void *)nlh;
|
||||
iov.iov_len = nlh->nlmsg_len;
|
||||
msg.msg_name = (void *)&dest_addr;
|
||||
msg.msg_namelen = sizeof(dest_addr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
|
||||
/* Read message from kernel */
|
||||
while(1){
|
||||
recvmsg(sock_fd, &msg, 0);
|
||||
switch (nlh->nlmsg_type)
|
||||
{
|
||||
case MSG_NETLINK_BRCM_WAKEUP_MONITOR_TASK:
|
||||
case MSG_NETLINK_BRCM_LINK_STATUS_CHANGED:
|
||||
/*process the message */
|
||||
fprintf(stderr, "No Handle\n");
|
||||
break;
|
||||
case MSG_NETLINK_BRCM_LINK_HOTPLUG:
|
||||
arg=createargumetstruct((char *)NLMSG_DATA(nlh));
|
||||
if(hotplug_call(arg)){
|
||||
fprintf(stderr, "Unable to call hotplug.\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
close(sock_fd);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef BCMHOTPROXY_H
|
||||
#define BCMHOTPROXY_H 1
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#define MSG_NETLINK_BRCM_WAKEUP_MONITOR_TASK 0X1000
|
||||
|
||||
#define MSG_NETLINK_BRCM_LINK_STATUS_CHANGED 0X2000
|
||||
|
||||
#define MSG_NETLINK_BRCM_LINK_HOTPLUG 0X3000
|
||||
#define MAX_PAYLOAD 1024 /* maximum payload size*/
|
||||
#ifndef NETLINK_BRCM_MONITOR
|
||||
#define NETLINK_BRCM_MONITOR 25
|
||||
#endif
|
||||
typedef struct hotplug_arg hotplug_arg;
|
||||
|
||||
struct hotplug_arg
|
||||
{
|
||||
char action[20];
|
||||
char inteface[20];
|
||||
char subsystem[20];
|
||||
|
||||
};
|
||||
#endif
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
#include "brcmdaemon.h"
|
||||
|
||||
/**************************************************************************
|
||||
Function: Print Usage
|
||||
|
||||
Description:
|
||||
Output the command-line options for this daemon.
|
||||
|
||||
Params:
|
||||
@argc - Standard argument count
|
||||
@argv - Standard argument array
|
||||
|
||||
Returns:
|
||||
returns void always
|
||||
**************************************************************************/
|
||||
void PrintUsage(int argc, char *argv[]) {
|
||||
if (argc >=1) {
|
||||
printf("Usage: %s -h -n\n", argv[0]);
|
||||
printf(" Options: \n");
|
||||
printf(" -ntDon't fork off as a daemon.\n");
|
||||
printf(" -htShow this help screen.\n");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: signal_handler
|
||||
|
||||
Description:
|
||||
This function handles select signals that the daemon may
|
||||
receive. This gives the daemon a chance to properly shut
|
||||
down in emergency situations. This function is installed
|
||||
as a signal handler in the 'main()' function.
|
||||
|
||||
Params:
|
||||
@sig - The signal received
|
||||
|
||||
Returns:
|
||||
returns void always
|
||||
**************************************************************************/
|
||||
void signal_handler(int sig) {
|
||||
|
||||
switch(sig) {
|
||||
case SIGHUP:
|
||||
syslog(LOG_WARNING, "Received SIGHUP signal.");
|
||||
break;
|
||||
case SIGTERM:
|
||||
syslog(LOG_WARNING, "Received SIGTERM signal.");
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_WARNING, "Unhandled signal (%d) %s", strsignal(sig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: main
|
||||
|
||||
Description:
|
||||
The c standard 'main' entry point function.
|
||||
|
||||
Params:
|
||||
@argc - count of command line arguments given on command line
|
||||
@argv - array of arguments given on command line
|
||||
|
||||
Returns:
|
||||
returns integer which is passed back to the parent process
|
||||
**************************************************************************/
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
#if defined(DEBUG)
|
||||
int daemonize = 0;
|
||||
#else
|
||||
int daemonize = 0;
|
||||
#endif
|
||||
|
||||
// Setup signal handling before we start
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGQUIT, signal_handler);
|
||||
|
||||
int c;
|
||||
while( (c = getopt(argc, argv, "nh|help")) != -1) {
|
||||
switch(c){
|
||||
case 'h':
|
||||
PrintUsage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
case 'n':
|
||||
daemonize = 0;
|
||||
break;
|
||||
default:
|
||||
PrintUsage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "%s daemon starting up", DAEMON_NAME);
|
||||
|
||||
// Setup syslog logging - see SETLOGMASK(3)
|
||||
#if defined(DEBUG)
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||
#else
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
|
||||
#endif
|
||||
|
||||
/* Our process ID and Session ID */
|
||||
pid_t pid, sid;
|
||||
|
||||
if (daemonize) {
|
||||
syslog(LOG_INFO, "starting the daemonizing process");
|
||||
|
||||
/* Fork off the parent process */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* If we got a good PID, then
|
||||
we can exit the parent process. */
|
||||
if (pid > 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Change the current working directory */
|
||||
if ((chdir("/")) < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Close out the standard file descriptors */
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
dispatcher();
|
||||
syslog(LOG_INFO, "%s daemon exiting", DAEMON_NAME);
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef BRCMDAEMON_H
|
||||
#define BRCMDAEMON_H 1
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define DAEMON_NAME "brcmnetlink"
|
||||
#define PID_FILE "/var/run/brcmnetlink.pid"
|
||||
#endif
|
||||
|
|
@ -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))
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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))
|
||||
|
|
@ -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}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
# Makefile for broadcom nvram to uci wrapper
|
||||
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
OBJS = nvram_emu_lib.o ucix.o main.o
|
||||
|
||||
all: libnvram main
|
||||
|
||||
dynamic: all
|
||||
|
||||
libnvram: nvram_emu_lib.o
|
||||
$(CC) -c $(CFLAGS) $(LDFLAGS) -fPIC -o ucix_shared.o ucix.c -luci
|
||||
$(CC) -c $(CFLAGS) $(LDFLAGS) -fPIC -o nvram_emu_lib.o nvram_emu_lib.c -luci
|
||||
$(CC) $(LDFLAGS) -shared -Wl,-soname,libnvram.so -o libnvram.so nvram_emu_lib.o ucix_shared.o -luci
|
||||
|
||||
main: main.o ucix.o
|
||||
$(CC) $(LDFLAGS) -o uci_test main.o ucix.o -luci
|
||||
|
||||
clean:
|
||||
rm -f libnvram.so ucix_shared.o uci_test ${OBJS}
|
||||
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// uci test program Copyright Benjamin Larsson 2012 <benjamin@southpole.se>
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
const char *ucitmp;
|
||||
|
||||
ctx = ucix_init("broadcom");
|
||||
if(!ctx)
|
||||
printf("Failed to load config file");
|
||||
|
||||
ucitmp = ucix_get_option(ctx, "broadcom", "nvram", "test");
|
||||
printf("test = %s\n",ucitmp);
|
||||
ucix_add_section(ctx, "broadcom", "nvram", "broadcom");
|
||||
ucix_add_option(ctx, "broadcom", "nvram", "test", "tomte");
|
||||
ucix_add_option(ctx, "broadcom", "nvram", "test2", "tomte2");
|
||||
printf("Hello world\n");
|
||||
ucix_commit(ctx, "broadcom");
|
||||
ucitmp = ucix_get_option(ctx, "broadcom", "nvram", "test");
|
||||
printf("test = %s\n",ucitmp);
|
||||
ucix_cleanup(ctx);
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
/** Broadcom libnvram.so compatible wrapper
|
||||
*
|
||||
* Copyright 2012 Benjamin Larsson <benjamin@southpole.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
|
||||
provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "uci.h"
|
||||
|
||||
|
||||
struct uci_context *ctx = NULL;
|
||||
struct uci_ptr ptr;
|
||||
int nvram_inited = 0;
|
||||
int nvram_debug = 0;
|
||||
|
||||
/** Function prototypes are taken from bcmnvram.h Copyright Broadcom Corporation.
|
||||
* Only some of the nvram_* functions exposed from libnvram.so are implemented.
|
||||
* get, getall, unset, set, commit
|
||||
*/
|
||||
|
||||
|
||||
/* uci does not support . in the key part, replace it with _ */
|
||||
|
||||
static const char * filter_dots_in_string(char *key) {
|
||||
int length = 0;
|
||||
int i;
|
||||
length = strlen(key);
|
||||
for (i=0 ; i<length ; i++) {
|
||||
if (key[i] == '.')
|
||||
key[i] = '_';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static void nvram_display_section(struct uci_section *s)
|
||||
{
|
||||
struct uci_element *e;
|
||||
struct uci_option *o;
|
||||
|
||||
printf("%s.%s=%s\n", s->package->e.name, s->e.name, s->type);
|
||||
uci_foreach_element(&s->options, e) {
|
||||
o = uci_to_option(e);
|
||||
printf("%s.%s.%s=%s\n", o->section->package->e.name, o->section->e.name, o->e.name, o->v.string);
|
||||
}
|
||||
}
|
||||
|
||||
void nvram_init() {
|
||||
if (!nvram_inited) {
|
||||
ctx = ucix_init("broadcom");
|
||||
if(!ctx) {
|
||||
printf("Failed to load config file \"broadcom\"\n");
|
||||
return;
|
||||
}
|
||||
ucix_add_section(ctx, "broadcom", "nvram", "broadcom");
|
||||
ucix_add_option(ctx, "broadcom", "nvram", "init", "1");
|
||||
ucix_commit(ctx, "broadcom");
|
||||
nvram_debug = ucix_get_option_int(ctx, "broadcom", "nvram", "debug");
|
||||
nvram_inited = 1;
|
||||
if (nvram_debug)
|
||||
printf("nvram_init()\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the value of an NVRAM variable. The pointer returned may be
|
||||
* invalid after a set.
|
||||
* @param name name of variable to get
|
||||
* @return value of variable or NULL if undefined
|
||||
*/
|
||||
const char * nvram_get(const char *name) {
|
||||
const char *ucitmp;
|
||||
nvram_init();
|
||||
ucitmp = ucix_get_option(ctx, "broadcom", "nvram", filter_dots_in_string(name));
|
||||
if (nvram_debug)
|
||||
printf("%s=nvram_get(%s)\n", ucitmp, name);
|
||||
|
||||
return ucitmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the value of an NVRAM variable. The name and value strings are
|
||||
* copied into private storage. Pointers to previously set values
|
||||
* may become invalid. The new value may be immediately
|
||||
* retrieved but will not be permanently stored until a commit.
|
||||
* @param name name of variable to set
|
||||
* @param value value of variable
|
||||
* @return 0 on success and errno on failure
|
||||
*/
|
||||
int nvram_set(const char *name, const char *value) {
|
||||
nvram_init();
|
||||
ucix_add_option(ctx, "broadcom", "nvram", filter_dots_in_string(name), value);
|
||||
ucix_commit(ctx, "broadcom");
|
||||
if (nvram_debug)
|
||||
printf("nvram_set(%s, %s)\n", filter_dots_in_string(name), value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unset an NVRAM variable. Pointers to previously set values
|
||||
* remain valid until a set.
|
||||
* @param name name of variable to unset
|
||||
* @return 0 on success and errno on failure
|
||||
* NOTE: use nvram_commit to commit this change to flash.
|
||||
*/
|
||||
int nvram_unset(const char *name){
|
||||
nvram_init();
|
||||
ucix_del(ctx, "broadcom", "nvram", filter_dots_in_string(name));
|
||||
ucix_commit(ctx, "broadcom");
|
||||
if (nvram_debug)
|
||||
printf("nvram_unset(%s)\n", filter_dots_in_string(name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Commit NVRAM variables to permanent storage. All pointers to values
|
||||
* may be invalid after a commit.
|
||||
* NVRAM values are undefined after a commit.
|
||||
* @return 0 on success and errno on failure
|
||||
*/
|
||||
int nvram_commit(void){
|
||||
nvram_init();
|
||||
ucix_commit(ctx, "broadcom");
|
||||
if (nvram_debug)
|
||||
printf("nvram_commit()\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get all NVRAM variables (format name=value\0 ... \0\0).
|
||||
* @param buf buffer to store variables
|
||||
* @param count size of buffer in bytes
|
||||
* @return 0 on success and errno on failure
|
||||
*/
|
||||
int nvram_getall(char *nvram_buf, int count) {
|
||||
nvram_init();
|
||||
|
||||
ptr.package = "broadcom";
|
||||
ptr.section = "nvram";
|
||||
|
||||
if (uci_lookup_ptr(ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return 1;
|
||||
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return 1;
|
||||
|
||||
nvram_display_section(ptr.s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <uci_config.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
static struct uci_ptr ptr;
|
||||
|
||||
static inline int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
memset(&ptr, 0, sizeof(ptr));
|
||||
ptr.package = p;
|
||||
ptr.section = s;
|
||||
ptr.option = o;
|
||||
ptr.value = t;
|
||||
return uci_lookup_ptr(ctx, &ptr, NULL, true);
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init(const char *config_file)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
uci_add_delta_path(ctx, "/var/state");
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init_path(const char *path, const char *config_file)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if(path)
|
||||
uci_set_confdir(ctx, path);
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ucix_cleanup(struct uci_context *ctx)
|
||||
{
|
||||
uci_free_context(ctx);
|
||||
}
|
||||
|
||||
void ucix_save(struct uci_context *ctx)
|
||||
{
|
||||
uci_set_savedir(ctx, "/tmp/.uci/");
|
||||
uci_save(ctx, NULL);
|
||||
}
|
||||
|
||||
void ucix_save_state(struct uci_context *ctx)
|
||||
{
|
||||
uci_set_savedir(ctx, "/var/state/");
|
||||
uci_save(ctx, NULL);
|
||||
}
|
||||
|
||||
const char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
const char *value = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return NULL;
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return NULL;
|
||||
e = ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_SECTION:
|
||||
value = uci_to_section(e)->type;
|
||||
break;
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(ptr.o->type) {
|
||||
case UCI_TYPE_STRING:
|
||||
value = ptr.o->v.string;
|
||||
break;
|
||||
default:
|
||||
value = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def)
|
||||
{
|
||||
const char *tmp = ucix_get_option(ctx, p, s, o);
|
||||
int ret = def;
|
||||
|
||||
if (tmp)
|
||||
ret = atoi(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, t))
|
||||
return;
|
||||
uci_set(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, o, (t)?(t):("")))
|
||||
return;
|
||||
uci_set(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_option(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if(!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_delete(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if(!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_revert(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&ptr.p->sections, e)
|
||||
if (!strcmp(t, uci_to_section(e)->type))
|
||||
cb(e->name, priv);
|
||||
}
|
||||
|
||||
int ucix_commit(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
return uci_commit(ctx, &ptr.p, false);
|
||||
}
|
||||
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#ifndef _UCI_H__
|
||||
#define _UCI_H__
|
||||
struct uci_context* ucix_init(const char *config_file);
|
||||
struct uci_context* ucix_init_path(const char *path, const char *config_file);
|
||||
void ucix_cleanup(struct uci_context *ctx);
|
||||
void ucix_save(struct uci_context *ctx);
|
||||
void ucix_save_state(struct uci_context *ctx);
|
||||
const char* ucix_get_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
int ucix_get_option_int(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, int def);
|
||||
void ucix_add_section(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *t);
|
||||
void ucix_add_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, const char *t);
|
||||
void ucix_add_option_int(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, int t);
|
||||
int ucix_commit(struct uci_context *ctx, const char *p);
|
||||
void ucix_revert(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
void ucix_del(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o);
|
||||
#endif
|
||||
115
broadcom-utils/Makefile
Normal file
115
broadcom-utils/Makefile
Normal 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))
|
||||
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
#PRG_VERSION := $(shell cd @top_srcdir@; if ! git describe --tags ;then echo version-$(PACKAGE_VERSION) ;fi )
|
||||
|
||||
AM_CFLAGS = $(OUR_CFLAGS)
|
||||
|
||||
bin_PROGRAMS = peripheral_manager
|
||||
dist_data_DATA = configs/hw
|
||||
|
||||
peripheral_manager_SOURCES = \
|
||||
src/peripheral_manager.c \
|
||||
src/ucix.c \
|
||||
src/ucix.h \
|
||||
src/server.c \
|
||||
src/server.h \
|
||||
src/led.c \
|
||||
src/led.h \
|
||||
src/sim_led.c \
|
||||
src/button.h \
|
||||
src/button.c \
|
||||
src/sim_button.c \
|
||||
src/catv.c \
|
||||
src/catv_monitor.c \
|
||||
src/catv.h \
|
||||
src/smbus.c \
|
||||
src/smbus.h \
|
||||
src/i2c.c \
|
||||
src/i2c.h \
|
||||
src/sfp.c \
|
||||
src/sfp.h
|
||||
|
||||
if BRCM_BOARD
|
||||
|
||||
bin_PROGRAMS += vox_test gpio_test
|
||||
|
||||
peripheral_manager_SOURCES += \
|
||||
src/gpio_led.c \
|
||||
src/gpio_led.h \
|
||||
src/gpio_button.c \
|
||||
src/gpio_button.h \
|
||||
src/gpio.c \
|
||||
src/gpio.h \
|
||||
src/gpio_shift_register.c \
|
||||
src/gpio_shift_register.h \
|
||||
src/touch_sx9512.c \
|
||||
src/touch_sx9512.h \
|
||||
src/sx9512.c \
|
||||
src/sx9512.h \
|
||||
src/vox.h \
|
||||
src/vox.c \
|
||||
src/prox_px3220.c
|
||||
|
||||
vox_test_SOURCES = \
|
||||
src/vox_test.c \
|
||||
src/gpio.c \
|
||||
src/gpio.h
|
||||
|
||||
gpio_test_SOURCES = \
|
||||
src/gpio_test.c \
|
||||
src/gpio.c \
|
||||
src/gpio.h \
|
||||
src/gpio_shift_register.c \
|
||||
src/gpio_shift_register.h \
|
||||
src/smbus.c \
|
||||
src/smbus.h \
|
||||
src/i2c.c \
|
||||
src/i2c.h \
|
||||
src/sx9512.c \
|
||||
src/sx9512.h
|
||||
|
||||
endif
|
||||
|
||||
peripheral_manager_LDADD = $(UCI_LIB) $(UBOX_LIB) $(UBUS_LIB) -lm
|
||||
|
||||
peripheral_manager_CFLAGS = $(AM_CFLAGS) -DPRG_VERSION=\"$(PRG_VERSION)\"
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
# test config for peripheral_manager
|
||||
# only contain options that peripheral_manager needs and that can be used
|
||||
# when compiling to host (not target hardware)
|
||||
|
||||
config board 'board'
|
||||
option hardware 'CG300'
|
||||
|
||||
# for CATV parsing we need this hardware
|
||||
# option hardware 'EG300'
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example for low level button.
|
||||
#
|
||||
#
|
||||
|
||||
config sim_button sim_buttons
|
||||
list buttons sim_button_A
|
||||
list buttons sim_button_B
|
||||
list buttons sim_button_c
|
||||
list buttons sim_button_d
|
||||
list buttons sim_button_e
|
||||
|
||||
config sim_button sim_button_A
|
||||
option addr 10
|
||||
option active hi
|
||||
|
||||
config sim_button sim_button_B
|
||||
option addr 11
|
||||
option active low
|
||||
|
||||
config sim_button sim_button_c
|
||||
option addr 12
|
||||
option active hi
|
||||
|
||||
config sim_button sim_button_d
|
||||
option addr 13
|
||||
option active hi
|
||||
|
||||
config sim_button sim_button_e
|
||||
option addr 14
|
||||
option active hi
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example for mapping system button to driver button.
|
||||
#
|
||||
# mapping serveral "functions" buttons to one physical can be done with the long press option
|
||||
# if
|
||||
#
|
||||
# this is a list of all button names. perifmanger will read this list then read out the specific button config
|
||||
|
||||
config button_map button_map
|
||||
list buttonnames RESET
|
||||
list buttonnames Wireless
|
||||
list buttonnames WPS
|
||||
list buttonnames DECTS
|
||||
list buttonnames DECTL
|
||||
list buttonnames TOUCH_NEAR
|
||||
list buttonnames TOUCH_FAR
|
||||
option minpress 100 # default minimum time a button nedes to be pressed.
|
||||
|
||||
config button_map RESET
|
||||
# list button gpio_reset
|
||||
list button sim_button_A # driver that is used for this button
|
||||
option minpress 5000 # don't allow button unless pressed for 5 seconds.
|
||||
option hotplug resetbutton
|
||||
|
||||
config button_map Wireless
|
||||
list button sim_button_B # driver that is used for this button
|
||||
list button sim_button_c # we support user having to press two at the same time to register a button event.
|
||||
option minpress 1000
|
||||
option hotplug ecobutton
|
||||
|
||||
# long press example one or the other of touch_near or touch_far will trigger not booth.
|
||||
|
||||
config button_map TOUCH_NEAR
|
||||
list button gpio_reset
|
||||
# list button sim_button_d # driver that is used for this button
|
||||
option hotplug touch_near
|
||||
|
||||
config button_map TOUCH_FAR
|
||||
list button sim_button_d # driver that is used for this button
|
||||
option longpress 3000 # this button has a long press option.
|
||||
option hotplug touch_far
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example for low level led driver.
|
||||
# here we list what the led can do and any info the driver needs to know to controll the led.
|
||||
#
|
||||
# would proably be smarter to name the leds as the color and not just A B C.
|
||||
# but this is an example to show there is no connection with the name and what it
|
||||
# does.
|
||||
#
|
||||
config sim_led sim_leds
|
||||
list leds sim_led_A
|
||||
list leds sim_led_B
|
||||
list leds sim_led_C
|
||||
|
||||
config sim_led sim_led_A
|
||||
option addr 1
|
||||
option color green
|
||||
option breading no
|
||||
|
||||
config sim_led sim_led_B
|
||||
option addr 7
|
||||
option color red
|
||||
option breading no
|
||||
|
||||
config sim_led sim_led_C
|
||||
option addr 3
|
||||
option color blue
|
||||
option breading yes
|
||||
option fadein yes
|
||||
option fadeout yes
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# gpio leds
|
||||
#
|
||||
config gpio_led gpio_leds
|
||||
list leds Status_green
|
||||
list leds Status_red
|
||||
list leds Wireless_green
|
||||
list leds Wireless_blue
|
||||
list leds WAN_green
|
||||
list leds WAN_yellow
|
||||
|
||||
config gpio_led Status_green
|
||||
option addr 39
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led Status_red
|
||||
option addr 38
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led Wireless_green
|
||||
option addr 37
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led Wireless_blue
|
||||
option addr 36
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led WAN_green
|
||||
option addr 9
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
config gpio_led WAN_yellow
|
||||
option addr 10
|
||||
option active low
|
||||
option mode direct
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# gpio buttons
|
||||
#
|
||||
|
||||
config gpio_button gpio_buttons
|
||||
list buttons gpio_reset
|
||||
|
||||
config gpio_button gpio_reset
|
||||
option addr 32
|
||||
option active low
|
||||
# option feedback
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# example mapping sim leds to system leds.
|
||||
#
|
||||
# the led_action list can be from one entry and up.
|
||||
#
|
||||
# led_action, list of leds to set.
|
||||
# button_action. list of button events to send out
|
||||
# effect_action, list of special effects to activate. (dim display.....)
|
||||
#
|
||||
|
||||
config led_map led_map
|
||||
list functions status
|
||||
list functions wifi
|
||||
list functions wps
|
||||
|
||||
config led_map led_status
|
||||
list led_action_ok 'sim_led_A = ON'
|
||||
list led_action_ok 'sim_led_B = OFF'
|
||||
list led_action_off 'sim_led_A = OFF'
|
||||
list led_action_off 'sim_led_B = OFF'
|
||||
list led_action_notice 'sim_led_A = FLASH_SLOW'
|
||||
list led_action_notice 'sim_led_B = OFF'
|
||||
list led_action_alert 'sim_led_A = OFF'
|
||||
list led_action_alert 'sim_led_B = FLASH_SLOW'
|
||||
list led_action_error 'sim_led_A = OFF'
|
||||
list led_action_error 'sim_led_B = FLASH_FAST'
|
||||
|
||||
config led_map led_wps
|
||||
# list led_action_ok 'WPS_green=ON'
|
||||
# list led_action_off 'WPS_green=OFF'
|
||||
# list led_action_notice 'WPS_green=FLASH_SLOW'
|
||||
# list led_action_alert 'WPS_green=FLASH_FAST'
|
||||
# list led_action_error 'WPS_green=OFF'
|
||||
|
||||
config led_map led_wifi
|
||||
# list led_action_ok 'Wireless_green = ON'
|
||||
# list led_action_ok 'Wireless_blue = OFF'
|
||||
# list led_action_eok 'Wireless_green = OFF'
|
||||
# list led_action_eok 'Wireless_blue = ON'
|
||||
# list led_action_off 'Wireless_green = OFF'
|
||||
# list led_action_off 'Wireless_blue = OFF'
|
||||
# list led_action_notice 'Wireless_green = FLASH_SLOW'
|
||||
# list led_action_notice 'Wireless_blue = OFF'
|
||||
# list led_action_alert 'Wireless_green = OFF'
|
||||
# list led_action_alert 'Wireless_blue = FLASH_SLOW'
|
||||
# list led_action_error 'Wireless_green = OFF'
|
||||
# list led_action_error 'Wireless_blue = FLASH_FAST'
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# function superfunctions
|
||||
#
|
||||
# Used when one led is controlled by seferal different functions
|
||||
# here we map in what state the underlying normal functions should have
|
||||
# to set a state, and what action to take in that state.
|
||||
|
||||
|
||||
# list available super functions.
|
||||
config led_map led_map
|
||||
list functions super_a
|
||||
|
||||
config led_map led_super_a
|
||||
list led_action_ok sim_led_C=ON
|
||||
list super_ok 'wifi_ok, wps_ok'
|
||||
|
||||
list led_action_off sim_led_C=OFF
|
||||
list super_off 'wifi_off, wps_off'
|
||||
|
||||
list led_action_notice sim_led_C=FLASH_SLOW
|
||||
list super_notice 'wifi_notice'
|
||||
list super_notice 'wps_notice'
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
dnl init stuff needs to be first in file
|
||||
AC_INIT([peripheral_manager], [0.1], [Kenneth Johansson <kenneth@southpole.se>])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
||||
CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
|
||||
-std=gnu11 \
|
||||
-pipe \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-inline \
|
||||
-Wundef \
|
||||
"-Wformat=2 -Wformat-security -Wformat-nonliteral" \
|
||||
-Wlogical-op \
|
||||
-Wsign-compare \
|
||||
-Wmissing-include-dirs \
|
||||
-Wold-style-definition \
|
||||
-Wpointer-arith \
|
||||
-Winit-self \
|
||||
-Wdeclaration-after-statement \
|
||||
-Wfloat-equal \
|
||||
-Wsuggest-attribute=noreturn \
|
||||
-Wmissing-prototypes \
|
||||
-Wstrict-prototypes \
|
||||
-Wredundant-decls \
|
||||
-Wmissing-declarations \
|
||||
-Wmissing-noreturn \
|
||||
-Wshadow \
|
||||
-Wendif-labels \
|
||||
-Wstrict-aliasing=2 \
|
||||
-Wwrite-strings \
|
||||
-Wno-long-long \
|
||||
-Wno-overlength-strings \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-unused-result \
|
||||
-Werror=overflow \
|
||||
-Wdate-time \
|
||||
-Wnested-externs \
|
||||
-ffast-math \
|
||||
-fno-common \
|
||||
-fdiagnostics-show-option \
|
||||
-fno-strict-aliasing \
|
||||
-fvisibility=hidden \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fstack-protector \
|
||||
-fstack-protector-strong \
|
||||
-fPIE \
|
||||
--param=ssp-buffer-size=4])
|
||||
|
||||
AC_SUBST([OUR_CFLAGS], "$with_cflags")
|
||||
|
||||
dnl check for uci , its manadatory
|
||||
AC_SEARCH_LIBS([uci_load], [uci], [], [AC_MSG_ERROR([*** UCI library not found])])
|
||||
|
||||
dnl check ubox , its manadatory
|
||||
AC_SEARCH_LIBS([uloop_init], [ubox], [], [AC_MSG_ERROR([*** UBOX library not found])])
|
||||
|
||||
dnl chek ubus , its manadatory
|
||||
AC_SEARCH_LIBS([ubus_connect], [ubus], [], [AC_MSG_ERROR([*** UBUS library not found])])
|
||||
|
||||
dnl check for board.h file
|
||||
AC_CHECK_HEADERS(board.h, AM_CONDITIONAL(BRCM_BOARD, true), AM_CONDITIONAL(BRCM_BOARD, false))
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([
|
||||
$PACKAGE_NAME $VERSION
|
||||
CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
|
||||
CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
||||
LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
|
||||
])
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
dnl Macros to check the presence of generic (non-typed) symbols.
|
||||
dnl Copyright (c) 2006-2008 Diego Pettenò <flameeyes@gmail.com>
|
||||
dnl Copyright (c) 2006-2008 xine project
|
||||
dnl Copyright (c) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2, or (at your option)
|
||||
dnl any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
dnl 02110-1301, USA.
|
||||
dnl
|
||||
dnl As a special exception, the copyright owners of the
|
||||
dnl macro gives unlimited permission to copy, distribute and modify the
|
||||
dnl configure scripts that are the output of Autoconf when processing the
|
||||
dnl Macro. You need not follow the terms of the GNU General Public
|
||||
dnl License when using or distributing such scripts, even though portions
|
||||
dnl of the text of the Macro appear in them. The GNU General Public
|
||||
dnl License (GPL) does govern all other use of the material that
|
||||
dnl constitutes the Autoconf Macro.
|
||||
dnl
|
||||
dnl This special exception to the GPL applies to versions of the
|
||||
dnl Autoconf Macro released by this project. When you make and
|
||||
dnl distribute a modified version of the Autoconf Macro, you may extend
|
||||
dnl this special exception to the GPL to apply to your modified version as
|
||||
dnl well.
|
||||
|
||||
dnl Check if FLAG in ENV-VAR is supported by compiler and append it
|
||||
dnl to WHERE-TO-APPEND variable
|
||||
dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG])
|
||||
|
||||
AC_DEFUN([CC_CHECK_FLAG_APPEND], [
|
||||
AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2],
|
||||
AS_TR_SH([cc_cv_$2_$3]),
|
||||
[eval "AS_TR_SH([cc_save_$2])='${$2}'"
|
||||
eval "AS_TR_SH([$2])='-Werror $3'"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; } ])],
|
||||
[eval "AS_TR_SH([cc_cv_$2_$3])='yes'"],
|
||||
[eval "AS_TR_SH([cc_cv_$2_$3])='no'"])
|
||||
eval "AS_TR_SH([$2])='$cc_save_$2'"])
|
||||
|
||||
AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes],
|
||||
[eval "$1='${$1} $3'"])
|
||||
])
|
||||
|
||||
dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2])
|
||||
AC_DEFUN([CC_CHECK_FLAGS_APPEND], [
|
||||
for flag in $3; do
|
||||
CC_CHECK_FLAG_APPEND($1, $2, $flag)
|
||||
done
|
||||
])
|
||||
|
||||
dnl Check if the flag is supported by linker (cacheable)
|
||||
dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
|
||||
|
||||
AC_DEFUN([CC_CHECK_LDFLAGS], [
|
||||
AC_CACHE_CHECK([if $CC supports $1 flag],
|
||||
AS_TR_SH([cc_cv_ldflags_$1]),
|
||||
[ac_save_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $1"
|
||||
AC_LINK_IFELSE([int main() { return 1; }],
|
||||
[eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
|
||||
[eval "AS_TR_SH([cc_cv_ldflags_$1])="])
|
||||
LDFLAGS="$ac_save_LDFLAGS"
|
||||
])
|
||||
|
||||
AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
|
||||
[$2], [$3])
|
||||
])
|
||||
|
||||
dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
|
||||
dnl the current linker to avoid undefined references in a shared object.
|
||||
AC_DEFUN([CC_NOUNDEFINED], [
|
||||
dnl We check $host for which systems to enable this for.
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
|
||||
case $host in
|
||||
dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
|
||||
dnl are requested, as different implementations are present; to avoid problems
|
||||
dnl use -Wl,-z,defs only for those platform not behaving this way.
|
||||
*-freebsd* | *-openbsd*) ;;
|
||||
*)
|
||||
dnl First of all check for the --no-undefined variant of GNU ld. This allows
|
||||
dnl for a much more readable command line, so that people can understand what
|
||||
dnl it does without going to look for what the heck -z defs does.
|
||||
for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
|
||||
CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
|
||||
break
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST([LDFLAGS_NOUNDEFINED])
|
||||
])
|
||||
|
||||
dnl Check for a -Werror flag or equivalent. -Werror is the GCC
|
||||
dnl and ICC flag that tells the compiler to treat all the warnings
|
||||
dnl as fatal. We usually need this option to make sure that some
|
||||
dnl constructs (like attributes) are not simply ignored.
|
||||
dnl
|
||||
dnl Other compilers don't support -Werror per se, but they support
|
||||
dnl an equivalent flag:
|
||||
dnl - Sun Studio compiler supports -errwarn=%all
|
||||
AC_DEFUN([CC_CHECK_WERROR], [
|
||||
AC_CACHE_CHECK(
|
||||
[for $CC way to treat warnings as errors],
|
||||
[cc_cv_werror],
|
||||
[CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
|
||||
[CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_CHECK_ATTRIBUTE], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
|
||||
AS_TR_SH([cc_cv_attribute_$1]),
|
||||
[ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
|
||||
[eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
|
||||
[eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
])
|
||||
|
||||
AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
|
||||
[AC_DEFINE(
|
||||
AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
|
||||
[Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
|
||||
)
|
||||
$4],
|
||||
[$5])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[constructor],,
|
||||
[void __attribute__((constructor)) ctor() { int a; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[format], [format(printf, n, n)],
|
||||
[void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[format_arg], [format_arg(printf)],
|
||||
[char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[visibility_$1], [visibility("$1")],
|
||||
[void __attribute__((visibility("$1"))) $1_function() { }],
|
||||
[$2], [$3])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[nonnull], [nonnull()],
|
||||
[void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[unused], ,
|
||||
[void some_function(void *foo, __attribute__((unused)) void *bar);],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[sentinel], ,
|
||||
[void some_function(void *foo, ...) __attribute__((sentinel));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[deprecated], ,
|
||||
[void some_function(void *foo, ...) __attribute__((deprecated));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[alias], [weak, alias],
|
||||
[void other_function(void *foo) { }
|
||||
void some_function(void *foo) __attribute__((weak, alias("other_function")));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[malloc], ,
|
||||
[void * __attribute__((malloc)) my_alloc(int n);],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_PACKED], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[packed], ,
|
||||
[struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_CONST], [
|
||||
CC_CHECK_ATTRIBUTE(
|
||||
[const], ,
|
||||
[int __attribute__((const)) twopow(int n) { return 1 << n; } ],
|
||||
[$1], [$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_FLAG_VISIBILITY], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
|
||||
[cc_cv_flag_visibility],
|
||||
[cc_flag_visibility_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
|
||||
cc_cv_flag_visibility='yes',
|
||||
cc_cv_flag_visibility='no')
|
||||
CFLAGS="$cc_flag_visibility_save_CFLAGS"])
|
||||
|
||||
AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
|
||||
[AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
|
||||
[Define this if the compiler supports the -fvisibility flag])
|
||||
$1],
|
||||
[$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_FUNC_EXPECT], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([if compiler has __builtin_expect function],
|
||||
[cc_cv_func_expect],
|
||||
[ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
|
||||
[int some_function() {
|
||||
int a = 3;
|
||||
return (int)__builtin_expect(a, 3);
|
||||
}])],
|
||||
[cc_cv_func_expect=yes],
|
||||
[cc_cv_func_expect=no])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
])
|
||||
|
||||
AS_IF([test "x$cc_cv_func_expect" = "xyes"],
|
||||
[AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
|
||||
[Define this if the compiler supports __builtin_expect() function])
|
||||
$1],
|
||||
[$2])
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
|
||||
AC_REQUIRE([CC_CHECK_WERROR])
|
||||
AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
|
||||
[cc_cv_attribute_aligned],
|
||||
[ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $cc_cv_werror"
|
||||
for cc_attribute_align_try in 64 32 16 8 4 2; do
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int main() {
|
||||
static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
|
||||
return c;
|
||||
}])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
|
||||
done
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_aligned" != "x"; then
|
||||
AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
|
||||
[Define the highest alignment supported])
|
||||
fi
|
||||
])
|
||||
|
|
@ -1,545 +0,0 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
#include "config.h"
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include "log.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "touch_sx9512.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
|
||||
static struct ubus_context *global_ubus_ctx;
|
||||
static struct blob_buf bblob;
|
||||
|
||||
static void button_ubus_interface_event(struct ubus_context *ubus_ctx, char *button, button_state_t pressed);
|
||||
|
||||
static void button_ubus_interface_event(struct ubus_context *ubus_ctx, char *button, button_state_t pressed)
|
||||
{
|
||||
char s[UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN];
|
||||
s[0]=0;
|
||||
strcat(s, UBUS_BUTTON_NAME_PREPEND);
|
||||
strcat(s, button);
|
||||
blob_buf_init(&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "action", pressed ? "pressed" : "released");
|
||||
ubus_send_event(ubus_ctx, s, bblob.head);
|
||||
}
|
||||
|
||||
|
||||
/* used to map in the driver buttons to a function button */
|
||||
struct button_drv_list {
|
||||
struct list_head list;
|
||||
struct timespec pressed_time;
|
||||
struct button_drv *drv;
|
||||
};
|
||||
|
||||
/**/
|
||||
struct function_button {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
int dimming;
|
||||
char *hotplug;
|
||||
char *hotplug_long;
|
||||
int minpress;
|
||||
int longpress; /* negative value means valid if mintime < time < abs(longpress ) */
|
||||
/* positive value means valid if time > longpreass */
|
||||
/* zero value means valid if time > mintime */
|
||||
struct list_head drv_list; /* list of all driver button that is needed to activate this button function */
|
||||
};
|
||||
|
||||
/* PUT every button from drivers into a list */
|
||||
struct drv_button_list{
|
||||
struct list_head list;
|
||||
struct button_drv *drv;
|
||||
};
|
||||
|
||||
/* list of all driver buttons added by drivers. */
|
||||
static LIST_HEAD(drv_buttons_list);
|
||||
|
||||
/* list containing all function buttons read from config file */
|
||||
static LIST_HEAD(buttons);
|
||||
|
||||
|
||||
void button_add( struct button_drv *drv)
|
||||
{
|
||||
struct drv_button_list *drv_node = malloc(sizeof(struct drv_button_list));
|
||||
|
||||
DBG(1,"called with button name [%s]", drv->name);
|
||||
drv_node->drv = drv;
|
||||
|
||||
list_add(&drv_node->list, &drv_buttons_list);
|
||||
}
|
||||
|
||||
static struct button_drv *get_drv_button(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_buttons_list) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
if (! strcmp(node->drv->name, name))
|
||||
return node->drv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct function_button *get_button(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if (! strcmp(node->name, name))
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! Read state for single button
|
||||
static button_state_t read_button_state(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
#ifdef HAVE_BOARD_H
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if(!strcmp(node->name, name)) {
|
||||
button_state_t state=BUTTON_ERROR;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv) {
|
||||
if(drv_node->drv->func->get_state(drv_node->drv))
|
||||
return BUTTON_PRESSED;
|
||||
else
|
||||
state=BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return BUTTON_ERROR;
|
||||
}
|
||||
|
||||
struct button_status {
|
||||
char name[BUTTON_MAX_NAME_LEN];
|
||||
button_state_t state;
|
||||
};
|
||||
|
||||
struct button_status_all {
|
||||
int n;
|
||||
struct button_status status[BUTTON_MAX];
|
||||
};
|
||||
|
||||
|
||||
//! Read states for all buttons
|
||||
static struct button_status_all * read_button_states(void)
|
||||
{
|
||||
static struct button_status_all p;
|
||||
struct list_head *i;
|
||||
p.n=0;
|
||||
#ifdef HAVE_BOARD_H
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
button_state_t state=BUTTON_ERROR;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
strcpy(p.status[p.n].name, node->name);
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv) {
|
||||
if(drv_node->drv->func->get_state(drv_node->drv))
|
||||
state=BUTTON_PRESSED;
|
||||
else
|
||||
state=BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
p.status[p.n].state = state;
|
||||
p.n++;
|
||||
}
|
||||
return &p;
|
||||
}
|
||||
|
||||
static void dump_drv_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_buttons_list) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
DBG(1,"button name = [%s]",node->drv->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_buttons_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
DBG(1,"button name = [%s]",node->name);
|
||||
{
|
||||
struct list_head *j;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv != NULL)
|
||||
DBG(1,"%13s drv button name = [%s]","",drv_node->drv->name);
|
||||
}
|
||||
DBG(1,"%13s minpress = %d","",node->minpress);
|
||||
DBG(1,"%13s longpress = %d","",node->longpress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Run the hotplug command associated with function button
|
||||
//! @retval 0 ok
|
||||
static int button_hotplug_cmd(const char *name, bool longpress)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if(!strcmp(node->name, name)) {
|
||||
char str[512];
|
||||
char *hotplug = node->hotplug;
|
||||
if(longpress && node->hotplug_long)
|
||||
hotplug = node->hotplug_long;
|
||||
if(!hotplug)
|
||||
return 1;
|
||||
DBG(1, "send key %s [%s] to system %s", node->name, hotplug, longpress ? "(longpress)" : "");
|
||||
snprintf(str, 512, "ACTION=register INTERFACE=%s /sbin/hotplug-call button &", hotplug);
|
||||
system(str);
|
||||
syslog(LOG_INFO, "%s",str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int timer_started(struct button_drv_list *button_drv)
|
||||
{
|
||||
if (button_drv->pressed_time.tv_sec == 0 )
|
||||
if (button_drv->pressed_time.tv_nsec == 0 )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void timer_start(struct button_drv_list *button_drv)
|
||||
{
|
||||
clock_gettime(CLOCK_MONOTONIC, &button_drv->pressed_time);
|
||||
}
|
||||
|
||||
static void timer_stop(struct button_drv_list *button_drv)
|
||||
{
|
||||
button_drv->pressed_time.tv_sec = 0;
|
||||
button_drv->pressed_time.tv_nsec = 0;
|
||||
}
|
||||
|
||||
|
||||
static button_press_type_t timer_valid(struct button_drv_list *button_drv, int mtimeout, int longpress)
|
||||
{
|
||||
struct timespec now;
|
||||
int sec;
|
||||
int nsec;
|
||||
int time_elapsed;
|
||||
|
||||
if (timer_started(button_drv)) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
sec = now.tv_sec - button_drv->pressed_time.tv_sec;
|
||||
nsec = now.tv_nsec - button_drv->pressed_time.tv_nsec;
|
||||
time_elapsed = sec*1000 + nsec/1000000;
|
||||
if ( mtimeout < time_elapsed) {
|
||||
if (longpress && (longpress < time_elapsed))
|
||||
return BUTTON_PRESS_LONG;
|
||||
return BUTTON_PRESS_SHORT;
|
||||
}
|
||||
}
|
||||
return BUTTON_PRESS_NONE;
|
||||
}
|
||||
|
||||
#define BUTTON_TIMEOUT 100
|
||||
static void button_handler(struct uloop_timeout *timeout);
|
||||
static struct uloop_timeout button_inform_timer = { .cb = button_handler };
|
||||
|
||||
static void button_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct list_head *i;
|
||||
int r;
|
||||
// DBG(1, "");
|
||||
|
||||
#ifdef HAVE_BOARD_H
|
||||
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
|
||||
/* clean out indicator status, set by any valid press again if we find it */
|
||||
led_pressindicator_set(PRESS_NONE);
|
||||
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if (drv_node->drv) {
|
||||
button_press_type_t time_type;
|
||||
button_state_t st = drv_node->drv->func->get_state(drv_node->drv);
|
||||
|
||||
if (st == BUTTON_PRESSED ) {
|
||||
if (! timer_started(drv_node)) {
|
||||
timer_start(drv_node);
|
||||
DBG(1, " %s pressed", drv_node->drv->name);
|
||||
// button_ubus_interface_event(global_ubus_ctx, node->name, BUTTON_PRESSED);
|
||||
}
|
||||
|
||||
time_type = timer_valid(drv_node, node->minpress, node->longpress);
|
||||
if( time_type == BUTTON_PRESS_LONG )
|
||||
led_pressindicator_set(PRESS_LONG);
|
||||
if( time_type == BUTTON_PRESS_SHORT )
|
||||
led_pressindicator_set(PRESS_SHORT);
|
||||
}
|
||||
|
||||
if (st == BUTTON_RELEASED ) {
|
||||
if (timer_started(drv_node)) {
|
||||
DBG(1, " %s released", drv_node->drv->name);
|
||||
if((r=timer_valid(drv_node, node->minpress, node->longpress))) {
|
||||
button_ubus_interface_event(global_ubus_ctx, node->name, BUTTON_RELEASED);
|
||||
if(node->dimming)
|
||||
led_dimming();
|
||||
DBG(1, " %s released timer_valid=%d", drv_node->drv->name,r);
|
||||
button_hotplug_cmd(node->name, r==BUTTON_PRESS_LONG);
|
||||
}
|
||||
}
|
||||
timer_stop(drv_node);
|
||||
}
|
||||
// DBG(1, " %s state = %d", drv_node->drv->name,st);
|
||||
}
|
||||
}
|
||||
}
|
||||
uloop_timeout_set(&button_inform_timer, BUTTON_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
static int button_state_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
// button_state_t state = read_button_state(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN);
|
||||
blob_buf_init(&bblob, 0);
|
||||
|
||||
switch(read_button_state(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN)) {
|
||||
case BUTTON_RELEASED:
|
||||
blobmsg_add_string(&bblob, "state", "released");
|
||||
break;
|
||||
case BUTTON_PRESSED:
|
||||
blobmsg_add_string(&bblob, "state", "pressed");
|
||||
break;
|
||||
default:
|
||||
blobmsg_add_string(&bblob, "state", "error");
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int button_press_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
button_hotplug_cmd(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN, 0);
|
||||
blob_buf_init(&bblob, 0);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int button_press_long_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
button_hotplug_cmd(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN, 1);
|
||||
blob_buf_init(&bblob, 0);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int buttons_state_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
int i;
|
||||
static struct button_status_all *p;
|
||||
p = read_button_states();
|
||||
blob_buf_init(&bblob, 0);
|
||||
for(i=0;i < p->n; i++) {
|
||||
switch(p->status[i].state) {
|
||||
case BUTTON_RELEASED:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "released");
|
||||
break;
|
||||
case BUTTON_PRESSED:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "pressed");
|
||||
break;
|
||||
default:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "error");
|
||||
}
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct ubus_method button_methods[] = {
|
||||
// { .name = "status", .handler = button_status_method },
|
||||
{ .name = "state", .handler = button_state_method },
|
||||
{ .name = "press", .handler = button_press_method },
|
||||
{ .name = "press_long", .handler = button_press_long_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type button_object_type = UBUS_OBJECT_TYPE("button", button_methods);
|
||||
|
||||
|
||||
static const struct ubus_method buttons_methods[] = {
|
||||
{ .name = "state", .handler = buttons_state_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type buttons_object_type = UBUS_OBJECT_TYPE("buttons", buttons_methods);
|
||||
|
||||
static struct ubus_object buttons_object = { .name = "buttons", .type = &buttons_object_type, .methods = buttons_methods, .n_methods = ARRAY_SIZE(buttons_methods), };
|
||||
|
||||
|
||||
void button_init( struct server_ctx *s_ctx)
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttonnames);
|
||||
int default_minpress = 100;
|
||||
char *s;
|
||||
int r;
|
||||
|
||||
global_ubus_ctx=s_ctx->ubus_ctx;
|
||||
|
||||
/* register buttons object with ubus */
|
||||
if((r=ubus_add_object(s_ctx->ubus_ctx, &buttons_object)))
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(r));
|
||||
|
||||
/* read out default global options */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "button_map", "minpress");
|
||||
DBG(1, "default minpress = [%s]", s);
|
||||
if (s){
|
||||
default_minpress = strtol(s,0,0);
|
||||
}
|
||||
|
||||
/* read function buttons from section button_map */
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"button_map", "buttonnames", &buttonnames);
|
||||
list_for_each_entry(node, &buttonnames, list) {
|
||||
struct function_button *function;
|
||||
|
||||
// DBG(1, "value = [%s]",node->val);
|
||||
|
||||
function = malloc(sizeof(struct function_button));
|
||||
memset(function,0,sizeof(struct function_button));
|
||||
function->name = node->val;
|
||||
|
||||
/* read out dimming */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "dimming");
|
||||
DBG(1, "dimming = [%s]", s);
|
||||
if (s){
|
||||
function->dimming = 1;
|
||||
}else
|
||||
function->dimming = 0;
|
||||
|
||||
/* read out minpress */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "minpress");
|
||||
DBG(1, "minpress = [%s]", s);
|
||||
if (s){
|
||||
function->minpress = strtol(s,0,0);
|
||||
}else
|
||||
function->minpress = default_minpress;
|
||||
|
||||
/* read out long_press */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "longpress");
|
||||
DBG(1, "longpress = [%s]", s);
|
||||
if (s){
|
||||
function->longpress = strtol(s,0,0);
|
||||
}
|
||||
|
||||
/* read out hotplug option */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "hotplug");
|
||||
DBG(1, "hotplug = [%s]", s);
|
||||
if (s){
|
||||
function->hotplug = s;
|
||||
}
|
||||
|
||||
/* read out hotplug option for longpress */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "hotplug_long");
|
||||
DBG(1, "hotplug_long = [%s]", s);
|
||||
if (s){
|
||||
function->hotplug_long = s;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&function->drv_list);
|
||||
|
||||
{
|
||||
struct ucilist *drv_node;
|
||||
LIST_HEAD(head);
|
||||
int num = 0;
|
||||
|
||||
/* read out all driver buttons that needs to be pressed for this button function. */
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,function->name, "button", &head);
|
||||
|
||||
list_for_each_entry(drv_node, &head, list) {
|
||||
struct button_drv_list *new_button;
|
||||
|
||||
num++;
|
||||
DBG(1,"function %s -> drv button %s", function->name, drv_node->val);
|
||||
|
||||
new_button = malloc(sizeof(struct button_drv_list));
|
||||
memset(new_button,0,sizeof(struct button_drv_list));
|
||||
|
||||
new_button->drv = get_drv_button(drv_node->val);
|
||||
|
||||
if(new_button->drv == NULL){
|
||||
syslog(LOG_WARNING, "%s wanted drv button [%s] but it can't be found. check spelling.",
|
||||
function->name,
|
||||
drv_node->val);
|
||||
}
|
||||
|
||||
list_add( &new_button->list, &function->drv_list);
|
||||
}
|
||||
if (num == 0 )
|
||||
syslog(LOG_WARNING, "Function %s did not have any mapping to a driver button", function->name);
|
||||
}
|
||||
|
||||
list_add(&function->list, &buttons);
|
||||
|
||||
/* register each button with ubus */
|
||||
{
|
||||
struct ubus_object *ubo;
|
||||
char name[UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN];
|
||||
ubo = malloc(sizeof(struct ubus_object));
|
||||
memset(ubo, 0, sizeof(struct ubus_object));
|
||||
|
||||
snprintf(name, UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN, "%s%s", UBUS_BUTTON_NAME_PREPEND, node->val);
|
||||
ubo->name = strdup(name);
|
||||
ubo->methods = button_methods;
|
||||
ubo->n_methods = ARRAY_SIZE(button_methods);
|
||||
ubo->type = &button_object_type;
|
||||
if((r=ubus_add_object(s_ctx->ubus_ctx, ubo)))
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(r));
|
||||
}
|
||||
}
|
||||
|
||||
uloop_timeout_set(&button_inform_timer, BUTTON_TIMEOUT);
|
||||
|
||||
dump_drv_list();
|
||||
dump_buttons_list();
|
||||
}
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef BUTTON_H
|
||||
#define BUTTON_H
|
||||
#include "server.h"
|
||||
|
||||
#define BUTTON_MAX 32
|
||||
#define BUTTON_MAX_NAME_LEN 16
|
||||
#define UBUS_BUTTON_NAME_PREPEND "button."
|
||||
#define UBUS_BUTTON_NAME_PREPEND_LEN sizeof(UBUS_BUTTON_NAME_PREPEND)
|
||||
|
||||
typedef enum {
|
||||
BUTTON_RELEASED,
|
||||
BUTTON_PRESSED,
|
||||
BUTTON_ERROR,
|
||||
} button_state_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_PRESS_NONE,
|
||||
BUTTON_PRESS_SHORT,
|
||||
BUTTON_PRESS_LONG,
|
||||
} button_press_type_t;
|
||||
|
||||
struct button_drv;
|
||||
|
||||
struct button_drv_func {
|
||||
button_state_t (*get_state)(struct button_drv *); /* Get button state, on,off ... */
|
||||
};
|
||||
|
||||
struct button_drv {
|
||||
const char *name; /* name, set in the confg file,has to be uniq */
|
||||
void *priv; /* for use by the driver */
|
||||
struct button_drv_func *func; /* function pointers for reading the button */
|
||||
};
|
||||
|
||||
void button_add( struct button_drv *drv);
|
||||
void button_init( struct server_ctx *s_ctx);
|
||||
|
||||
#endif /* BUTTON_H */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef CATV_H
|
||||
#include "libubus.h"
|
||||
|
||||
#include "ucix.h"
|
||||
|
||||
struct catv_handler;
|
||||
|
||||
struct catv_handler * catv_init(struct uci_context *uci_ctx, const char * i2c_bus, int i2c_addr_a0,int i2c_addr_a2);
|
||||
void catv_destroy(struct catv_handler *h);
|
||||
int catv_ubus_populate(struct catv_handler *h, struct ubus_context *ubus_ctx);
|
||||
|
||||
#endif /* CATV_H */
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "log.h"
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include "libubus.h"
|
||||
#include <uci_config.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
typedef enum {
|
||||
STATE_OFF,
|
||||
STATE_OK,
|
||||
STATE_NOTICE,
|
||||
STATE_ALERT,
|
||||
STATE_ERROR,
|
||||
}state_t;
|
||||
|
||||
state_t state;
|
||||
|
||||
static struct ubus_context *ubus_ctx;
|
||||
static char *ubus_socket;
|
||||
|
||||
#define CATV_MONITOR_TIME (1000 * 10) /* 10 sec in ms */
|
||||
|
||||
void catv_monitor_init(struct server_ctx *s_ctx);
|
||||
void catv_monitor_set_socket(char *socket_name);
|
||||
|
||||
static void set_led(state_t state);
|
||||
static int is_enabled(void);
|
||||
|
||||
static void catv_monitor_handler(struct uloop_timeout *timeout);
|
||||
struct uloop_timeout catv_monitor_timer = { .cb = catv_monitor_handler };
|
||||
|
||||
static void
|
||||
catv_status_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
uint32_t rem;
|
||||
const char *data;
|
||||
|
||||
rem = blob_len(msg);
|
||||
|
||||
__blob_for_each_attr(cur, blob_data(msg), rem) {
|
||||
if (!strcmp("RF enable", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
if (!strncasecmp("on", data, 2))
|
||||
*(int*)req->priv = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*(int*)req->priv = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static int is_enabled(void)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf b;
|
||||
int enabled = 0;
|
||||
int ret;
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, "catv", &id)) {
|
||||
DBG(4, "Failed to look up catv object\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&b, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
ret = ubus_invoke(ubus_ctx, id, "status", b.head, catv_status_cb, &enabled, 3000);
|
||||
|
||||
if (ret)
|
||||
DBG(1,"catv_monitor: ret = %s", ubus_strerror(ret));
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static void
|
||||
catv_vpd_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
uint32_t rem;
|
||||
const char *data = "-inf";
|
||||
|
||||
rem = blob_len(msg);
|
||||
|
||||
/* no response */
|
||||
if ( rem == 0 ) {
|
||||
state = STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
__blob_for_each_attr(cur, blob_data(msg), rem) {
|
||||
if (!strcmp("VPD", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
}
|
||||
}
|
||||
|
||||
/* no cable */
|
||||
if (!strcmp("-inf", data)) {
|
||||
state = STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
catv_alarm_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
uint32_t rem;
|
||||
const char *data = "-inf";
|
||||
|
||||
rem = blob_len(msg);
|
||||
|
||||
/* no response */
|
||||
if ( rem == 0 ) {
|
||||
state = STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
__blob_for_each_attr(cur, blob_data(msg), rem) {
|
||||
if (!strcasecmp("Alarm VPD HI", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_ALERT;
|
||||
}
|
||||
}else if (!strcasecmp("Alarm VPD LO", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_ALERT;
|
||||
}
|
||||
}else if (!strcasecmp("Warning VPD HI", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_NOTICE;
|
||||
}
|
||||
}else if (!strcasecmp("Warning VPD LO", blobmsg_name(cur))) {
|
||||
data = blobmsg_data(cur);
|
||||
/* if on */
|
||||
if (!strcmp("on", data)) {
|
||||
state = STATE_NOTICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void catv_monitor_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf b;
|
||||
int ret;
|
||||
|
||||
/* start to set new state to OK */
|
||||
/* then checks turn on different errors */
|
||||
state = STATE_OK;
|
||||
|
||||
if (is_enabled()) {
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, "catv", &id)) {
|
||||
DBG(1, "Failed to look up catv object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&b, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
/* first check alarms, they set notice/alert if present */
|
||||
ret = ubus_invoke(ubus_ctx, id, "alarm", b.head, catv_alarm_cb, 0, 3000);
|
||||
if (ret)
|
||||
DBG(1,"ret = %s", ubus_strerror(ret));
|
||||
|
||||
/* then check cable in, it sets Error,*/
|
||||
ret = ubus_invoke(ubus_ctx, id, "vpd", b.head, catv_vpd_cb, 0, 3000);
|
||||
if (ret)
|
||||
DBG(1,"ret = %s", ubus_strerror(ret));
|
||||
}else
|
||||
state = STATE_OFF;
|
||||
|
||||
set_led(state);
|
||||
|
||||
uloop_timeout_set(&catv_monitor_timer, CATV_MONITOR_TIME);
|
||||
}
|
||||
|
||||
static void set_led(state_t lstate)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf b;
|
||||
int ret;
|
||||
static state_t old_state = -1;
|
||||
|
||||
if ( lstate == old_state )
|
||||
return;
|
||||
old_state = lstate;
|
||||
|
||||
memset(&b, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
switch (lstate) {
|
||||
case STATE_OFF:
|
||||
blobmsg_add_string(&b, "state", "off"); break;
|
||||
case STATE_OK:
|
||||
blobmsg_add_string(&b, "state", "ok"); break;
|
||||
case STATE_NOTICE:
|
||||
blobmsg_add_string(&b, "state", "notice"); break;
|
||||
case STATE_ALERT:
|
||||
blobmsg_add_string(&b, "state", "alert"); break;
|
||||
case STATE_ERROR:
|
||||
blobmsg_add_string(&b, "state", "error"); break;
|
||||
}
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, "led.ext", &id)) {
|
||||
DBG(1, "Failed to look up led.ext object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ubus_invoke(ubus_ctx, id, "set", b.head, NULL, 0, 3000);
|
||||
|
||||
if ( ret )
|
||||
DBG(1,"catv_moitor: set led failed [%s]", ubus_strerror(ret));
|
||||
}
|
||||
|
||||
void catv_monitor_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
ubus_ctx = ubus_connect(ubus_socket);
|
||||
if (!ubus_ctx) {
|
||||
syslog(LOG_ERR,"catv monitor: Failed to connect to ubus\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* start monitor timer */
|
||||
uloop_timeout_set(&catv_monitor_timer, CATV_MONITOR_TIME);
|
||||
}
|
||||
|
||||
void catv_monitor_set_socket(char *socket_name)
|
||||
{
|
||||
if (socket_name)
|
||||
ubus_socket = strdup(socket_name);
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include "gpio.h"
|
||||
#include "log.h"
|
||||
|
||||
#define DEVFILE_BRCM_BOARD "/dev/brcmboard"
|
||||
|
||||
static int brcmboard = -1;
|
||||
|
||||
|
||||
int board_ioctl_init(void) {
|
||||
if (brcmboard == -1){
|
||||
brcmboard = open(DEVFILE_BRCM_BOARD, O_RDWR);
|
||||
if ( brcmboard == -1 ) {
|
||||
syslog(LOG_ERR, "failed to open: %s", DEVFILE_BRCM_BOARD);
|
||||
return 1;
|
||||
}
|
||||
DBG(1, "fd %d allocated\n", brcmboard);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_buf_len, int offset) {
|
||||
BOARD_IOCTL_PARMS IoctlParms = {0};
|
||||
|
||||
IoctlParms.string = string_buf;
|
||||
IoctlParms.strLen = string_buf_len;
|
||||
IoctlParms.offset = offset;
|
||||
IoctlParms.action = action;
|
||||
IoctlParms.buf = (char*)"";
|
||||
IoctlParms.result = 0;
|
||||
|
||||
if (brcmboard != -1){
|
||||
if ( ioctl(brcmboard, ioctl_id, &IoctlParms) < 0 ) {
|
||||
syslog(LOG_ERR, "ioctl: %d failed", ioctl_id);
|
||||
return(-255);
|
||||
}
|
||||
|
||||
}
|
||||
return IoctlParms.result;
|
||||
}
|
||||
|
||||
|
||||
gpio_state_t gpio_get_state(gpio_t gpio)
|
||||
{
|
||||
return board_ioctl(BOARD_IOCTL_GET_GPIO, 0, 0, NULL, gpio, 0);
|
||||
}
|
||||
|
||||
void gpio_set_state(gpio_t gpio, gpio_state_t state)
|
||||
{
|
||||
board_ioctl(BOARD_IOCTL_SET_GPIO, 0, 0, NULL, gpio, state);
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <board.h>
|
||||
|
||||
typedef int gpio_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_STATE_LOW,
|
||||
GPIO_STATE_HIGH,
|
||||
} gpio_state_t;
|
||||
|
||||
int board_ioctl_init(void);
|
||||
int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_buf_len, int offset);
|
||||
#define gpio_init() board_ioctl_init()
|
||||
gpio_state_t gpio_get_state(gpio_t gpio);
|
||||
void gpio_set_state(gpio_t gpio, gpio_state_t state);
|
||||
|
||||
#endif /* GPIO_H */
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "button.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "gpio.h"
|
||||
#include <board.h>
|
||||
|
||||
void gpio_button_init(struct server_ctx *s_ctx);
|
||||
|
||||
struct gpio_button_data {
|
||||
int addr;
|
||||
int active;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
static button_state_t gpio_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
struct gpio_button_data *p = (struct gpio_button_data *)drv->priv;
|
||||
int value;
|
||||
|
||||
value = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, p->addr, 0);
|
||||
|
||||
if(p->active)
|
||||
p->state = !!value;
|
||||
else
|
||||
p->state = !value;
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func func = {
|
||||
.get_state = gpio_button_get_state,
|
||||
};
|
||||
|
||||
void gpio_button_init(struct server_ctx *s_ctx) {
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"gpio_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct gpio_button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct gpio_button_data));
|
||||
memset(data,0,sizeof(struct gpio_button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "active");
|
||||
data->active = -1;
|
||||
if (s){
|
||||
if (!strncasecmp("hi",s,2))
|
||||
data->active = 1;
|
||||
else if (!strncasecmp("low",s,3))
|
||||
data->active = 0;
|
||||
|
||||
}
|
||||
DBG(1, "active = %d", data->active);
|
||||
|
||||
data->button.func = &func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
}
|
||||
|
||||
gpio_init();
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <board.h>
|
||||
#include "led.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_shift_register.h"
|
||||
|
||||
gpio_shift_register_t led_gpio_shift_register;
|
||||
|
||||
void gpio_led_init(struct server_ctx *s_ctx);
|
||||
|
||||
typedef enum {
|
||||
LOW,
|
||||
HI,
|
||||
UNKNOWN,
|
||||
} active_t;
|
||||
|
||||
typedef enum {
|
||||
MODE_UNKNOWN,
|
||||
DIRECT,
|
||||
SHIFTREG_BRCM,
|
||||
SHIFTREG_GPIO,
|
||||
} gpio_mode_t;
|
||||
|
||||
struct gpio_led_data {
|
||||
int addr;
|
||||
active_t active;
|
||||
int state;
|
||||
gpio_mode_t mode;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
static int gpio_led_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct gpio_led_data *p = (struct gpio_led_data *)drv->priv;
|
||||
int bit_val = 0;
|
||||
|
||||
if(state) {
|
||||
if(p->active)
|
||||
bit_val=1;
|
||||
} else {
|
||||
if(!p->active)
|
||||
bit_val=1;
|
||||
}
|
||||
|
||||
p->state = state;
|
||||
|
||||
switch (p->mode) {
|
||||
case DIRECT:
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, p->addr, bit_val);
|
||||
break;
|
||||
case SHIFTREG_BRCM:
|
||||
board_ioctl( BOARD_IOCTL_LED_CTRL, 0, 0, NULL, p->addr, bit_val);
|
||||
break;
|
||||
case SHIFTREG_GPIO:
|
||||
gpio_shift_register_cached_set(&led_gpio_shift_register, p->addr, bit_val);
|
||||
break;
|
||||
default:
|
||||
DBG(1,"access mode not supported [%d,%s]", p->mode, p->led.name);
|
||||
}
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static led_state_t gpio_led_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct gpio_led_data *p = (struct gpio_led_data *)drv->priv;
|
||||
DBG(1, "state for %s", drv->name);
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = gpio_led_set_state,
|
||||
.get_state = gpio_led_get_state,
|
||||
};
|
||||
|
||||
void gpio_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
int gpio_shiftreg_clk=0, gpio_shiftreg_dat=1, gpio_shiftreg_mask=2, gpio_shiftreg_bits=0;
|
||||
char *s;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_clk")))
|
||||
gpio_shiftreg_clk = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_clk = [%d]", gpio_shiftreg_clk);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_dat")))
|
||||
gpio_shiftreg_dat = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_dat = [%d]", gpio_shiftreg_dat);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_mask")))
|
||||
gpio_shiftreg_mask = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_mask = [%d]", gpio_shiftreg_mask);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_bits")))
|
||||
gpio_shiftreg_bits = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_bits = [%d]", gpio_shiftreg_bits);
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"gpio_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct gpio_led_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct gpio_led_data));
|
||||
memset(data,0,sizeof(struct gpio_led_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s) {
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "mode");
|
||||
DBG(1, "mode = [%s]", s);
|
||||
if (s) {
|
||||
|
||||
if (!strncasecmp("direct",s,3))
|
||||
data->mode = DIRECT;
|
||||
else if (!strncasecmp("sr",s,5))
|
||||
data->mode = SHIFTREG_BRCM;
|
||||
else if (!strncasecmp("csr",s,4))
|
||||
data->mode = SHIFTREG_GPIO;
|
||||
else
|
||||
DBG(1, "Mode %s : Not supported!", s);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "active");
|
||||
DBG(1, "active = [%s]", s);
|
||||
if (s) {
|
||||
data->active = UNKNOWN;
|
||||
if (!strncasecmp("hi",s,3))
|
||||
data->active = HI;
|
||||
if (!strncasecmp("low",s,3))
|
||||
data->active = LOW;
|
||||
}
|
||||
data->led.func = &func;
|
||||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
}
|
||||
gpio_init();
|
||||
gpio_shift_register_init(&led_gpio_shift_register, gpio_shiftreg_clk, gpio_shiftreg_dat, gpio_shiftreg_mask, gpio_shiftreg_bits);
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#include "gpio_shift_register.h"
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
int gpio_shift_register_init(gpio_shift_register_t *p, gpio_t gpio_clk, gpio_t gpio_dat, gpio_t gpio_mask, int size)
|
||||
{
|
||||
p->clk=gpio_clk;
|
||||
p->dat=gpio_dat;
|
||||
p->mask=gpio_mask;
|
||||
p->size=size;
|
||||
p->state_cache=0;
|
||||
gpio_set_state(p->clk, 0);
|
||||
gpio_set_state(p->dat, 0);
|
||||
gpio_set_state(p->mask, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_shift_register_set(gpio_shift_register_t *p, int state)
|
||||
{
|
||||
int i;
|
||||
if(!p->size)
|
||||
return;
|
||||
gpio_set_state(p->mask, 0); //mask low
|
||||
for(i=p->size; i; i--) {
|
||||
gpio_set_state(p->clk, 0); //clk low
|
||||
gpio_set_state(p->dat, (state>>(i-1)) & 1); //place bit
|
||||
gpio_set_state(p->clk, 1); //clk high
|
||||
}
|
||||
gpio_set_state(p->mask, 1); //mask high / sreg load
|
||||
p->state_cache=state; //update internal register copy
|
||||
}
|
||||
|
||||
|
||||
void gpio_shift_register_cached_set(gpio_shift_register_t *p, shift_register_index_t index, gpio_state_t state)
|
||||
{
|
||||
if(!p->size)
|
||||
return;
|
||||
if(!(index < p->size)) {
|
||||
syslog(LOG_ERR, "index %d out of bounds", index);
|
||||
return;
|
||||
}
|
||||
//update internal register copy
|
||||
if(state)
|
||||
p->state_cache |= (1<<index);
|
||||
else
|
||||
p->state_cache &= ~(1<<index);
|
||||
gpio_shift_register_set(p, p->state_cache);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef GPIO_SHIFT_REGISTER_H
|
||||
#define GPIO_SHIFT_REGISTER_H
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
typedef int shift_register_index_t;
|
||||
|
||||
typedef struct {
|
||||
gpio_t clk;
|
||||
gpio_t dat;
|
||||
gpio_t mask;
|
||||
int size;
|
||||
int state_cache;
|
||||
} gpio_shift_register_t;
|
||||
|
||||
int gpio_shift_register_init(gpio_shift_register_t *p, gpio_t gpio_clk, gpio_t gpio_dat, gpio_t gpio_mask, int size);
|
||||
void gpio_shift_register_set(gpio_shift_register_t *p, int state);
|
||||
void gpio_shift_register_cached_set(gpio_shift_register_t *p, shift_register_index_t address, gpio_state_t bit_val);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,376 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
//#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
//#include <limits.h>
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
//#include <syslog.h>
|
||||
//#include <config.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "smbus.h"
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_shift_register.h"
|
||||
#include "sx9512.h"
|
||||
|
||||
#define DEV_I2C "/dev/i2c-0"
|
||||
|
||||
int verbose, debug_level;
|
||||
|
||||
|
||||
#define CMDS \
|
||||
X(NONE, "none", 0, 0, "", "") \
|
||||
X(GPIO_GET, "gpio_get", 1, 1, "Get pin state", "<pin>") \
|
||||
X(GPIO_SET, "gpio_set", 2, 2, "Set pin state", "<pin> <state>") \
|
||||
X(SH_SET, "sh_set", 5, 5, "Set shift register state", "<clk> <dat> <mask> <size> <state>") \
|
||||
X(SMBUS_READ, "smbus_read", 3, 3, "Read from I2C/SMBUS device", "<addr> <reg> <len>") \
|
||||
X(SMBUS_WRITE, "smbus_write", 3, 3, "Write to I2C/SMBUS device", "<addr> <reg> <hex_data>") \
|
||||
X(SX9512_BUTTON, "sx9512_button", 0, 0, "Read SX9512 buttons (endless loop)", "") \
|
||||
X(SX9512_READ, "sx9512_read", 0, 0, "Look at configuration data (compare to default)", "") \
|
||||
X(SX9512_INIT, "sx9512_init", 0, 1, "Init SX9512 config to device defaults", "[device]") \
|
||||
X(SX9512_NVM_LOAD, "sx9512_nvm_load", 0, 0, "SX9512 load values from NVM", "") \
|
||||
X(SX9512_NVM_STORE, "sx9512_nvm_store", 0, 0, "SX9512 store config to NVM", "") \
|
||||
X(SX9512_RESET, "sx9512_reset", 0, 0, "Send reset command to SX9512", "")
|
||||
|
||||
|
||||
#define X(id, str, min_arg, max_arg, desc, arg_desc) CMD_##id,
|
||||
enum { CMDS CMDS_AMOUNT } cmd;
|
||||
#undef X
|
||||
|
||||
struct cmd {
|
||||
const char *str;
|
||||
int min_arg, max_arg;
|
||||
const char *desc, *arg_desc;
|
||||
};
|
||||
|
||||
#define X(id, str, min_arg, max_arg, desc, arg_desc) { str, min_arg, max_arg, desc, arg_desc },
|
||||
const struct cmd cmd_data[] = { CMDS };
|
||||
#undef X
|
||||
|
||||
|
||||
#define SX9512_DEVCFGS \
|
||||
X(NONE, "none" ) \
|
||||
X(DEFAULT, "default") \
|
||||
X(CLEAR, "clear" ) \
|
||||
X(CG300, "cg300" ) \
|
||||
X(CG301, "cg301" ) \
|
||||
X(EG300, "eg300" ) \
|
||||
X(DG400, "dg400" )
|
||||
|
||||
#define X(a, b) SX9512_DEVCFG_##a,
|
||||
enum sx9512_devcfg { SX9512_DEVCFGS SX9512_DEVCFG_AMOUNT };
|
||||
#undef X
|
||||
|
||||
#define X(a, b) b,
|
||||
const char *sx9512_devcfg_str[] = { SX9512_DEVCFGS };
|
||||
#undef X
|
||||
|
||||
|
||||
static enum sx9512_devcfg sx9512_devcfg_str_to_id(const char *s)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<SX9512_DEVCFG_AMOUNT; i++) {
|
||||
if(!strcmp(s, sx9512_devcfg_str[i]))
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void print_usage(char *prg_name)
|
||||
{
|
||||
int i;
|
||||
char tmp[64];
|
||||
printf("Usage: %s [options...] <cmd> <arg(s)>\n", prg_name);
|
||||
printf("Options:\n");
|
||||
printf(" -v, --verbose Verbose output\n");
|
||||
printf(" -h, --help Show this help screen.\n");
|
||||
printf("Commands:\n");
|
||||
for(i=0;i<CMDS_AMOUNT;i++) {
|
||||
sprintf(tmp, "%s %s", cmd_data[i].str, cmd_data[i].arg_desc);
|
||||
printf(" %-40.40s %s\n", tmp, cmd_data[i].desc);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, ch, r, fd=0;
|
||||
int pin, state;
|
||||
int pin_clk, pin_dat, pin_mask;
|
||||
gpio_shift_register_t p;
|
||||
int addr=0, s, n, l;
|
||||
enum sx9512_devcfg devcfg=0;
|
||||
uint8_t tmp[32];
|
||||
char *str_value=0, *eptr, str_hex[3];
|
||||
struct sx9512_reg_nvm nvm, nvm_def;
|
||||
while(1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
ch = getopt_long(argc, argv, "vh", long_options, &option_index);
|
||||
if(ch == -1)
|
||||
break;
|
||||
switch (ch) {
|
||||
case 'v':
|
||||
verbose=1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//i=argc-optind;
|
||||
if((argc-optind)<1) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: need cmd");
|
||||
}
|
||||
for(i=0;i<CMDS_AMOUNT;i++) {
|
||||
if(!strcmp(argv[optind], cmd_data[i].str))
|
||||
cmd=i;
|
||||
}
|
||||
if(!cmd) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: bad cmd %s", argv[optind]);
|
||||
}
|
||||
optind++;
|
||||
if((argc-optind)<cmd_data[cmd].min_arg) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: too few arguments");
|
||||
}
|
||||
if((argc-optind)>cmd_data[cmd].max_arg) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: too many arguments");
|
||||
}
|
||||
switch(cmd) {
|
||||
case CMD_GPIO_GET:
|
||||
case CMD_GPIO_SET:
|
||||
case CMD_SH_SET:
|
||||
gpio_init();
|
||||
break;
|
||||
case CMD_SMBUS_READ:
|
||||
case CMD_SMBUS_WRITE:
|
||||
addr=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
if(verbose)
|
||||
printf("Open I2C device %s\n", DEV_I2C);
|
||||
fd = open(DEV_I2C, O_RDWR);
|
||||
if(fd < 0)
|
||||
error(-1, errno, "could not open %s", DEV_I2C);
|
||||
if(verbose)
|
||||
printf("Set I2C addr=%02x\n", addr);
|
||||
if(ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
error(0, errno, "could not set address %x for i2c chip", addr);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CMD_SX9512_BUTTON:
|
||||
case CMD_SX9512_READ:
|
||||
case CMD_SX9512_INIT:
|
||||
case CMD_SX9512_NVM_LOAD:
|
||||
case CMD_SX9512_NVM_STORE:
|
||||
case CMD_SX9512_RESET:
|
||||
if((fd=sx9512_init(DEV_I2C, SX9512_I2C_ADDRESS, NULL))<0)
|
||||
error(-1, errno, "could not init SX9512");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
case CMD_GPIO_GET:
|
||||
pin=strtol(argv[optind],0,0);
|
||||
if(verbose)
|
||||
printf("Get gpio %d state\n", pin);
|
||||
r=gpio_get_state(pin);
|
||||
if(verbose)
|
||||
printf("state=%d\n", r);
|
||||
return(r);
|
||||
case CMD_GPIO_SET:
|
||||
pin=strtol(argv[optind],0,0);
|
||||
optind++;
|
||||
state=strtol(argv[optind],0,0);
|
||||
if(state!=0 && state!=1) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: bad state %d", state);
|
||||
}
|
||||
if(verbose)
|
||||
printf("Set gpio %d state to %d\n", pin, state);
|
||||
gpio_set_state(pin, state);
|
||||
break;
|
||||
case CMD_SH_SET:
|
||||
pin_clk=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
pin_dat=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
pin_mask=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
s=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
state=strtol(argv[optind],NULL,16);
|
||||
if(verbose)
|
||||
printf("Set shift register (clk=%d, dat=%d, mask=%d, size=%d) state to %X\n", pin_clk, pin_dat, pin_mask, s, state);
|
||||
gpio_shift_register_init(&p, pin_clk, pin_dat, pin_mask, s);
|
||||
gpio_shift_register_set(&p, state);
|
||||
break;
|
||||
case CMD_SMBUS_READ:
|
||||
s=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
n=strtol(argv[optind],NULL,0);
|
||||
if(s+n>256)
|
||||
n=256-s;
|
||||
if(verbose)
|
||||
printf("smbus read start (addr=%02x, reg=%02x, len=%d)\n", addr, s, n);
|
||||
for(i=s; i<(s+n); i+=32) {
|
||||
l=n-(i-s);
|
||||
if(l>32)
|
||||
l=32;
|
||||
if(verbose)
|
||||
printf("smbus read (reg=%02x, len=%d)\n", i, l);
|
||||
r=i2c_smbus_read_i2c_block_data(fd, i, l, (__u8 *)&tmp);
|
||||
if(r<0) {
|
||||
error(0, errno, "I2C read error (%d)", r);
|
||||
close(fd);
|
||||
return(-1);
|
||||
}
|
||||
printf("%02X:", i/32);
|
||||
for(j=0; j<l; j++)
|
||||
printf("%02x", tmp[j]);
|
||||
printf("\n");
|
||||
}
|
||||
close(fd);
|
||||
if(n==1)
|
||||
return(tmp[0]);
|
||||
break;
|
||||
case CMD_SMBUS_WRITE:
|
||||
s=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
str_value = argv[optind];
|
||||
n=strlen(str_value);
|
||||
if(n%2)
|
||||
error(-1, errno, "Error: odd length hex value %s", str_value);
|
||||
n>>=1;
|
||||
if(s+n>256)
|
||||
n=256-s;
|
||||
if(verbose)
|
||||
printf("smbus write start (addr=%02x, reg=%02x, len=%d, val=%s)\n", addr, s, n, str_value);
|
||||
for(i=0; i<n; i+=32) {
|
||||
l=n-i;
|
||||
if(l>32)
|
||||
l=32;
|
||||
str_hex[2]=0;
|
||||
for(j=0; j<l; j++) {
|
||||
str_hex[0]=str_value[(i+j)<<1];
|
||||
str_hex[1]=str_value[((i+j)<<1)+1];
|
||||
tmp[j]=strtol(str_hex, &eptr,16);
|
||||
if((errno != 0 && tmp[j] == 0) || eptr==str_hex)
|
||||
error(-1, errno, "hex conversion error at %d (%s)", j, str_hex);
|
||||
}
|
||||
if(verbose)
|
||||
printf("smbus write (reg=%02x, len=%d, val=%.*s)\n", s+i, l, l*2, str_value+(i*2));
|
||||
r=i2c_smbus_write_i2c_block_data(fd, s+i, l, tmp);
|
||||
if(r<0) {
|
||||
error(0, errno, "I2C write error (%d)", r);
|
||||
close(fd);
|
||||
return(-1);
|
||||
}
|
||||
printf("%02X:", i/32);
|
||||
for(j=0; j<l; j++)
|
||||
printf("%02x ", tmp[j]);
|
||||
printf("\n");
|
||||
}
|
||||
close(fd);
|
||||
break;
|
||||
case CMD_SX9512_BUTTON:
|
||||
while(1) {
|
||||
if(verbose)
|
||||
printf("Start reading buttons from SX9512\n");
|
||||
struct sx9512_touch_state touch_state;
|
||||
if(sx9512_read_status_cached(fd, &touch_state))
|
||||
error(-1, errno, "I2C read error");
|
||||
//printf("[state %02X]\n", touch_state.state);
|
||||
if(touch_state.touched)
|
||||
printf("[touch %02X]\n", touch_state.touched);
|
||||
if(touch_state.released)
|
||||
printf("[release %02X]\n", touch_state.released);
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
break;
|
||||
case CMD_SX9512_READ:
|
||||
if(verbose)
|
||||
printf("Read SX9512 registers (and compare to defaults)\n");
|
||||
sx9512_reg_nvm_init_defaults(&nvm_def, 0xff, 0xff);
|
||||
if(sx9512_reg_nvm_read(fd, &nvm))
|
||||
error(-1, errno, "while reading nvm registers");
|
||||
s=sizeof(nvm);
|
||||
for(i=0; i<s; i++)
|
||||
printf("%02x: %02x (%02x)0 %s\n", SX9512_REG_NVM_AREA_START+i, ((uint8_t *)&nvm)[i], ((uint8_t *)&nvm_def)[i], sx9512_reg_name(SX9512_REG_NVM_AREA_START+i));
|
||||
break;
|
||||
case CMD_SX9512_INIT:
|
||||
if((argc-optind)==1)
|
||||
devcfg = sx9512_devcfg_str_to_id(argv[optind]);
|
||||
switch(devcfg) {
|
||||
case SX9512_DEVCFG_DEFAULT:
|
||||
sx9512_reg_nvm_init_defaults(&nvm, 0xff, 0xff);
|
||||
break;
|
||||
case SX9512_DEVCFG_CLEAR:
|
||||
memset(&nvm, 0, sizeof(nvm));
|
||||
break;
|
||||
case SX9512_DEVCFG_CG300:
|
||||
sx9512_reg_nvm_init_cg300(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_CG301:
|
||||
sx9512_reg_nvm_init_cg301(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_EG300:
|
||||
sx9512_reg_nvm_init_eg300(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_DG400:
|
||||
sx9512_reg_nvm_init_dg400(&nvm);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: bad device arg, valid options are:\n");
|
||||
for(i=0;i<SX9512_DEVCFG_AMOUNT;i++)
|
||||
fprintf(stderr, "%s ", sx9512_devcfg_str[i]);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
if(verbose)
|
||||
printf("Init SX9512 registers to %s\n", sx9512_devcfg_str[devcfg]);
|
||||
if(sx9512_reg_nvm_write(fd, &nvm))
|
||||
error(-1, errno, "while writing nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_NVM_LOAD:
|
||||
if(sx9512_reg_nvm_load(fd))
|
||||
error(-1, errno, "while loading nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_NVM_STORE:
|
||||
if(sx9512_reg_nvm_store(fd))
|
||||
error(-1, errno, "while storing nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_RESET:
|
||||
if(sx9512_reset(fd))
|
||||
error(-1, errno, "while trying to reset");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "smbus.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
|
||||
void dump_i2c(int fd,int start,int stop)
|
||||
{
|
||||
int i;
|
||||
int res;
|
||||
|
||||
for (i=start ; i < stop; i++) {
|
||||
res = i2c_smbus_read_byte_data(fd,i);
|
||||
if (res < 0){perror("i2c error\n");}
|
||||
DBG(1,"/dev/i2c-0 READ %d = 0x%02x\n",i,(unsigned char)res);
|
||||
}
|
||||
}
|
||||
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long funcs_needed)
|
||||
{
|
||||
int fd = open(bus, O_RDWR);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_INFO,"%s: could not open %s\n",__func__, bus);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
syslog(LOG_INFO,"%s: could not set address %x for i2c chip\n",
|
||||
__func__, addr);
|
||||
error:
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
if(funcs_needed) {
|
||||
unsigned long funcs;
|
||||
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
|
||||
syslog(LOG_INFO,"%s: could not get I2C_FUNCS\n",__func__);
|
||||
goto error;
|
||||
}
|
||||
if((funcs & funcs_needed) != funcs_needed) {
|
||||
syslog(LOG_INFO,"%s: lacking I2C capabilities, have %lx, need %lx\n",
|
||||
__func__, funcs, funcs_needed);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
void dump_i2c(int fd,int start,int stop);
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long functions_needed);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,934 +0,0 @@
|
|||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
#include "log.h"
|
||||
#include "led.h"
|
||||
|
||||
static struct blob_buf bblob;
|
||||
|
||||
typedef enum {
|
||||
LED_OFF,
|
||||
LED_OK,
|
||||
LED_EOK,
|
||||
LED_NOTICE,
|
||||
LED_ALERT,
|
||||
LED_ERROR,
|
||||
LED_CUSTOM,
|
||||
LED_ACTION_MAX,
|
||||
} led_action_t;
|
||||
|
||||
typedef enum {
|
||||
LEDS_NORMAL,
|
||||
LEDS_PROXIMITY,
|
||||
LEDS_SILENT,
|
||||
LEDS_INFO,
|
||||
LEDS_TEST,
|
||||
LEDS_PROD,
|
||||
LEDS_RESET,
|
||||
LEDS_ALLON,
|
||||
LEDS_ALLOFF,
|
||||
LEDS_MAX,
|
||||
} leds_state_t;
|
||||
|
||||
/* Names for led_action_t */
|
||||
static const char * const fn_actions[LED_ACTION_MAX] =
|
||||
{ "off", "ok", "eok", "notice", "alert", "error", "custom"};
|
||||
|
||||
/* Names for led_state_t */
|
||||
static const char* const led_states[LED_STATES_MAX] =
|
||||
{ "off", "on", "flash_slow", "flash_fast","pulsing", "fadeon", "fadeoff" };
|
||||
|
||||
/* Names for leds_state_t */
|
||||
static const char* const leds_states[LEDS_MAX] =
|
||||
{ "normal", "proximity", "silent", "info", "test", "production", "reset", "allon" , "alloff"};
|
||||
|
||||
/* lowest level, contain states, timers,pointer to driver for a single physical led.*/
|
||||
struct led {
|
||||
struct list_head list;
|
||||
led_state_t state; /* state that this led should have, set from the config file */
|
||||
struct led_drv *drv;
|
||||
};
|
||||
|
||||
struct super_functions {
|
||||
struct list_head list;
|
||||
led_action_t state; /* state that the function need to match */
|
||||
struct function_led *function;
|
||||
};
|
||||
|
||||
struct super_list {
|
||||
struct list_head list;
|
||||
struct list_head sf_list; /* this list contains states that needs to match for this super fuction action to be active */
|
||||
};
|
||||
|
||||
/*middle layer contains lists of leds /buttons/... that should be set to a specific state */
|
||||
struct function_action {
|
||||
const char *name; /* If name is set this led action is in use by the board. */
|
||||
struct list_head led_list;
|
||||
struct list_head button_list;
|
||||
struct list_head super_list; /* list of super function lists */
|
||||
};
|
||||
|
||||
/* main struct for the function leds.*/
|
||||
struct function_led {
|
||||
const char *name; /* If name is set this led function is in use by the board. */
|
||||
led_action_t state; /* state of the function led. contain what action is currently set */
|
||||
int dimming; /* should this led be dimmed */
|
||||
int brightness; /* Brightness of the led */
|
||||
int timeout; /* if time is after */
|
||||
int press_indicator; /* record if this is part of press indictor */
|
||||
struct function_action actions[LED_ACTION_MAX];
|
||||
};
|
||||
|
||||
struct function_led *leds; /* Array of functions, LED_FUNCTIONS + super_functions */
|
||||
static int total_functions; /* number of entries in leds array */
|
||||
|
||||
static leds_state_t global_state; /* global state for the leds,overrids individual states */
|
||||
static press_t press_state; /* global state for the press indicator */
|
||||
|
||||
static led_action_t dimming_level; /* The min level where dimming should not happen on led */
|
||||
static int dimming_timeout; /* The time to turn on leds when we have dimming on */
|
||||
static int dimming_count; /* as long as this is not zero show all leds */
|
||||
|
||||
#define FLASH_TIMEOUT 250 /* this is the delay for the update loop. 4 times a second */
|
||||
#define FLASH_HZ (1000/FLASH_TIMEOUT)
|
||||
|
||||
int get_index_by_name(const char *const*array, int max, const char *name);
|
||||
int get_index_for_function(const char *name);
|
||||
struct led_drv *get_drv_led(char *name);
|
||||
static void dump_drv_list(void);
|
||||
static void dump_led(void);
|
||||
static void all_leds_off(void);
|
||||
static void all_leds_on(void);
|
||||
static void all_leds(led_state_t state);
|
||||
static const char * get_function_action( const char *s, struct function_led **function, int *action);
|
||||
static void super_update(void);
|
||||
|
||||
/* we find out the index for a match in an array of char pointers containing max number of pointers */
|
||||
int get_index_by_name(const char *const*array, int max, const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < max ; i++ ){
|
||||
if (!strcasecmp(name, array[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_index_for_function(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0 ; i < total_functions; i++) {
|
||||
if (!strcasecmp(name, leds[i].name))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PUT every led from drivers into a list */
|
||||
struct drv_led_list{
|
||||
struct list_head list;
|
||||
struct led_drv *drv;
|
||||
};
|
||||
LIST_HEAD(drv_leds_list);
|
||||
|
||||
void led_add( struct led_drv *drv)
|
||||
{
|
||||
struct drv_led_list *drv_node = malloc(sizeof(struct drv_led_list));
|
||||
|
||||
DBG(1,"called with led name [%s]", drv->name);
|
||||
drv_node->drv = drv;
|
||||
|
||||
list_add(&drv_node->list, &drv_leds_list);
|
||||
}
|
||||
|
||||
static void all_leds(led_state_t state) {
|
||||
struct drv_led_list *node;
|
||||
DBG(1, "set to state %d",state);
|
||||
|
||||
list_for_each_entry(node, &drv_leds_list, list) {
|
||||
node->drv->func->set_state( node->drv, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void all_leds_off(void) {
|
||||
all_leds(OFF);
|
||||
}
|
||||
|
||||
static void all_leds_on(void) {
|
||||
all_leds(ON);
|
||||
}
|
||||
|
||||
#define TEST_TIMEOUT 250
|
||||
static void test_handler(struct uloop_timeout *timeout);
|
||||
static struct uloop_timeout test_inform_timer = { .cb = test_handler };
|
||||
|
||||
static void test_handler(struct uloop_timeout *timeout) {
|
||||
|
||||
static int cnt = 0;
|
||||
static led_state_t state = OFF;
|
||||
|
||||
static struct drv_led_list *led;
|
||||
DBG(1,"cnt = %d state %d",cnt,state);
|
||||
|
||||
/* flash all leads 2 times.*/
|
||||
if ( cnt < 4) {
|
||||
cnt++;
|
||||
if (state == OFF){
|
||||
all_leds_on();
|
||||
state = ON;
|
||||
}else{
|
||||
all_leds_off();
|
||||
state = OFF;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (global_state == LEDS_RESET){
|
||||
cnt = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* cycle through every led once */
|
||||
if (cnt == 4 ) {
|
||||
cnt++;
|
||||
led = list_first_entry(&drv_leds_list, struct drv_led_list, list );
|
||||
}
|
||||
if (cnt == 5 ) {
|
||||
if (state == OFF){
|
||||
led->drv->func->set_state(led->drv, ON);
|
||||
state = ON;
|
||||
}else{
|
||||
led->drv->func->set_state(led->drv, OFF);
|
||||
/* was this the last led ? if so stop */
|
||||
if ( list_is_last(&led->list, &drv_leds_list) ){
|
||||
cnt = 0;
|
||||
state = OFF;
|
||||
goto done;
|
||||
}else{ /* nope more leds in list. get next and turn it on */
|
||||
led = (struct drv_led_list *)led->list.next;
|
||||
led->drv->func->set_state(led->drv, ON);
|
||||
state = ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
if (global_state == LEDS_TEST || global_state == LEDS_RESET)
|
||||
uloop_timeout_set(&test_inform_timer, TEST_TIMEOUT);
|
||||
else{
|
||||
cnt = 0;
|
||||
state = OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* go over the driver list for any led name that matches name and returna pointer to driver. */
|
||||
struct led_drv *get_drv_led(char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_leds_list) {
|
||||
struct drv_led_list *node = list_entry(i, struct drv_led_list, list);
|
||||
if (!strcmp(node->drv->name, name))
|
||||
return node->drv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dump_drv_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_leds_list) {
|
||||
struct drv_led_list *node = list_entry(i, struct drv_led_list, list);
|
||||
DBG(1,"led name = [%s]",node->drv->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_led(void)
|
||||
{
|
||||
int i,j;
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
if ( leds[i].actions[j].name != NULL ) {
|
||||
struct led *led;
|
||||
struct super_list *sl;
|
||||
|
||||
/* print out action list */
|
||||
list_for_each_entry(led, &leds[i].actions[j].led_list, list) {
|
||||
DBG(1,"%-15s %-8s %-15s %-10s",
|
||||
leds[i].name,
|
||||
leds[i].actions[j].name,
|
||||
led->drv->name,
|
||||
led_states[led->state]);
|
||||
}
|
||||
/* print out super function list */
|
||||
list_for_each_entry(sl, &leds[i].actions[j].super_list, list) {
|
||||
struct super_functions *sf;
|
||||
DBG(1," AND list");
|
||||
list_for_each_entry(sf, &sl->sf_list, list) {
|
||||
DBG(1,"\tfunction [%s] action [%s]",sf->function->name, fn_actions[sf->state]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* loop over every function, if it is a super function update the state */
|
||||
static void super_update(void)
|
||||
{
|
||||
int i,j;
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
if ( leds[i].actions[j].name != NULL ) {
|
||||
struct super_list *sl;
|
||||
list_for_each_entry(sl, &leds[i].actions[j].super_list, list) {
|
||||
struct super_functions *sf;
|
||||
int status = 0;
|
||||
// DBG(1," AND list");
|
||||
list_for_each_entry(sf, &sl->sf_list, list) {
|
||||
// DBG(1,"\tfunction [%s] action [%s]",sf->function->name, fn_actions[sf->state]);
|
||||
if (sf->function->state == sf->state ) {
|
||||
status = 1;
|
||||
} else {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status){
|
||||
leds[i].state = j;
|
||||
DBG(3,"\tSet super function [%s] to action [%s]",leds[i].name, fn_actions[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return 0 = OK, -1 = error */
|
||||
static int set_function_led(const char* fn_name, const char* action) {
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
int act_idx = get_index_by_name(fn_actions , LED_ACTION_MAX, action );
|
||||
struct led *led;
|
||||
|
||||
if(led_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid led name [%s]", fn_name);
|
||||
return -1;
|
||||
}
|
||||
if(act_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid action [%s] for led [%s]", action, fn_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
leds[led_idx].state = act_idx;
|
||||
|
||||
list_for_each_entry(led, &leds[led_idx].actions[act_idx].led_list, list) {
|
||||
if (led->drv){
|
||||
led->drv->func->set_state(led->drv, led->state);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brightness_function_led(const char* fn_name, int brightness) {
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
struct led *led;
|
||||
|
||||
if(led_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid led name [%s]", fn_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
leds[led_idx].brightness = brightness;
|
||||
|
||||
list_for_each_entry(led, &leds[led_idx].actions[ leds[led_idx].state ].led_list, list) {
|
||||
if (led->drv){
|
||||
if (led->drv->func->set_brightness){
|
||||
led->drv->func->set_brightness(led->drv, brightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timeout_function_led(const char* fn_name, int timeout) {
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
|
||||
if(led_idx == -1) {
|
||||
syslog(LOG_WARNING, "called over ubus with non valid led name [%s]", fn_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* store timeout as number of passes on the flash loop */
|
||||
/* in the loop decrement the timeout */
|
||||
leds[led_idx].timeout = FLASH_HZ * timeout;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
LED_STATE,
|
||||
LED_BRIGHTNESS,
|
||||
LED_TIMEOUT,
|
||||
__LED_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy led_policy[] = {
|
||||
[LED_STATE] = { .name = "state", .type = BLOBMSG_TYPE_STRING },
|
||||
[LED_BRIGHTNESS] = { .name = "brightness", .type = BLOBMSG_TYPE_INT32 },
|
||||
[LED_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
|
||||
};
|
||||
|
||||
static int led_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__LED_MAX];
|
||||
char* state;
|
||||
int number;
|
||||
char *fn_name = strchr(obj->name, '.') + 1;
|
||||
|
||||
blobmsg_parse(led_policy, ARRAY_SIZE(led_policy), tb, blob_data(msg), blob_len(msg));
|
||||
if (tb[LED_STATE]) {
|
||||
state = blobmsg_data(tb[LED_STATE]);
|
||||
DBG(1,"set led [%s]->[%s]", fn_name, state);
|
||||
if (set_function_led(fn_name, state) ){
|
||||
return UBUS_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[LED_BRIGHTNESS]) {
|
||||
number = blobmsg_get_u32(tb[LED_BRIGHTNESS]);
|
||||
DBG(1,"set brightness [%s]->[%x]", fn_name, number);
|
||||
if (brightness_function_led(fn_name, number) ){
|
||||
return UBUS_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[LED_TIMEOUT]) {
|
||||
number = blobmsg_get_u32(tb[LED_TIMEOUT]);
|
||||
DBG(1,"set timeout [%s]->[%x]", fn_name, number);
|
||||
timeout_function_led(fn_name, number);
|
||||
} else // remove timeout
|
||||
timeout_function_led(fn_name, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_status_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
char *fn_name = strchr(obj->name, '.') + 1;
|
||||
int led_idx = get_index_for_function(fn_name);
|
||||
DBG(1,"for led %s",leds[led_idx].name);
|
||||
|
||||
blob_buf_init (&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "state",fn_actions[leds[led_idx].state]);
|
||||
blobmsg_add_u32(&bblob, "brightness",leds[led_idx].brightness);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leds_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__LED_MAX];
|
||||
|
||||
blobmsg_parse(led_policy, ARRAY_SIZE(led_policy), tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
if (tb[LED_STATE]) {
|
||||
char* state;
|
||||
int state_idx;
|
||||
|
||||
state = blobmsg_data(tb[LED_STATE]);
|
||||
state_idx = get_index_by_name(leds_states, LEDS_MAX , state);
|
||||
|
||||
if (state_idx == -1) {
|
||||
syslog(LOG_WARNING, "leds_set_method: Unknown state %s.", state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
global_state = state_idx;
|
||||
|
||||
if (global_state == LEDS_INFO) {
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
if (global_state == LEDS_PROD) {
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
if (global_state == LEDS_TEST || global_state == LEDS_RESET) {
|
||||
all_leds_off();
|
||||
uloop_timeout_set(&test_inform_timer, TEST_TIMEOUT);
|
||||
}
|
||||
if (global_state == LEDS_ALLON) {
|
||||
all_leds_on();
|
||||
}
|
||||
if (global_state == LEDS_ALLOFF) {
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
DBG(1,"led global state set to [%s] wanted [%s]", leds_states[global_state], state);
|
||||
}else
|
||||
syslog(LOG_WARNING, "Unknown attribute [%s]", (char *)blob_data(msg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leds_status_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
|
||||
blob_buf_init (&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "state", leds_states[global_state]);
|
||||
DBG(1,"leds global state is [%s]",leds_states[global_state]);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ubus_method led_methods[] = {
|
||||
UBUS_METHOD("set", led_set_method, led_policy),
|
||||
{ .name = "status", .handler = led_status_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type led_object_type =
|
||||
UBUS_OBJECT_TYPE("led", led_methods);
|
||||
|
||||
static const struct ubus_method leds_methods[] = {
|
||||
UBUS_METHOD("set", leds_set_method, led_policy),
|
||||
{ .name = "status", .handler = leds_status_method },
|
||||
// { .name = "proximity", .handler = leds_proximity_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type leds_object_type =
|
||||
UBUS_OBJECT_TYPE("leds", leds_methods);
|
||||
|
||||
#define LED_OBJECTS 1
|
||||
static struct ubus_object led_objects[LED_OBJECTS] = {
|
||||
{ .name = "leds", .type = &leds_object_type, .methods = leds_methods, .n_methods = ARRAY_SIZE(leds_methods), },
|
||||
};
|
||||
|
||||
static void flash_handler(struct uloop_timeout *timeout);
|
||||
static struct uloop_timeout flash_inform_timer = { .cb = flash_handler };
|
||||
|
||||
static void flash_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
static int counter = 1; /* bit 0 is fast flash bit 2 is slow flash */
|
||||
int i;
|
||||
led_state_t slow=OFF,fast=OFF;
|
||||
counter++;
|
||||
|
||||
/* count down dimming to zero */
|
||||
if (dimming_count)
|
||||
dimming_count--;
|
||||
|
||||
if (counter & 1 )
|
||||
fast = ON;
|
||||
if (counter & 4 )
|
||||
slow = ON;
|
||||
|
||||
super_update();
|
||||
|
||||
if (global_state == LEDS_NORMAL ||
|
||||
global_state == LEDS_INFO ) {
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
struct led *led;
|
||||
if (leds[i].press_indicator && (press_state != PRESS_NONE) ) {
|
||||
// DBG(1,"INDICATE_PRESS on %s",leds[i].name);
|
||||
list_for_each_entry(led, &leds[i].actions[leds[i].state].led_list, list) {
|
||||
if (led->drv){
|
||||
if (press_state == PRESS_LONG)
|
||||
led->drv->func->set_state(led->drv, ON);
|
||||
else
|
||||
led->drv->func->set_state(led->drv, fast);
|
||||
}
|
||||
}
|
||||
|
||||
/* normal operation, flash else reset state */
|
||||
} else {
|
||||
led_action_t action_state = leds[i].state;
|
||||
|
||||
/* in case of info mode suppress OK state. that is if OK -> turn it into OFF */
|
||||
if (global_state == LEDS_INFO) {
|
||||
if (action_state == LED_OK)
|
||||
action_state = LED_OFF;
|
||||
}
|
||||
|
||||
/* is this function dimmed ? */
|
||||
if (leds[i].dimming) {
|
||||
/* if timer is not active we should dimm */
|
||||
if (!dimming_count){
|
||||
if (action_state < dimming_level)
|
||||
action_state = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* is there a timeout on this led ?*/
|
||||
if (leds[i].timeout) {
|
||||
leds[i].timeout--;
|
||||
/* if it has timedout set state to OFF */
|
||||
if (! leds[i].timeout) {
|
||||
leds[i].state = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(led, &leds[i].actions[action_state].led_list, list) {
|
||||
|
||||
if (led->state == FLASH_FAST) {
|
||||
if (led->drv) {
|
||||
if (led->drv->func->support) {
|
||||
if (led->drv->func->support(led->drv, FLASH_FAST)) {
|
||||
/* hardware support flash */
|
||||
led->drv->func->set_state(led->drv, FLASH_FAST);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* emulate flash with on/off */
|
||||
led->drv->func->set_state(led->drv, fast);
|
||||
}
|
||||
}else if (led->state == FLASH_SLOW) {
|
||||
if (led->drv) {
|
||||
if (led->drv->func->support) {
|
||||
if (led->drv->func->support(led->drv, FLASH_SLOW)) {
|
||||
/* hardware support flash */
|
||||
led->drv->func->set_state(led->drv, FLASH_SLOW);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* emulate flash with on/off */
|
||||
led->drv->func->set_state(led->drv, slow);
|
||||
}
|
||||
}else{
|
||||
if (led->drv)
|
||||
led->drv->func->set_state(led->drv, led->state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uloop_timeout_set(&flash_inform_timer, FLASH_TIMEOUT);
|
||||
}
|
||||
|
||||
void led_pressindicator_set(press_t type){
|
||||
|
||||
/* press long has prio over short so if it's already set to long do not change */
|
||||
if (type == PRESS_SHORT && press_state == PRESS_LONG)
|
||||
return;
|
||||
|
||||
press_state = type;
|
||||
}
|
||||
|
||||
void led_dimming(void){
|
||||
|
||||
/* we resuse the flash timer and decrement dimmming_count on every loop */
|
||||
/* set the intial value so that we get the correct timeout */
|
||||
dimming_count = dimming_timeout * (1000/FLASH_TIMEOUT);
|
||||
}
|
||||
|
||||
/*
|
||||
input: s, string of comma separated function_action names, 'wifi_ok, wps_ok'
|
||||
|
||||
return:
|
||||
NULL if no valid function actionpair found.
|
||||
pointer to start of unused part of string.
|
||||
|
||||
fills in the function pointer with NULL or a real function
|
||||
fills in action with 0 or real index (include 0),
|
||||
|
||||
*/
|
||||
const char * get_function_action( const char *s, struct function_led **function, int *action)
|
||||
{
|
||||
const char *first, *last, *end, *p;
|
||||
char func[100], act[20];
|
||||
|
||||
DBG(1,"start [%s]", s);
|
||||
|
||||
*function = NULL;
|
||||
*action = 0;
|
||||
|
||||
/* if string is zero length give up. */
|
||||
if ( 0 == strlen(s))
|
||||
return NULL;
|
||||
|
||||
end = s + strlen(s);
|
||||
|
||||
/* find first alpha char */
|
||||
while (!isalnum(*s)){
|
||||
s++;
|
||||
if (s == end)
|
||||
return NULL;
|
||||
}
|
||||
first = s;
|
||||
|
||||
/* find , or end of string or space/tab */
|
||||
while ( (*s != ',') && (!isblank(*s))) {
|
||||
s++;
|
||||
if (s == end)
|
||||
break;
|
||||
}
|
||||
last = s;
|
||||
|
||||
/* scan backwards for _ */
|
||||
while (*s != '_' && s > first){
|
||||
s--;
|
||||
}
|
||||
|
||||
/* if we could not find a _ char bail out */
|
||||
if (*s != '_')
|
||||
return NULL;
|
||||
|
||||
/* extract function name */
|
||||
p = first;
|
||||
while (p != s) {
|
||||
func[p-first] = *p;
|
||||
p++;
|
||||
}
|
||||
func[p-first] = 0;
|
||||
|
||||
/* extract action name */
|
||||
p = s + 1;
|
||||
while (p != last) {
|
||||
act[p-(s+1)] = *p;
|
||||
p++;
|
||||
}
|
||||
act[p-(s+1)] = 0;
|
||||
|
||||
DBG(1,"function[%s] action[%s] func_idx %d", func, act, get_index_for_function(func));
|
||||
*function = &leds[get_index_for_function(func)];
|
||||
*action = get_index_by_name(fn_actions , LED_ACTION_MAX, act );
|
||||
|
||||
if (*last == ',')
|
||||
last++;
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
/* when this is called all driver leds needs to exist */
|
||||
void led_init( struct server_ctx *s_ctx)
|
||||
{
|
||||
int i,j;
|
||||
LIST_HEAD(led_map_list);
|
||||
struct ucilist *map_node;
|
||||
const char *s;
|
||||
|
||||
dump_drv_list();
|
||||
|
||||
/* register leds with ubus */
|
||||
for (i=0 ; i<LED_OBJECTS ; i++) {
|
||||
int ret = ubus_add_object(s_ctx->ubus_ctx, &led_objects[i]);
|
||||
if (ret)
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(ret));
|
||||
}
|
||||
|
||||
/* read out the function leds */
|
||||
ucix_get_option_list( s_ctx->uci_ctx, "hw", "led_map", "functions" , &led_map_list);
|
||||
|
||||
total_functions = 0;
|
||||
list_for_each_entry(map_node, &led_map_list, list) {
|
||||
total_functions++;
|
||||
}
|
||||
|
||||
leds = malloc(sizeof(struct function_led) * total_functions);
|
||||
memset(leds, 0, sizeof(struct function_led) * total_functions);
|
||||
|
||||
/* set function name & regiter with ubus */
|
||||
i = 0;
|
||||
list_for_each_entry(map_node, &led_map_list, list) {
|
||||
char name[100];
|
||||
int ret;
|
||||
struct ubus_object *ubo;
|
||||
ubo = malloc(sizeof(struct ubus_object));
|
||||
memset(ubo, 0, sizeof(struct ubus_object));
|
||||
|
||||
leds[i].name = strdup(map_node->val);
|
||||
|
||||
sprintf(name, "led.%s", leds[i].name);
|
||||
ubo->name = strdup(name);
|
||||
ubo->methods = led_methods;
|
||||
ubo->n_methods = ARRAY_SIZE(led_methods);
|
||||
ubo->type = &led_object_type;
|
||||
|
||||
ret = ubus_add_object(s_ctx->ubus_ctx, ubo);
|
||||
if (ret)
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(ret));
|
||||
i++;
|
||||
}
|
||||
|
||||
/* we create a top list of led functions */
|
||||
/* that list contains a new list of actions */
|
||||
/* every action contains led actions lists */
|
||||
/* the led states is attached to the drv_leds lists */
|
||||
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
char led_fn_name[256];
|
||||
char led_action[256];
|
||||
|
||||
LIST_HEAD(led_action_list);
|
||||
struct ucilist *node;
|
||||
snprintf(led_fn_name, 256, "led_%s", leds[i].name);
|
||||
snprintf(led_action, 256, "led_action_%s", fn_actions[j]);
|
||||
ucix_get_option_list( s_ctx->uci_ctx, "hw", led_fn_name, led_action , &led_action_list);
|
||||
|
||||
INIT_LIST_HEAD( &leds[i].actions[j].led_list );
|
||||
|
||||
if (!list_empty(&led_action_list)) {
|
||||
|
||||
/* Found led with action, init structs */
|
||||
leds[i].state = LED_OFF;
|
||||
leds[i].brightness = 100;
|
||||
|
||||
leds[i].actions[j].name = fn_actions[j];
|
||||
|
||||
/* fill in led actions */
|
||||
DBG(2,"%-15s has led actions %s -> ", led_fn_name, fn_actions[j]);
|
||||
list_for_each_entry(node, &led_action_list, list) {
|
||||
char led_name[256],led_state[256];
|
||||
struct led *led;
|
||||
struct led_drv *drv;
|
||||
char *c;
|
||||
s = strdup(node->val);
|
||||
led_name[0]=0;
|
||||
led_state[0]=0;
|
||||
|
||||
/* get pointer to low level led driver. by removing the = sign and
|
||||
storing the remaining two strings.
|
||||
*/
|
||||
c = strchr(s,'=');
|
||||
if( c == NULL)
|
||||
continue; /* no = found, abort */
|
||||
*c = ' ';
|
||||
|
||||
sscanf(s, "%s %s", led_name, led_state);
|
||||
drv = get_drv_led(led_name);
|
||||
|
||||
if (drv) {
|
||||
led = malloc(sizeof(struct led));
|
||||
led->drv = drv;
|
||||
led->state = get_index_by_name(led_states, LED_STATES_MAX, led_state);
|
||||
list_add(&led->list, &leds[i].actions[j].led_list);
|
||||
}else {
|
||||
syslog(LOG_ERR,"Config specified use of led name [%s]. But it's not registerd with a led driver.", led_name);
|
||||
}
|
||||
DBG(2, "%-35s%s","",node->val);
|
||||
free((void*)s);
|
||||
}
|
||||
|
||||
/* fill in button actions */
|
||||
|
||||
/* fill in xxx actions */
|
||||
}else {
|
||||
DBG(2,"%-15s has no actions -> %s", led_fn_name, fn_actions[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read in functions that have function list (super functions) */
|
||||
for (i = 0; i < total_functions ; i++) {
|
||||
for (j = 0 ; j < LED_ACTION_MAX; j++ ) {
|
||||
char led_fn_name[256];
|
||||
char super_action[256];
|
||||
LIST_HEAD(super_action_list);
|
||||
struct ucilist *node;
|
||||
snprintf(led_fn_name, 256, "led_%s", leds[i].name);
|
||||
snprintf(super_action, 256, "super_%s", fn_actions[j]);
|
||||
ucix_get_option_list( s_ctx->uci_ctx, "hw", led_fn_name, super_action , &super_action_list);
|
||||
INIT_LIST_HEAD( &leds[i].actions[j].super_list );
|
||||
|
||||
if (!list_empty(&super_action_list)) {
|
||||
DBG(1,"A:%s %s is a super function ",led_fn_name,super_action);
|
||||
|
||||
list_for_each_entry(node, &super_action_list, list) {
|
||||
struct function_led *function;
|
||||
int action_ix;
|
||||
struct super_list *sl = malloc(sizeof(struct super_list));
|
||||
memset(sl, 0, sizeof(struct super_list));
|
||||
list_add(&sl->list, &leds[i].actions[j].super_list);
|
||||
INIT_LIST_HEAD( &sl->sf_list );
|
||||
|
||||
DBG(1,"add to super list %s",node->val);
|
||||
|
||||
s = node->val;
|
||||
while ((s = get_function_action(s, &function, &action_ix))){
|
||||
if (function) {
|
||||
struct super_functions *sf = malloc(sizeof(struct super_functions));
|
||||
memset(sf, 0, sizeof(struct super_functions));
|
||||
sf->state = action_ix;
|
||||
sf->function = function;
|
||||
list_add(&sf->list, &sl->sf_list);
|
||||
DBG(1,"C %s %s",function->name, fn_actions[action_ix]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
DBG(1,"A:%s %s is a normal function ",led_fn_name,super_action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* setup and read dimming options for led */
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(dimm_list);
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "led_map", "dimming_level");
|
||||
dimming_level = LED_OFF;
|
||||
if (s) {
|
||||
DBG(1,"Dimming init");
|
||||
for(i=0 ; i < LED_ACTION_MAX ; i++) {
|
||||
if (! strncasecmp(s, fn_actions[i], strlen(fn_actions[i]))){
|
||||
dimming_level = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "led_map", "dimming_on");
|
||||
dimming_timeout = 0;
|
||||
if (s) {
|
||||
dimming_timeout = strtol(s, NULL, 0);
|
||||
}
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"led_map", "dimming", &dimm_list);
|
||||
list_for_each_entry(node, &dimm_list, list) {
|
||||
int ix;
|
||||
s = node->val;
|
||||
ix = get_index_for_function(s);
|
||||
if (ix != -1){
|
||||
leds[ix].dimming = 1;
|
||||
DBG(1,"dimming on led [%s]", leds[ix].name);
|
||||
}else
|
||||
syslog(LOG_ERR,"dimming Led [%s] don't exist", s);
|
||||
}
|
||||
}
|
||||
|
||||
DBG(1,"Dimming level %s", fn_actions[dimming_level]);
|
||||
DBG(1,"Dimming timeout %d", dimming_timeout);
|
||||
|
||||
{
|
||||
struct ucilist *node;
|
||||
/* read function buttons from section button_map */
|
||||
LIST_HEAD(press_indicator);
|
||||
|
||||
/* read in generic configuration. press indicator listdefault params..... */
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"led_map", "press_indicator", &press_indicator);
|
||||
list_for_each_entry(node, &press_indicator, list) {
|
||||
int ix;
|
||||
s = node->val;
|
||||
s +=4; /*remove 'led_' from string */
|
||||
DBG(1,"press indicator %s [%s]",node->val, s);
|
||||
ix = get_index_for_function(s);
|
||||
// DBG(1,"press indicator %s [%s]->%d",node->val, s, ix);
|
||||
leds[ix].press_indicator = 1;
|
||||
}
|
||||
}
|
||||
uloop_timeout_set(&flash_inform_timer, FLASH_TIMEOUT);
|
||||
|
||||
dump_led();
|
||||
all_leds_off();
|
||||
}
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
#include "server.h"
|
||||
|
||||
typedef enum {
|
||||
OFF,
|
||||
ON,
|
||||
FLASH_SLOW,
|
||||
FLASH_FAST,
|
||||
PULSING,
|
||||
FADEON,
|
||||
FADEOFF,
|
||||
NEED_INIT, /* set on loading config */
|
||||
LED_STATES_MAX,
|
||||
} led_state_t;
|
||||
|
||||
typedef enum {
|
||||
NONE,
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
YELLOW,
|
||||
WHITE,
|
||||
} led_color_t;
|
||||
|
||||
typedef enum {
|
||||
PRESS_NONE,
|
||||
PRESS_SHORT,
|
||||
PRESS_LONG,
|
||||
} press_t;
|
||||
|
||||
struct led_drv;
|
||||
|
||||
struct led_drv_func{
|
||||
int (*set_state)(struct led_drv *, led_state_t); /* Set led state, on,off,flash ... */
|
||||
led_state_t (*get_state)(struct led_drv *); /* Get led state, on,off,flash ... */
|
||||
int (*set_color)(struct led_drv *, led_color_t); /* Set led color */
|
||||
led_color_t (*get_color)(struct led_drv *); /* Get led color */
|
||||
int (*set_brightness)(struct led_drv *, int ); /* Set led brightness */
|
||||
int (*get_brightness)(struct led_drv *); /* Get led brightness */
|
||||
int (*support) (struct led_drv *, led_state_t); /* do driver has hardware support for state */
|
||||
};
|
||||
|
||||
struct led_drv {
|
||||
const char *name; /* name, set in the confg file,has to be uniq */
|
||||
void *priv; /* for use by the driver */
|
||||
struct led_drv_func *func; /* function pointers for controlling the led */
|
||||
};
|
||||
|
||||
void led_add( struct led_drv *);
|
||||
void led_init(struct server_ctx *);
|
||||
|
||||
void led_dimming(void);
|
||||
void led_pressindicator_set(press_t type);
|
||||
|
||||
#endif /* LED_H */
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
/* Use this */
|
||||
#include <syslog.h>
|
||||
|
||||
extern int debug_level;
|
||||
|
||||
#define DBG_RAW(...) fprintf( stderr, __VA_ARGS__ );
|
||||
#define DBG(level,fmt, args...) \
|
||||
do { \
|
||||
if (level <= debug_level) \
|
||||
syslog( LOG_DEBUG,"%-20s: " fmt , __func__, ##args); \
|
||||
} while(0)
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
#include <config.h>
|
||||
#include <getopt.h>
|
||||
#include "log.h"
|
||||
#include "ucix.h"
|
||||
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubus.h>
|
||||
|
||||
#include "server.h"
|
||||
|
||||
int debug_level = 0;
|
||||
|
||||
static const char *config_path = "/lib/db/config";
|
||||
static const char *config_file = "hw";
|
||||
|
||||
static char *ubus_socket;
|
||||
|
||||
void catv_monitor_set_socket(char *);
|
||||
|
||||
void print_usage(char *prg_name);
|
||||
|
||||
void print_usage(char *prg_name) {
|
||||
printf("Usage: %s -h -f\n", prg_name);
|
||||
printf(" Options: \n");
|
||||
printf(" -f, --foreground\tDon't fork off as a daemon.\n");
|
||||
printf(" -d, --debug=NUM\tSet debug level. Higher = more output\n");
|
||||
printf(" -c, --config=FILE\tConfig file to use. default = %s/%s\n", config_path, config_file);
|
||||
printf(" -s, --socket=FILE\tSet the unix domain socket to connect to for ubus\n");
|
||||
printf(" -h\t\tShow this help screen.\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
int daemonize = 1;
|
||||
pid_t pid, sid;
|
||||
struct uci_context *uci_ctx = NULL;
|
||||
static struct ubus_context *ubus_ctx = NULL;
|
||||
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"foreground", no_argument, 0, 'f'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"debug", required_argument, 0, 'd'},
|
||||
{"config",required_argument, 0, 'c'},
|
||||
{"socket",required_argument, 0, 's'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
ch = getopt_long(argc, argv, "hvfhd:c:s:",
|
||||
long_options, &option_index);
|
||||
|
||||
if (ch == -1)
|
||||
break;
|
||||
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
daemonize = 0;
|
||||
break;
|
||||
case 'd':
|
||||
debug_level = strtol(optarg, 0, 0);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
config_file = basename(optarg);
|
||||
config_path = dirname(optarg);
|
||||
break;
|
||||
case 's':
|
||||
ubus_socket = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
printf("Extra arguments discarded: ");
|
||||
while (optind < argc)
|
||||
printf("%s ", argv[optind++]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/* Setup logging */
|
||||
if (daemonize) {
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog(PACKAGE, LOG_CONS, LOG_USER);
|
||||
|
||||
syslog(LOG_INFO, "%s daemon starting up", PACKAGE);
|
||||
} else {
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog(PACKAGE, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||
|
||||
syslog(LOG_INFO, "%s program starting up", PACKAGE);
|
||||
}
|
||||
|
||||
/* daemonize */
|
||||
if (daemonize) {
|
||||
syslog(LOG_INFO, "starting the daemonizing process");
|
||||
|
||||
/* Fork off the parent process */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* If we got a good PID, then
|
||||
we can exit the parent process. */
|
||||
if (pid > 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Change the current working directory */
|
||||
if ((chdir("/")) < 0) {
|
||||
/* Log the failure */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Close out the standard file descriptors */
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
/* open configuration file */
|
||||
uci_ctx = ucix_init_path(config_path , config_file, 0 );
|
||||
if (! uci_ctx ) {
|
||||
syslog(LOG_ERR,"Failed to load config file \"%s/%s\"\n", config_path, config_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* connect to ubus */
|
||||
ubus_ctx = ubus_connect(ubus_socket);
|
||||
if (!ubus_ctx) {
|
||||
syslog(LOG_ERR,"Failed to connect to ubus. Can't continue.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* connect ubus handler to ubox evenet loop */
|
||||
if (uloop_init() != 0) {
|
||||
syslog(LOG_ERR,"Could not init event loop, Can't continue.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ubus_add_uloop(ubus_ctx);
|
||||
|
||||
catv_monitor_set_socket(ubus_socket);
|
||||
|
||||
server_start(uci_ctx, ubus_ctx);
|
||||
|
||||
ubus_free(ubus_ctx);
|
||||
|
||||
DBG(1,"testing\n");
|
||||
syslog(LOG_INFO, "%s exiting", PACKAGE);
|
||||
|
||||
uloop_done();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
#include <syslog.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "button.h"
|
||||
|
||||
#include "smbus.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "ucix.h"
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
/* register names, from page 29, */
|
||||
#define PX3220_SYSCONF 0x00
|
||||
#define PX3220_IRQ_STATUS 0x01
|
||||
#define PX3220_IRQ_CLEAR 0x02
|
||||
#define PX3220_IR_DATA_LOW 0x0A
|
||||
#define PX3220_IR_DATA_HIGH 0x0B
|
||||
#define PX3220_PS_DATA_LOW 0x0E
|
||||
#define PX3220_PS_DATA_HIGH 0x0F
|
||||
#define PX3220_PS_LOW_THRESH_L 0x2A
|
||||
#define PX3220_PS_LOW_THRESH_H 0x2B
|
||||
#define PX3220_PS_HIGH_THRESH_L 0x2C
|
||||
#define PX3220_PS_HIGH_THRESH_H 0x2D
|
||||
|
||||
#define IRQ_BUTTON 33
|
||||
|
||||
struct i2c_reg_tab {
|
||||
char addr;
|
||||
char value;
|
||||
char range; /* if set registers starting from addr to addr+range will be set to the same value */
|
||||
};
|
||||
|
||||
struct button_data {
|
||||
int addr;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
static const struct i2c_reg_tab i2c_init_tab_vox25[]={
|
||||
{PX3220_SYSCONF, 0x04, 0x00 }, /* Reset */
|
||||
{PX3220_SYSCONF, 0x02, 0x00 }, /* Power on IR */
|
||||
{PX3220_IRQ_STATUS, 0x01, 0x00 },
|
||||
{0x20, 0x17, 0x00 },
|
||||
{0x23, 0x03, 0x00 },
|
||||
{PX3220_PS_LOW_THRESH_L, 0x00, 0x00 },
|
||||
{PX3220_PS_LOW_THRESH_H, 0x18, 0x00 },
|
||||
{PX3220_PS_HIGH_THRESH_L, 0x00, 0x00 },
|
||||
{PX3220_PS_HIGH_THRESH_H, 0x14, 0x00 },
|
||||
};
|
||||
|
||||
int dev;
|
||||
int shadow_proximity;
|
||||
|
||||
void do_init_tab(const struct i2c_reg_tab *tab, int len );
|
||||
|
||||
|
||||
void do_init_tab(const struct i2c_reg_tab *tab, int len )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < len ; i++){
|
||||
int y;
|
||||
int ret;
|
||||
for ( y = 0 ; y <= tab[i].range; y++ ){
|
||||
DBG(3,"%s: addr %02X = %02X ",__func__,(unsigned char)tab[i].addr+y, (unsigned char)tab[i].value);
|
||||
ret = i2c_smbus_write_byte_data(dev, tab[i].addr+y, tab[i].value);
|
||||
if (ret < 0){
|
||||
perror("write to i2c dev\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void px3220_check(void)
|
||||
{
|
||||
int got_irq;
|
||||
unsigned short reg_low, reg_high, ps_val;
|
||||
|
||||
shadow_proximity = 0;
|
||||
if (dev){
|
||||
got_irq = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, IRQ_BUTTON, 0);
|
||||
|
||||
/* got_irq is active low */
|
||||
if (!got_irq) {
|
||||
reg_low = i2c_smbus_read_byte_data(dev, PX3220_PS_DATA_LOW);
|
||||
|
||||
reg_high = i2c_smbus_read_byte_data(dev, PX3220_PS_DATA_HIGH);
|
||||
|
||||
ps_val = ((reg_high & 0x3F) << 4) | (reg_low & 0xF);
|
||||
|
||||
if (ps_val > 0x58)
|
||||
shadow_proximity |= 0x1;
|
||||
else
|
||||
shadow_proximity |= 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
if (shadow_proximity)
|
||||
DBG(1,"shadow_proximity [%x]", shadow_proximity);
|
||||
}
|
||||
|
||||
static button_state_t px3220_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
struct button_data *p = (struct button_data *)drv->priv;
|
||||
|
||||
if (p->addr == 0 ){
|
||||
if (shadow_proximity & 1 ) {
|
||||
shadow_proximity &= ~0x1;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->addr == 1 ){
|
||||
if (shadow_proximity & 2 ) {
|
||||
shadow_proximity &= ~0x2;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
p->state = BUTTON_RELEASED;
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func button_func = {
|
||||
.get_state = px3220_button_get_state,
|
||||
};
|
||||
|
||||
void px3220_init(struct server_ctx *s_ctx) {
|
||||
|
||||
const char *p;
|
||||
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
p = ucix_get_option(s_ctx->uci_ctx, "hw", "board", "hardware");
|
||||
if (p == 0){
|
||||
syslog(LOG_INFO, "%s: Missing Hardware identifier in configuration. I2C is not started\n",__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Driver only existfor VOX25 board */
|
||||
if (strcmp("VOX25", p))
|
||||
return;
|
||||
|
||||
/* open i2c device */
|
||||
dev = i2c_open_dev("/dev/i2c-0", 0x1E,
|
||||
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE);
|
||||
if (dev < 0) {
|
||||
syslog(LOG_INFO,"%s: could not open i2c touch device\n",__func__);
|
||||
dev = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
do_init_tab(i2c_init_tab_vox25, sizeof(i2c_init_tab_vox25)/sizeof(struct i2c_reg_tab));
|
||||
|
||||
|
||||
/* read config file */
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"3220_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct button_data));
|
||||
memset(data,0,sizeof(struct button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
data->button.func = &button_func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef PROX_PX3220_H
|
||||
#define PROX_PX3220_H
|
||||
|
||||
#include "server.h"
|
||||
|
||||
void px3220_init(struct server_ctx *);
|
||||
void px3220_check(void);
|
||||
|
||||
#endif /* PROX_PX3220_H */
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#include "config.h"
|
||||
#include <syslog.h>
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "led.h"
|
||||
#include "button.h"
|
||||
#include "catv.h"
|
||||
#include "sfp.h"
|
||||
#include "touch_sx9512.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
struct server_ctx server;
|
||||
|
||||
void sim_led_init(struct server_ctx *);
|
||||
void sim_button_init(struct server_ctx *);
|
||||
|
||||
void gpio_led_init(struct server_ctx *);
|
||||
void gpio_button_init(struct server_ctx *);
|
||||
|
||||
void catv_monitor_init(struct server_ctx *);
|
||||
void vox_init(struct server_ctx *);
|
||||
|
||||
struct catv_handler *catv_h;
|
||||
struct sfp_handler *sfp_h;
|
||||
|
||||
void server_start(struct uci_context *uci_ctx, struct ubus_context *ubus_ctx)
|
||||
|
||||
{
|
||||
DBG(1, "init server context.");
|
||||
server.uci_ctx = uci_ctx;
|
||||
server.ubus_ctx = ubus_ctx;
|
||||
|
||||
DBG(1, "run init function for all hardware drivers.");
|
||||
|
||||
sim_led_init(&server);
|
||||
sim_button_init(&server);
|
||||
|
||||
#ifdef HAVE_BOARD_H
|
||||
gpio_led_init(&server);
|
||||
gpio_button_init(&server);
|
||||
|
||||
sx9512_handler_init(&server);
|
||||
|
||||
px3220_init(&server);
|
||||
|
||||
vox_init(&server);
|
||||
#endif
|
||||
|
||||
DBG(1, "connect generic buttons/leds to hardware drivers.");
|
||||
led_init(&server);
|
||||
button_init(&server);
|
||||
|
||||
sfp_h = sfp_init(uci_ctx);
|
||||
if (sfp_h) {
|
||||
sfp_ubus_populate(sfp_h, ubus_ctx);
|
||||
}
|
||||
|
||||
catv_h = catv_init(uci_ctx, "/dev/i2c-0", 0x50, 0x51);
|
||||
if (catv_h){
|
||||
catv_ubus_populate(catv_h, ubus_ctx);
|
||||
}
|
||||
|
||||
catv_monitor_init(&server);
|
||||
|
||||
DBG(1, "give control to uloop main loop.");
|
||||
uloop_run();
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
#include <libubus.h>
|
||||
#include "ucix.h"
|
||||
|
||||
struct server_ctx {
|
||||
struct uci_context *uci_ctx;
|
||||
struct ubus_context *ubus_ctx;
|
||||
};
|
||||
|
||||
void server_start( struct uci_context *uci_ctx, struct ubus_context *ubus_ctx);
|
||||
|
||||
#endif /* SERVER_H */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef SFP_H
|
||||
#include "libubus.h"
|
||||
#include "ucix.h"
|
||||
|
||||
struct sfp_handler;
|
||||
|
||||
struct sfp_handler * sfp_init(struct uci_context *uci_ctx);
|
||||
int sfp_ubus_populate(struct sfp_handler *h, struct ubus_context *ubus_ctx);
|
||||
void sfp_destroy(struct sfp_handler *h);
|
||||
|
||||
#endif /*SFP_H*/
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "button.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
|
||||
void sim_button_init(struct server_ctx *s_ctx);
|
||||
|
||||
struct sim_data {
|
||||
int addr;
|
||||
int active;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
struct drv_button_list{
|
||||
struct list_head list;
|
||||
struct button_drv *drv;
|
||||
};
|
||||
|
||||
static button_state_t sim_get_state(struct button_drv *drv)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
struct sim_data *p = (struct sim_data *)drv->priv;
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func func = {
|
||||
.get_state = sim_get_state,
|
||||
};
|
||||
|
||||
static LIST_HEAD(sim_buttons);
|
||||
|
||||
|
||||
enum {
|
||||
SIM_NAME,
|
||||
SIM_STATE,
|
||||
__SIM_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy sim_policy[] = {
|
||||
[SIM_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
|
||||
[SIM_STATE] = { .name = "state", .type = BLOBMSG_TYPE_STRING },
|
||||
};
|
||||
|
||||
static struct button_drv *get_drv_button(char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &sim_buttons) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
if (! strcmp(node->drv->name, name))
|
||||
return node->drv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sim_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__SIM_MAX];
|
||||
DBG(1, "");
|
||||
|
||||
blobmsg_parse(sim_policy, ARRAY_SIZE(sim_policy), tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
if ( tb[SIM_NAME] ) {
|
||||
if ( tb[SIM_STATE] ) {
|
||||
struct button_drv *bt = get_drv_button((char *)blobmsg_data(tb[SIM_NAME]));
|
||||
DBG(1," name = %s",(char *)blobmsg_data(tb[SIM_NAME]));
|
||||
DBG(1," state = %s",(char *)blobmsg_data(tb[SIM_STATE]));
|
||||
|
||||
if (bt) {
|
||||
struct sim_data *p = (struct sim_data *)bt->priv;
|
||||
|
||||
if(!strcasecmp("pressed", (char *)blobmsg_data(tb[SIM_STATE]))){
|
||||
p->state = BUTTON_PRESSED;
|
||||
}
|
||||
if(!strcasecmp("released", (char *)blobmsg_data(tb[SIM_STATE]))){
|
||||
p->state = BUTTON_RELEASED;
|
||||
}
|
||||
}else
|
||||
DBG(1," button = %s not found",(char *)blobmsg_data(tb[SIM_NAME]));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_status_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_buf blob;
|
||||
struct list_head *i;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
memset(&blob,0,sizeof(struct blob_buf));
|
||||
blob_buf_init(&blob, 0);
|
||||
|
||||
list_for_each(i, &sim_buttons) {
|
||||
struct drv_button_list *node = list_entry(i, struct drv_button_list, list);
|
||||
const char *state;
|
||||
struct sim_data *p = (struct sim_data *)node->drv->priv;
|
||||
|
||||
if(p->state == BUTTON_RELEASED)
|
||||
state = "Released";
|
||||
else
|
||||
state = "Pressed";
|
||||
|
||||
blobmsg_add_string(&blob, node->drv->name, state);
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, blob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct ubus_method sim_methods[] = {
|
||||
UBUS_METHOD("set", sim_set_method, sim_policy),
|
||||
{ .name = "status",
|
||||
.handler = sim_status_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type sim_object_type =
|
||||
UBUS_OBJECT_TYPE("sim", sim_methods);
|
||||
|
||||
#define SIM_OBJECTS 1
|
||||
static struct ubus_object sim_objects[SIM_OBJECTS] = {
|
||||
{ .name = "button",
|
||||
.type = &sim_object_type,
|
||||
.methods = sim_methods,
|
||||
.n_methods = ARRAY_SIZE(sim_methods),
|
||||
},
|
||||
};
|
||||
|
||||
void sim_button_init(struct server_ctx *s_ctx) {
|
||||
int i,ret;
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"sim_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct sim_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct sim_data));
|
||||
memset(data,0,sizeof(struct sim_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "active");
|
||||
data->active = -1;
|
||||
if (s){
|
||||
if (!strncasecmp("hi",s,2))
|
||||
data->active = 1;
|
||||
else if (!strncasecmp("low",s,3))
|
||||
data->active = 0;
|
||||
|
||||
}
|
||||
DBG(1, "active = %d", data->active);
|
||||
|
||||
data->button.func = &func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
|
||||
{ /* save button in internal list, we need this for ubus set/status */
|
||||
struct drv_button_list *bt = malloc(sizeof(struct drv_button_list));
|
||||
memset(bt, 0, sizeof(struct drv_button_list));
|
||||
bt->drv = &data->button;
|
||||
list_add(&bt->list, &sim_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<SIM_OBJECTS ; i++) {
|
||||
ret = ubus_add_object(s_ctx->ubus_ctx, &sim_objects[i]);
|
||||
if (ret)
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "led.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
void sim_led_init(struct server_ctx *s_ctx);
|
||||
|
||||
static int sim_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
DBG(1, "state %x on %s", state, drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static led_state_t sim_get_state(struct led_drv *drv)
|
||||
{
|
||||
DBG(1, "state for %s", drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_set_color(struct led_drv *drv, led_color_t color)
|
||||
{
|
||||
DBG(1, "color %d on %s", color, drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static led_color_t sim_get_color(struct led_drv *drv)
|
||||
{
|
||||
DBG(1, "color for %s", drv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = sim_set_state,
|
||||
.get_state = sim_get_state,
|
||||
.set_color = sim_set_color,
|
||||
.get_color = sim_get_color,
|
||||
};
|
||||
|
||||
struct sim_data {
|
||||
int addr;
|
||||
led_color_t color;
|
||||
int state;
|
||||
int pulsing;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
void sim_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"sim_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct sim_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct sim_data));
|
||||
memset(data,0,sizeof(struct sim_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "color");
|
||||
if (s){
|
||||
if (!strncasecmp("red",s,3))
|
||||
data->color = RED;
|
||||
else if (!strncasecmp("green",s,5))
|
||||
data->color = GREEN;
|
||||
else if (!strncasecmp("blue",s,4))
|
||||
data->color = BLUE;
|
||||
else if (!strncasecmp("yellow",s,6))
|
||||
data->color = YELLOW;
|
||||
else if (!strncasecmp("white",s,5))
|
||||
data->color = WHITE;
|
||||
}
|
||||
DBG(1, "color = [%s]=(%d)", s,data->color);
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "pulsing");
|
||||
DBG(1, "pulsing = [%s]", s);
|
||||
if (s){
|
||||
if (!strncasecmp("yes",s,3))
|
||||
data->pulsing = 1;
|
||||
}
|
||||
data->led.func = &func;
|
||||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
smbus.c - SMBus level access helper functions
|
||||
|
||||
Copyright (C) 1995-1997 Simon G. Vogl
|
||||
Copyright (C) 1998-1999 Frodo Looijaard <frodol@dds.nl>
|
||||
Copyright (C) 2012-2013 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include "smbus.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
|
||||
/* Compatibility defines */
|
||||
#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN
|
||||
#define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA
|
||||
#endif
|
||||
#ifndef I2C_FUNC_SMBUS_PEC
|
||||
#define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC
|
||||
#endif
|
||||
|
||||
__s32 i2c_smbus_access(int file, char read_write, __u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_smbus_ioctl_data args;
|
||||
__s32 err;
|
||||
|
||||
args.read_write = read_write;
|
||||
args.command = command;
|
||||
args.size = size;
|
||||
args.data = data;
|
||||
|
||||
err = ioctl(file, I2C_SMBUS, &args);
|
||||
if (err == -1)
|
||||
err = -errno;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
__s32 i2c_smbus_write_quick(int file, __u8 value)
|
||||
{
|
||||
return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_read_byte(int file)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0x0FF & data.byte;
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_byte(int file, __u8 value)
|
||||
{
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, value,
|
||||
I2C_SMBUS_BYTE, NULL);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_read_byte_data(int file, __u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0x0FF & data.byte;
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.byte = value;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_read_word_data(int file, __u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0x0FFFF & data.word;
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.word = value;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.word = value;
|
||||
if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_PROC_CALL, &data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FFFF & data.word;
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i, err;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data);
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
|
||||
ask for less than 32 bytes, your code will only work with kernels
|
||||
2.6.23 and later. */
|
||||
__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
__u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i, err;
|
||||
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
data.block[0] = length;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
|
||||
length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
|
||||
I2C_SMBUS_I2C_BLOCK_DATA, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
|
||||
__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
|
||||
__u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i, err;
|
||||
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
|
||||
err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_BLOCK_PROC_CALL, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
smbus.h - SMBus level access helper functions
|
||||
|
||||
Copyright (C) 1995-97 Simon G. Vogl
|
||||
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef LIB_I2C_SMBUS_H
|
||||
#define LIB_I2C_SMBUS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
extern __s32 i2c_smbus_access(int file, char read_write, __u8 command,
|
||||
int size, union i2c_smbus_data *data);
|
||||
|
||||
extern __s32 i2c_smbus_write_quick(int file, __u8 value);
|
||||
extern __s32 i2c_smbus_read_byte(int file);
|
||||
extern __s32 i2c_smbus_write_byte(int file, __u8 value);
|
||||
extern __s32 i2c_smbus_read_byte_data(int file, __u8 command);
|
||||
extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
|
||||
extern __s32 i2c_smbus_read_word_data(int file, __u8 command);
|
||||
extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
|
||||
extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
|
||||
extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values);
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
|
||||
ask for less than 32 bytes, your code will only work with kernels
|
||||
2.6.23 and later. */
|
||||
extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
__u8 *values);
|
||||
extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length,
|
||||
const __u8 *values);
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
|
||||
__u8 *values);
|
||||
|
||||
#endif /* LIB_I2C_SMBUS_H */
|
||||
|
|
@ -1,348 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "sx9512.h"
|
||||
#include "smbus.h"
|
||||
#include "i2c.h"
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
#define X(name, reserved, default) { #name, reserved, default },
|
||||
const struct sx9512_reg_data sx9512_reg_data[] = { SX9512_REGS };
|
||||
#undef X
|
||||
|
||||
|
||||
//! init the sx9512 and optionally program the registers
|
||||
|
||||
//! @param addr I2C address (0=0x2c)
|
||||
//! @param nvm compare and if different program the registers and flash the NVM with these contents
|
||||
//! @return file descriptor for SX9512 I2C device
|
||||
//! @retval -1 error
|
||||
int sx9512_init(const char *dev, int addr, struct sx9512_reg_nvm *nvm)
|
||||
{
|
||||
int fd, i;
|
||||
struct sx9512_reg_nvm nvm_read;
|
||||
if(!addr)
|
||||
addr=SX9512_I2C_ADDRESS;
|
||||
if((fd=i2c_open_dev(dev, addr, I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE))<0)
|
||||
return -1;
|
||||
/*fd = open(dev, O_RDWR);
|
||||
if(fd < 0) {
|
||||
error(0, errno, "could not open %s", dev);
|
||||
return -1;
|
||||
}
|
||||
if(ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
error(0, errno, "could not set address %x for i2c chip", SX9512_I2C_ADDRESS);
|
||||
close(fd);
|
||||
return -1;
|
||||
}*/
|
||||
if(nvm) {
|
||||
if(sx9512_reg_nvm_read(fd, &nvm_read)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
for(i=0;(unsigned int)i<sizeof(struct sx9512_reg_nvm);i++) {
|
||||
if(sx9512_reg_reserved(i+SX9512_REG_NVM_AREA_START))
|
||||
continue;
|
||||
if(((uint8_t *)nvm)[i] != ((uint8_t *)&nvm_read)[i]) {
|
||||
fprintf(stderr, "sx9512_init: register mismatch, setting default values and burning to NVM\n");
|
||||
if(sx9512_reg_nvm_write(fd, nvm)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
sx9512_reg_nvm_store(fd); //store to NVM
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
const char *sx9512_reg_name(sx9512_reg_t reg)
|
||||
{
|
||||
return sx9512_reg_data[reg].name;
|
||||
}
|
||||
|
||||
|
||||
//! SX9512 check if reg is reserved
|
||||
int sx9512_reg_reserved(sx9512_reg_t reg)
|
||||
{
|
||||
if(reg==SX9512_REG_I2C_SOFT_RESET)
|
||||
return 0;
|
||||
if(reg>=SX9512_REGS_AMOUNT)
|
||||
return 1;
|
||||
return sx9512_reg_data[reg].reserved;
|
||||
}
|
||||
|
||||
|
||||
//! send reset command
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reset(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_I2C_SOFT_RESET, 0xde)<0)
|
||||
return -1;
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_I2C_SOFT_RESET, 0x00)<0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send reset command but retain LED values
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reset_restore_led_state(int fd)
|
||||
{
|
||||
int r;
|
||||
uint8_t p[4];
|
||||
if((r=i2c_smbus_read_i2c_block_data(fd, SX9512_REG_LED1_ON, 4, (__u8 *)&p))<0)
|
||||
return r;
|
||||
if(sx9512_reset(fd))
|
||||
return -1;
|
||||
if((r=i2c_smbus_write_i2c_block_data(fd, SX9512_REG_LED1_ON, 4, (__u8 *)&p))<0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read interrupt reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_interrupt(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_IRQ_SRC))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read touch reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_buttons(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_TOUCH_STATUS))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read prox reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_proximity(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_PROX_STATUS))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read status regs
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_read_status(int fd, struct sx9512_reg_status *status)
|
||||
{
|
||||
//REG_IRQ_SRC not working if using block read for some reason.
|
||||
//if(i2c_smbus_read_i2c_block_data(fd, SX9512_REG_IRQ_SRC, sizeof(struct sx9512_reg_status), (uint8_t *)status)<0)
|
||||
//return -1;
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_IRQ_SRC))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[0]=r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_TOUCH_STATUS))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[1]=r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_PROX_STATUS))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[2]=r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read status cached
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_read_status_cached(int fd, struct sx9512_touch_state *touch_state)
|
||||
{
|
||||
static uint8_t last_state=0;
|
||||
struct sx9512_reg_status status;
|
||||
touch_state->touched=0;
|
||||
touch_state->released=0;
|
||||
if(sx9512_read_status(fd, &status))
|
||||
error(-1, errno, "I2C read error");
|
||||
touch_state->state=status.touch_status | !!((*(uint8_t *)&status.prox_status) & 0xc0);
|
||||
if(*(uint8_t *)&status.irq_src) {
|
||||
if(status.irq_src.touch || status.irq_src.prox_near)
|
||||
touch_state->touched = (last_state ^ touch_state->state) & touch_state->state;
|
||||
if(status.irq_src.release || status.irq_src.prox_far)
|
||||
touch_state->released = (last_state ^ touch_state->state) & last_state;
|
||||
}
|
||||
last_state=touch_state->state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send cmd to load values from NVM to RAM
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_load(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0x08)<0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send cmd to store RAM to NVM
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_store(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0x50)<0)
|
||||
return -1;
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0xa0)<0)
|
||||
return -1;
|
||||
//Wait 500ms then power off/on
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read whole NVM region
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_read(int fd, struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int r, s, i, rl;
|
||||
s=sizeof(struct sx9512_reg_nvm);
|
||||
for(i=0; i<s; i+=32) {
|
||||
rl=s-i;
|
||||
if(rl>32)
|
||||
rl=32;
|
||||
if((r=i2c_smbus_read_i2c_block_data(fd, SX9512_REG_NVM_AREA_START+i, rl, (uint8_t *)p+i))<0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! write whole NVM region
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_write(int fd, struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int r, s, i, rl;
|
||||
s=sizeof(struct sx9512_reg_nvm);
|
||||
for(i=0; i<s; i+=32) {
|
||||
rl=s-i;
|
||||
if(rl>32)
|
||||
rl=32;
|
||||
if((r=i2c_smbus_write_i2c_block_data(fd, SX9512_REG_NVM_AREA_START+i, rl, (uint8_t *)p+i))<0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! init NVM struct
|
||||
void sx9512_reg_nvm_init(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
memset(p, 0, sizeof(struct sx9512_reg_nvm));
|
||||
p->cap_sense_op.set_to_0x14=0x14;
|
||||
}
|
||||
|
||||
|
||||
//! init NVM struct to defaults
|
||||
void sx9512_reg_nvm_init_defaults(struct sx9512_reg_nvm *p, uint8_t capsense_channels, uint8_t led_channels)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init(p);
|
||||
p->irq_mask.touch=1;
|
||||
p->irq_mask.release=1;
|
||||
p->irq_mask.prox_near=1;
|
||||
p->irq_mask.prox_far=1;
|
||||
if(led_channels) {
|
||||
p->led_map[0]=0x00;
|
||||
//p->led_map[1]=led_channels;
|
||||
p->led_map[1]=0x00; //default all leds off
|
||||
p->led_pwm_freq=0x10;
|
||||
p->led_idle=0xff;
|
||||
p->led1_on=0xff;
|
||||
p->led2_on=0xff;
|
||||
p->led_pwr_idle=0xff;
|
||||
p->led_pwr_on=0xff;
|
||||
}
|
||||
p->cap_sense_enable=capsense_channels;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].ls_control=0x01;
|
||||
p->cap_sense_range[i].delta_cin_range=0x03;
|
||||
p->cap_sense_thresh[i]=0x04;
|
||||
}
|
||||
p->cap_sense_thresh[0]=0x02;
|
||||
p->cap_sense_op.auto_compensation=0;
|
||||
p->cap_sense_op.proximity_bl0=1;
|
||||
p->cap_sense_op.proximity_combined_channels=0;
|
||||
p->cap_sense_mode.raw_filter=0x03;
|
||||
p->cap_sense_mode.touch_reporting=1;
|
||||
p->cap_sense_mode.cap_sense_digital_gain=0;
|
||||
p->cap_sense_mode.cap_sense_report_mode=0;
|
||||
p->cap_sense_debounce.cap_sense_prox_near_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_prox_far_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_touch_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_release_debounce=1;
|
||||
p->cap_sense_neg_comp_thresh=0x80;
|
||||
p->cap_sense_pos_comp_thresh=0x80;
|
||||
p->cap_sense_pos_filt.cap_sense_prox_hyst=0;
|
||||
p->cap_sense_pos_filt.cap_sense_pos_comp_debounce=2;
|
||||
p->cap_sense_pos_filt.cap_sense_avg_pos_filt_coef=7;
|
||||
p->cap_sense_neg_filt.cap_sense_touch_hyst=0;
|
||||
p->cap_sense_neg_filt.cap_sense_neg_comp_debounce=2;
|
||||
p->cap_sense_neg_filt.cap_sense_avg_neg_filt_coef=5;
|
||||
p->spo_chan_map=0xff;
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_cg300(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init_defaults(p, 0x0f, 0x3c);
|
||||
p->led_map[0]=0x01;
|
||||
p->led_map[1]=0x3c;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].delta_cin_range=0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_cg301(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init_defaults(p, 0x3b, 0x7f);
|
||||
p->led_map[1]=0x7f;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].delta_cin_range=0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_eg300(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
sx9512_reg_nvm_init_defaults(p, 0x0f, 0xff);
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_dg400(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
sx9512_reg_nvm_init_defaults(p, 0x3f, 0x00);
|
||||
}
|
||||
|
|
@ -1,605 +0,0 @@
|
|||
#ifndef _SX9512_H
|
||||
#define _SX9512_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BIT_ORDER_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define SX9512_I2C_ADDRESS 0x2b
|
||||
#define SX9512B_I2C_ADDRESS 0x2d
|
||||
#define SX9512_CHANNELS 8
|
||||
|
||||
#define SX9512_REG_NVM_AREA_START 0x07
|
||||
#define SX9512_REG_NVM_AREA_END 0x62
|
||||
|
||||
#define SX9512_REG_I2C_SOFT_RESET 0xff
|
||||
|
||||
//Name, reserved, default value
|
||||
#define SX9512_REGS \
|
||||
X(IRQ_SRC, 0, 0x00) \
|
||||
X(TOUCH_STATUS, 0, 0x00) \
|
||||
X(PROX_STATUS, 0, 0x00) \
|
||||
X(COMP_STATUS, 0, 0x00) \
|
||||
X(NVM_CTRL, 0, 0x00) \
|
||||
X(R_05, 1, 0x00) \
|
||||
X(R_06, 1, 0x00) \
|
||||
X(SPO2_MODE, 0, 0x00) \
|
||||
X(PWR_KEY, 0, 0x00) \
|
||||
X(IRQ_MASK, 0, 0x00) \
|
||||
X(R_0A, 1, 0x00) \
|
||||
X(R_0B, 1, 0x00) \
|
||||
X(LED_MAP1, 0, 0x00) \
|
||||
X(LED_MAP2, 0, 0x00) \
|
||||
X(LED_PWM_FREQ, 0, 0x00) \
|
||||
X(LED_MODE, 0, 0x00) \
|
||||
X(LED_IDLE, 0, 0x00) \
|
||||
X(LED_OFF_DELAY, 0, 0x00) \
|
||||
X(LED1_ON, 0, 0x00) \
|
||||
X(LED1_FADE, 0, 0x00) \
|
||||
X(LED2_ON, 0, 0x00) \
|
||||
X(LED2_FADE, 0, 0x00) \
|
||||
X(LED_PWR_IDLE, 0, 0x00) \
|
||||
X(LED_PWR_ON, 0, 0x00) \
|
||||
X(LED_PWR_OFF, 0, 0x00) \
|
||||
X(LED_PWR_FADE, 0, 0x00) \
|
||||
X(LED_PWR_ON_PW, 0, 0x00) \
|
||||
X(LED_PWR_MODE, 0, 0x00) \
|
||||
X(R_1C, 1, 0x00) \
|
||||
X(R_1D, 1, 0x00) \
|
||||
X(CAP_SENSE_ENABLE, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE0, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE1, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE2, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE3, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE4, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE5, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE6, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE7, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE_ALL, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH0, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH1, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH2, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH3, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH4, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH5, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH6, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH7, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH_COMB, 0, 0x00) \
|
||||
X(CAP_SENSE_OP, 0, 0x00) \
|
||||
X(CAP_SENSE_MODE, 0, 0x00) \
|
||||
X(CAP_SENSE_DEBOUNCE, 0, 0x00) \
|
||||
X(CAP_SENSE_NEG_COMP_THRESH, 0, 0x00) \
|
||||
X(CAP_SENSE_POS_COMP_THRESH, 0, 0x00) \
|
||||
X(CAP_SENSE_POS_FILT, 0, 0x00) \
|
||||
X(CAP_SENSE_NEG_FILT, 0, 0x00) \
|
||||
X(CAP_SENSE_STUCK, 0, 0x00) \
|
||||
X(CAP_SENSE_FRAME_SKIP, 0, 0x00) \
|
||||
X(CAP_SENSE_MISC, 0, 0x00) \
|
||||
X(PROX_COMB_CHAN_MASK, 0, 0x00) \
|
||||
X(R_3C, 1, 0x00) \
|
||||
X(R_3D, 1, 0x00) \
|
||||
X(SPO_CHAN_MAP, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL0, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL1, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL2, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL3, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL4, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL5, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL6, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL7, 0, 0x00) \
|
||||
X(SPO_LEVEL_IDLE, 0, 0x00) \
|
||||
X(SPO_LEVEL_PROX, 0, 0x00) \
|
||||
X(R_49, 1, 0x00) \
|
||||
X(R_4A, 1, 0x00) \
|
||||
X(BUZZER_TRIGGER, 0, 0x00) \
|
||||
X(BUZZER_FREQ, 0, 0x00) \
|
||||
X(R_4D, 1, 0x00) \
|
||||
X(R_4E, 1, 0x00) \
|
||||
X(R_4F, 1, 0x00) \
|
||||
X(R_50, 1, 0x00) \
|
||||
X(R_51, 1, 0x00) \
|
||||
X(R_52, 1, 0x00) \
|
||||
X(R_53, 1, 0x00) \
|
||||
X(R_54, 1, 0x00) \
|
||||
X(R_55, 1, 0x00) \
|
||||
X(R_56, 1, 0x00) \
|
||||
X(R_57, 1, 0x00) \
|
||||
X(R_58, 1, 0x00) \
|
||||
X(R_59, 1, 0x00) \
|
||||
X(R_5A, 1, 0x00) \
|
||||
X(R_5B, 1, 0x00) \
|
||||
X(R_5C, 1, 0x00) \
|
||||
X(R_5D, 1, 0x00) \
|
||||
X(R_5E, 1, 0x00) \
|
||||
X(R_5F, 1, 0x00) \
|
||||
X(R_60, 1, 0x00) \
|
||||
X(R_61, 1, 0x00) \
|
||||
X(CAP_SENSE_CHAN_SELECT, 0, 0x00) \
|
||||
X(CAP_SENSE_USEFUL_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_USEFUL_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_AVERAGE_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_AVERAGE_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_DIFF_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_DIFF_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_COMP_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_COMP_LSB, 0, 0x00)
|
||||
|
||||
|
||||
#define X(name, reserved, default) SX9512_REG_##name,
|
||||
typedef enum { SX9512_REGS SX9512_REGS_AMOUNT } sx9512_reg_t;
|
||||
#undef X
|
||||
|
||||
|
||||
struct sx9512_reg_data {
|
||||
const char *name;
|
||||
uint8_t reserved, default_value;
|
||||
};
|
||||
|
||||
|
||||
//! Interrupt source
|
||||
|
||||
//! The Irq Source register will indicate that the specified event has occurred since the last read of this register. If the
|
||||
//! NIRQ function is selected for SPO2 then it will indicate the occurrence of any of these events that are not masked
|
||||
//! out in register 0x09.
|
||||
//! The Irq mask in register 0x09 will prevent an Irq from being indicated by the NIRQ pin but it will not prevent the
|
||||
//! IRQ from being noted in this register.
|
||||
struct sx9512_reg_irq_src {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t reset:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t release:1;
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t compensation_done:1; //!< write 1 to trigger compensation on all channels
|
||||
uint8_t conversion_done:1;
|
||||
uint8_t :1;
|
||||
#else
|
||||
uint8_t :1;
|
||||
uint8_t conversion_done:1;
|
||||
uint8_t compensation_done:1; //!< write 1 to trigger compensation on all channels
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t release:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t reset:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Proximity status
|
||||
struct sx9512_reg_prox_status {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t prox_bl0:1; //!< proximity detected on BL0
|
||||
uint8_t prox_multi:1; //!< proximity detected on combined channels
|
||||
uint8_t prox_multi_comp_pending:1; //!< compensation pending for combined channel prox sensing
|
||||
uint8_t :5;
|
||||
#else
|
||||
uint8_t :5;
|
||||
uint8_t prox_multi_comp_pending:1; //!< compensation pending for combined channel prox sensing
|
||||
uint8_t prox_multi:1; //!< proximity detected on combined channels
|
||||
uint8_t prox_bl0:1; //!< proximity detected on BL0
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! NVM Control
|
||||
|
||||
//! The NVM Area field indicates which of the user NVM areas are currently programmed and active (1, 2 or 3). The
|
||||
//! NVM Read bit gives the ability to manually request that the contents of the NVM be transferred to the registers
|
||||
//! and NVM Burn field gives the ability to burn the current registers to the next available NVM area.
|
||||
//! Normally, the transfer of data from the NVM to the registers is done automatically on power up and upon a reset
|
||||
//! but occasionally a user might want to force a read manually.
|
||||
//! Registers 0x07 through 0x62 are stored to NVM and loaded from NVM.
|
||||
//! After writing 0xA0 (ie NVM burn), wait for at least 500ms and then power off-on the IC for changes to be effective.
|
||||
//! Caution, there are only three user areas and attempts to burn values beyond user area 3 will be ignored.
|
||||
struct sx9512_reg_nvm_ctrl {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t nvm_burn:4; //!< write 0x50 followed by 0xA0 to initiate transfer of reg 0x07-0x62 to NVM
|
||||
uint8_t nvm_read:1; //!< trigger NVM read to registers
|
||||
uint8_t nvm_area:3; //!< indicates current active NVM area
|
||||
#else
|
||||
uint8_t nvm_area:3; //!< indicates current active NVM area
|
||||
uint8_t nvm_read:1; //!< trigger NVM read to registers
|
||||
uint8_t nvm_burn:4; //!< write 0x50 followed by 0xA0 to initiate transfer of reg 0x07-0x62 to NVM
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! SPO2 Mode Control
|
||||
|
||||
//! The SPO2 Config field will specify the functionality of the SPO pin. When selected as NIRQ, the open drain output
|
||||
//! will go low whenever a non-masked Irq occurs and the NIRQ will go back high after a register 0x00 is read over
|
||||
//! the I2C. When selected as Buzzer, the SPO2 pin will drive a 2 phase 2 frequency signal onto an external buzzer
|
||||
//! for each specified event (see Buzzer section). When selected as SPO2, pin operates as an analog output similar
|
||||
//! to SPO1 (see SPO section). If selected as TV power state, the pin is driven from the system PMIC with a high
|
||||
//! (SPO2 = SVDD) indicating that the system power is on and a low (SPO2 = GND) when the system power is off.
|
||||
//! The TV Power State bit reads back the current state of SPO2 if SPO2 is selected for TV power state, otherwise
|
||||
//! the system should write to this bit to indicate the current system power state. The SX9512/12B/13/13B needs to
|
||||
//! know the current state in able to correctly process some of the LED modes for the Power Button (see LED
|
||||
//! modes).
|
||||
struct sx9512_reg_spo2_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :1;
|
||||
uint8_t spo2_config:2; //!< set function of SPO2 pin
|
||||
uint8_t tv_power_state:1; //!< if SPO2 set to TV power state input then TV power state indicated by this bit.
|
||||
uint8_t :4;
|
||||
#else
|
||||
uint8_t :4;
|
||||
uint8_t tv_power_state:1; //!< if SPO2 set to TV power state input then TV power state indicated by this bit.
|
||||
uint8_t spo2_config:2; //!< set function of SPO2 pin
|
||||
uint8_t :1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Interrupt Request Mask
|
||||
|
||||
//! Set which Irqs will trigger an NIRQ (if enabled on SPO2) and report in reg 0x00
|
||||
//! 0=Disable IRQ
|
||||
//! 1=Enable IRQ
|
||||
struct sx9512_reg_irq_mask {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t reset:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t release:1;
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t compensation_done:1;
|
||||
uint8_t :2;
|
||||
#else
|
||||
uint8_t :2;
|
||||
uint8_t compensation_done:1;
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t release:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t reset:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED Mode
|
||||
struct sx9512_reg_led_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_fade_repeat:4;
|
||||
uint8_t :1;
|
||||
uint8_t led_fading:1;
|
||||
uint8_t led_mode:2;
|
||||
#else
|
||||
uint8_t led_mode:2;
|
||||
uint8_t led_fading:1;
|
||||
uint8_t :1;
|
||||
uint8_t led_fade_repeat:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED off delay
|
||||
struct sx9512_reg_led_off_delay {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_engine1_delay_off_time:4;
|
||||
uint8_t led_engine2_delay_off_time:4;
|
||||
#else
|
||||
uint8_t led_engine2_delay_off_time:4;
|
||||
uint8_t led_engine1_delay_off_time:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED Engine fade in/out timing
|
||||
struct sx9512_reg_led_fade {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_engine_fade_in_time:4;
|
||||
uint8_t led_engine_fade_out_time:4;
|
||||
#else
|
||||
uint8_t led_engine_fade_out_time:4;
|
||||
uint8_t led_engine_fade_in_time:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED power button mode
|
||||
struct sx9512_reg_led_pwr_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t power_led_off_mode:1;
|
||||
uint8_t power_led_max_level:1;
|
||||
uint8_t power_led_breath_max:1;
|
||||
uint8_t power_led_waveform:1;
|
||||
uint8_t :2;
|
||||
uint8_t power_button_enable:1;
|
||||
uint8_t led_touch_poarity_invert:1;
|
||||
#else
|
||||
uint8_t led_touch_poarity_invert:1;
|
||||
uint8_t power_button_enable:1;
|
||||
uint8_t :2;
|
||||
uint8_t power_led_waveform:1;
|
||||
uint8_t power_led_breath_max:1;
|
||||
uint8_t power_led_max_level:1;
|
||||
uint8_t power_led_off_mode:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense delta Cin range and LS control
|
||||
struct sx9512_reg_cap_sense_range {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t ls_control:2;
|
||||
uint8_t :4;
|
||||
uint8_t delta_cin_range:2;
|
||||
#else
|
||||
uint8_t delta_cin_range:2;
|
||||
uint8_t :4;
|
||||
uint8_t ls_control:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense auto compensation, proximity on BL0 and combined channel proximity
|
||||
struct sx9512_reg_cap_sense_op {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t auto_compensation:1;
|
||||
uint8_t proximity_bl0:1;
|
||||
uint8_t proximity_combined_channels:1;
|
||||
uint8_t set_to_0x14:5;
|
||||
#else
|
||||
uint8_t set_to_0x14:5;
|
||||
uint8_t proximity_combined_channels:1;
|
||||
uint8_t proximity_bl0:1;
|
||||
uint8_t auto_compensation:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense raw data filter coef, digital gain, I2C touch reporting and CapSense
|
||||
struct sx9512_reg_cap_sense_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t raw_filter:3;
|
||||
uint8_t touch_reporting:1;
|
||||
uint8_t cap_sense_digital_gain:2;
|
||||
uint8_t cap_sense_report_mode:2;
|
||||
#else
|
||||
uint8_t cap_sense_report_mode:2;
|
||||
uint8_t cap_sense_digital_gain:2;
|
||||
uint8_t touch_reporting:1;
|
||||
uint8_t raw_filter:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense debounce
|
||||
struct sx9512_reg_cap_sense_debounce {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_prox_near_debounce:2;
|
||||
uint8_t cap_sense_prox_far_debounce:2;
|
||||
uint8_t cap_sense_touch_debounce:2;
|
||||
uint8_t cap_sense_release_debounce:2;
|
||||
#else
|
||||
uint8_t cap_sense_release_debounce:2;
|
||||
uint8_t cap_sense_touch_debounce:2;
|
||||
uint8_t cap_sense_prox_far_debounce:2;
|
||||
uint8_t cap_sense_prox_near_debounce:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense positive filter coef, positive auto compensation debounce and proximity hyst
|
||||
struct sx9512_reg_cap_sense_pos_filt {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_prox_hyst:3;
|
||||
uint8_t cap_sense_pos_comp_debounce:2;
|
||||
uint8_t cap_sense_avg_pos_filt_coef:3;
|
||||
#else
|
||||
uint8_t cap_sense_avg_pos_filt_coef:3;
|
||||
uint8_t cap_sense_pos_comp_debounce:2;
|
||||
uint8_t cap_sense_prox_hyst:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense negative filter coef, negative auto compensation debounce and touch hyst
|
||||
struct sx9512_reg_cap_sense_neg_filt {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_touch_hyst:3;
|
||||
uint8_t cap_sense_neg_comp_debounce:2;
|
||||
uint8_t cap_sense_avg_neg_filt_coef:3;
|
||||
#else
|
||||
uint8_t cap_sense_avg_neg_filt_coef:3;
|
||||
uint8_t cap_sense_neg_comp_debounce:2;
|
||||
uint8_t cap_sense_touch_hyst:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense stuck-at timer and periodic compensation timer
|
||||
struct sx9512_reg_cap_sense_stuck {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_stuck_at_timer:4;
|
||||
uint8_t cap_sense_periodic_comp:4;
|
||||
#else
|
||||
uint8_t cap_sense_periodic_comp:4;
|
||||
uint8_t cap_sense_stuck_at_timer:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense frame skip setting from active and sleep
|
||||
struct sx9512_reg_cap_sense_frame_skip {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_active_frame_skip:4;
|
||||
uint8_t cap_sense_sleep_frame_skip:4;
|
||||
#else
|
||||
uint8_t cap_sense_sleep_frame_skip:4;
|
||||
uint8_t cap_sense_active_frame_skip:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense sleep enable, auto compensation channels threshold, inactive BL control
|
||||
struct sx9512_reg_cap_sense_misc {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :2;
|
||||
uint8_t comp_chan_num_thresh:2;
|
||||
uint8_t cap_sense_sleep_mode_enable:1;
|
||||
uint8_t :1;
|
||||
uint8_t cap_sense_inactive_bl_mode:2;
|
||||
#else
|
||||
uint8_t cap_sense_inactive_bl_mode:2;
|
||||
uint8_t :1;
|
||||
uint8_t cap_sense_sleep_mode_enable:1;
|
||||
uint8_t comp_chan_num_thresh:2;
|
||||
uint8_t :2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! SPO analog output for proximity
|
||||
struct sx9512_reg_spo_level_prox {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t spo_report_prox:1;
|
||||
uint8_t spo_prox_channel_mapping:1;
|
||||
uint8_t spo_level_prox:6;
|
||||
#else
|
||||
uint8_t spo_level_prox:6;
|
||||
uint8_t spo_prox_channel_mapping:1;
|
||||
uint8_t spo_report_prox:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Buzzer trigger event selection
|
||||
struct sx9512_reg_buzzer_trigger {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :3;
|
||||
uint8_t buzzer_near:1;
|
||||
uint8_t buzzer_far:1;
|
||||
uint8_t buzzer_touch:1;
|
||||
uint8_t buzzer_release:1;
|
||||
uint8_t buzzer_idle_level:1;
|
||||
#else
|
||||
uint8_t buzzer_idle_level:1;
|
||||
uint8_t buzzer_release:1;
|
||||
uint8_t buzzer_touch:1;
|
||||
uint8_t buzzer_far:1;
|
||||
uint8_t buzzer_near:1;
|
||||
uint8_t :3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Buzzer duration frequency
|
||||
struct sx9512_reg_buzzer_freq {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t buzzer_phase1_duration:2;
|
||||
uint8_t buzzer_phase1_freq:2;
|
||||
uint8_t buzzer_phase2_duration:2;
|
||||
uint8_t buzzer_phase2_freq:2;
|
||||
#else
|
||||
uint8_t buzzer_phase2_freq:2;
|
||||
uint8_t buzzer_phase2_duration:2;
|
||||
uint8_t buzzer_phase1_freq:2;
|
||||
uint8_t buzzer_phase1_duration:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg_nvm {
|
||||
struct sx9512_reg_spo2_mode spo2_mode; //!< SPO2 mode control
|
||||
uint8_t pwr_key; //!< Power key control
|
||||
struct sx9512_reg_irq_mask irq_mask; //!< Interrupt request mask
|
||||
uint8_t reserved_0a[2];
|
||||
uint8_t led_map[2]; //!< LED map for engine 1/2
|
||||
uint8_t led_pwm_freq; //!< LED PWM frequency
|
||||
struct sx9512_reg_led_mode led_mode; //!< LED mode
|
||||
uint8_t led_idle; //!< LED idle level
|
||||
struct sx9512_reg_led_off_delay led_off_delay; //!< LED off delay
|
||||
uint8_t led1_on; //!< LED engine 1 on level
|
||||
struct sx9512_reg_led_fade led1_fade; //!< LED engine 1 fade in/out time
|
||||
uint8_t led2_on; //!< LED engine 2 on level
|
||||
struct sx9512_reg_led_fade led2_fade; //!< LED engine 2 fade in/out time
|
||||
uint8_t led_pwr_idle; //!< LED power button idle level
|
||||
uint8_t led_pwr_on; //!< LED power button on level
|
||||
uint8_t led_pwr_off; //!< LED power button off level
|
||||
uint8_t led_pwr_fade; //!< LED power button fade in/out time
|
||||
uint8_t led_pwr_on_pw; //!< LED power on pulse width
|
||||
struct sx9512_reg_led_pwr_mode led_pwr_mode; //!< LED power button mode
|
||||
uint8_t reserved_1c[2];
|
||||
uint8_t cap_sense_enable; //!< CapSense enable
|
||||
struct sx9512_reg_cap_sense_range cap_sense_range[9]; //!< CapSense delta Cin range and LS control chan 0-7
|
||||
//struct sx9512_reg_cap_sense_range cap_sense_range_all; //!< CapSense delta Cin range and LS control for prox sensor (combined channels)
|
||||
uint8_t cap_sense_thresh[9]; //!< CapSense detection threshold for chan 0-7
|
||||
//uint8_t cap_sense_thesh_comb; //!< CapSense detection threshold for prox sensor (combined channels)
|
||||
struct sx9512_reg_cap_sense_op cap_sense_op; //!< CapSense auto compensation, proximity on BL0 and combined channel proximity enable
|
||||
struct sx9512_reg_cap_sense_mode cap_sense_mode; //!< CapSense raw data filter coef, digital gain, I2C touch reporting and CapSense reporting
|
||||
struct sx9512_reg_cap_sense_debounce cap_sense_debounce; //!< CapSense debounce
|
||||
uint8_t cap_sense_neg_comp_thresh; //!< CapSense negative auto compensation threshold
|
||||
uint8_t cap_sense_pos_comp_thresh; //!< CapSense positive auto compensation threshold
|
||||
struct sx9512_reg_cap_sense_pos_filt cap_sense_pos_filt; //!< CapSense positive filter coef, positive auto compensation debounce and proximity hyst
|
||||
struct sx9512_reg_cap_sense_neg_filt cap_sense_neg_filt; //!< CapSense negative filter coef, negative auto compensation debounce and touch hyst
|
||||
struct sx9512_reg_cap_sense_stuck cap_sense_stuck; //!< CapSense stuck-at timer and periodic compensation timer
|
||||
struct sx9512_reg_cap_sense_frame_skip cap_sense_frame_skip; //!< CapSense frame skip setting from active and sleep
|
||||
struct sx9512_reg_cap_sense_misc cap_sense_misc; //!< CapSense sleep enable, auto compensation channels threshold, inactive BL control
|
||||
uint8_t prox_comb_chan_mask; //!< Proximity combined channel mode channel mapping
|
||||
uint8_t reserved_3c[2];
|
||||
uint8_t spo_chan_map; //!< SPO channel mapping
|
||||
uint8_t spo_level_bl[8]; //!< SPO analog output levels
|
||||
uint8_t spo_level_idle; //!< SPO analog output level for idle
|
||||
struct sx9512_reg_spo_level_prox spo_level_prox; //!< SPO analog output for proximity
|
||||
uint8_t reserved_49[2];
|
||||
struct sx9512_reg_buzzer_trigger buzzer_trigger; //!< Buzzer trigger event selection
|
||||
struct sx9512_reg_buzzer_freq buzzer_freq; //!< Buzzer duration frequency
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg {
|
||||
struct sx9512_reg_irq_src irq_src; //!< Interrupt source
|
||||
uint8_t touch_status; //!< Touch status
|
||||
struct sx9512_reg_prox_status prox_status; //!< Proximity status
|
||||
uint8_t comp_status; //!< Compensation status
|
||||
struct sx9512_reg_nvm_ctrl nvm_ctrl; //!< NVM control
|
||||
struct sx9512_reg_nvm nvm; //!< Non-volatile memory
|
||||
uint8_t cap_sense_chan_select; //!< CapSense channel select for readback
|
||||
uint16_t cap_sense_useful_data; //!< CapSense useful data
|
||||
uint16_t cap_sense_average_data; //!< CapSense average data
|
||||
uint16_t cap_sense_diff_data; //!< CapSense diff data
|
||||
uint16_t cap_sense_comp; //!< CapSense compensation DAC value
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg_status {
|
||||
struct sx9512_reg_irq_src irq_src; //!< Interrupt source
|
||||
uint8_t touch_status; //!< Touch status
|
||||
struct sx9512_reg_prox_status prox_status; //!< Proximity status
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_touch_state {
|
||||
uint8_t state;
|
||||
uint8_t touched;
|
||||
uint8_t released;
|
||||
};
|
||||
|
||||
|
||||
int sx9512_init(const char *dev, int addr, struct sx9512_reg_nvm *nvm);
|
||||
const char *sx9512_reg_name(sx9512_reg_t reg);
|
||||
int sx9512_reg_reserved(sx9512_reg_t reg);
|
||||
int sx9512_reset(int fd);
|
||||
int sx9512_reset_restore_led_state(int fd);
|
||||
int sx9512_read_interrupt(int fd);
|
||||
int sx9512_read_buttons(int fd);
|
||||
int sx9512_read_proximity(int fd);
|
||||
int sx9512_read_status(int fd, struct sx9512_reg_status *status);
|
||||
int sx9512_read_status_cached(int fd, struct sx9512_touch_state *touch_state);
|
||||
int sx9512_reg_nvm_load(int fd);
|
||||
int sx9512_reg_nvm_store(int fd);
|
||||
int sx9512_reg_nvm_read(int fd, struct sx9512_reg_nvm *p);
|
||||
int sx9512_reg_nvm_write(int fd, struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_defaults(struct sx9512_reg_nvm *p, uint8_t capsense_channels, uint8_t led_channels);
|
||||
void sx9512_reg_nvm_init_cg300(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_cg301(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_eg300(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_dg400(struct sx9512_reg_nvm *p);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,447 +0,0 @@
|
|||
#include <syslog.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
#include "smbus.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "ucix.h"
|
||||
#include "i2c.h"
|
||||
|
||||
#include "touch_sx9512.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define SX9512_IRQ_RESET 1<<7
|
||||
#define SX9512_IRQ_TOUCH 1<<6
|
||||
#define SX9512_IRQ_RELEASE 1<<5
|
||||
#define SX9512_IRQ_NEAR 1<<4
|
||||
#define SX9512_IRQ_FAR 1<<3
|
||||
#define SX9512_IRQ_COM 1<<2
|
||||
#define SX9512_IRQ_CONV 1<<1
|
||||
|
||||
|
||||
struct i2c_reg_tab {
|
||||
char addr;
|
||||
char value;
|
||||
char range; /* if set registers starting from addr to addr+range will be set to the same value */
|
||||
};
|
||||
|
||||
struct i2c_touch{
|
||||
int dev;
|
||||
int shadow_irq;
|
||||
int shadow_touch;
|
||||
int shadow_proximity;
|
||||
int addr;
|
||||
int irq_button;
|
||||
};
|
||||
|
||||
struct led_data {
|
||||
int addr;
|
||||
led_state_t state;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
struct sx9512_list{
|
||||
struct list_head list;
|
||||
struct led_data *drv;
|
||||
};
|
||||
|
||||
/* holds all leds that is configured to be used. needed for reset */
|
||||
static LIST_HEAD(sx9512_leds);
|
||||
static struct i2c_touch i2c_touch_current; /* pointer to current active table */
|
||||
static int sx9512_led_set_state(struct led_drv *drv, led_state_t state);
|
||||
static led_state_t sx9512_led_get_state(struct led_drv *drv);
|
||||
static int sx9512_set_state(struct led_data *p, led_state_t state);
|
||||
extern struct uloop_timeout i2c_touch_reset_timer;
|
||||
|
||||
|
||||
/* sx9512 needs a reset every 30 minutes. to recalibrate the touch detection */
|
||||
#define I2C_RESET_TIME (1000 * 60 * 30) /* 30 min in ms */
|
||||
static void sx9512_reset_handler(struct uloop_timeout *timeout);
|
||||
struct uloop_timeout i2c_touch_reset_timer = { .cb = sx9512_reset_handler };
|
||||
|
||||
static void sx9512_reset_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct list_head *i;
|
||||
//do_init_tab(i2c_touch_current);
|
||||
sx9512_reset_restore_led_state(i2c_touch_current.dev);
|
||||
|
||||
list_for_each(i, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(i, struct sx9512_list, list);
|
||||
sx9512_set_state(node->drv, node->drv->state);
|
||||
}
|
||||
|
||||
uloop_timeout_set(&i2c_touch_reset_timer, I2C_RESET_TIME);
|
||||
}
|
||||
|
||||
/* set state regardless of previous state */
|
||||
static int sx9512_set_state(struct led_data *p, led_state_t state)
|
||||
{
|
||||
int ret;
|
||||
int bit = 1 << p->addr;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_LED_MAP2);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, LedMap2 register\n");
|
||||
|
||||
if (state == ON)
|
||||
ret = ret | bit;
|
||||
else if (state == OFF)
|
||||
ret = ret & ~bit;
|
||||
else{
|
||||
syslog(LOG_ERR,"%s: Led %s: Set to not supported state %d\n",__func__, p->led.name, state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->state = state;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(i2c_touch_current.dev, SX9512_REG_LED_MAP2, ret);
|
||||
if (ret < 0 ) {
|
||||
syslog(LOG_ERR, "Could not write to i2c device, LedMap2 register\n");
|
||||
return -1;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/* set state if not same as current state */
|
||||
static int sx9512_led_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct led_data *p = (struct led_data *)drv->priv;
|
||||
|
||||
if (!i2c_touch_current.dev)
|
||||
return -1;
|
||||
|
||||
if (p->addr > 7){
|
||||
DBG(1,"Led %s:with address %d outside range 0-7\n",drv->name, p->addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (state == p->state ) {
|
||||
DBG(3,"skipping set");
|
||||
return state;
|
||||
}
|
||||
|
||||
return sx9512_set_state(p, state);
|
||||
}
|
||||
|
||||
static led_state_t sx9512_led_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct led_data *p = (struct led_data *)drv->priv;
|
||||
DBG(1, "state for %s", drv->name);
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct led_drv_func led_func = {
|
||||
.set_state = sx9512_led_set_state,
|
||||
.get_state = sx9512_led_get_state,
|
||||
};
|
||||
|
||||
struct button_data {
|
||||
int addr;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
void sx9512_check(void)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
|
||||
int got_irq = 0;
|
||||
int ret;
|
||||
|
||||
if (!i2c_touch_current.dev)
|
||||
return;
|
||||
|
||||
if (i2c_touch_current.irq_button) {
|
||||
int button;
|
||||
button = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, i2c_touch_current.irq_button, 0);
|
||||
if (button == 0)
|
||||
got_irq = 1;
|
||||
}
|
||||
if ( got_irq ) {
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_IRQ_SRC);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, irq status register\n");
|
||||
i2c_touch_current.shadow_irq = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_TOUCH_STATUS);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, touch register\n");
|
||||
i2c_touch_current.shadow_touch = ret;
|
||||
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_PROX_STATUS);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, proximity register\n");
|
||||
i2c_touch_current.shadow_proximity = ret;
|
||||
}
|
||||
#if 0
|
||||
DEBUG_PRINT("%02x %02x %02x: irq ->",
|
||||
i2c_touch->shadow_irq ,
|
||||
i2c_touch->shadow_touch,
|
||||
i2c_touch->shadow_proximity);
|
||||
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_RESET )
|
||||
DEBUG_PRINT_RAW(" Reset ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_TOUCH )
|
||||
DEBUG_PRINT_RAW(" Touch ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_RELEASE )
|
||||
DEBUG_PRINT_RAW(" Release ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_NEAR )
|
||||
DEBUG_PRINT_RAW(" Near ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_FAR )
|
||||
DEBUG_PRINT_RAW(" Far ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_COM )
|
||||
DEBUG_PRINT_RAW(" Com ");
|
||||
if (i2c_touch->shadow_irq & SX9512_IRQ_CONV )
|
||||
DEBUG_PRINT_RAW(" Conv ");
|
||||
|
||||
DEBUG_PRINT_RAW("\n");
|
||||
#endif
|
||||
|
||||
return ;
|
||||
}
|
||||
/*
|
||||
button address 0- 7 maps to touch event 0-7
|
||||
button address 8 proximity BL0 NEAR
|
||||
button address 9 proximity BL0 FAR
|
||||
|
||||
return BUTTON_RELEASED = no action on this button
|
||||
return BUTTON_PRESSED = button pressed
|
||||
return -1 = error
|
||||
*/
|
||||
|
||||
static button_state_t sx9512_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
struct button_data *p = (struct button_data *)drv->priv;
|
||||
int bit = 1 << p->addr;
|
||||
|
||||
if (!i2c_touch_current.dev)
|
||||
return -1;
|
||||
|
||||
if (p->addr < 8) {
|
||||
if ( bit & i2c_touch_current.shadow_touch ) {
|
||||
i2c_touch_current.shadow_touch = i2c_touch_current.shadow_touch & ~bit;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
|
||||
/* if the button was already pressed and we don't have a release irq report it as still pressed */
|
||||
if( p->state == BUTTON_PRESSED){
|
||||
if (! (i2c_touch_current.shadow_irq & SX9512_IRQ_RELEASE) ) {
|
||||
return BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
return p->state = BUTTON_RELEASED;
|
||||
|
||||
/* proximity NEAR */
|
||||
}else if (p->addr == 8 ) {
|
||||
bit = 1<<7;
|
||||
if( i2c_touch_current.shadow_irq & SX9512_IRQ_NEAR ) {
|
||||
i2c_touch_current.shadow_irq &= ~SX9512_IRQ_NEAR;
|
||||
if ( bit & i2c_touch_current.shadow_proximity ) {
|
||||
i2c_touch_current.shadow_proximity = i2c_touch_current.shadow_proximity & ~bit;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
return BUTTON_RELEASED;
|
||||
|
||||
/* proximity FAR */
|
||||
}else if (p->addr == 9) {
|
||||
if( i2c_touch_current.shadow_irq & SX9512_IRQ_FAR ) {
|
||||
i2c_touch_current.shadow_irq &= ~SX9512_IRQ_FAR;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
return BUTTON_RELEASED;
|
||||
}else {
|
||||
DBG(1,"Button address out of range %d\n",p->addr);
|
||||
return BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
static struct button_drv_func button_func = {
|
||||
.get_state = sx9512_button_get_state,
|
||||
};
|
||||
|
||||
|
||||
static void sx9512_button_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttons);
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"9512_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct button_data));
|
||||
memset(data,0,sizeof(struct button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->button.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s){
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
data->button.func = &button_func;
|
||||
data->button.priv = data;
|
||||
|
||||
button_add(&data->button);
|
||||
}
|
||||
}
|
||||
|
||||
static void sx9512_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"9512_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct led_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct led_data));
|
||||
memset(data,0,sizeof(struct led_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s) {
|
||||
data->addr = strtol(s,0,0);
|
||||
}
|
||||
|
||||
data->led.func = &led_func;
|
||||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
|
||||
{ /* save leds in internal list, we need this for handling reset, we need to restore state */
|
||||
struct sx9512_list *ll = malloc(sizeof(struct sx9512_list));
|
||||
memset(ll, 0, sizeof( struct sx9512_list));
|
||||
ll->drv = data;
|
||||
list_add(&ll->list, &sx9512_leds);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void sx9512_handler_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
char *s, *sx9512_i2c_device;
|
||||
int i, fd, sx9512_i2c_address, sx9512_irq_pin, sx9512_active_capsense_channels, sx9512_active_led_channels;
|
||||
struct sx9512_reg_nvm nvm;
|
||||
struct list_head *il;
|
||||
|
||||
if(!(sx9512_i2c_device = ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_i2c_device"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_i2c_device");
|
||||
return;
|
||||
}
|
||||
DBG(1, "sx9512_i2c_device = [%s]", sx9512_i2c_device);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_i2c_address"))) {
|
||||
DBG(0, "Warning: option is missing: sx9512_i2c_address, setting to default (%02X)", SX9512_I2C_ADDRESS);
|
||||
sx9512_i2c_address = SX9512_I2C_ADDRESS;
|
||||
} else
|
||||
sx9512_i2c_address = strtol(s,0,16);
|
||||
DBG(1, "sx9512_i2c_address = [%02X]", sx9512_i2c_address);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_irq_pin"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_irq_pin");
|
||||
return;
|
||||
}
|
||||
sx9512_irq_pin = strtol(s,0,0);
|
||||
DBG(1, "sx9512_irq_pin = [%d]", sx9512_irq_pin);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_active_capsense_channels"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_active_capsense_channels");
|
||||
return;
|
||||
}
|
||||
sx9512_active_capsense_channels = strtol(s,0,16);
|
||||
DBG(1, "sx9512_active_capsense_channels = [%02X]", sx9512_active_capsense_channels);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_active_led_channels"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_active_led_channels");
|
||||
return;
|
||||
}
|
||||
sx9512_active_led_channels = strtol(s,0,16);
|
||||
DBG(1, "sx9512_active_led_channels = [%02X]", sx9512_active_led_channels);
|
||||
|
||||
sx9512_reg_nvm_init_defaults(&nvm, sx9512_active_capsense_channels, sx9512_active_led_channels);
|
||||
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_led_intensity"))) {
|
||||
nvm.led2_on = nvm.led1_on = strtol(s,0,16);
|
||||
DBG(1, "sx9512_led_intensity = [%02X]", nvm.led1_on);
|
||||
}
|
||||
|
||||
for(i=0;i<8;i++) {
|
||||
char tmpstr[22];
|
||||
sprintf(tmpstr, "sx9512_threshold_bl%d", i);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", tmpstr))) {
|
||||
nvm.cap_sense_thresh[i] = strtol(s,0,16);
|
||||
DBG(1, "sx9512_threshold_bl%d = [%02X]", i, nvm.cap_sense_thresh[i]);
|
||||
}
|
||||
}
|
||||
|
||||
LIST_HEAD(sx9512_init_regs);
|
||||
struct ucilist *node;
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw","sx9512_init_regs", "regs", &sx9512_init_regs);
|
||||
list_for_each_entry(node,&sx9512_init_regs,list) {
|
||||
sx9512_reg_t reg;
|
||||
uint8_t val;
|
||||
int repeat;
|
||||
reg = strtol(node->val,0,16);
|
||||
if(sx9512_reg_reserved(reg)) {
|
||||
DBG(0, "Error: invalid sx9512 reg [%02X]", reg);
|
||||
return;
|
||||
}
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw", node->val, "val");
|
||||
val = strtol(s,0,16);
|
||||
if(!(s = ucix_get_option(s_ctx->uci_ctx, "hw", node->val, "repeat")))
|
||||
repeat=1;
|
||||
else
|
||||
repeat=strtol(s,0,0);
|
||||
for(i=0;i<repeat;i++) {
|
||||
DBG(1, "sx9512_init_reg[%02X:%s=%02X]", reg, sx9512_reg_name(reg), val);
|
||||
((uint8_t *)&nvm)[reg-SX9512_REG_NVM_AREA_START] = val;
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
if((fd = sx9512_init(sx9512_i2c_device, sx9512_i2c_address, &nvm))<1)
|
||||
return;
|
||||
i2c_touch_current.dev=fd;
|
||||
i2c_touch_current.addr=sx9512_i2c_address;
|
||||
i2c_touch_current.irq_button=sx9512_irq_pin;
|
||||
|
||||
sx9512_button_init(s_ctx);
|
||||
sx9512_led_init(s_ctx);
|
||||
/* Force set of initial state for leds. */
|
||||
list_for_each(il, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(il, struct sx9512_list, list);
|
||||
sx9512_set_state(node->drv, node->drv->state);
|
||||
}
|
||||
/* start reset timer */
|
||||
uloop_timeout_set(&i2c_touch_reset_timer, I2C_RESET_TIME);
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef TOUCH_SX9512_H
|
||||
#define TOUCH_SX9512_H
|
||||
|
||||
#include "server.h"
|
||||
#include "sx9512.h"
|
||||
|
||||
void sx9512_handler_init(struct server_ctx *);
|
||||
void sx9512_check(void);
|
||||
|
||||
#endif /* TOUCH_SX9512_H */
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* ucix
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
* Copyright (C) 2010 Steven Barth <steven@midlink.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ucix.h"
|
||||
|
||||
struct uci_ptr uci_ptr;
|
||||
|
||||
int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
memset(&uci_ptr, 0, sizeof(uci_ptr));
|
||||
uci_ptr.package = p;
|
||||
uci_ptr.section = s;
|
||||
uci_ptr.option = o;
|
||||
uci_ptr.value = t;
|
||||
return uci_lookup_ptr(ctx, &uci_ptr, NULL, true);
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init(const char *config_file, int state)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
uci_set_confdir(ctx, "/etc/config");
|
||||
if(state)
|
||||
uci_set_savedir(ctx, "/var/state/");
|
||||
else
|
||||
uci_set_savedir(ctx, "/tmp/.uci/");
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->confdir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init_path(const char *vpath, const char *config_file, int state)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
char buf[256];
|
||||
if(!vpath)
|
||||
return ucix_init(config_file, state);
|
||||
ctx = uci_alloc_context();
|
||||
buf[255] = '\0';
|
||||
snprintf(buf, 255, "%s", vpath);
|
||||
uci_set_confdir(ctx, buf);
|
||||
// snprintf(buf, 255, "%s%s", vpath, (state)?("/var/state"):("/tmp/.uci"));
|
||||
// uci_add_delta_path(ctx, buf);
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->confdir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int ucix_get_option_list(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, struct list_head *l)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return 1;
|
||||
if (!(uci_ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return 1;
|
||||
e = uci_ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(uci_ptr.o->type) {
|
||||
case UCI_TYPE_LIST:
|
||||
uci_foreach_element(&uci_ptr.o->v.list, e)
|
||||
{
|
||||
struct ucilist *ul = malloc(sizeof(struct ucilist));
|
||||
ul->val = strdup((e->name)?(e->name):(""));
|
||||
list_add_tail(&ul->list, l);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
const char *value = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return NULL;
|
||||
if (!(uci_ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return NULL;
|
||||
e = uci_ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_SECTION:
|
||||
value = uci_to_section(e)->type;
|
||||
break;
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(uci_ptr.o->type) {
|
||||
case UCI_TYPE_STRING:
|
||||
value = uci_ptr.o->v.string;
|
||||
break;
|
||||
default:
|
||||
value = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (value) ? (strdup(value)):(NULL);
|
||||
}
|
||||
|
||||
void ucix_add_list(struct uci_context *ctx, const char *p, const char *s, const char *o, struct list_head *vals)
|
||||
{
|
||||
struct list_head *q;
|
||||
list_for_each(q, vals)
|
||||
{
|
||||
struct ucilist *ul = container_of(q, struct ucilist, list);
|
||||
if(ucix_get_ptr(ctx, p, s, o, (ul->val)?(ul->val):("")))
|
||||
return;
|
||||
uci_add_list(ctx, &uci_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&uci_ptr.p->sections, e)
|
||||
if (!strcmp(t, uci_to_section(e)->type))
|
||||
cb(e->name, priv);
|
||||
}
|
||||
|
||||
void ucix_for_each_section_option(struct uci_context *ctx,
|
||||
const char *p, const char *s,
|
||||
void (*cb)(const char*, const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&uci_ptr.s->options, e)
|
||||
{
|
||||
struct uci_option *o = uci_to_option(e);
|
||||
cb(o->e.name, o->v.string, priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* ucix
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
* Copyright (C) 2010 Steven Barth <steven@midlink.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UCI_H__
|
||||
#define _UCI_H__
|
||||
#include <uci.h>
|
||||
#include <libubox/list.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef uci_to_delta
|
||||
// Support older version of uci, where this function was named
|
||||
// differently
|
||||
#define uci_add_delta_path uci_add_history_path
|
||||
#endif
|
||||
|
||||
struct ucilist {
|
||||
struct list_head list;
|
||||
char *val;
|
||||
};
|
||||
|
||||
extern struct uci_ptr uci_ptr;
|
||||
|
||||
int ucix_get_ptr(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, const char *t);
|
||||
struct uci_context* ucix_init(const char *config_file, int state);
|
||||
struct uci_context* ucix_init_path(const char *vpath, const char *config_file, int state);
|
||||
int ucix_save_state(struct uci_context *ctx, const char *p);
|
||||
char* ucix_get_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
int ucix_get_option_list(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, struct list_head *l);
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(const char*, void*), void *priv);
|
||||
void ucix_for_each_section_option(struct uci_context *ctx,
|
||||
const char *p, const char *s,
|
||||
void (*cb)(const char*, const char*, void*), void *priv);
|
||||
void ucix_add_list(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o, struct list_head *vals);
|
||||
|
||||
static inline void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if (!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_delete(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if (!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_revert(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_list_single(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if (ucix_get_ptr(ctx, p, s, o, t))
|
||||
return;
|
||||
uci_add_list(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if (ucix_get_ptr(ctx, p, s, o, t))
|
||||
return;
|
||||
uci_set(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, t))
|
||||
return;
|
||||
uci_set(ctx, &uci_ptr);
|
||||
}
|
||||
|
||||
static inline void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_option(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
static inline void ucix_add_list_single_int(struct uci_context *ctx, const char *p, const char *s, const char *o, const int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_list_single(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
static inline int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def)
|
||||
{
|
||||
char *tmp = ucix_get_option(ctx, p, s, o);
|
||||
int ret = def;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
ret = atoi(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int ucix_save(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
uci_save(ctx, uci_ptr.p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ucix_commit(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
return uci_commit(ctx, &uci_ptr.p, false);
|
||||
}
|
||||
|
||||
static inline void ucix_cleanup(struct uci_context *ctx)
|
||||
{
|
||||
uci_free_context(ctx);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "led.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define SPI_SLAVE_SELECT 1
|
||||
|
||||
struct vox_data {
|
||||
int addr;
|
||||
led_state_t state;
|
||||
int brightness;
|
||||
struct led_drv led;
|
||||
};
|
||||
|
||||
void vox_init(struct server_ctx *s_ctx);
|
||||
|
||||
static int vox_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
char spi_data[6] = {0,0,0,0,0,0};
|
||||
|
||||
if (p->state == state)
|
||||
return state;
|
||||
|
||||
memset(spi_data, 0, 6);
|
||||
|
||||
spi_data[0] = p->addr;
|
||||
|
||||
if (state == ON) {
|
||||
spi_data[1] = 1;
|
||||
spi_data[2] = 0x0;
|
||||
spi_data[3] = 0x0;
|
||||
spi_data[4] = 0x0;
|
||||
spi_data[4] = 0x0;
|
||||
} else if(state == PULSING) {
|
||||
spi_data[1] = 3;
|
||||
spi_data[2] = 0xa0;
|
||||
} else if(state == FLASH_SLOW) {
|
||||
spi_data[1] = 2;
|
||||
spi_data[3] = 0x95;
|
||||
} else if(state == FLASH_FAST) {
|
||||
spi_data[1] = 2;
|
||||
spi_data[3] = 0x20;
|
||||
}
|
||||
|
||||
DBG(2,"vox_set_state %x %x %x %x",spi_data[0],spi_data[1],spi_data[2],spi_data[3]);
|
||||
board_ioctl(BOARD_IOCTL_SPI_WRITE, SPI_SLAVE_SELECT, 0, spi_data, 6, 0);
|
||||
|
||||
p->state = state;
|
||||
return state;
|
||||
}
|
||||
|
||||
static led_state_t vox_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
return p->state;
|
||||
}
|
||||
|
||||
/* input brightness is in %. 0-100 */
|
||||
/* internal brightness is 5 steps. 0-4 */
|
||||
/*
|
||||
step, level percent mapping.
|
||||
0 0 -> 20
|
||||
1 21 -> 40
|
||||
2 41 -> 60
|
||||
3 61 -> 80
|
||||
4 81 -> 100
|
||||
|
||||
*/
|
||||
|
||||
static int vox_set_brightness(struct led_drv *drv, int level)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
int new = (level * 5)/101; /* really level/(101/5) */
|
||||
char spi_data[6] = {0,0,0,0,0,0};
|
||||
|
||||
if (new == p->brightness)
|
||||
return level;
|
||||
|
||||
p->brightness = new;
|
||||
|
||||
memset(spi_data, 0, 6);
|
||||
|
||||
spi_data[0] = p->addr;
|
||||
spi_data[1] = 6;
|
||||
spi_data[2] = p->brightness;
|
||||
|
||||
DBG(2,"vox_set_state %x %x %x %x",spi_data[0],spi_data[1],spi_data[2],spi_data[3]);
|
||||
board_ioctl(BOARD_IOCTL_SPI_WRITE, SPI_SLAVE_SELECT, 0, spi_data, 6, 0);
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static int vox_get_brightness(struct led_drv *drv)
|
||||
{
|
||||
struct vox_data *p = (struct vox_data *)drv->priv;
|
||||
return p->brightness * (100/5);
|
||||
}
|
||||
|
||||
static int vox_support(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
|
||||
case OFF:
|
||||
case ON:
|
||||
case FLASH_SLOW:
|
||||
case FLASH_FAST:
|
||||
case PULSING:
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = vox_set_state,
|
||||
.get_state = vox_get_state,
|
||||
.set_brightness = vox_set_brightness,
|
||||
.get_brightness = vox_get_brightness,
|
||||
.support = vox_support,
|
||||
};
|
||||
|
||||
void vox_init(struct server_ctx *s_ctx) {
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
int register_spi = 0;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"vox_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct vox_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct vox_data));
|
||||
memset(data,0,sizeof(struct vox_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , data->led.name, "addr");
|
||||
DBG(1, "addr = [%s]", s);
|
||||
if (s) {
|
||||
data->addr = strtol(s,0,0);
|
||||
}else
|
||||
syslog(LOG_ERR,"vox_led config needs addr option\n");
|
||||
|
||||
data->led.func = &func;
|
||||
data->led.priv = data;
|
||||
data->state = NEED_INIT;
|
||||
data->brightness = 4;
|
||||
led_add(&data->led);
|
||||
register_spi = 1;
|
||||
}
|
||||
|
||||
/* if config entries for vox leds exist register the spi as used. */
|
||||
if(register_spi) {
|
||||
/* arg 4 is the spi mode encoded in a string pointer */
|
||||
/* mode is decribed i/bcm963xx/shared/opensource/include/bcm963xx/bcmSpiRes.h */
|
||||
board_ioctl(BOARD_IOCTL_SPI_INIT, SPI_SLAVE_SELECT, 0, (char*)0, 0, 391000);
|
||||
board_ioctl_init();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
int debug_level;
|
||||
struct termios orig_termios;
|
||||
|
||||
#define SPI_SLAVE_SELECT 1
|
||||
|
||||
void reset_terminal_mode(void);
|
||||
void set_conio_terminal_mode( void );
|
||||
int kbhit( void );
|
||||
int getch( void );
|
||||
void display(void);
|
||||
void inc(void);
|
||||
void dec(void);
|
||||
|
||||
void reset_terminal_mode( void)
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &orig_termios);
|
||||
}
|
||||
|
||||
void set_conio_terminal_mode( void )
|
||||
{
|
||||
struct termios new_termios;
|
||||
|
||||
/* take two copies - one for now, one for later */
|
||||
tcgetattr(0, &orig_termios);
|
||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
||||
|
||||
/* register cleanup handler, and set the new terminal mode */
|
||||
atexit(reset_terminal_mode);
|
||||
cfmakeraw(&new_termios);
|
||||
tcsetattr(0, TCSANOW, &new_termios);
|
||||
}
|
||||
|
||||
int kbhit( void )
|
||||
{
|
||||
struct timeval tv = { 0L, 0L };
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
return select(1, &fds, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
int getch( void )
|
||||
{
|
||||
int r = 0;
|
||||
int c = 0;
|
||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
||||
return r;
|
||||
} else {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
int ret = 0;
|
||||
ret |= (c >> 24) & 0x000000ff;
|
||||
ret |= (c >> 8) & 0x0000ff00;
|
||||
ret |= (c << 8) & 0x00ff0000;
|
||||
ret |= (c << 24) & 0xff000000;
|
||||
return ret;
|
||||
#else
|
||||
return c;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char spi_data [6] = {8,3,0,0,0,0};
|
||||
int pos;
|
||||
|
||||
void display(void){
|
||||
|
||||
printf("\r");
|
||||
printf("%02x %02x %02x %02x %02x %02x \r",
|
||||
spi_data[0],
|
||||
spi_data[1],
|
||||
spi_data[2],
|
||||
spi_data[3],
|
||||
spi_data[4],
|
||||
spi_data[5]
|
||||
);
|
||||
|
||||
|
||||
if (pos){
|
||||
int jump = pos/2;
|
||||
printf("\e[%dC",pos+jump);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void inc(void){
|
||||
|
||||
int byte = pos/2;
|
||||
int nibble = pos%2;
|
||||
|
||||
int val_hi = (spi_data[byte] >> 4 ) & 0xF;
|
||||
int val_lo = spi_data[byte] & 0xF;
|
||||
|
||||
if(!nibble) {
|
||||
val_hi++;
|
||||
if(val_hi > 0xF )
|
||||
val_hi = 0xf;
|
||||
}else{
|
||||
val_lo++;
|
||||
if(val_lo > 0xF )
|
||||
val_lo = 0xf;
|
||||
}
|
||||
|
||||
spi_data[byte] = val_hi << 4 | val_lo;
|
||||
}
|
||||
|
||||
void dec(void){
|
||||
int byte = pos/2;
|
||||
int nibble = pos%2;
|
||||
|
||||
int val_hi = (spi_data[byte] >> 4 ) & 0xF;
|
||||
int val_lo = spi_data[byte] & 0xF;
|
||||
|
||||
if(!nibble) {
|
||||
val_hi--;
|
||||
if(val_hi < 0 )
|
||||
val_hi = 0;
|
||||
}else{
|
||||
val_lo--;
|
||||
if(val_lo < 0 )
|
||||
val_lo = 0;
|
||||
}
|
||||
|
||||
spi_data[byte] = val_hi << 4 | val_lo;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
|
||||
board_ioctl_init();
|
||||
/* arg 4 is the spi mode encoded in a string pointer */
|
||||
/* mode is decribed i/bcm963xx/shared/opensource/include/bcm963xx/bcmSpiRes.h */
|
||||
board_ioctl(BOARD_IOCTL_SPI_INIT, SPI_SLAVE_SELECT, 0, (char *)0, 0, 391000);
|
||||
set_conio_terminal_mode();
|
||||
fflush(stdout);
|
||||
|
||||
display();
|
||||
|
||||
while ( 'q' != (char)(ch = getch())) {
|
||||
/* right */
|
||||
if (ch == 4414235) {
|
||||
pos++;
|
||||
if (pos > 11)
|
||||
pos = 11;
|
||||
}
|
||||
/* left */
|
||||
if (ch == 4479771) {
|
||||
pos--;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
}
|
||||
/* up */
|
||||
if (ch == 4283163) {
|
||||
inc();
|
||||
}
|
||||
/* down */
|
||||
if (ch == 4348699) {
|
||||
dec();
|
||||
}
|
||||
/* enter */
|
||||
if (ch == '\r') {
|
||||
board_ioctl(BOARD_IOCTL_SPI_WRITE, SPI_SLAVE_SELECT, 0, (char*)spi_data, 6, 0);
|
||||
}
|
||||
display();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -10,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"
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
CC = gcc
|
||||
MAKEDEPEND = makedepend
|
||||
CDEBUG = -g
|
||||
CFLAGS = ${CDEBUG} ${INCL} -Wall
|
||||
LDFLAGS = ${CDEBUG}
|
||||
LIBDIR =
|
||||
LOCLIBS =
|
||||
LIBS = ${LOCLIBS} ${SYSLIBS}
|
||||
OBJS = bitstream.o mask.o qrenc.o qrencode.o qrinput.o qrspec.o rscode.o split.o
|
||||
SRCS = bitstream.c mask.c qrenc.c qrencode.c qrinput.c qrspec.c rscode.c split.c
|
||||
LIBSRCS =
|
||||
ISRCS = bitstream.h mask.h qrencode.h qrencode_inner.h qrinput.h qrspec.h rscode.h split.h config.h
|
||||
ALLSRCS = ${SRCS} ${ISRCS} ${LIBSRCS}
|
||||
|
||||
all: qrencode
|
||||
|
||||
qrencode: ${OBJS}
|
||||
${CC} ${LDFLAGS} -o qrencode ${OBJS} ${LIBDIR} ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f qrencode core *.o *.BAK *.bak *.CKP a.out
|
||||
|
||||
install:
|
||||
install -c -s -o bin -g bin -m 555 qrencode /usr/local/bin
|
||||
|
||||
depend:
|
||||
${MAKEDEPEND} ${INCL} ${SRCS} ${LIBSRCS}
|
||||
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Binary sequence class.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitstream.h"
|
||||
|
||||
BitStream *BitStream_new(void)
|
||||
{
|
||||
BitStream *bstream;
|
||||
|
||||
bstream = (BitStream *)malloc(sizeof(BitStream));
|
||||
bstream->data = NULL;
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
static BitStream *BitStream_newFromNum(int bits, unsigned int num)
|
||||
{
|
||||
unsigned int mask;
|
||||
int i;
|
||||
char *p;
|
||||
BitStream *bstream;
|
||||
|
||||
bstream = BitStream_new();
|
||||
bstream->data = (char *)malloc(bits + 1);
|
||||
|
||||
p = bstream->data;
|
||||
mask = 1 << (bits - 1);
|
||||
for(i=0; i<bits; i++) {
|
||||
if(num & mask) {
|
||||
*p = '1';
|
||||
} else {
|
||||
*p = '0';
|
||||
}
|
||||
p++;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
static BitStream *BitStream_newFromBytes(int size, unsigned char *data)
|
||||
{
|
||||
unsigned char mask;
|
||||
int i, j;
|
||||
char *p;
|
||||
BitStream *bstream;
|
||||
|
||||
bstream = BitStream_new();
|
||||
bstream->data = (char *)malloc(size * 8 + 1);
|
||||
|
||||
p = bstream->data;
|
||||
for(i=0; i<size; i++) {
|
||||
mask = 0x80;
|
||||
for(j=0; j<8; j++) {
|
||||
if(data[i] & mask) {
|
||||
*p = '1';
|
||||
} else {
|
||||
*p = '0';
|
||||
}
|
||||
p++;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
void BitStream_append(BitStream *bstream, BitStream *arg)
|
||||
{
|
||||
int l1, l2;
|
||||
char *data;
|
||||
|
||||
if(arg == NULL || arg->data == NULL) {
|
||||
return;
|
||||
}
|
||||
if(bstream->data == NULL) {
|
||||
bstream->data = strdup(arg->data);
|
||||
return;
|
||||
}
|
||||
|
||||
l1 = strlen(bstream->data);
|
||||
l2 = strlen(arg->data);
|
||||
data = (char *)malloc(l1 + l2 + 1);
|
||||
strcpy(data, bstream->data);
|
||||
strcat(data, arg->data);
|
||||
|
||||
free(bstream->data);
|
||||
bstream->data = data;
|
||||
}
|
||||
|
||||
void BitStream_appendNum(BitStream *bstream, int bits, unsigned int num)
|
||||
{
|
||||
BitStream *b;
|
||||
|
||||
b = BitStream_newFromNum(bits, num);
|
||||
BitStream_append(bstream, b);
|
||||
BitStream_free(b);
|
||||
}
|
||||
|
||||
void BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data)
|
||||
{
|
||||
BitStream *b;
|
||||
|
||||
b = BitStream_newFromBytes(size, data);
|
||||
BitStream_append(bstream, b);
|
||||
BitStream_free(b);
|
||||
}
|
||||
|
||||
unsigned int BitStream_size(BitStream *bstream)
|
||||
{
|
||||
if(bstream == NULL) return 0;
|
||||
if(bstream->data == NULL) return 0;
|
||||
|
||||
return strlen(bstream->data);
|
||||
}
|
||||
|
||||
unsigned char *BitStream_toByte(BitStream *bstream)
|
||||
{
|
||||
int i, j, size, bytes;
|
||||
unsigned char *data, v;
|
||||
char *p;
|
||||
|
||||
size = BitStream_size(bstream);
|
||||
data = (unsigned char *)malloc((size + 7) / 8);
|
||||
bytes = size / 8;
|
||||
|
||||
p = bstream->data;
|
||||
for(i=0; i<bytes; i++) {
|
||||
v = 0;
|
||||
for(j=0; j<8; j++) {
|
||||
v = v << 1;
|
||||
v |= *p == '1';
|
||||
p++;
|
||||
}
|
||||
data[i] = v;
|
||||
}
|
||||
if(size & 7) {
|
||||
v = 0;
|
||||
for(j=0; j<(size & 7); j++) {
|
||||
v = v << 1;
|
||||
v |= *p == '1';
|
||||
p++;
|
||||
}
|
||||
data[bytes] = v;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void BitStream_free(BitStream *bstream)
|
||||
{
|
||||
if(bstream->data != NULL) {
|
||||
free(bstream->data);
|
||||
}
|
||||
free(bstream);
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Binary sequence class.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __BITSTREAM_H__
|
||||
#define __BITSTREAM_H__
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
} BitStream;
|
||||
|
||||
extern BitStream *BitStream_new(void);
|
||||
extern void BitStream_append(BitStream *bstream, BitStream *arg);
|
||||
extern void BitStream_appendNum(BitStream *bstream, int bits, unsigned int num);
|
||||
extern void BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data);
|
||||
extern unsigned int BitStream_size(BitStream *bstream);
|
||||
extern unsigned char *BitStream_toByte(BitStream *bstream);
|
||||
extern void BitStream_free(BitStream *bstream);
|
||||
|
||||
#endif /* __BITSTREAM_H__ */
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Masking.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "qrencode.h"
|
||||
#include "qrencode_inner.h"
|
||||
#include "qrspec.h"
|
||||
#include "mask.h"
|
||||
|
||||
/**
|
||||
* Demerit coefficients.
|
||||
* See Section 8.8.2, pp.45, JIS X0510:2004.
|
||||
*/
|
||||
#define N1 (3)
|
||||
#define N2 (3)
|
||||
#define N3 (40)
|
||||
#define N4 (10)
|
||||
|
||||
#define MASKMAKER(__exp__) \
|
||||
int x, y;\
|
||||
unsigned int b = 0;\
|
||||
\
|
||||
for(y=0; y<width; y++) {\
|
||||
for(x=0; x<width; x++) {\
|
||||
if(*s & 0x80) {\
|
||||
*d = *s;\
|
||||
} else {\
|
||||
*d = *s ^ ((__exp__) == 0);\
|
||||
}\
|
||||
b += (*d & 1);\
|
||||
s++; d++;\
|
||||
}\
|
||||
}\
|
||||
return b;
|
||||
|
||||
static int Mask_mask0(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((x+y)&1)
|
||||
}
|
||||
|
||||
static int Mask_mask1(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(y&1)
|
||||
}
|
||||
|
||||
static int Mask_mask2(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(x%3)
|
||||
}
|
||||
|
||||
static int Mask_mask3(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((x+y)%3)
|
||||
}
|
||||
|
||||
static int Mask_mask4(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(((y/2)+(x/3))&1)
|
||||
}
|
||||
|
||||
static int Mask_mask5(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER(((x*y)&1)+(x*y)%3)
|
||||
}
|
||||
|
||||
static int Mask_mask6(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((((x*y)&1)+(x*y)%3)&1)
|
||||
}
|
||||
|
||||
static int Mask_mask7(int width, const unsigned char *s, unsigned char *d)
|
||||
{
|
||||
MASKMAKER((((x*y)%3)+((x+y)&1))&1)
|
||||
}
|
||||
|
||||
typedef int MaskMaker(int, const unsigned char *, unsigned char *);
|
||||
static MaskMaker *maskMakers[] = {
|
||||
Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3,
|
||||
Mask_mask4, Mask_mask5, Mask_mask6, Mask_mask7
|
||||
};
|
||||
|
||||
unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask)
|
||||
{
|
||||
unsigned char *masked;
|
||||
|
||||
masked = (unsigned char *)malloc(width * width);
|
||||
|
||||
maskMakers[mask](width, frame, masked);
|
||||
|
||||
return masked;
|
||||
}
|
||||
|
||||
static int runLength[QRSPEC_WIDTH_MAX + 1];
|
||||
|
||||
//static int n1;
|
||||
//static int n2;
|
||||
//static int n3;
|
||||
//static int n4;
|
||||
|
||||
static int Mask_calcN1N3(int length, int *runLength)
|
||||
{
|
||||
int i;
|
||||
int demerit = 0;
|
||||
int fact;
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
if(runLength[i] >= 5) {
|
||||
demerit += N1 + (runLength[i] - 5);
|
||||
//n1 += N1 + (runLength[i] - 5);
|
||||
}
|
||||
if((i & 1)) {
|
||||
if(i >= 3 && i < length-2 && (runLength[i] % 3) == 0) {
|
||||
fact = runLength[i] / 3;
|
||||
if(runLength[i-2] == fact &&
|
||||
runLength[i-1] == fact &&
|
||||
runLength[i+1] == fact &&
|
||||
runLength[i+2] == fact) {
|
||||
if(runLength[i-3] < 0 || runLength[i-3] >= 4 * fact) {
|
||||
demerit += N3;
|
||||
//n3 += N3;
|
||||
} else if(i+3 >= length || runLength[i+3] >= 4 * fact) {
|
||||
demerit += N3;
|
||||
//n3 += N3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
int Mask_evaluateSymbol(int width, unsigned char *frame)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char *p;
|
||||
unsigned char b22, w22;
|
||||
unsigned int i;
|
||||
int head;
|
||||
int demerit = 0;
|
||||
|
||||
p = frame;
|
||||
i = 0;
|
||||
for(y=0; y<width; y++) {
|
||||
head = 0;
|
||||
runLength[0] = 1;
|
||||
for(x=0; x<width; x++) {
|
||||
if(x > 0 && y > 0) {
|
||||
b22 = p[0] & p[-1] & p[-width] & p [-width-1];
|
||||
w22 = p[0] | p[-1] | p[-width] | p [-width-1];
|
||||
if((b22 | (w22 ^ 1))&1) {
|
||||
demerit += N2;
|
||||
}
|
||||
}
|
||||
if(x == 0 && (p[0] & 1)) {
|
||||
runLength[0] = -1;
|
||||
head = 1;
|
||||
runLength[head] = 1;
|
||||
} else if(x > 0) {
|
||||
if((p[0] ^ p[-1]) & 1) {
|
||||
head++;
|
||||
runLength[head] = 1;
|
||||
} else {
|
||||
runLength[head]++;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
demerit += Mask_calcN1N3(head+1, runLength);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for(x=0; x<width; x++) {
|
||||
head = 0;
|
||||
runLength[0] = 1;
|
||||
p = frame + x;
|
||||
for(y=0; y<width; y++) {
|
||||
if(y == 0 && (p[0] & 1)) {
|
||||
runLength[0] = -1;
|
||||
head = 1;
|
||||
runLength[head] = 1;
|
||||
} else if(y > 0) {
|
||||
if((p[0] ^ p[-width]) & 1) {
|
||||
head++;
|
||||
runLength[head] = 1;
|
||||
} else {
|
||||
runLength[head]++;
|
||||
}
|
||||
}
|
||||
p+=width;
|
||||
}
|
||||
demerit += Mask_calcN1N3(head+1, runLength);
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level)
|
||||
{
|
||||
int i;
|
||||
unsigned char *mask, *bestMask;
|
||||
int minDemerit = INT_MAX;
|
||||
int bestMaskNum = 0;
|
||||
int blacks;
|
||||
int demerit;
|
||||
|
||||
bestMask = NULL;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
// n1 = n2 = n3 = n4 = 0;
|
||||
demerit = 0;
|
||||
mask = (unsigned char *)malloc(width * width);
|
||||
blacks = maskMakers[i](width, frame, mask);
|
||||
blacks += QRcode_writeFormatInformation(width, mask, i, level);
|
||||
blacks = 100 * blacks / (width * width);
|
||||
demerit = (abs(blacks - 50) / 5) * N4;
|
||||
// n4 = demerit;
|
||||
demerit += Mask_evaluateSymbol(width, mask);
|
||||
// printf("(%d,%d,%d,%d)=%d\n", n1, n2, n3 ,n4, demerit);
|
||||
if(demerit < minDemerit) {
|
||||
minDemerit = demerit;
|
||||
bestMaskNum = i;
|
||||
if(bestMask != NULL) {
|
||||
free(bestMask);
|
||||
}
|
||||
bestMask = mask;
|
||||
} else {
|
||||
free(mask);
|
||||
}
|
||||
}
|
||||
|
||||
return bestMask;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Masking.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __MASK_H__
|
||||
#define __MASK_H__
|
||||
|
||||
#include "qrinput.h"
|
||||
|
||||
extern unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask);
|
||||
extern int Mask_evaluateSymbol(int width, unsigned char *frame);
|
||||
extern unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level);
|
||||
|
||||
#endif /* __MASK_H__ */
|
||||
|
|
@ -1,452 +0,0 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* QR Code encoding tool
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <png.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "qrencode.h"
|
||||
|
||||
static int casesensitive = 1;
|
||||
static int eightbit = 0;
|
||||
static int version = 0;
|
||||
static int size = 3;
|
||||
static int margin = 4;
|
||||
static int structured = 0;
|
||||
static QRecLevel level = QR_ECLEVEL_L;
|
||||
static QRencodeMode hint = QR_MODE_8;
|
||||
|
||||
static const struct option options[] = {
|
||||
{"help" , no_argument , NULL, 'h'},
|
||||
{"output" , required_argument, NULL, 'o'},
|
||||
{"level" , required_argument, NULL, 'l'},
|
||||
{"size" , required_argument, NULL, 's'},
|
||||
{"symversion" , required_argument, NULL, 'v'},
|
||||
{"margin" , required_argument, NULL, 'm'},
|
||||
{"structured" , no_argument , NULL, 'S'},
|
||||
{"kanji" , no_argument , NULL, 'k'},
|
||||
{"casesensitive", no_argument , NULL, 'c'},
|
||||
{"ignorecase" , no_argument , NULL, 'i'},
|
||||
{"8bit" , no_argument , NULL, '8'},
|
||||
{"version" , no_argument , NULL, 'V'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static char *optstring = "ho:l:s:v:m:Skci8V";
|
||||
|
||||
static void usage(int help, int longopt)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"qrencode version 3.0.3\n"
|
||||
"Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi\n");
|
||||
if(help) {
|
||||
if(longopt) {
|
||||
fprintf(stderr,
|
||||
"Usage: qrencode [OPTION]... [STRING]\n"
|
||||
"Encode input data in a QR Code and save as a PNG image.\n\n"
|
||||
" -h, --help display the help message. -h displays only the help of short\n"
|
||||
" options.\n\n"
|
||||
" -o FILENAME, --output=FILENAME\n"
|
||||
" write PNG image to FILENAME. If '-' is specified, the result\n"
|
||||
" will be output to standard output. If -S is given, structured\n"
|
||||
" symbols are written to FILENAME-01.png, FILENAME-02.png, ...;\n"
|
||||
" if specified, remove a trailing '.png' from FILENAME.\n\n"
|
||||
" -s NUMBER, --size=NUMBER\n"
|
||||
" specify the size of dot (pixel). (default=3)\n\n"
|
||||
" -l {LMQH}, --level={LMQH}\n"
|
||||
" specify error collectin level from L (lowest) to H (highest).\n"
|
||||
" (default=L)\n\n"
|
||||
" -v NUMBER, --symversion=NUMBER\n"
|
||||
" specify the version of the symbol. (default=auto)\n\n"
|
||||
" -m NUMBER, --margin=NUMBER\n"
|
||||
" specify the width of margin. (default=4)\n\n"
|
||||
" -S, --structured\n"
|
||||
" make structured symbols. Version must be specified.\n\n"
|
||||
" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n"
|
||||
" -c, --casesensitive\n"
|
||||
" encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
|
||||
" -i, --ignorecase\n"
|
||||
" ignore case distinctions and use only upper-case characters.\n\n"
|
||||
" -8, -8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
|
||||
" -V, --version\n"
|
||||
" display the version number and copyrights of the qrencode.\n\n"
|
||||
" [STRING] input data. If it is not specified, data will be taken from\n"
|
||||
" standard input.\n"
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Usage: qrencode [OPTION]... [STRING]\n"
|
||||
"Encode input data in a QR Code and save as a PNG image.\n\n"
|
||||
" -h display this message.\n"
|
||||
" --help display the usage of long options.\n"
|
||||
" -o FILENAME write PNG image to FILENAME. If '-' is specified, the result\n"
|
||||
" will be output to standard output. If -S is given, structured\n"
|
||||
" symbols are written to FILENAME-01.png, FILENAME-02.png, ...;\n"
|
||||
" if specified, remove a trailing '.png' from FILENAME.\n"
|
||||
" -s NUMBER specify the size of dot (pixel). (default=3)\n"
|
||||
" -l {LMQH} specify error collectin level from L (lowest) to H (highest).\n"
|
||||
" (default=L)\n"
|
||||
" -v NUMBER specify the version of the symbol. (default=auto)\n"
|
||||
" -m NUMBER specify the width of margin. (default=4)\n"
|
||||
" -S make structured symbols. Version must be specified.\n"
|
||||
" -k assume that the input text contains kanji (shift-jis).\n"
|
||||
" -c encode lower-case alphabet characters in 8-bit mode. (default)\n"
|
||||
" -i ignore case distinctions and use only upper-case characters.\n"
|
||||
" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
|
||||
" -V display the version number and copyrights of the qrencode.\n"
|
||||
" [STRING] input data. If it is not specified, data will be taken from\n"
|
||||
" standard input.\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_DATA_SIZE (7090 * 16) /* from the specification */
|
||||
static char *readStdin(void)
|
||||
{
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = (char *)malloc(MAX_DATA_SIZE);
|
||||
ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
|
||||
if(ret == 0) {
|
||||
fprintf(stderr, "No input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(!feof(stdin)) {
|
||||
fprintf(stderr, "Input data is too large.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
buffer[ret] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int writePNG(QRcode *qrcode, const char *outfile)
|
||||
{
|
||||
FILE *fp;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
unsigned char *row, *p, *q;
|
||||
int x, y, xx, yy, bit;
|
||||
int realwidth;
|
||||
|
||||
realwidth = (qrcode->width + margin * 2) * size;
|
||||
row = (unsigned char *)malloc((realwidth + 7) / 8);
|
||||
if(row == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(outfile[0] == '-' && outfile[1] == '\0') {
|
||||
fp = stdout;
|
||||
} else {
|
||||
fp = fopen(outfile, "wb");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "Failed to create file: %s\n", outfile);
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if(png_ptr == NULL) {
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Failed to initialize PNG writer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if(info_ptr == NULL) {
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Failed to initialize PNG write.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Failed to write PNG image.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_set_IHDR(png_ptr, info_ptr,
|
||||
realwidth, realwidth,
|
||||
1,
|
||||
PNG_COLOR_TYPE_GRAY,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
/* top margin */
|
||||
memset(row, 0xff, (realwidth + 7) / 8);
|
||||
for(y=0; y<margin * size; y++) {
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
|
||||
/* data */
|
||||
p = qrcode->data;
|
||||
for(y=0; y<qrcode->width; y++) {
|
||||
bit = 7;
|
||||
memset(row, 0xff, (realwidth + 7) / 8);
|
||||
q = row;
|
||||
q += margin * size / 8;
|
||||
bit = 7 - (margin * size % 8);
|
||||
for(x=0; x<qrcode->width; x++) {
|
||||
for(xx=0; xx<size; xx++) {
|
||||
*q ^= (*p & 1) << bit;
|
||||
bit--;
|
||||
if(bit < 0) {
|
||||
q++;
|
||||
bit = 7;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
for(yy=0; yy<size; yy++) {
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
}
|
||||
/* bottom margin */
|
||||
memset(row, 0xff, (realwidth + 7) / 8);
|
||||
for(y=0; y<margin * size; y++) {
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(fp);
|
||||
free(row);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QRcode *encode(const char *intext)
|
||||
{
|
||||
QRcode *code;
|
||||
|
||||
if(eightbit) {
|
||||
code = QRcode_encodeString8bit(intext, version, level);
|
||||
} else {
|
||||
code = QRcode_encodeString(intext, version, level, hint, casesensitive);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static void qrencode(const char *intext, const char *outfile)
|
||||
{
|
||||
QRcode *qrcode;
|
||||
|
||||
qrcode = encode(intext);
|
||||
if(qrcode == NULL) {
|
||||
fprintf(stderr, "Failed to encode the input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
writePNG(qrcode, outfile);
|
||||
QRcode_free(qrcode);
|
||||
}
|
||||
|
||||
static QRcode_List *encodeStructured(const char *intext)
|
||||
{
|
||||
QRcode_List *list;
|
||||
|
||||
if(eightbit) {
|
||||
list = QRcode_encodeString8bitStructured(intext, version, level);
|
||||
} else {
|
||||
list = QRcode_encodeStringStructured(intext, version, level, hint, casesensitive);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void qrencodeStructured(const char *intext, const char *outfile)
|
||||
{
|
||||
QRcode_List *qrlist, *p;
|
||||
char filename[FILENAME_MAX];
|
||||
char *base, *q, *suffix = NULL;
|
||||
int i = 1;
|
||||
|
||||
base = strdup(outfile);
|
||||
if(base == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(strlen(base) > 4) {
|
||||
q = base + strlen(base) - 4;
|
||||
if(strcasecmp(".png", q) == 0) {
|
||||
suffix = strdup(q);
|
||||
*q = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
qrlist = encodeStructured(intext);
|
||||
if(qrlist == NULL) {
|
||||
fprintf(stderr, "Failed to encode the input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(p = qrlist; p != NULL; p = p->next) {
|
||||
if(p->code == NULL) {
|
||||
fprintf(stderr, "Failed to encode the input data.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(suffix) {
|
||||
snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix);
|
||||
} else {
|
||||
snprintf(filename, FILENAME_MAX, "%s-%02d", base, i);
|
||||
}
|
||||
writePNG(p->code, filename);
|
||||
i++;
|
||||
}
|
||||
|
||||
free(base);
|
||||
if(suffix) {
|
||||
free(suffix);
|
||||
}
|
||||
|
||||
QRcode_List_free(qrlist);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt, lindex = -1;
|
||||
char *outfile = NULL;
|
||||
char *intext = NULL;
|
||||
|
||||
while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
|
||||
switch(opt) {
|
||||
case 'h':
|
||||
if(lindex == 0) {
|
||||
usage(1, 1);
|
||||
} else {
|
||||
usage(1, 0);
|
||||
}
|
||||
exit(0);
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case 's':
|
||||
size = atoi(optarg);
|
||||
if(size <= 0) {
|
||||
fprintf(stderr, "Invalid size: %d\n", size);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
version = atoi(optarg);
|
||||
if(version < 0) {
|
||||
fprintf(stderr, "Invalid version: %d\n", version);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
switch(*optarg) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
level = QR_ECLEVEL_L;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
level = QR_ECLEVEL_M;
|
||||
break;
|
||||
case 'q':
|
||||
case 'Q':
|
||||
level = QR_ECLEVEL_Q;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
level = QR_ECLEVEL_H;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid level: %s\n", optarg);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
margin = atoi(optarg);
|
||||
if(margin < 0) {
|
||||
fprintf(stderr, "Invalid margin: %d\n", margin);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
structured = 1;
|
||||
case 'k':
|
||||
hint = QR_MODE_KANJI;
|
||||
break;
|
||||
case 'c':
|
||||
casesensitive = 1;
|
||||
break;
|
||||
case 'i':
|
||||
casesensitive = 0;
|
||||
break;
|
||||
case '8':
|
||||
eightbit = 1;
|
||||
break;
|
||||
case 'V':
|
||||
usage(0, 0);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Try `qrencode --help' for more information.\n");
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(argc == 1) {
|
||||
usage(1, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(outfile == NULL) {
|
||||
fprintf(stderr, "No output filename is given.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(optind < argc) {
|
||||
intext = argv[optind];
|
||||
}
|
||||
if(intext == NULL) {
|
||||
intext = readStdin();
|
||||
}
|
||||
|
||||
if(structured) {
|
||||
if(version == 0) {
|
||||
fprintf(stderr, "Version must be specified to encode structured symbols.\n");
|
||||
exit(1);
|
||||
}
|
||||
qrencodeStructured(intext, outfile);
|
||||
} else {
|
||||
qrencode(intext, outfile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,591 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "qrencode.h"
|
||||
#include "qrencode_inner.h"
|
||||
#include "qrspec.h"
|
||||
#include "bitstream.h"
|
||||
#include "qrinput.h"
|
||||
#include "rscode.h"
|
||||
#include "split.h"
|
||||
#include "mask.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Raw code
|
||||
*****************************************************************************/
|
||||
|
||||
static void RSblock_init(RSblock *block, int dl, unsigned char *data, int el)
|
||||
{
|
||||
RS *rs;
|
||||
|
||||
block->dataLength = dl;
|
||||
block->data = data;
|
||||
block->eccLength = el;
|
||||
block->ecc = (unsigned char *)malloc(el);
|
||||
|
||||
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
|
||||
encode_rs_char(rs, data, block->ecc);
|
||||
}
|
||||
|
||||
QRRawCode *QRraw_new(QRinput *input)
|
||||
{
|
||||
QRRawCode *raw;
|
||||
int *spec;
|
||||
int i;
|
||||
RSblock *rsblock;
|
||||
unsigned char *p;
|
||||
|
||||
p = QRinput_getByteStream(input);
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
raw = (QRRawCode *)malloc(sizeof(QRRawCode));
|
||||
raw->datacode = p;
|
||||
spec = QRspec_getEccSpec(input->version, input->level);
|
||||
if(spec == NULL) {
|
||||
free(raw);
|
||||
return NULL;
|
||||
}
|
||||
raw->version = input->version;
|
||||
raw->blocks = QRspec_rsBlockNum(spec);
|
||||
raw->rsblock = (RSblock *)malloc(sizeof(RSblock) * raw->blocks);
|
||||
|
||||
rsblock = raw->rsblock;
|
||||
p = raw->datacode;
|
||||
for(i=0; i<QRspec_rsBlockNum1(spec); i++) {
|
||||
RSblock_init(rsblock, QRspec_rsDataCodes1(spec), p,
|
||||
QRspec_rsEccCodes1(spec));
|
||||
p += QRspec_rsDataCodes1(spec);
|
||||
rsblock++;
|
||||
}
|
||||
for(i=0; i<QRspec_rsBlockNum2(spec); i++) {
|
||||
RSblock_init(rsblock, QRspec_rsDataCodes2(spec), p,
|
||||
QRspec_rsEccCodes2(spec));
|
||||
p += QRspec_rsDataCodes2(spec);
|
||||
rsblock++;
|
||||
}
|
||||
|
||||
raw->b1 = QRspec_rsBlockNum1(spec);
|
||||
raw->dataLength = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec)
|
||||
+ QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec);
|
||||
raw->eccLength = QRspec_rsBlockNum(spec) * QRspec_rsEccCodes1(spec);
|
||||
raw->count = 0;
|
||||
|
||||
free(spec);
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a code (byte).
|
||||
* This function can be called iteratively.
|
||||
* @param raw raw code.
|
||||
* @return code
|
||||
*/
|
||||
unsigned char QRraw_getCode(QRRawCode *raw)
|
||||
{
|
||||
int col, row;
|
||||
unsigned char ret;
|
||||
|
||||
if(raw->count < raw->dataLength) {
|
||||
row = raw->count % raw->blocks;
|
||||
col = raw->count / raw->blocks;
|
||||
if(col >= raw->rsblock[row].dataLength) {
|
||||
row += raw->b1;
|
||||
}
|
||||
ret = raw->rsblock[row].data[col];
|
||||
} else if(raw->count < raw->dataLength + raw->eccLength) {
|
||||
row = (raw->count - raw->dataLength) % raw->blocks;
|
||||
col = (raw->count - raw->dataLength) / raw->blocks;
|
||||
ret = raw->rsblock[row].ecc[col];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
raw->count++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void QRraw_free(QRRawCode *raw)
|
||||
{
|
||||
int i;
|
||||
|
||||
free(raw->datacode);
|
||||
for(i=0; i<raw->blocks; i++) {
|
||||
free(raw->rsblock[i].ecc);
|
||||
}
|
||||
free(raw->rsblock);
|
||||
free(raw);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Frame filling
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
unsigned char *frame;
|
||||
int x, y;
|
||||
int dir;
|
||||
int bit;
|
||||
} FrameFiller;
|
||||
|
||||
static FrameFiller *FrameFiller_new(int width, unsigned char *frame)
|
||||
{
|
||||
FrameFiller *filler;
|
||||
|
||||
filler = (FrameFiller *)malloc(sizeof(FrameFiller));
|
||||
filler->width = width;
|
||||
filler->frame = frame;
|
||||
filler->x = width - 1;
|
||||
filler->y = width - 1;
|
||||
filler->dir = -1;
|
||||
filler->bit = -1;
|
||||
|
||||
return filler;
|
||||
}
|
||||
|
||||
static unsigned char *FrameFiller_next(FrameFiller *filler)
|
||||
{
|
||||
unsigned char *p;
|
||||
int x, y, w;
|
||||
|
||||
if(filler->bit == -1) {
|
||||
filler->bit = 0;
|
||||
return filler->frame + filler->y * filler->width + filler->x;
|
||||
}
|
||||
|
||||
x = filler->x;
|
||||
y = filler->y;
|
||||
p = filler->frame;
|
||||
w = filler->width;
|
||||
|
||||
if(filler->bit == 0) {
|
||||
x--;
|
||||
filler->bit++;
|
||||
} else {
|
||||
x++;
|
||||
y += filler->dir;
|
||||
filler->bit--;
|
||||
}
|
||||
|
||||
if(filler->dir < 0) {
|
||||
if(y < 0) {
|
||||
y = 0;
|
||||
x -= 2;
|
||||
filler->dir = 1;
|
||||
if(x == 6) {
|
||||
x--;
|
||||
y = 9;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(y == w) {
|
||||
y = w - 1;
|
||||
x -= 2;
|
||||
filler->dir = -1;
|
||||
if(x == 6) {
|
||||
x--;
|
||||
y -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(x < 0 || y < 0) return NULL;
|
||||
|
||||
filler->x = x;
|
||||
filler->y = y;
|
||||
|
||||
if(p[y * w + x] & 0x80) {
|
||||
// This tail recursion could be optimized.
|
||||
return FrameFiller_next(filler);
|
||||
}
|
||||
return &p[y * w + x];
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned char *FrameFiller_fillerTest(int version)
|
||||
{
|
||||
int width, length;
|
||||
unsigned char *frame, *p;
|
||||
FrameFiller *filler;
|
||||
int i, j;
|
||||
unsigned char cl = 1;
|
||||
unsigned char ch = 0;
|
||||
|
||||
width = QRspec_getWidth(version);
|
||||
frame = QRspec_newFrame(version);
|
||||
filler = FrameFiller_new(width, frame);
|
||||
length = QRspec_getDataLength(version, QR_ECLEVEL_L)
|
||||
+ QRspec_getECCLength(version, QR_ECLEVEL_L);
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
for(j=0; j<8; j++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = ch | cl;
|
||||
cl++;
|
||||
if(cl == 9) {
|
||||
cl = 1;
|
||||
ch += 0x10;
|
||||
}
|
||||
}
|
||||
}
|
||||
length = QRspec_getRemainder(version);
|
||||
for(i=0; i<length; i++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = 0xa0;
|
||||
}
|
||||
p = FrameFiller_next(filler);
|
||||
free(filler);
|
||||
if(p != NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
|
||||
int QRcode_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level)
|
||||
{
|
||||
unsigned int format;
|
||||
unsigned char v;
|
||||
int i;
|
||||
int blacks = 0;
|
||||
|
||||
format = QRspec_getFormatInfo(mask, level);
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
if(format & 1) {
|
||||
blacks += 2;
|
||||
v = 0x85;
|
||||
} else {
|
||||
v = 0x84;
|
||||
}
|
||||
frame[width * 8 + width - 1 - i] = v;
|
||||
if(i < 6) {
|
||||
frame[width * i + 8] = v;
|
||||
} else {
|
||||
frame[width * (i + 1) + 8] = v;
|
||||
}
|
||||
format= format >> 1;
|
||||
}
|
||||
for(i=0; i<7; i++) {
|
||||
if(format & 1) {
|
||||
blacks += 2;
|
||||
v = 0x85;
|
||||
} else {
|
||||
v = 0x84;
|
||||
}
|
||||
frame[width * (width - 7 + i) + 8] = v;
|
||||
if(i == 0) {
|
||||
frame[width * 8 + 7] = v;
|
||||
} else {
|
||||
frame[width * 8 + 6 - i] = v;
|
||||
}
|
||||
format= format >> 1;
|
||||
}
|
||||
|
||||
return blacks;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* QR-code encoding
|
||||
*****************************************************************************/
|
||||
|
||||
static QRcode *QRcode_new(int version, int width, unsigned char *data)
|
||||
{
|
||||
QRcode *qrcode;
|
||||
|
||||
qrcode = (QRcode *)malloc(sizeof(QRcode));
|
||||
qrcode->version = version;
|
||||
qrcode->width = width;
|
||||
qrcode->data = data;
|
||||
|
||||
return qrcode;
|
||||
}
|
||||
|
||||
void QRcode_free(QRcode *qrcode)
|
||||
{
|
||||
if(qrcode == NULL) return;
|
||||
|
||||
if(qrcode->data != NULL) {
|
||||
free(qrcode->data);
|
||||
}
|
||||
free(qrcode);
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeMask(QRinput *input, int mask)
|
||||
{
|
||||
int width, version;
|
||||
QRRawCode *raw;
|
||||
unsigned char *frame, *masked, *p, code, bit;
|
||||
FrameFiller *filler;
|
||||
int i, j;
|
||||
QRcode *qrcode;
|
||||
|
||||
if(input->version < 0 || input->version > QRSPEC_VERSION_MAX) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if(input->level < QR_ECLEVEL_L || input->level > QR_ECLEVEL_H) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
raw = QRraw_new(input);
|
||||
if(raw == NULL) return NULL;
|
||||
|
||||
version = raw->version;
|
||||
width = QRspec_getWidth(version);
|
||||
frame = QRspec_newFrame(version);
|
||||
filler = FrameFiller_new(width, frame);
|
||||
|
||||
/* inteleaved data and ecc codes */
|
||||
for(i=0; i<raw->dataLength + raw->eccLength; i++) {
|
||||
code = QRraw_getCode(raw);
|
||||
bit = 0x80;
|
||||
for(j=0; j<8; j++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = 0x02 | ((bit & code) != 0);
|
||||
bit = bit >> 1;
|
||||
}
|
||||
}
|
||||
QRraw_free(raw);
|
||||
/* remainder bits */
|
||||
j = QRspec_getRemainder(version);
|
||||
for(i=0; i<j; i++) {
|
||||
p = FrameFiller_next(filler);
|
||||
*p = 0x02;
|
||||
}
|
||||
free(filler);
|
||||
/* masking */
|
||||
if(mask < 0) {
|
||||
masked = Mask_mask(width, frame, input->level);
|
||||
} else {
|
||||
masked = Mask_makeMask(width, frame, mask);
|
||||
QRcode_writeFormatInformation(width, masked, mask, input->level);
|
||||
}
|
||||
qrcode = QRcode_new(version, width, masked);
|
||||
|
||||
free(frame);
|
||||
|
||||
return qrcode;
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeInput(QRinput *input)
|
||||
{
|
||||
return QRcode_encodeMask(input, -1);
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode *code;
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
QRinput_append(input, QR_MODE_8, strlen(string), (unsigned char *)string);
|
||||
code = QRcode_encodeInput(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode *code;
|
||||
int ret;
|
||||
|
||||
if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
ret = Split_splitStringToQRinput(string, input, hint, casesensitive);
|
||||
if(ret < 0) {
|
||||
QRinput_free(input);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
code = QRcode_encodeInput(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Structured QR-code encoding
|
||||
*****************************************************************************/
|
||||
|
||||
static QRcode_List *QRcode_List_newEntry(void)
|
||||
{
|
||||
QRcode_List *entry;
|
||||
|
||||
entry = (QRcode_List *)malloc(sizeof(QRcode_List));
|
||||
if(entry == NULL) return NULL;
|
||||
|
||||
entry->next = NULL;
|
||||
entry->code = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void QRcode_List_freeEntry(QRcode_List *entry)
|
||||
{
|
||||
if(entry->code != NULL) QRcode_free(entry->code);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
void QRcode_List_free(QRcode_List *qrlist)
|
||||
{
|
||||
QRcode_List *list = qrlist, *next;
|
||||
|
||||
while(list != NULL) {
|
||||
next = list->next;
|
||||
QRcode_List_freeEntry(list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
int QRcode_List_size(QRcode_List *qrlist)
|
||||
{
|
||||
QRcode_List *list = qrlist;
|
||||
int size = 0;
|
||||
|
||||
while(list != NULL) {
|
||||
size++;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned char QRcode_parity(const char *str, int size)
|
||||
{
|
||||
unsigned char parity = 0;
|
||||
int i;
|
||||
|
||||
for(i=0; i<size; i++) {
|
||||
parity ^= str[i];
|
||||
}
|
||||
|
||||
return parity;
|
||||
}
|
||||
#endif
|
||||
|
||||
QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s)
|
||||
{
|
||||
QRcode_List *head = NULL;
|
||||
QRcode_List *tail = NULL;
|
||||
QRinput_InputList *list = s->head;
|
||||
|
||||
while(list != NULL) {
|
||||
if(head == NULL) {
|
||||
head = QRcode_List_newEntry();
|
||||
tail = head;
|
||||
} else {
|
||||
tail->next = QRcode_List_newEntry();
|
||||
tail = tail->next;
|
||||
}
|
||||
tail->code = QRcode_encodeInput(list->input);
|
||||
if(tail->code == NULL) {
|
||||
QRcode_List_free(head);
|
||||
return NULL;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static QRcode_List *QRcode_encodeInputToStructured(QRinput *input)
|
||||
{
|
||||
QRinput_Struct *s;
|
||||
QRcode_List *codes;
|
||||
|
||||
s = QRinput_splitQRinputToStruct(input);
|
||||
if(s == NULL) return NULL;
|
||||
|
||||
codes = QRcode_encodeInputStructured(s);
|
||||
QRinput_Struct_free(s);
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode_List *codes;
|
||||
int ret;
|
||||
|
||||
if(version <= 0) return NULL;
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
ret = QRinput_append(input, QR_MODE_8, strlen(string), (unsigned char *)string);
|
||||
if(ret < 0) {
|
||||
QRinput_free(input);
|
||||
return NULL;
|
||||
}
|
||||
codes = QRcode_encodeInputToStructured(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive)
|
||||
{
|
||||
QRinput *input;
|
||||
QRcode_List *codes;
|
||||
int ret;
|
||||
|
||||
if(version <= 0) return NULL;
|
||||
if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input = QRinput_new2(version, level);
|
||||
if(input == NULL) return NULL;
|
||||
|
||||
ret = Split_splitStringToQRinput(string, input, hint, casesensitive);
|
||||
if(ret < 0) {
|
||||
QRinput_free(input);
|
||||
return NULL;
|
||||
}
|
||||
codes = QRcode_encodeInputToStructured(input);
|
||||
QRinput_free(input);
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
|
@ -1,423 +0,0 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/** \mainpage
|
||||
* Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D
|
||||
* symbology.
|
||||
*
|
||||
* \section encoding Encoding
|
||||
*
|
||||
* There are two ways to encode data: <b>encoding a string</b> or
|
||||
* <b>encoding a structured data</b>.
|
||||
*
|
||||
* \subsection encoding-string Encoding a string
|
||||
* You can encode a string by calling QRcode_encodeString().
|
||||
* The given string is parsed automatically and encoded. If you want to encode
|
||||
* data that can be represented as a C string style (NUL terminated), you can
|
||||
* simply use this way.
|
||||
*
|
||||
* If the input data contains Kanji (Shift-JIS) characters and you want to
|
||||
* encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint.
|
||||
* Otherwise, all of non-alphanumeric characters are encoded as 8 bit data.
|
||||
* If you want to encode a whole string in 8 bit mode, use
|
||||
* QRcode_encodeString8bit() instead.
|
||||
*
|
||||
* Please note that a C string can not contain NUL character. If your data
|
||||
* contains NUL, you should chose the second way.
|
||||
*
|
||||
* \subsection encoding-input Encoding a structured data
|
||||
* You can construct a structured input data manually. If the structure of the
|
||||
* input data is known, you can use this way.
|
||||
* At first, you must create a ::QRinput object by QRinput_new(). Then, you can
|
||||
* add input data to the QRinput object by QRinput_append().
|
||||
* Finally you can call QRcode_encodeInput() to encode the QRinput data.
|
||||
* You can reuse the QRinput data again to encode it in other symbols with
|
||||
* different parameters.
|
||||
*
|
||||
* \section result Result
|
||||
* The encoded symbol is resulted as a ::QRcode object. It will contain
|
||||
* its version number, width of the symbol and an array represents the symbol.
|
||||
* See ::QRcode for the details. You can free the object by QRcode_free().
|
||||
*
|
||||
* Please note that the version of the result may be larger than specified.
|
||||
* In such cases, the input data would be too large to be encoded in the
|
||||
* symbol of the specified version.
|
||||
*
|
||||
* \section structured Structured append
|
||||
* Libqrencode can generate "Structured-appended" symbols that enables to split
|
||||
* a large data set into mulitple QR codes. A QR code reader concatenates
|
||||
* multiple QR code symbols into a string.
|
||||
* Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured()
|
||||
* to generate structured-appended symbols. This functions returns an instance
|
||||
* of ::QRcode_List. The returned list is a singly-linked list of QRcode: you
|
||||
* can retrieve each QR code in this way:
|
||||
*
|
||||
* \code
|
||||
* QRcode_List *qrcodes;
|
||||
* QRcode_List *entry;
|
||||
* QRcode *qrcode;
|
||||
*
|
||||
* qrcodes = QRcode_encodeStringStructured(...);
|
||||
* entry = qrcodes;
|
||||
* while(entry != NULL) {
|
||||
* qrcode = entry->code;
|
||||
* // do something
|
||||
* entry = entry->next;
|
||||
* }
|
||||
* QRcode_List_free(entry);
|
||||
* \endcode
|
||||
*
|
||||
* Instead of using auto-parsing functions, you can construct your own
|
||||
* structured input. At first, instantiate an object of ::QRinput_Struct
|
||||
* by calling QRinput_Struct_new(). This object can hold multiple ::QRinput,
|
||||
* and one QR code is generated for a ::QRinput.
|
||||
* QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct
|
||||
* object. In order to generate structured-appended symbols, it is required to
|
||||
* embed headers to each symbol. You can use
|
||||
* QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate
|
||||
* headers to each symbol. You should call this function just once before
|
||||
* encoding symbols.
|
||||
*/
|
||||
|
||||
#ifndef __QRENCODE_H__
|
||||
#define __QRENCODE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Encoding mode.
|
||||
*/
|
||||
typedef enum {
|
||||
QR_MODE_NUL = -1, ///< Terminator (NUL character)
|
||||
QR_MODE_NUM = 0, ///< Numeric mode
|
||||
QR_MODE_AN, ///< Alphabet-numeric mode
|
||||
QR_MODE_8, ///< 8-bit data mode
|
||||
QR_MODE_KANJI, ///< Kanji (shift-jis) mode
|
||||
QR_MODE_STRUCTURE, ///< Internal use only
|
||||
} QRencodeMode;
|
||||
|
||||
/**
|
||||
* Level of error correction.
|
||||
*/
|
||||
typedef enum {
|
||||
QR_ECLEVEL_L = 0, ///< lowest
|
||||
QR_ECLEVEL_M,
|
||||
QR_ECLEVEL_Q,
|
||||
QR_ECLEVEL_H ///< highest
|
||||
} QRecLevel;
|
||||
|
||||
/******************************************************************************
|
||||
* Input data (qrinput.c)
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Singly linked list to contain input strings. An instance of this class
|
||||
* contains its version and error correction level too. It is required to
|
||||
* set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(),
|
||||
* or use QRinput_new2() to instantiate an object.
|
||||
*/
|
||||
typedef struct _QRinput QRinput;
|
||||
|
||||
/**
|
||||
* Instantiate an input data object. The version is set to 0 (auto-select)
|
||||
* and the error correction level is set to QR_ECLEVEL_L.
|
||||
* @return an input object (initialized). On error, NULL is returned and errno
|
||||
* is set to indicate the error.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern QRinput *QRinput_new(void);
|
||||
|
||||
/**
|
||||
* Instantiate an input data object.
|
||||
* @param version version number.
|
||||
* @param level Error correction level.
|
||||
* @return an input object (initialized). On error, NULL is returned and errno
|
||||
* is set to indicate the error.
|
||||
* @throw ENOMEM unable to allocate memory for input objects.
|
||||
* @throw EINVAL invalid arguments.
|
||||
*/
|
||||
extern QRinput *QRinput_new2(int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Append data to an input object.
|
||||
* The data is copied and appended to the input object.
|
||||
* @param input input object.
|
||||
* @param mode encoding mode.
|
||||
* @param size size of data (byte).
|
||||
* @param data a pointer to the memory area of the input data.
|
||||
* @retval 0 success.
|
||||
* @retval -1 an error occurred and errno is set to indeicate the error.
|
||||
* See Execptions for the details.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
* @throw EINVAL input data is invalid.
|
||||
*
|
||||
*/
|
||||
extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data);
|
||||
|
||||
/**
|
||||
* Get current version.
|
||||
* @param input input object.
|
||||
* @return current version.
|
||||
*/
|
||||
extern int QRinput_getVersion(QRinput *input);
|
||||
|
||||
/**
|
||||
* Set version of the QR-code that is to be encoded.
|
||||
* @param input input object.
|
||||
* @param version version number (0 = auto)
|
||||
* @retval 0 success.
|
||||
* @retval -1 invalid argument.
|
||||
*/
|
||||
extern int QRinput_setVersion(QRinput *input, int version);
|
||||
|
||||
/**
|
||||
* Get current error correction level.
|
||||
* @param input input object.
|
||||
* @return Current error correcntion level.
|
||||
*/
|
||||
extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input);
|
||||
|
||||
/**
|
||||
* Set error correction level of the QR-code that is to be encoded.
|
||||
* @param input input object.
|
||||
* @param level Error correction level.
|
||||
* @retval 0 success.
|
||||
* @retval -1 invalid argument.
|
||||
*/
|
||||
extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Free the input object.
|
||||
* All of data chunks in the input object are freed too.
|
||||
* @param input input object.
|
||||
*/
|
||||
extern void QRinput_free(QRinput *input);
|
||||
|
||||
/**
|
||||
* Validate the input data.
|
||||
* @param mode encoding mode.
|
||||
* @param size size of data (byte).
|
||||
* @param data a pointer to the memory area of the input data.
|
||||
* @retval 0 success.
|
||||
* @retval -1 invalid arguments.
|
||||
*/
|
||||
extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data);
|
||||
|
||||
/**
|
||||
* Set of QRinput for structured symbols.
|
||||
*/
|
||||
typedef struct _QRinput_Struct QRinput_Struct;
|
||||
|
||||
/**
|
||||
* Instantiate a set of input data object.
|
||||
* @return an instance of QRinput_Struct. On error, NULL is returned and errno
|
||||
* is set to indicate the error.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern QRinput_Struct *QRinput_Struct_new(void);
|
||||
|
||||
/**
|
||||
* Set parity of structured symbols.
|
||||
* @param s structured input object.
|
||||
* @param parity parity of s.
|
||||
*/
|
||||
extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity);
|
||||
|
||||
/**
|
||||
* Append a QRinput object to the set.
|
||||
* @warning never append the same QRinput object twice.
|
||||
* @param s structured input object.
|
||||
* @param input an input object.
|
||||
* @retval >0 number of input objects in the structure.
|
||||
* @retval -1 an error occurred. See Exceptions for the details.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input);
|
||||
|
||||
/**
|
||||
* Free all of QRinput in the set.
|
||||
* @param s a structured input object.
|
||||
*/
|
||||
extern void QRinput_Struct_free(QRinput_Struct *s);
|
||||
|
||||
/**
|
||||
* Split a QRinput to QRinput_Struct. It calculates a parity, set it, then
|
||||
* insert structured-append headers.
|
||||
* @param input input object. Version number and error correction level must be
|
||||
* set.
|
||||
* @return a set of input data. On error, NULL is returned, and errno is set
|
||||
* to indicate the error. See Exceptions for the details.
|
||||
* @throw ERANGE input data is too large.
|
||||
* @throw EINVAL invalid input data.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input);
|
||||
|
||||
/**
|
||||
* Insert structured-append headers to the input structure. It calculates
|
||||
* a parity and set it if the parity is not set yet.
|
||||
* @param s input structure
|
||||
* @retval 0 success.
|
||||
* @retval -1 an error occurred and errno is set to indeicate the error.
|
||||
* See Execptions for the details.
|
||||
* @throw EINVAL invalid input object.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s);
|
||||
|
||||
/******************************************************************************
|
||||
* QRcode output (qrencode.c)
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* QRcode class.
|
||||
* Symbol data is represented as an array contains width*width uchars.
|
||||
* Each uchar represents a module (dot). If the less significant bit of
|
||||
* the uchar is 1, the corresponding module is black. The other bits are
|
||||
* meaningless for usual applications, but here its specification is described.
|
||||
*
|
||||
* <pre>
|
||||
* MSB 76543210 LSB
|
||||
* |||||||`- 1=black/0=white
|
||||
* ||||||`-- data and ecc code area
|
||||
* |||||`--- format information
|
||||
* ||||`---- version information
|
||||
* |||`----- timing pattern
|
||||
* ||`------ alignment pattern
|
||||
* |`------- finder pattern and separator
|
||||
* `-------- non-data modules (format, timing, etc.)
|
||||
* </pre>
|
||||
*/
|
||||
typedef struct {
|
||||
int version; ///< version of the symbol
|
||||
int width; ///< width of the symbol
|
||||
unsigned char *data; ///< symbol data
|
||||
} QRcode;
|
||||
|
||||
/**
|
||||
* Singly-linked list of QRcode. Used to represent a structured symbols.
|
||||
* A list is terminated with NULL.
|
||||
*/
|
||||
typedef struct _QRcode_List QRcode_List;
|
||||
|
||||
struct _QRcode_List {
|
||||
QRcode *code;
|
||||
QRcode_List *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a symbol from the input data.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param input input data.
|
||||
* @return an instance of QRcode class. The version of the result QRcode may
|
||||
* be larger than the designated version. On error, NULL is returned,
|
||||
* and errno is set to indicate the error. See Exceptions for the
|
||||
* details.
|
||||
* @throw EINVAL invalid input object.
|
||||
* @throw ENOMEM unable to allocate memory for input objects.
|
||||
*/
|
||||
extern QRcode *QRcode_encodeInput(QRinput *input);
|
||||
|
||||
/**
|
||||
* Create a symbol from the string. The library automatically parses the input
|
||||
* string and encodes in a QR Code symbol.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param string input string. It must be NULL terminated.
|
||||
* @param version version of the symbol. If 0, the library chooses the minimum
|
||||
* version for the given input data.
|
||||
* @param level error correction level.
|
||||
* @param hint tell the library how non-alphanumerical characters should be
|
||||
* encoded. If QR_MODE_KANJI is given, kanji characters will be
|
||||
* encoded as Shif-JIS characters. If QR_MODE_8 is given, all of
|
||||
* non-alphanumerical characters will be encoded as is. If you want
|
||||
* to embed UTF-8 string, choose this.
|
||||
* @param casesensitive case-sensitive(1) or not(0).
|
||||
* @return an instance of QRcode class. The version of the result QRcode may
|
||||
* be larger than the designated version. On error, NULL is returned,
|
||||
* and errno is set to indicate the error. See Exceptions for the
|
||||
* details.
|
||||
* @throw EINVAL invalid input object.
|
||||
* @throw ENOMEM unable to allocate memory for input objects.
|
||||
*/
|
||||
extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
|
||||
/**
|
||||
* Same to ::QRcode_qncodeString, but encode whole data in 8-bit mode.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
*/
|
||||
extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Free the instance of QRcode class.
|
||||
* @param qrcode an instance of QRcode class.
|
||||
*/
|
||||
extern void QRcode_free(QRcode *qrcode);
|
||||
|
||||
/**
|
||||
* Create structured symbols from the input data.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param s
|
||||
* @return a singly-linked list of QRcode.
|
||||
*/
|
||||
extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s);
|
||||
|
||||
/**
|
||||
* Create structured symbols from the string. The library automatically parses
|
||||
* the input string and encodes in a QR Code symbol.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
* @param string input string. It should be NULL terminated.
|
||||
* @param version version of the symbol.
|
||||
* @param level error correction level.
|
||||
* @param hint tell the library how non-alphanumerical characters should be
|
||||
* encoded. If QR_MODE_KANJI is given, kanji characters will be
|
||||
* encoded as Shif-JIS characters. If QR_MODE_8 is given, all of
|
||||
* non-alphanumerical characters will be encoded as is. If you want
|
||||
* to embed UTF-8 string, choose this.
|
||||
* @param casesensitive case-sensitive(1) or not(0).
|
||||
* @return a singly-linked list of QRcode.
|
||||
*/
|
||||
extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
|
||||
/**
|
||||
* Same to QRcode_qncodeStringStructured, but encode whole data in 8-bit mode.
|
||||
* @warning This function is THREAD UNSAFE.
|
||||
*/
|
||||
extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return the number of symbols included in a QRcode_List.
|
||||
* @param qrlist a head entry of a QRcode_List.
|
||||
* @return number of symbols in the list.
|
||||
*/
|
||||
extern int QRcode_List_size(QRcode_List *qrlist);
|
||||
|
||||
/**
|
||||
* Free the QRcode_List.
|
||||
* @param qrlist a head entry of a QRcode_List.
|
||||
*/
|
||||
extern void QRcode_List_free(QRcode_List *qrlist);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __QRENCODE_H__ */
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Header for internal use
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __QRENCODE_INNER_H__
|
||||
#define __QRENCODE_INNER_H__
|
||||
|
||||
/**
|
||||
* This header file includes definitions for inner use.
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* Raw code
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int dataLength;
|
||||
unsigned char *data;
|
||||
int eccLength;
|
||||
unsigned char *ecc;
|
||||
} RSblock;
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
unsigned char *datacode;
|
||||
int blocks;
|
||||
RSblock *rsblock;
|
||||
int count;
|
||||
int dataLength;
|
||||
int eccLength;
|
||||
int b1;
|
||||
} QRRawCode;
|
||||
|
||||
extern QRRawCode *QRraw_new(QRinput *input);
|
||||
extern unsigned char QRraw_getCode(QRRawCode *raw);
|
||||
extern void QRraw_free(QRRawCode *raw);
|
||||
|
||||
/******************************************************************************
|
||||
* Frame filling
|
||||
*****************************************************************************/
|
||||
extern unsigned char *FrameFiller_fillerTest(int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
extern int QRcode_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level);
|
||||
|
||||
extern QRcode *QRcode_encodeMask(QRinput *input, int mask);
|
||||
#endif /* __QRENCODE_INNER_H__ */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Input data chunk class
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __QRINPUT_H__
|
||||
#define __QRINPUT_H__
|
||||
|
||||
#include "qrencode.h"
|
||||
#include "bitstream.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Entry of input data
|
||||
*****************************************************************************/
|
||||
typedef struct _QRinput_List QRinput_List;
|
||||
|
||||
struct _QRinput_List {
|
||||
QRencodeMode mode;
|
||||
int size; ///< Size of data chunk (byte).
|
||||
unsigned char *data; ///< Data chunk.
|
||||
BitStream *bstream;
|
||||
QRinput_List *next;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Input Data
|
||||
*****************************************************************************/
|
||||
struct _QRinput {
|
||||
int version;
|
||||
QRecLevel level;
|
||||
QRinput_List *head;
|
||||
QRinput_List *tail;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Structured append input data
|
||||
*****************************************************************************/
|
||||
typedef struct _QRinput_InputList QRinput_InputList;
|
||||
|
||||
struct _QRinput_InputList {
|
||||
QRinput *input;
|
||||
QRinput_InputList *next;
|
||||
};
|
||||
|
||||
struct _QRinput_Struct {
|
||||
int size; ///< number of structured symbols
|
||||
int parity;
|
||||
QRinput_InputList *head;
|
||||
QRinput_InputList *tail;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert a structured-append header to the head of the input data.
|
||||
* @param input input data.
|
||||
* @param size number of structured symbols.
|
||||
* @param index index number of the symbol. (1 <= index <= size)
|
||||
* @param parity parity among input data. (NOTE: each symbol of a set of structured symbols has the same parity data)
|
||||
* @retval 0 success.
|
||||
* @retval -1 error occurred and errno is set to indeicate the error. See Execptions for the details.
|
||||
* @throw EINVAL invalid parameter.
|
||||
* @throw ENOMEM unable to allocate memory.
|
||||
*/
|
||||
extern int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, unsigned char parity);
|
||||
|
||||
/**
|
||||
* Pack all bit streams padding bits into a byte array.
|
||||
* @param input input data.
|
||||
* @return padded merged byte stream
|
||||
*/
|
||||
extern unsigned char *QRinput_getByteStream(QRinput *input);
|
||||
|
||||
|
||||
extern int QRinput_estimateBitsModeNum(int size);
|
||||
extern int QRinput_estimateBitsModeAn(int size);
|
||||
extern int QRinput_estimateBitsMode8(int size);
|
||||
extern int QRinput_estimateBitsModeKanji(int size);
|
||||
|
||||
extern int QRinput_estimateBitStreamSize(QRinput *input, int version);
|
||||
extern BitStream *QRinput_mergeBitStream(QRinput *input);
|
||||
extern BitStream *QRinput_getBitStream(QRinput *input);
|
||||
extern int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits);
|
||||
extern QRinput *QRinput_dup(QRinput *input);
|
||||
extern int QRinput_splitEntry(QRinput_List *entry, int bytes);
|
||||
|
||||
extern const signed char QRinput_anTable[];
|
||||
|
||||
/**
|
||||
* Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
|
||||
* @param __c__ character
|
||||
* @return value
|
||||
*/
|
||||
#define QRinput_lookAnTable(__c__) \
|
||||
((__c__ & 0x80)?-1:QRinput_anTable[(int)__c__])
|
||||
|
||||
/**
|
||||
* Length of a segment of structured-append header.
|
||||
*/
|
||||
#define STRUCTURE_HEADER_BITS 20
|
||||
|
||||
/**
|
||||
* Maximum number of symbols in a set of structured-appended symbols.
|
||||
*/
|
||||
#define MAX_STRUCTURED_SYMBOLS 16
|
||||
|
||||
#endif /* __QRINPUT_H__ */
|
||||
|
|
@ -1,587 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* QR Code specification in convenient format.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "qrspec.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Version and capacity
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int width; //< Edge length of the symbol
|
||||
int words; //< Data capacity (bytes)
|
||||
int remainder; //< Remainder bit (bits)
|
||||
int ec[4]; //< Number of ECC code (bytes)
|
||||
} QRspec_Capacity;
|
||||
|
||||
/**
|
||||
* Table of the capacity of symbols
|
||||
* See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
|
||||
*/
|
||||
static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = {
|
||||
{ 0, 0, 0, { 0, 0, 0, 0}},
|
||||
{ 21, 26, 0, { 7, 10, 13, 17}}, // 1
|
||||
{ 25, 44, 7, { 10, 16, 22, 28}},
|
||||
{ 29, 70, 7, { 15, 26, 36, 44}},
|
||||
{ 33, 100, 7, { 20, 36, 52, 64}},
|
||||
{ 37, 134, 7, { 26, 48, 72, 88}}, // 5
|
||||
{ 41, 172, 7, { 36, 64, 96, 112}},
|
||||
{ 45, 196, 0, { 40, 72, 108, 130}},
|
||||
{ 49, 242, 0, { 48, 88, 132, 156}},
|
||||
{ 53, 292, 0, { 60, 110, 160, 192}},
|
||||
{ 57, 346, 0, { 72, 130, 192, 224}}, //10
|
||||
{ 61, 404, 0, { 80, 150, 224, 264}},
|
||||
{ 65, 466, 0, { 96, 176, 260, 308}},
|
||||
{ 69, 532, 0, { 104, 198, 288, 352}},
|
||||
{ 73, 581, 3, { 120, 216, 320, 384}},
|
||||
{ 77, 655, 3, { 132, 240, 360, 432}}, //15
|
||||
{ 81, 733, 3, { 144, 280, 408, 480}},
|
||||
{ 85, 815, 3, { 168, 308, 448, 532}},
|
||||
{ 89, 901, 3, { 180, 338, 504, 588}},
|
||||
{ 93, 991, 3, { 196, 364, 546, 650}},
|
||||
{ 97, 1085, 3, { 224, 416, 600, 700}}, //20
|
||||
{101, 1156, 4, { 224, 442, 644, 750}},
|
||||
{105, 1258, 4, { 252, 476, 690, 816}},
|
||||
{109, 1364, 4, { 270, 504, 750, 900}},
|
||||
{113, 1474, 4, { 300, 560, 810, 960}},
|
||||
{117, 1588, 4, { 312, 588, 870, 1050}}, //25
|
||||
{121, 1706, 4, { 336, 644, 952, 1110}},
|
||||
{125, 1828, 4, { 360, 700, 1020, 1200}},
|
||||
{129, 1921, 3, { 390, 728, 1050, 1260}},
|
||||
{133, 2051, 3, { 420, 784, 1140, 1350}},
|
||||
{137, 2185, 3, { 450, 812, 1200, 1440}}, //30
|
||||
{141, 2323, 3, { 480, 868, 1290, 1530}},
|
||||
{145, 2465, 3, { 510, 924, 1350, 1620}},
|
||||
{149, 2611, 3, { 540, 980, 1440, 1710}},
|
||||
{153, 2761, 3, { 570, 1036, 1530, 1800}},
|
||||
{157, 2876, 0, { 570, 1064, 1590, 1890}}, //35
|
||||
{161, 3034, 0, { 600, 1120, 1680, 1980}},
|
||||
{165, 3196, 0, { 630, 1204, 1770, 2100}},
|
||||
{169, 3362, 0, { 660, 1260, 1860, 2220}},
|
||||
{173, 3532, 0, { 720, 1316, 1950, 2310}},
|
||||
{177, 3706, 0, { 750, 1372, 2040, 2430}} //40
|
||||
};
|
||||
|
||||
int QRspec_getDataLength(int version, QRecLevel level)
|
||||
{
|
||||
return qrspecCapacity[version].words - qrspecCapacity[version].ec[level];
|
||||
}
|
||||
|
||||
int QRspec_getECCLength(int version, QRecLevel level)
|
||||
{
|
||||
return qrspecCapacity[version].ec[level];
|
||||
}
|
||||
|
||||
int QRspec_getMinimumVersion(int size, QRecLevel level)
|
||||
{
|
||||
int i;
|
||||
int words;
|
||||
|
||||
for(i=1; i<= QRSPEC_VERSION_MAX; i++) {
|
||||
words = qrspecCapacity[i].words - qrspecCapacity[i].ec[level];
|
||||
if(words >= size) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int QRspec_getWidth(int version)
|
||||
{
|
||||
return qrspecCapacity[version].width;
|
||||
}
|
||||
|
||||
int QRspec_getRemainder(int version)
|
||||
{
|
||||
return qrspecCapacity[version].remainder;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Length indicator
|
||||
*****************************************************************************/
|
||||
|
||||
static const int lengthTableBits[4][3] = {
|
||||
{10, 12, 14},
|
||||
{ 9, 11, 13},
|
||||
{ 8, 16, 16},
|
||||
{ 8, 10, 12}
|
||||
};
|
||||
|
||||
int QRspec_lengthIndicator(QRencodeMode mode, int version)
|
||||
{
|
||||
int l;
|
||||
|
||||
if(mode == QR_MODE_STRUCTURE) return 0;
|
||||
if(version <= 9) {
|
||||
l = 0;
|
||||
} else if(version <= 26) {
|
||||
l = 1;
|
||||
} else {
|
||||
l = 2;
|
||||
}
|
||||
|
||||
return lengthTableBits[mode][l];
|
||||
}
|
||||
|
||||
int QRspec_maximumWords(QRencodeMode mode, int version)
|
||||
{
|
||||
int l;
|
||||
int bits;
|
||||
int words;
|
||||
|
||||
if(mode == QR_MODE_STRUCTURE) return 3;
|
||||
if(version <= 9) {
|
||||
l = 0;
|
||||
} else if(version <= 26) {
|
||||
l = 1;
|
||||
} else {
|
||||
l = 2;
|
||||
}
|
||||
|
||||
bits = lengthTableBits[mode][l];
|
||||
words = (1 << bits) - 1;
|
||||
if(mode == QR_MODE_KANJI) {
|
||||
words *= 2; // the number of bytes is required
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Error correction code
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Table of the error correction code (Reed-Solomon block)
|
||||
* See Table 12-16 (pp.30-36), JIS X0510:2004.
|
||||
*/
|
||||
static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = {
|
||||
{{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}},
|
||||
{{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, // 1
|
||||
{{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}},
|
||||
{{ 1, 0}, { 1, 0}, { 2, 0}, { 2, 0}},
|
||||
{{ 1, 0}, { 2, 0}, { 2, 0}, { 4, 0}},
|
||||
{{ 1, 0}, { 2, 0}, { 2, 2}, { 2, 2}}, // 5
|
||||
{{ 2, 0}, { 4, 0}, { 4, 0}, { 4, 0}},
|
||||
{{ 2, 0}, { 4, 0}, { 2, 4}, { 4, 1}},
|
||||
{{ 2, 0}, { 2, 2}, { 4, 2}, { 4, 2}},
|
||||
{{ 2, 0}, { 3, 2}, { 4, 4}, { 4, 4}},
|
||||
{{ 2, 2}, { 4, 1}, { 6, 2}, { 6, 2}}, //10
|
||||
{{ 4, 0}, { 1, 4}, { 4, 4}, { 3, 8}},
|
||||
{{ 2, 2}, { 6, 2}, { 4, 6}, { 7, 4}},
|
||||
{{ 4, 0}, { 8, 1}, { 8, 4}, {12, 4}},
|
||||
{{ 3, 1}, { 4, 5}, {11, 5}, {11, 5}},
|
||||
{{ 5, 1}, { 5, 5}, { 5, 7}, {11, 7}}, //15
|
||||
{{ 5, 1}, { 7, 3}, {15, 2}, { 3, 13}},
|
||||
{{ 1, 5}, {10, 1}, { 1, 15}, { 2, 17}},
|
||||
{{ 5, 1}, { 9, 4}, {17, 1}, { 2, 19}},
|
||||
{{ 3, 4}, { 3, 11}, {17, 4}, { 9, 16}},
|
||||
{{ 3, 5}, { 3, 13}, {15, 5}, {15, 10}}, //20
|
||||
{{ 4, 4}, {17, 0}, {17, 6}, {19, 6}},
|
||||
{{ 2, 7}, {17, 0}, { 7, 16}, {34, 0}},
|
||||
{{ 4, 5}, { 4, 14}, {11, 14}, {16, 14}},
|
||||
{{ 6, 4}, { 6, 14}, {11, 16}, {30, 2}},
|
||||
{{ 8, 4}, { 8, 13}, { 7, 22}, {22, 13}}, //25
|
||||
{{10, 2}, {19, 4}, {28, 6}, {33, 4}},
|
||||
{{ 8, 4}, {22, 3}, { 8, 26}, {12, 28}},
|
||||
{{ 3, 10}, { 3, 23}, { 4, 31}, {11, 31}},
|
||||
{{ 7, 7}, {21, 7}, { 1, 37}, {19, 26}},
|
||||
{{ 5, 10}, {19, 10}, {15, 25}, {23, 25}}, //30
|
||||
{{13, 3}, { 2, 29}, {42, 1}, {23, 28}},
|
||||
{{17, 0}, {10, 23}, {10, 35}, {19, 35}},
|
||||
{{17, 1}, {14, 21}, {29, 19}, {11, 46}},
|
||||
{{13, 6}, {14, 23}, {44, 7}, {59, 1}},
|
||||
{{12, 7}, {12, 26}, {39, 14}, {22, 41}}, //35
|
||||
{{ 6, 14}, { 6, 34}, {46, 10}, { 2, 64}},
|
||||
{{17, 4}, {29, 14}, {49, 10}, {24, 46}},
|
||||
{{ 4, 18}, {13, 32}, {48, 14}, {42, 32}},
|
||||
{{20, 4}, {40, 7}, {43, 22}, {10, 67}},
|
||||
{{19, 6}, {18, 31}, {34, 34}, {20, 61}},//40
|
||||
};
|
||||
|
||||
int *QRspec_getEccSpec(int version, QRecLevel level)
|
||||
{
|
||||
int b1, b2;
|
||||
int data, ecc;
|
||||
int *array;
|
||||
|
||||
b1 = eccTable[version][level][0];
|
||||
b2 = eccTable[version][level][1];
|
||||
data = QRspec_getDataLength(version, level);
|
||||
ecc = QRspec_getECCLength(version, level);
|
||||
|
||||
array = (int *)malloc(sizeof(int) * 6);
|
||||
if(array == NULL) return NULL;
|
||||
|
||||
if(b2 == 0) {
|
||||
array[0] = b1;
|
||||
array[1] = data / b1;
|
||||
array[2] = ecc / b1;
|
||||
array[3] = array[4] = array[5] = 0;
|
||||
} else {
|
||||
array[0] = b1;
|
||||
array[1] = data / (b1 + b2);
|
||||
array[2] = ecc / (b1 + b2);
|
||||
array[3] = b2;
|
||||
array[4] = array[1] + 1;
|
||||
array[5] = (ecc - (array[2] * b1)) / b2;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Alignment pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Positions of alignment patterns.
|
||||
* This array includes only the second and the third position of the alignment
|
||||
* patterns. Rest of them can be calculated from the distance between them.
|
||||
*
|
||||
* See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
|
||||
*/
|
||||
static const int alignmentPattern[QRSPEC_VERSION_MAX+1][2] = {
|
||||
{ 0, 0},
|
||||
{ 0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, // 1- 5
|
||||
{34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, // 6-10
|
||||
{30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, //11-15
|
||||
{26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, //16-20
|
||||
{28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, //21-25
|
||||
{30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, //26-30
|
||||
{30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, //31-35
|
||||
{24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, //35-40
|
||||
};
|
||||
|
||||
QRspec_Alignment *QRspec_getAlignmentPattern(int version)
|
||||
{
|
||||
int width;
|
||||
int d, w, x, y, cx, cy;
|
||||
QRspec_Alignment *al;
|
||||
int *p;
|
||||
|
||||
if(version < 2) return NULL;
|
||||
|
||||
al = (QRspec_Alignment *)malloc(sizeof(QRspec_Alignment));
|
||||
|
||||
width = qrspecCapacity[version].width;
|
||||
d = alignmentPattern[version][1] - alignmentPattern[version][0];
|
||||
if(d < 0) {
|
||||
w = 2;
|
||||
} else {
|
||||
w = (width - alignmentPattern[version][0]) / d + 2;
|
||||
}
|
||||
|
||||
al->n = w * w - 3;
|
||||
al->pos = (int *)malloc(sizeof(int) * al->n * 2);
|
||||
|
||||
if(al->n == 1) {
|
||||
al->pos[0] = alignmentPattern[version][0];
|
||||
al->pos[1] = alignmentPattern[version][0];
|
||||
|
||||
return al;
|
||||
}
|
||||
#if 0
|
||||
/* Just for debug purpose */
|
||||
printf("%d ", version);
|
||||
cx = alignmentPattern[version][0];
|
||||
for(x=0; x<w-1; x++) {
|
||||
printf(" %3d", cx);
|
||||
cx += d;
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
p = al->pos;
|
||||
|
||||
cx = alignmentPattern[version][0];
|
||||
for(x=1; x<w - 1; x++) {
|
||||
p[0] = 6;
|
||||
p[1] = cx;
|
||||
p[2] = cx;
|
||||
p[3] = 6;
|
||||
cx += d;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
cy = alignmentPattern[version][0];
|
||||
for(y=0; y<w-1; y++) {
|
||||
cx = alignmentPattern[version][0];
|
||||
for(x=0; x<w-1; x++) {
|
||||
p[0] = cx;
|
||||
p[1] = cy;
|
||||
cx += d;
|
||||
p += 2;
|
||||
}
|
||||
cy += d;
|
||||
}
|
||||
|
||||
return al;
|
||||
}
|
||||
|
||||
void QRspec_freeAlignment(QRspec_Alignment *al)
|
||||
{
|
||||
if(al != NULL) {
|
||||
if(al->pos != NULL) {
|
||||
free(al->pos);
|
||||
}
|
||||
free(al);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Version information pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Version information pattern (BCH coded).
|
||||
* See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
|
||||
*/
|
||||
static const unsigned int versionPattern[QRSPEC_VERSION_MAX - 6] = {
|
||||
0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
|
||||
0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
|
||||
0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
|
||||
0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
|
||||
0x27541, 0x28c69
|
||||
};
|
||||
|
||||
unsigned int QRspec_getVersionPattern(int version)
|
||||
{
|
||||
if(version < 7 || version > QRSPEC_VERSION_MAX) return 0;
|
||||
|
||||
return versionPattern[version -7];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
|
||||
/* See calcFormatInfo in tests/test_qrspec.c */
|
||||
static const unsigned int formatInfo[4][8] = {
|
||||
{0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976},
|
||||
{0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0},
|
||||
{0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed},
|
||||
{0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b}
|
||||
};
|
||||
|
||||
unsigned int QRspec_getFormatInfo(int mask, QRecLevel level)
|
||||
{
|
||||
if(mask < 0 || mask > 7) return 0;
|
||||
|
||||
return formatInfo[level][mask];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Frame
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Cache of initial frames.
|
||||
*/
|
||||
/* C99 says that static storage shall be initialized to a null pointer
|
||||
* by compiler. */
|
||||
static unsigned char *frames[QRSPEC_VERSION_MAX + 1];
|
||||
|
||||
/**
|
||||
* Put a finder pattern.
|
||||
* @param frame
|
||||
* @param width
|
||||
* @param ox,oy upper-left coordinate of the pattern
|
||||
*/
|
||||
static void putFinderPattern(unsigned char *frame, int width, int ox, int oy)
|
||||
{
|
||||
static const unsigned char finder[] = {
|
||||
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
|
||||
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
|
||||
0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
|
||||
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
|
||||
};
|
||||
int x, y;
|
||||
const unsigned char *s;
|
||||
|
||||
frame += oy * width + ox;
|
||||
s = finder;
|
||||
for(y=0; y<7; y++) {
|
||||
for(x=0; x<7; x++) {
|
||||
frame[x] = s[x];
|
||||
}
|
||||
frame += width;
|
||||
s += 7;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an alignment pattern.
|
||||
* @param frame
|
||||
* @param width
|
||||
* @param ox,oy center coordinate of the pattern
|
||||
*/
|
||||
static void putAlignmentPattern(unsigned char *frame, int width, int ox, int oy)
|
||||
{
|
||||
static const unsigned char finder[] = {
|
||||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||||
0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
|
||||
0xa1, 0xa0, 0xa1, 0xa0, 0xa1,
|
||||
0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
|
||||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||||
};
|
||||
int x, y;
|
||||
const unsigned char *s;
|
||||
|
||||
frame += (oy - 2) * width + ox - 2;
|
||||
s = finder;
|
||||
for(y=0; y<5; y++) {
|
||||
for(x=0; x<5; x++) {
|
||||
frame[x] = s[x];
|
||||
}
|
||||
frame += width;
|
||||
s += 5;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *QRspec_createFrame(int version)
|
||||
{
|
||||
unsigned char *frame, *p, *q;
|
||||
int width;
|
||||
int x, y;
|
||||
unsigned int verinfo, v;
|
||||
QRspec_Alignment *alignment;
|
||||
|
||||
width = qrspecCapacity[version].width;
|
||||
frame = (unsigned char *)malloc(width * width);
|
||||
memset(frame, 0, width * width);
|
||||
/* Finder pattern */
|
||||
putFinderPattern(frame, width, 0, 0);
|
||||
putFinderPattern(frame, width, width - 7, 0);
|
||||
putFinderPattern(frame, width, 0, width - 7);
|
||||
/* Separator */
|
||||
p = frame;
|
||||
q = frame + width * (width - 7);
|
||||
for(y=0; y<7; y++) {
|
||||
p[7] = 0xc0;
|
||||
p[width - 8] = 0xc0;
|
||||
q[7] = 0xc0;
|
||||
p += width;
|
||||
q += width;
|
||||
}
|
||||
memset(frame + width * 7, 0xc0, 8);
|
||||
memset(frame + width * 8 - 8, 0xc0, 8);
|
||||
memset(frame + width * (width - 8), 0xc0, 8);
|
||||
/* Mask format information area */
|
||||
memset(frame + width * 8, 0x84, 9);
|
||||
memset(frame + width * 9 - 8, 0x84, 8);
|
||||
p = frame + 8;
|
||||
for(y=0; y<8; y++) {
|
||||
*p = 0x84;
|
||||
p += width;
|
||||
}
|
||||
p = frame + width * (width - 7) + 8;
|
||||
for(y=0; y<7; y++) {
|
||||
*p = 0x84;
|
||||
p += width;
|
||||
}
|
||||
/* Timing pattern */
|
||||
p = frame + width * 6 + 8;
|
||||
q = frame + width * 8 + 6;
|
||||
for(x=1; x<width-15; x++) {
|
||||
*p = 0x90 | (x & 1);
|
||||
*q = 0x90 | (x & 1);
|
||||
p++;
|
||||
q += width;
|
||||
}
|
||||
/* Alignment pattern */
|
||||
alignment = QRspec_getAlignmentPattern(version);
|
||||
if(alignment != NULL) {
|
||||
for(x=0; x<alignment->n; x++) {
|
||||
putAlignmentPattern(frame, width,
|
||||
alignment->pos[x*2], alignment->pos[x*2+1]);
|
||||
}
|
||||
QRspec_freeAlignment(alignment);
|
||||
}
|
||||
/* Version information */
|
||||
if(version >= 7) {
|
||||
verinfo = QRspec_getVersionPattern(version);
|
||||
|
||||
p = frame + width * (width - 11);
|
||||
v = verinfo;
|
||||
for(x=0; x<6; x++) {
|
||||
for(y=0; y<3; y++) {
|
||||
p[width * y + x] = 0x88 | (v & 1);
|
||||
v = v >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
p = frame + width - 11;
|
||||
v = verinfo;
|
||||
for(y=0; y<6; y++) {
|
||||
for(x=0; x<3; x++) {
|
||||
p[x] = 0x88 | (v & 1);
|
||||
v = v >> 1;
|
||||
}
|
||||
p += width;
|
||||
}
|
||||
}
|
||||
/* and a little bit... */
|
||||
frame[width * (width - 8) + 8] = 0x81;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
unsigned char *QRspec_newFrame(int version)
|
||||
{
|
||||
unsigned char *frame;
|
||||
int width;
|
||||
|
||||
if(version < 1 || version > QRSPEC_VERSION_MAX) return NULL;
|
||||
|
||||
if(frames[version] == NULL) {
|
||||
frames[version] = QRspec_createFrame(version);
|
||||
}
|
||||
width = qrspecCapacity[version].width;
|
||||
frame = (unsigned char *)malloc(width * width);
|
||||
memcpy(frame, frames[version], width * width);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void QRspec_clearCache(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
|
||||
if(frames[i] != NULL) {
|
||||
free(frames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* QR Code specification in convenient format.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __QRSPEC_H__
|
||||
#define __QRSPEC_H__
|
||||
|
||||
#include "qrencode.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Version and capacity
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Maximum version (size) of QR-code symbol.
|
||||
*/
|
||||
#define QRSPEC_VERSION_MAX 40
|
||||
|
||||
/**
|
||||
* Maximum width of a symbol
|
||||
*/
|
||||
#define QRSPEC_WIDTH_MAX 177
|
||||
|
||||
/**
|
||||
* Return maximum data code length (bytes) for the version.
|
||||
* @param version
|
||||
* @param level
|
||||
* @return maximum size (bytes)
|
||||
*/
|
||||
extern int QRspec_getDataLength(int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return maximum error correction code length (bytes) for the version.
|
||||
* @param version
|
||||
* @param level
|
||||
* @return ECC size (bytes)
|
||||
*/
|
||||
extern int QRspec_getECCLength(int version, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return a version number that satisfies the input code length.
|
||||
* @param size input code length (byte)
|
||||
* @param level
|
||||
* @return version number
|
||||
*/
|
||||
extern int QRspec_getMinimumVersion(int size, QRecLevel level);
|
||||
|
||||
/**
|
||||
* Return the width of the symbol for the version.
|
||||
* @param version
|
||||
* @return width
|
||||
*/
|
||||
extern int QRspec_getWidth(int version);
|
||||
|
||||
/**
|
||||
* Return the numer of remainder bits.
|
||||
* @param version
|
||||
* @return number of remainder bits
|
||||
*/
|
||||
extern int QRspec_getRemainder(int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Length indicator
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return the size of lenght indicator for the mode and version.
|
||||
* @param mode
|
||||
* @param version
|
||||
* @return the size of the appropriate length indicator (bits).
|
||||
*/
|
||||
extern int QRspec_lengthIndicator(QRencodeMode mode, int version);
|
||||
|
||||
/**
|
||||
* Return the maximum length for the mode and version.
|
||||
* @param mode
|
||||
* @param version
|
||||
* @return the maximum length (bytes)
|
||||
*/
|
||||
extern int QRspec_maximumWords(QRencodeMode mode, int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Error correction code
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return an array of ECC specification.
|
||||
* @param version
|
||||
* @param level
|
||||
* @return an array of ECC specification contains as following:
|
||||
* {# of type1 blocks, # of data code, # of ecc code,
|
||||
* # of type2 blocks, # of data code, # of ecc code}
|
||||
* It can be freed by calling free().
|
||||
*/
|
||||
int *QRspec_getEccSpec(int version, QRecLevel level);
|
||||
|
||||
#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3])
|
||||
#define QRspec_rsBlockNum1(__spec__) (__spec__[0])
|
||||
#define QRspec_rsDataCodes1(__spec__) (__spec__[1])
|
||||
#define QRspec_rsEccCodes1(__spec__) (__spec__[2])
|
||||
#define QRspec_rsBlockNum2(__spec__) (__spec__[3])
|
||||
#define QRspec_rsDataCodes2(__spec__) (__spec__[4])
|
||||
#define QRspec_rsEccCodes2(__spec__) (__spec__[5])
|
||||
|
||||
/******************************************************************************
|
||||
* Alignment pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Array of positions of alignment patterns.
|
||||
* X and Y coordinates are interleaved into 'pos'.
|
||||
*/
|
||||
typedef struct {
|
||||
int n; //< Number of patterns
|
||||
int *pos;
|
||||
} QRspec_Alignment;
|
||||
|
||||
/**
|
||||
* Return positions of alignment patterns.
|
||||
* @param version
|
||||
* @return a QRspec_Alignment object that contains all of positions of alignment
|
||||
* patterns.
|
||||
*/
|
||||
extern QRspec_Alignment *QRspec_getAlignmentPattern(int version);
|
||||
|
||||
/**
|
||||
* Free QRspec_Alignment instance.
|
||||
* @param al QRspec_Alignment instance.
|
||||
*/
|
||||
extern void QRspec_freeAlignment(QRspec_Alignment *al);
|
||||
|
||||
/******************************************************************************
|
||||
* Version information pattern
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return BCH encoded version information pattern that is used for the symbol
|
||||
* of version 7 or greater. Use lower 18 bits.
|
||||
* @param version
|
||||
* @return BCH encoded version information pattern
|
||||
*/
|
||||
extern unsigned int QRspec_getVersionPattern(int version);
|
||||
|
||||
/******************************************************************************
|
||||
* Format information
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return BCH encoded format information pattern.
|
||||
* @param mask
|
||||
* @param level
|
||||
* @return BCH encoded format information pattern
|
||||
*/
|
||||
extern unsigned int QRspec_getFormatInfo(int mask, QRecLevel level);
|
||||
|
||||
/******************************************************************************
|
||||
* Frame
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Return a copy of initialized frame.
|
||||
* When the same version is requested twice or more, a copy of cached frame
|
||||
* is returned.
|
||||
* WARNING: Thread unsafe!!!
|
||||
* @param version
|
||||
* @return Array of unsigned char. You can free it by free().
|
||||
*/
|
||||
extern unsigned char *QRspec_newFrame(int version);
|
||||
|
||||
/**
|
||||
* Clear the frame cache. Typically for debug.
|
||||
* WARNING: Thread unsafe!!!
|
||||
*/
|
||||
extern void QRspec_clearCache(void);
|
||||
|
||||
#endif /* __QRSPEC_H__ */
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
|
||||
* editted and packed into a pair of .c and .h files.
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
* (libfec is released under the GNU Lesser General Public License.)
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "rscode.h"
|
||||
|
||||
/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs
|
||||
*
|
||||
*/
|
||||
typedef unsigned char data_t;
|
||||
|
||||
|
||||
/**
|
||||
* Reed-Solomon codec control block
|
||||
*/
|
||||
struct _RS {
|
||||
int mm; /* Bits per symbol */
|
||||
int nn; /* Symbols per block (= (1<<mm)-1) */
|
||||
data_t *alpha_to; /* log lookup table */
|
||||
data_t *index_of; /* Antilog lookup table */
|
||||
data_t *genpoly; /* Generator polynomial */
|
||||
int nroots; /* Number of generator roots = number of parity symbols */
|
||||
int fcr; /* First consecutive root, index form */
|
||||
int prim; /* Primitive element, index form */
|
||||
int iprim; /* prim-th root of 1, index form */
|
||||
int pad; /* Padding bytes in shortened block */
|
||||
int gfpoly;
|
||||
struct _RS *next;
|
||||
};
|
||||
|
||||
RS *rslist = NULL;
|
||||
|
||||
static inline int modnn(RS *rs, int x){
|
||||
while (x >= rs->nn) {
|
||||
x -= rs->nn;
|
||||
x = (x >> rs->mm) + (x & rs->nn);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
#define MODNN(x) modnn(rs,x)
|
||||
|
||||
#define MM (rs->mm)
|
||||
#define NN (rs->nn)
|
||||
#define ALPHA_TO (rs->alpha_to)
|
||||
#define INDEX_OF (rs->index_of)
|
||||
#define GENPOLY (rs->genpoly)
|
||||
#define NROOTS (rs->nroots)
|
||||
#define FCR (rs->fcr)
|
||||
#define PRIM (rs->prim)
|
||||
#define IPRIM (rs->iprim)
|
||||
#define PAD (rs->pad)
|
||||
#define A0 (NN)
|
||||
|
||||
|
||||
/* Initialize a Reed-Solomon codec
|
||||
* symsize = symbol size, bits
|
||||
* gfpoly = Field generator polynomial coefficients
|
||||
* fcr = first root of RS code generator polynomial, index form
|
||||
* prim = primitive element to generate polynomial roots
|
||||
* nroots = RS code generator polynomial degree (number of roots)
|
||||
* pad = padding bytes at front of shortened block
|
||||
*/
|
||||
static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
|
||||
{
|
||||
RS *rs;
|
||||
|
||||
|
||||
/* Common code for intializing a Reed-Solomon control block (char or int symbols)
|
||||
* Copyright 2004 Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
//#undef NULL
|
||||
//#define NULL ((void *)0)
|
||||
|
||||
int i, j, sr,root,iprim;
|
||||
|
||||
rs = NULL;
|
||||
/* Check parameter ranges */
|
||||
if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(fcr < 0 || fcr >= (1<<symsize))
|
||||
goto done;
|
||||
if(prim <= 0 || prim >= (1<<symsize))
|
||||
goto done;
|
||||
if(nroots < 0 || nroots >= (1<<symsize))
|
||||
goto done; /* Can't have more roots than symbol values! */
|
||||
if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
|
||||
goto done; /* Too much padding */
|
||||
|
||||
rs = (RS *)calloc(1,sizeof(RS));
|
||||
if(rs == NULL)
|
||||
goto done;
|
||||
|
||||
rs->mm = symsize;
|
||||
rs->nn = (1<<symsize)-1;
|
||||
rs->pad = pad;
|
||||
|
||||
rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
|
||||
if(rs->alpha_to == NULL){
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
|
||||
if(rs->index_of == NULL){
|
||||
free(rs->alpha_to);
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Generate Galois field lookup tables */
|
||||
rs->index_of[0] = A0; /* log(zero) = -inf */
|
||||
rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */
|
||||
sr = 1;
|
||||
for(i=0;i<rs->nn;i++){
|
||||
rs->index_of[sr] = i;
|
||||
rs->alpha_to[i] = sr;
|
||||
sr <<= 1;
|
||||
if(sr & (1<<symsize))
|
||||
sr ^= gfpoly;
|
||||
sr &= rs->nn;
|
||||
}
|
||||
if(sr != 1){
|
||||
/* field generator polynomial is not primitive! */
|
||||
free(rs->alpha_to);
|
||||
free(rs->index_of);
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Form RS code generator polynomial from its roots */
|
||||
rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1));
|
||||
if(rs->genpoly == NULL){
|
||||
free(rs->alpha_to);
|
||||
free(rs->index_of);
|
||||
free(rs);
|
||||
rs = NULL;
|
||||
goto done;
|
||||
}
|
||||
rs->fcr = fcr;
|
||||
rs->prim = prim;
|
||||
rs->nroots = nroots;
|
||||
rs->gfpoly = gfpoly;
|
||||
|
||||
/* Find prim-th root of 1, used in decoding */
|
||||
for(iprim=1;(iprim % prim) != 0;iprim += rs->nn)
|
||||
;
|
||||
rs->iprim = iprim / prim;
|
||||
|
||||
rs->genpoly[0] = 1;
|
||||
for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) {
|
||||
rs->genpoly[i+1] = 1;
|
||||
|
||||
/* Multiply rs->genpoly[] by @**(root + x) */
|
||||
for (j = i; j > 0; j--){
|
||||
if (rs->genpoly[j] != 0)
|
||||
rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)];
|
||||
else
|
||||
rs->genpoly[j] = rs->genpoly[j-1];
|
||||
}
|
||||
/* rs->genpoly[0] can never be zero */
|
||||
rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)];
|
||||
}
|
||||
/* convert rs->genpoly[] to index form for quicker encoding */
|
||||
for (i = 0; i <= nroots; i++)
|
||||
rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
|
||||
done:;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
|
||||
{
|
||||
RS *rs;
|
||||
|
||||
for(rs = rslist; rs != NULL; rs = rs->next) {
|
||||
if(rs->nroots != nroots) continue;
|
||||
if(rs->pad != pad) continue;
|
||||
if(rs->mm != symsize) continue;
|
||||
if(rs->gfpoly != gfpoly) continue;
|
||||
if(rs->fcr != fcr) continue;
|
||||
if(rs->prim != prim) continue;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
rs = init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad);
|
||||
rs->next = rslist;
|
||||
rslist = rs;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
void free_rs_char(RS *rs)
|
||||
{
|
||||
free(rs->alpha_to);
|
||||
free(rs->index_of);
|
||||
free(rs->genpoly);
|
||||
free(rs);
|
||||
}
|
||||
|
||||
/* The guts of the Reed-Solomon encoder, meant to be #included
|
||||
* into a function body with the following typedefs, macros and variables supplied
|
||||
* according to the code parameters:
|
||||
|
||||
* data_t - a typedef for the data symbol
|
||||
* data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded
|
||||
* data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols
|
||||
* NROOTS - the number of roots in the RS code generator polynomial,
|
||||
* which is the same as the number of parity symbols in a block.
|
||||
Integer variable or literal.
|
||||
*
|
||||
* NN - the total number of symbols in a RS block. Integer variable or literal.
|
||||
* PAD - the number of pad symbols in a block. Integer variable or literal.
|
||||
* ALPHA_TO - The address of an array of NN elements to convert Galois field
|
||||
* elements in index (log) form to polynomial form. Read only.
|
||||
* INDEX_OF - The address of an array of NN elements to convert Galois field
|
||||
* elements in polynomial form to index (log) form. Read only.
|
||||
* MODNN - a function to reduce its argument modulo NN. May be inline or a macro.
|
||||
* GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form
|
||||
|
||||
* The memset() and memmove() functions are used. The appropriate header
|
||||
* file declaring these functions (usually <string.h>) must be included by the calling
|
||||
* program.
|
||||
|
||||
* Copyright 2004, Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
|
||||
#undef A0
|
||||
#define A0 (NN) /* Special reserved value encoding zero in index form */
|
||||
|
||||
void encode_rs_char(RS *rs, const data_t *data, data_t *parity)
|
||||
{
|
||||
int i, j;
|
||||
data_t feedback;
|
||||
|
||||
memset(parity,0,NROOTS*sizeof(data_t));
|
||||
|
||||
for(i=0;i<NN-NROOTS-PAD;i++){
|
||||
feedback = INDEX_OF[data[i] ^ parity[0]];
|
||||
if(feedback != A0){ /* feedback term is non-zero */
|
||||
#ifdef UNNORMALIZED
|
||||
/* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
|
||||
* always be for the polynomials constructed by init_rs()
|
||||
*/
|
||||
feedback = MODNN(NN - GENPOLY[NROOTS] + feedback);
|
||||
#endif
|
||||
for(j=1;j<NROOTS;j++)
|
||||
parity[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS-j])];
|
||||
}
|
||||
/* Shift */
|
||||
memmove(&parity[0],&parity[1],sizeof(data_t)*(NROOTS-1));
|
||||
if(feedback != A0)
|
||||
parity[NROOTS-1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])];
|
||||
else
|
||||
parity[NROOTS-1] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
|
||||
* editted and packed into a pair of .c and .h files.
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
* (libfec is released under the GNU Lesser General Public License.)
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __RSCODE_H__
|
||||
#define __RSCODE_H__
|
||||
|
||||
/*
|
||||
* General purpose RS codec, 8-bit symbols.
|
||||
*/
|
||||
|
||||
typedef struct _RS RS;
|
||||
|
||||
/* WARNING: Thread unsafe!!! */
|
||||
extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
|
||||
extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity);
|
||||
extern void free_rs_char(RS *rs);
|
||||
|
||||
#endif /* __RSCODE_H__ */
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Input data splitter.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "qrencode.h"
|
||||
#include "qrinput.h"
|
||||
#include "qrspec.h"
|
||||
#include "split.h"
|
||||
|
||||
#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10)
|
||||
#define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0)
|
||||
|
||||
static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint)
|
||||
{
|
||||
unsigned char c, d;
|
||||
unsigned int word;
|
||||
|
||||
c = string[0];
|
||||
|
||||
if(c == '\0') return QR_MODE_NUL;
|
||||
if(isdigit(c)) {
|
||||
return QR_MODE_NUM;
|
||||
} else if(isalnum(c)) {
|
||||
return QR_MODE_AN;
|
||||
} else if(hint == QR_MODE_KANJI) {
|
||||
d = string[1];
|
||||
if(d != '\0') {
|
||||
word = ((unsigned int)c << 8) | d;
|
||||
if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) {
|
||||
return QR_MODE_KANJI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QR_MODE_8;
|
||||
}
|
||||
|
||||
static int Split_eatNum(const char *string, QRinput *input, QRencodeMode hint);
|
||||
static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint);
|
||||
static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint);
|
||||
static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint);
|
||||
|
||||
static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint)
|
||||
{
|
||||
const char *p;
|
||||
int ret;
|
||||
int run;
|
||||
int dif;
|
||||
int ln;
|
||||
QRencodeMode mode;
|
||||
|
||||
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
|
||||
|
||||
p = string;
|
||||
while(isdigit(*p)) {
|
||||
p++;
|
||||
}
|
||||
run = p - string;
|
||||
mode = Split_identifyMode(p, hint);
|
||||
if(mode == QR_MODE_8) {
|
||||
dif = QRinput_estimateBitsModeNum(run) + 4 + ln
|
||||
+ QRinput_estimateBitsMode8(1) /* + 4 + l8 */
|
||||
- QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
|
||||
if(dif > 0) {
|
||||
return Split_eat8(string, input, hint);
|
||||
}
|
||||
}
|
||||
if(mode == QR_MODE_AN) {
|
||||
dif = QRinput_estimateBitsModeNum(run) + 4 + ln
|
||||
+ QRinput_estimateBitsModeAn(1) /* + 4 + la */
|
||||
- QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */;
|
||||
if(dif > 0) {
|
||||
return Split_eatAn(string, input, hint);
|
||||
}
|
||||
}
|
||||
|
||||
ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint)
|
||||
{
|
||||
const char *p, *q;
|
||||
int ret;
|
||||
int run;
|
||||
int dif;
|
||||
int la, ln;
|
||||
|
||||
la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
|
||||
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
|
||||
|
||||
p = string;
|
||||
while(isalnum(*p)) {
|
||||
if(isdigit(*p)) {
|
||||
q = p;
|
||||
while(isdigit(*q)) {
|
||||
q++;
|
||||
}
|
||||
dif = QRinput_estimateBitsModeAn(p - string) /* + 4 + la */
|
||||
+ QRinput_estimateBitsModeNum(q - p) + 4 + ln
|
||||
- QRinput_estimateBitsModeAn(q - string) /* - 4 - la */;
|
||||
if(dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
p = q;
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
run = p - string;
|
||||
|
||||
if(*p && !isalnum(*p)) {
|
||||
dif = QRinput_estimateBitsModeAn(run) + 4 + la
|
||||
+ QRinput_estimateBitsMode8(1) /* + 4 + l8 */
|
||||
- QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
|
||||
if(dif > 0) {
|
||||
return Split_eat8(string, input, hint);
|
||||
}
|
||||
}
|
||||
|
||||
ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint)
|
||||
{
|
||||
const char *p;
|
||||
int ret;
|
||||
int run;
|
||||
|
||||
p = string;
|
||||
while(Split_identifyMode(p, hint) == QR_MODE_KANJI) {
|
||||
p += 2;
|
||||
}
|
||||
run = p - string;
|
||||
ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint)
|
||||
{
|
||||
const char *p, *q;
|
||||
QRencodeMode mode;
|
||||
int ret;
|
||||
int run;
|
||||
int dif;
|
||||
int la, ln;
|
||||
|
||||
la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
|
||||
ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
|
||||
|
||||
p = string + 1;
|
||||
while(*p != '\0') {
|
||||
mode = Split_identifyMode(p, hint);
|
||||
if(mode == QR_MODE_KANJI) {
|
||||
break;
|
||||
}
|
||||
if(mode == QR_MODE_NUM) {
|
||||
q = p;
|
||||
while(isdigit(*q)) {
|
||||
q++;
|
||||
}
|
||||
dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
|
||||
+ QRinput_estimateBitsModeNum(q - p) + 4 + ln
|
||||
- QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
|
||||
if(dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
p = q;
|
||||
}
|
||||
} else if(mode == QR_MODE_AN) {
|
||||
q = p;
|
||||
while(isalnum(*q)) {
|
||||
q++;
|
||||
}
|
||||
dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
|
||||
+ QRinput_estimateBitsModeAn(q - p) + 4 + la
|
||||
- QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
|
||||
if(dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
p = q;
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
run = p - string;
|
||||
ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string);
|
||||
if(ret < 0) return -1;
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
static int Split_splitString(const char *string, QRinput *input,
|
||||
QRencodeMode hint)
|
||||
{
|
||||
int length;
|
||||
QRencodeMode mode;
|
||||
|
||||
if(*string == '\0') return 0;
|
||||
|
||||
mode = Split_identifyMode(string, hint);
|
||||
if(mode == QR_MODE_NUM) {
|
||||
length = Split_eatNum(string, input, hint);
|
||||
} else if(mode == QR_MODE_AN) {
|
||||
length = Split_eatAn(string, input, hint);
|
||||
} else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) {
|
||||
length = Split_eatKanji(string, input, hint);
|
||||
} else {
|
||||
length = Split_eat8(string, input, hint);
|
||||
}
|
||||
if(length == 0) return 0;
|
||||
if(length < 0) return -1;
|
||||
return Split_splitString(&string[length], input, hint);
|
||||
}
|
||||
|
||||
static char *dupAndToUpper(const char *str, QRencodeMode hint)
|
||||
{
|
||||
char *newstr, *p;
|
||||
QRencodeMode mode;
|
||||
|
||||
newstr = strdup(str);
|
||||
if(newstr == NULL) return NULL;
|
||||
|
||||
p = newstr;
|
||||
while(*p != '\0') {
|
||||
mode = Split_identifyMode(p, hint);
|
||||
if(mode == QR_MODE_KANJI) {
|
||||
p += 2;
|
||||
} else {
|
||||
if (*p >= 'a' && *p <= 'z') {
|
||||
*p = (char)((int)*p - 32);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return newstr;
|
||||
}
|
||||
|
||||
int Split_splitStringToQRinput(const char *string, QRinput *input,
|
||||
QRencodeMode hint, int casesensitive)
|
||||
{
|
||||
char *newstr;
|
||||
int ret;
|
||||
|
||||
if(!casesensitive) {
|
||||
newstr = dupAndToUpper(string, hint);
|
||||
if(newstr == NULL) return -1;
|
||||
ret = Split_splitString(newstr, input, hint);
|
||||
free(newstr);
|
||||
} else {
|
||||
ret = Split_splitString(string, input, hint);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* Input data splitter.
|
||||
* Copyright (C) 2006, 2007, 2008 Kentaro Fukuchi <fukuchi@megaui.net>
|
||||
*
|
||||
* The following data / specifications are taken from
|
||||
* "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
|
||||
* or
|
||||
* "Automatic identification and data capture techniques --
|
||||
* QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __SPLIT_H__
|
||||
#define __SPLIT_H__
|
||||
|
||||
#include "qrencode.h"
|
||||
|
||||
/**
|
||||
* Split the input string (null terminated) into QRinput.
|
||||
* @param string input string
|
||||
* @param hint give QR_MODE_KANJI if the input string contains Kanji character encoded in Shift-JIS. If not, give QR_MODE_8.
|
||||
* @param casesensitive 0 for case-insensitive encoding (all alphabet characters are replaced to UPPER-CASE CHARACTERS.
|
||||
* @retval 0 success.
|
||||
* @retval -1 an error occurred.
|
||||
*/
|
||||
extern int Split_splitStringToQRinput(const char *string, QRinput *input,
|
||||
QRencodeMode hint, int casesensitive);
|
||||
|
||||
#endif /* __SPLIT_H__ */
|
||||
|
|
@ -8,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))
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
CC = gcc
|
||||
CFLAGS = -g -Wall
|
||||
LOCLIBS =
|
||||
LIBS = -luci -lubus -lubox -lpthread
|
||||
OBJS = questd.o dumper.o port.o arping.o usb.o ndisc.o dslstats.o tools.o igmp.o
|
||||
SRCS = questd.c dumper.c port.c arping.c usb.c ndisc.c dslstats.c tools.c igmp.c
|
||||
LIBSRCS =
|
||||
ISRCS = questd.h
|
||||
|
||||
all: questd
|
||||
|
||||
questd: ${OBJS}
|
||||
${CC} ${LDFLAGS} ${LIBSRCS} -o questd ${OBJS} ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f questd *.o
|
||||
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* arping -- arping tool for questd
|
||||
*
|
||||
* Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
|
||||
* Author: Sukru Senli sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
|
||||
struct in_addr src;
|
||||
struct in_addr dst;
|
||||
struct sockaddr_ll me;
|
||||
struct sockaddr_ll he;
|
||||
int sock_fd;
|
||||
|
||||
//void *mempcpy(void *dst, const void *src, size_t n);
|
||||
|
||||
static int
|
||||
send_pack(struct in_addr *src_addr, struct in_addr *dst_addr, struct sockaddr_ll *ME, struct sockaddr_ll *HE)
|
||||
{
|
||||
int err;
|
||||
unsigned char buf[256];
|
||||
struct arphdr *ah = (struct arphdr *) buf;
|
||||
unsigned char *p = (unsigned char *) (ah + 1);
|
||||
|
||||
ah->ar_hrd = htons(ARPHRD_ETHER);
|
||||
ah->ar_pro = htons(ETH_P_IP);
|
||||
ah->ar_hln = ME->sll_halen;
|
||||
ah->ar_pln = 4;
|
||||
ah->ar_op = htons(ARPOP_REQUEST);
|
||||
|
||||
p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
|
||||
p = mempcpy(p, src_addr, 4);
|
||||
|
||||
p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
|
||||
p = mempcpy(p, dst_addr, 4);
|
||||
|
||||
err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool
|
||||
recv_pack(char *buf, int len, struct sockaddr_ll *FROM)
|
||||
{
|
||||
struct arphdr *ah = (struct arphdr *) buf;
|
||||
unsigned char *p = (unsigned char *) (ah + 1);
|
||||
struct in_addr src_ip, dst_ip;
|
||||
|
||||
/* Filter out wild packets */
|
||||
if (FROM->sll_pkttype != PACKET_HOST
|
||||
&& FROM->sll_pkttype != PACKET_BROADCAST
|
||||
&& FROM->sll_pkttype != PACKET_MULTICAST)
|
||||
return false;
|
||||
|
||||
/* Only these types are recognized */
|
||||
if (ah->ar_op != htons(ARPOP_REPLY))
|
||||
return false;
|
||||
|
||||
/* ARPHRD check and this darned FDDI hack here :-( */
|
||||
if (ah->ar_hrd != htons(FROM->sll_hatype)
|
||||
&& (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
|
||||
return false;
|
||||
|
||||
/* Protocol must be IP. */
|
||||
if (ah->ar_pro != htons(ETH_P_IP)
|
||||
|| (ah->ar_pln != 4)
|
||||
|| (ah->ar_hln != me.sll_halen)
|
||||
|| (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
|
||||
return false;
|
||||
|
||||
(src_ip.s_addr) = *(uint32_t*)(p + ah->ar_hln);
|
||||
(dst_ip.s_addr) = *(uint32_t*)(p + ah->ar_hln + 4 + ah->ar_hln);
|
||||
|
||||
if (dst.s_addr != src_ip.s_addr)
|
||||
return false;
|
||||
|
||||
if ((src.s_addr != dst_ip.s_addr) || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
arping(char *targetIP, char *device, int toms)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
struct ifreq ifr;
|
||||
int probe_fd;
|
||||
|
||||
sock_fd = socket(AF_PACKET, SOCK_DGRAM, 0);
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, device, IF_NAMESIZE);
|
||||
|
||||
if (ioctl(sock_fd, SIOCGIFINDEX, &ifr, sizeof(ifr)) < 0) {
|
||||
close(sock_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
me.sll_family = AF_PACKET;
|
||||
me.sll_ifindex = ifr.ifr_ifindex;
|
||||
me.sll_protocol = htons(ETH_P_ARP);
|
||||
bind(sock_fd, (struct sockaddr *) &me, sizeof(me));
|
||||
|
||||
socklen_t mlen = sizeof(me);
|
||||
getsockname(sock_fd, (struct sockaddr *) &me, &mlen);
|
||||
|
||||
he = me;
|
||||
memset(he.sll_addr, -1, he.sll_halen);
|
||||
|
||||
inet_pton(AF_INET, targetIP, &(dst.s_addr));
|
||||
|
||||
/* Get the sender IP address */
|
||||
probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
saddr.sin_port = htons(1025);
|
||||
saddr.sin_addr = dst;
|
||||
connect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
|
||||
getsockname(probe_fd, (struct sockaddr *) &saddr, &slen);
|
||||
src = saddr.sin_addr;
|
||||
close(probe_fd);
|
||||
|
||||
send_pack(&src, &dst, &me, &he);
|
||||
|
||||
char packet[64];
|
||||
struct sockaddr_ll from;
|
||||
socklen_t alen = sizeof(from);
|
||||
bool connected = false;
|
||||
int cc = -1;
|
||||
|
||||
fd_set read_fds, write_fds, except_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_ZERO(&write_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(sock_fd, &read_fds);
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = toms * 1000;
|
||||
|
||||
if (select(sock_fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1)
|
||||
{
|
||||
cc = recvfrom(sock_fd, packet, sizeof(packet), 0, (struct sockaddr *) &from, &alen);
|
||||
}
|
||||
|
||||
if (cc >= 0)
|
||||
connected = recv_pack(packet, cc, &from);
|
||||
|
||||
close(sock_fd);
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* dslstats -- collects adsl information for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: martin.schroder@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
#define DSLDEBUG(...) {} //printf(__VA_ARGS__)
|
||||
|
||||
void dslstats_init(struct dsl_stats *self){
|
||||
*self = (struct dsl_stats){0};
|
||||
}
|
||||
|
||||
void dslstats_load(struct dsl_stats *self){
|
||||
FILE *fp;
|
||||
char line[128];
|
||||
char name[64];
|
||||
char sep[64];
|
||||
char arg1[64];
|
||||
char arg2[64];
|
||||
|
||||
// start with default bearer 0 (we can support more later)
|
||||
DSLBearer *bearer = &self->bearers[0];
|
||||
DSLCounters *counters = &self->counters[0];
|
||||
int done = 0;
|
||||
|
||||
if(!(fp = popen("xdslctl info --stats", "r"))) return;
|
||||
|
||||
while(!done && fgets(line, sizeof(line), fp) != NULL) {
|
||||
DSLDEBUG("LINE: %d, %s, args:%d\n", strlen(line), line, narg);
|
||||
name[0] = 0; arg1[0] = 0; arg2[0] = 0;
|
||||
remove_newline(line);
|
||||
int narg = sscanf(line, "%[^\t]%[\t ]%[^\t]%[\t]%[^\t]", name, sep, arg1, sep, arg2);
|
||||
switch(narg){
|
||||
case 0: { // sections
|
||||
if(strstr(line, "Bearer")){
|
||||
int id = 0;
|
||||
if(sscanf(strstr(line, "Bearer"), "Bearer %d", &id) > 0){
|
||||
if(id < DSLSTATS_BEARER_COUNT){
|
||||
bearer = &self->bearers[id];
|
||||
DSLDEBUG("Switching bearer: %d\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// it is possible to add more stats like this though
|
||||
/*
|
||||
else if(strstr(name, "Latest 15 minutes time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_CURRENT_15];
|
||||
else if(strstr(name, "Previous 15 minutes time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_PREVIOUS_15];
|
||||
else if(strstr(name, "Latest 1 day time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_CURRENT_DAY];
|
||||
else if(strstr(name, "Previous 1 day time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_PREVIOUS_DAY];
|
||||
else if(strstr(name, "Since Link time =") == name) counters = &self->counters[DSLSTATS_COUNTERS_SINCE_LINK]; */
|
||||
} break;
|
||||
case 1: { // various one liners
|
||||
if(strstr(line, "Total time =") == line) counters = &self->counters[DSLSTATS_COUNTER_TOTALS];
|
||||
else if(strstr(line, "Latest 15 minutes time =") == line) done = 1; // we stop parsing at this right now
|
||||
else if(strstr(line, "Status") == line && strlen(line) > 9) strncpy(self->status, line + 8, sizeof(self->status));
|
||||
} break;
|
||||
case 3: {
|
||||
if(strstr(name, "Link Power State") == name) strncpy(self->link_power_state, arg1, sizeof(self->link_power_state));
|
||||
else if(strstr(name, "Mode") == name) strncpy(self->mode, arg1, sizeof(self->mode));
|
||||
else if(strstr(name, "VDSL2 Profile") == name) strncpy(self->vdsl2_profile, arg1, sizeof(self->vdsl2_profile));
|
||||
else if(strstr(name, "TPS") == name) strncpy(self->traffic, arg1, sizeof(self->traffic));
|
||||
else if(strstr(name, "Trellis") == name){
|
||||
char tmp[2][64];
|
||||
if(sscanf(arg1, "U:%s /D:%s", tmp[0], tmp[1])){
|
||||
DSLDEBUG("TRELLIS: %s %s\n", tmp[0], tmp[1]);
|
||||
if(strcmp(tmp[0], "ON") == 0) self->trellis.down = 1;
|
||||
else self->trellis.down = 0;
|
||||
if(strcmp(tmp[1], "ON") == 0) self->trellis.up = 1;
|
||||
else self->trellis.up = 0;
|
||||
}
|
||||
}
|
||||
else if(strstr(name, "Line Status") == name) strncpy(self->line_status, arg1, sizeof(self->line_status));
|
||||
else if(strstr(name, "Bearer") == name){
|
||||
unsigned long id, up, down, ret;
|
||||
if((ret = sscanf(arg1, "%lu, Upstream rate = %lu Kbps, Downstream rate = %lu Kbps", &id, &up, &down)) == 3){
|
||||
if(id < DSLSTATS_BEARER_COUNT){
|
||||
bearer = &self->bearers[id];
|
||||
bearer->rate.up = up;
|
||||
bearer->rate.down = down;
|
||||
DSLDEBUG("Switching bearer: %d\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strstr(name, "Max") == name) {
|
||||
sscanf(arg1, "Upstream rate = %lf Kbps, Downstream rate = %lf Kbps", &bearer->max_rate.up, &bearer->max_rate.down);
|
||||
}
|
||||
DSLDEBUG("PARSED: name:%s, arg1:%s\n", name, arg1);
|
||||
} break;
|
||||
case 5: {
|
||||
if(strstr(name, "SNR") == name) {
|
||||
self->snr.down = atof(arg1);
|
||||
self->snr.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "Attn") == name){
|
||||
self->attn.down = atof(arg1);
|
||||
self->attn.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "Pwr") == name){
|
||||
self->pwr.down = atof(arg1);
|
||||
self->pwr.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "MSGc") == name){
|
||||
bearer->msgc.down = atof(arg1);
|
||||
bearer->msgc.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "B:") == name){
|
||||
bearer->b.down = atof(arg1);
|
||||
bearer->b.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "M:") == name){
|
||||
bearer->m.down = atof(arg1);
|
||||
bearer->m.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "T:") == name){
|
||||
bearer->t.down = atof(arg1);
|
||||
bearer->t.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "R:") == name){
|
||||
bearer->r.down = atof(arg1);
|
||||
bearer->r.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "S:") == name){
|
||||
bearer->s.down = atof(arg1);
|
||||
bearer->s.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "L:") == name){
|
||||
bearer->l.down = atof(arg1);
|
||||
bearer->l.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "D:") == name){
|
||||
bearer->d.down = atof(arg1);
|
||||
bearer->d.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "delay:") == name){
|
||||
bearer->delay.down = atof(arg1);
|
||||
bearer->delay.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "INP:") == name){
|
||||
bearer->inp.down = atof(arg1);
|
||||
bearer->inp.up = atof(arg2);
|
||||
}
|
||||
else if(strstr(name, "SF:") == name){
|
||||
bearer->sf.down = atoll(arg1);
|
||||
bearer->sf.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "SFErr:") == name){
|
||||
bearer->sf_err.down = atoll(arg1);
|
||||
bearer->sf_err.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "RS:") == name){
|
||||
bearer->rs.down = atoll(arg1);
|
||||
bearer->rs.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "RSCorr:") == name){
|
||||
bearer->rs_corr.down = atoll(arg1);
|
||||
bearer->rs_corr.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "RSUnCorr:") == name){
|
||||
bearer->rs_uncorr.down = atoll(arg1);
|
||||
bearer->rs_uncorr.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "HEC:") == name){
|
||||
bearer->hec.down = atoll(arg1);
|
||||
bearer->hec.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "OCD:") == name){
|
||||
bearer->ocd.down = atoll(arg1);
|
||||
bearer->ocd.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "LCD:") == name){
|
||||
bearer->lcd.down = atoll(arg1);
|
||||
bearer->lcd.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "Total Cells:") == name){
|
||||
bearer->total_cells.down = atoll(arg1);
|
||||
bearer->total_cells.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "Data Cells:") == name){
|
||||
bearer->data_cells.down = atoll(arg1);
|
||||
bearer->data_cells.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "Bit Errors:") == name){
|
||||
bearer->bit_errors.down = atoll(arg1);
|
||||
bearer->bit_errors.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "ES:") == name){
|
||||
counters->es.down = atoll(arg1);
|
||||
counters->es.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "SES:") == name){
|
||||
counters->ses.down = atoll(arg1);
|
||||
counters->ses.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "UAS:") == name){
|
||||
counters->uas.down = atoll(arg1);
|
||||
counters->uas.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "FEC:") == name){
|
||||
counters->fec.down = atoll(arg1);
|
||||
counters->fec.up = atoll(arg2);
|
||||
}
|
||||
else if(strstr(name, "CRC:") == name){
|
||||
counters->crc.down = atoll(arg1);
|
||||
counters->crc.up = atoll(arg2);
|
||||
}
|
||||
DSLDEBUG("PARSED: name:%s, arg1:%s, arg2:%s\n", name, arg1, arg2);
|
||||
} break;
|
||||
default: {
|
||||
DSLDEBUG("ERROR: line:%s, fcnt:%d, name:%s, arg1:%s, arg2:%s\n", line, narg, name, arg1, arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
}
|
||||
|
||||
void dslstats_free(struct dsl_stats *self){
|
||||
|
||||
}
|
||||
|
||||
void dslstats_to_blob_buffer(struct dsl_stats *self, struct blob_buf *b){
|
||||
void *t, *array, *obj;
|
||||
DSLBearer *bearer = &self->bearers[0];
|
||||
DSLCounters *counter = &self->counters[DSLSTATS_COUNTER_TOTALS];
|
||||
//dslstats_load(self);
|
||||
|
||||
t = blobmsg_open_table(b, "dslstats");
|
||||
blobmsg_add_string(b, "mode", self->mode);
|
||||
blobmsg_add_string(b, "traffic", self->traffic);
|
||||
blobmsg_add_string(b, "status", self->status);
|
||||
blobmsg_add_string(b, "link_power_state", self->link_power_state);
|
||||
blobmsg_add_string(b, "line_status", self->line_status);
|
||||
blobmsg_add_u8(b, "trellis_up", self->trellis.up);
|
||||
blobmsg_add_u8(b, "trellis_down", self->trellis.down);
|
||||
blobmsg_add_u32(b, "snr_up_x100", self->snr.up * 100);
|
||||
blobmsg_add_u32(b, "snr_down_x100", self->snr.down * 100);
|
||||
blobmsg_add_u32(b, "pwr_up_x100", self->pwr.up * 100);
|
||||
blobmsg_add_u32(b, "pwr_down_x100", self->pwr.down * 100);
|
||||
blobmsg_add_u32(b, "attn_up_x100", self->attn.up * 100);
|
||||
blobmsg_add_u32(b, "attn_down_x100", self->attn.down * 100);
|
||||
|
||||
// add bearer data (currently only one bearer)
|
||||
array = blobmsg_open_array(b, "bearers");
|
||||
obj = blobmsg_open_table(b, NULL);
|
||||
blobmsg_add_u32(b, "max_rate_up", bearer->max_rate.up);
|
||||
blobmsg_add_u32(b, "max_rate_down", bearer->max_rate.down);
|
||||
blobmsg_add_u32(b, "rate_up", bearer->rate.up);
|
||||
blobmsg_add_u32(b, "rate_down", bearer->rate.down);
|
||||
blobmsg_add_u32(b, "msgc_up", bearer->msgc.up);
|
||||
blobmsg_add_u32(b, "msgc_down", bearer->msgc.down);
|
||||
blobmsg_add_u32(b, "b_down", bearer->b.down);
|
||||
blobmsg_add_u32(b, "b_up", bearer->b.up);
|
||||
blobmsg_add_u32(b, "m_down", bearer->m.down);
|
||||
blobmsg_add_u32(b, "m_up", bearer->m.up);
|
||||
blobmsg_add_u32(b, "t_down", bearer->t.down);
|
||||
blobmsg_add_u32(b, "t_up", bearer->t.up);
|
||||
blobmsg_add_u32(b, "r_down", bearer->r.down);
|
||||
blobmsg_add_u32(b, "r_up", bearer->r.up);
|
||||
blobmsg_add_u32(b, "s_down_x10000", bearer->s.down * 10000);
|
||||
blobmsg_add_u32(b, "s_up_x10000", bearer->s.up * 10000);
|
||||
blobmsg_add_u32(b, "l_down", bearer->l.down);
|
||||
blobmsg_add_u32(b, "l_up", bearer->l.up);
|
||||
blobmsg_add_u32(b, "d_down", bearer->d.down);
|
||||
blobmsg_add_u32(b, "d_up", bearer->d.up);
|
||||
blobmsg_add_u32(b, "delay_down", bearer->delay.down);
|
||||
blobmsg_add_u32(b, "delay_up", bearer->delay.up);
|
||||
blobmsg_add_u32(b, "inp_down_x100", bearer->inp.down * 100);
|
||||
blobmsg_add_u32(b, "inp_up_x100", bearer->inp.up * 100);
|
||||
blobmsg_add_u64(b, "sf_down", bearer->sf.down);
|
||||
blobmsg_add_u64(b, "sf_up", bearer->sf.up);
|
||||
blobmsg_add_u64(b, "sf_err_down", bearer->sf_err.down);
|
||||
blobmsg_add_u64(b, "sf_err_up", bearer->sf_err.up);
|
||||
blobmsg_add_u64(b, "rs_down", bearer->rs.down);
|
||||
blobmsg_add_u64(b, "rs_up", bearer->rs.up);
|
||||
blobmsg_add_u64(b, "rs_corr_down", bearer->rs_corr.down);
|
||||
blobmsg_add_u64(b, "rs_corr_up", bearer->rs_corr.up);
|
||||
blobmsg_add_u64(b, "rs_uncorr_down", bearer->rs_uncorr.down);
|
||||
blobmsg_add_u64(b, "rs_uncorr_up", bearer->rs_uncorr.up);
|
||||
blobmsg_add_u64(b, "hec_down", bearer->hec.down);
|
||||
blobmsg_add_u64(b, "hec_up", bearer->hec.up);
|
||||
blobmsg_add_u64(b, "ocd_down", bearer->ocd.down);
|
||||
blobmsg_add_u64(b, "ocd_up", bearer->ocd.up);
|
||||
blobmsg_add_u64(b, "lcd_down", bearer->lcd.down);
|
||||
blobmsg_add_u64(b, "lcd_up", bearer->lcd.up);
|
||||
blobmsg_add_u64(b, "total_cells_down", bearer->total_cells.down);
|
||||
blobmsg_add_u64(b, "total_cells_up", bearer->total_cells.up);
|
||||
blobmsg_add_u64(b, "data_cells_down", bearer->data_cells.down);
|
||||
blobmsg_add_u64(b, "data_cells_up", bearer->data_cells.up);
|
||||
blobmsg_add_u64(b, "bit_errors_down", bearer->bit_errors.down);
|
||||
blobmsg_add_u64(b, "bit_errors_up", bearer->bit_errors.up);
|
||||
blobmsg_close_table(b, obj);
|
||||
blobmsg_close_array(b, array);
|
||||
|
||||
// add counter data (currently only totals)
|
||||
//counter = &self->counters[DSLSTATS_COUNTER_TOTALS];
|
||||
array = blobmsg_open_table(b, "counters");
|
||||
obj = blobmsg_open_table(b, "totals");
|
||||
blobmsg_add_u64(b, "fec_down", counter->fec.down);
|
||||
blobmsg_add_u64(b, "fec_up", counter->fec.up);
|
||||
blobmsg_add_u64(b, "crc_down", counter->crc.down);
|
||||
blobmsg_add_u64(b, "crc_up", counter->crc.up);
|
||||
blobmsg_add_u64(b, "es_down", counter->es.down);
|
||||
blobmsg_add_u64(b, "es_up", counter->es.up);
|
||||
blobmsg_add_u64(b, "ses_down", counter->ses.down);
|
||||
blobmsg_add_u64(b, "ses_up", counter->ses.up);
|
||||
blobmsg_add_u64(b, "uas_down", counter->uas.down);
|
||||
blobmsg_add_u64(b, "uas_up", counter->uas.up);
|
||||
blobmsg_close_table(b, obj);
|
||||
blobmsg_close_array(b, array);
|
||||
|
||||
blobmsg_close_table(b, t);
|
||||
}
|
||||
|
||||
|
||||
int dslstats_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg){
|
||||
static struct blob_buf bb;
|
||||
static struct dsl_stats dslstats;
|
||||
|
||||
dslstats_init(&dslstats);
|
||||
blob_buf_init(&bb, 0);
|
||||
|
||||
dslstats_load(&dslstats);
|
||||
dslstats_to_blob_buffer(&dslstats, &bb);
|
||||
|
||||
ubus_send_reply(ctx, req, bb.head);
|
||||
|
||||
dslstats_free(&dslstats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* dslstats -- collects adsl information for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: martin.schroder@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum {
|
||||
DSLSTATS_BEARER_0 = 0,
|
||||
DSLSTATS_BEARER_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
DSLSTATS_COUNTER_TOTALS,
|
||||
DSLSTATS_COUNTER_CURRENT_15,
|
||||
DSLSTATS_COUNTER_PREVIOUS_15,
|
||||
DSLSTATS_COUNTER_CURRENT_DAY,
|
||||
DSLSTATS_COUNTER_PREVIOUS_DAY,
|
||||
DSLSTATS_COUNTER_SINCE_LINK,
|
||||
DSLSTATS_COUNTER_COUNT
|
||||
};
|
||||
|
||||
typedef struct { double up; double down; } UpDown;
|
||||
typedef struct dsl_bearer {
|
||||
|
||||
UpDown max_rate;
|
||||
UpDown rate;
|
||||
UpDown msgc;
|
||||
UpDown b,m,t,r,s,l,d;
|
||||
UpDown delay;
|
||||
UpDown inp;
|
||||
UpDown sf, sf_err;
|
||||
UpDown rs, rs_corr, rs_uncorr;
|
||||
UpDown hec, ocd, lcd;
|
||||
UpDown total_cells, data_cells, bit_errors;
|
||||
|
||||
} DSLBearer;
|
||||
|
||||
typedef struct dsl_counters {
|
||||
UpDown es, ses, uas;
|
||||
UpDown fec, crc;
|
||||
} DSLCounters;
|
||||
|
||||
typedef struct dsl_stats {
|
||||
char mode[64];
|
||||
char traffic[64];
|
||||
char status[64];
|
||||
char link_power_state[64];
|
||||
char line_status[64];
|
||||
char vdsl2_profile[64];
|
||||
UpDown trellis;
|
||||
UpDown snr;
|
||||
UpDown pwr;
|
||||
UpDown attn;
|
||||
DSLBearer bearers[DSLSTATS_BEARER_COUNT];
|
||||
DSLCounters counters[DSLSTATS_COUNTER_COUNT];
|
||||
} DSLStats;
|
||||
|
||||
void dslstats_init(struct dsl_stats *self);
|
||||
void dslstats_load(struct dsl_stats *self);
|
||||
void dslstats_to_blob_buffer(struct dsl_stats *self, struct blob_buf *b);
|
||||
int dslstats_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* dumper -- collects router device and system info for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
struct uci_context *db_ctx;
|
||||
static bool dbLoaded = false;
|
||||
static struct uci_ptr ptr;
|
||||
|
||||
void
|
||||
init_db_hw_config(void)
|
||||
{
|
||||
db_ctx = uci_alloc_context();
|
||||
uci_set_confdir(db_ctx, "/lib/db/config/");
|
||||
if(uci_load(db_ctx, "hw", NULL) == UCI_OK)
|
||||
dbLoaded = true;
|
||||
}
|
||||
|
||||
static void
|
||||
get_db_hw_value(char *opt, char **val)
|
||||
{
|
||||
memset(&ptr, 0, sizeof(ptr));
|
||||
ptr.package = "hw";
|
||||
ptr.section = "board";
|
||||
ptr.value = NULL;
|
||||
|
||||
*val = "";
|
||||
|
||||
if (!dbLoaded)
|
||||
return;
|
||||
|
||||
ptr.option = opt;
|
||||
if (uci_lookup_ptr(db_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return;
|
||||
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return;
|
||||
|
||||
if(!ptr.o->v.string)
|
||||
return;
|
||||
|
||||
*val = ptr.o->v.string;
|
||||
}
|
||||
|
||||
void
|
||||
get_jif_val(jiffy_counts_t *p_jif)
|
||||
{
|
||||
FILE *file;
|
||||
char line[128];
|
||||
int ret;
|
||||
|
||||
if ((file = fopen("/proc/stat", "r"))) {
|
||||
while(fgets(line, sizeof(line), file) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
ret = sscanf(line, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle,
|
||||
&p_jif->iowait, &p_jif->irq, &p_jif->softirq, &p_jif->steal);
|
||||
|
||||
if (ret >= 4) {
|
||||
p_jif->total = p_jif->usr + p_jif->nic + p_jif->sys + p_jif->idle
|
||||
+ p_jif->iowait + p_jif->irq + p_jif->softirq + p_jif->steal;
|
||||
|
||||
p_jif->busy = p_jif->total - p_jif->idle - p_jif->iowait;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_specs(Spec *spec)
|
||||
{
|
||||
char *val;
|
||||
|
||||
spec->wifi = false;
|
||||
spec->adsl = false;
|
||||
spec->vdsl = false;
|
||||
spec->voice = false;
|
||||
spec->dect = false;
|
||||
spec->vports = 0;
|
||||
spec->eports = 0;
|
||||
|
||||
get_db_hw_value("hasWifi", &val);
|
||||
if (!strcmp(val, "1")) spec->wifi = true;
|
||||
|
||||
get_db_hw_value("hasAdsl", &val);
|
||||
if (!strcmp(val, "1")) spec->adsl = true;
|
||||
|
||||
get_db_hw_value("hasVdsl", &val);
|
||||
if (!strcmp(val, "1")) spec->vdsl = true;
|
||||
|
||||
get_db_hw_value("hasVoice", &val);
|
||||
if (!strcmp(val, "1")) spec->voice = true;
|
||||
|
||||
get_db_hw_value("hasDect", &val);
|
||||
if (!strcmp(val, "1")) spec->dect = true;
|
||||
|
||||
get_db_hw_value("VoicePorts", &val);
|
||||
if (spec->voice) spec->vports = atoi(val);
|
||||
|
||||
get_db_hw_value("ethernetPorts", &val);
|
||||
spec->eports = atoi(val);
|
||||
}
|
||||
|
||||
void
|
||||
dump_keys(Key *keys)
|
||||
{
|
||||
get_db_hw_value("authKey", &keys->auth);
|
||||
get_db_hw_value("desKey", &keys->des);
|
||||
get_db_hw_value("wpaKey", &keys->wpa);
|
||||
}
|
||||
|
||||
void
|
||||
dump_static_router_info(Router *router)
|
||||
{
|
||||
get_db_hw_value("boardId", &router->boardid);
|
||||
get_db_hw_value("hardwareVersion", &router->hardware);
|
||||
get_db_hw_value("routerModel", &router->model);
|
||||
get_db_hw_value("iopVersion", &router->firmware);
|
||||
get_db_hw_value("brcmVersion", &router->brcmver);
|
||||
get_db_hw_value("filesystem", &router->filesystem);
|
||||
get_db_hw_value("socModel", &router->socmod);
|
||||
get_db_hw_value("socRevision", &router->socrev);
|
||||
get_db_hw_value("cfeVersion", &router->cfever);
|
||||
get_db_hw_value("kernelVersion", &router->kernel);
|
||||
get_db_hw_value("BaseMacAddr", &router->basemac);
|
||||
get_db_hw_value("serialNumber", &router->serialno);
|
||||
}
|
||||
|
||||
void
|
||||
dump_hostname(Router *router)
|
||||
{
|
||||
FILE *file;
|
||||
char line[64];
|
||||
char name[64];
|
||||
|
||||
strcpy(router->name, "");
|
||||
if ((file = fopen("/proc/sys/kernel/hostname", "r"))) {
|
||||
while(fgets(line, sizeof(line), file) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
if (sscanf(line, "%s", name) == 1)
|
||||
break;
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
strcpy(router->name, name);
|
||||
}
|
||||
|
||||
void
|
||||
dump_sysinfo(Router *router, Memory *memory)
|
||||
{
|
||||
struct sysinfo sinfo;
|
||||
long int seconds;
|
||||
int days, hours, minutes;
|
||||
|
||||
if (sysinfo(&sinfo) == 0) {
|
||||
seconds = sinfo.uptime;
|
||||
days = seconds / (60 * 60 * 24);
|
||||
seconds -= days * (60 * 60 * 24);
|
||||
hours = seconds / (60 * 60);
|
||||
seconds -= hours * (60 * 60);
|
||||
minutes = seconds / 60;
|
||||
seconds -= minutes * 60;
|
||||
sprintf(router->uptime, "%dd %dh %dm %lds", days, hours, minutes, seconds);
|
||||
|
||||
router->procs = sinfo.procs;
|
||||
|
||||
memory->total = (sinfo.totalram / 1024);
|
||||
memory->free = (sinfo.freeram / 1024);
|
||||
memory->used = ((sinfo.totalram - sinfo.freeram) / 1024);
|
||||
memory->shared = (sinfo.sharedram / 1024);
|
||||
memory->buffers = (sinfo.bufferram / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_cpuinfo(Router *router, jiffy_counts_t *prev_jif, jiffy_counts_t *cur_jif)
|
||||
{
|
||||
unsigned total_diff, cpu;
|
||||
|
||||
total_diff = (unsigned)(cur_jif->total - prev_jif->total);
|
||||
|
||||
if (total_diff == 0) total_diff = 1;
|
||||
|
||||
cpu = 100 * (unsigned)(cur_jif->usr - prev_jif->usr) / total_diff;
|
||||
|
||||
router->cpu = cpu;
|
||||
}
|
||||
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
#include "igmp.h"
|
||||
|
||||
char* convert_to_ipaddr(int ip)
|
||||
{
|
||||
struct in_addr ip_addr;
|
||||
ip_addr.s_addr = ip;
|
||||
return inet_ntoa(ip_addr);
|
||||
}
|
||||
|
||||
char* single_space(char* str){
|
||||
char *from, *to;
|
||||
int space = 0;
|
||||
from = to = str;
|
||||
while(1) {
|
||||
if(space && *from == ' ' && to[-1] == ' ') {
|
||||
++from;
|
||||
} else {
|
||||
space = (*from == ' ') ? 1 : 0;
|
||||
*to++ = *from++;
|
||||
if(!to[-1])
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int igmp_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg) {
|
||||
|
||||
struct blob_buf bb;
|
||||
IGMPtable table[MAX_IGMP_ENTRY];
|
||||
FILE *snptable;
|
||||
char line[256];
|
||||
int idx = 0;
|
||||
void *t, *a;
|
||||
|
||||
if ((snptable = fopen("/proc/net/igmp_snooping", "r"))) {
|
||||
while(fgets(line, sizeof(line), snptable) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
table[idx].exists = false;
|
||||
if(sscanf(single_space(line),"%s %s %s %s %x %x %x %s %x %x %x %d %x %d",
|
||||
table[idx].bridge, table[idx].device, table[idx].srcdev, table[idx].tags, &(table[idx].lantci), &(table[idx].wantci),
|
||||
&(table[idx].group), table[idx].mode, &(table[idx].RxGroup), &(table[idx].source), &(table[idx].reporter),
|
||||
&(table[idx].timeout), &(table[idx].Index), &(table[idx].ExcludPt)) == 14)
|
||||
{
|
||||
table[idx].exists = true;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
fclose(snptable);
|
||||
} else
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
blob_buf_init(&bb, 0);
|
||||
|
||||
a = blobmsg_open_array(&bb, "table");
|
||||
for (idx = 0; idx < MAX_IGMP_ENTRY; idx++) {
|
||||
if (!table[idx].exists)
|
||||
break;
|
||||
t = blobmsg_open_table(&bb, NULL);
|
||||
blobmsg_add_string(&bb,"bridge", table[idx].bridge);
|
||||
blobmsg_add_string(&bb,"device", table[idx].device);
|
||||
blobmsg_add_string(&bb,"srcdev", table[idx].srcdev);
|
||||
blobmsg_add_string(&bb,"tags", table[idx].tags);
|
||||
blobmsg_add_u32(&bb,"lantci", table[idx].lantci);
|
||||
blobmsg_add_u32(&bb,"wantci", table[idx].wantci);
|
||||
blobmsg_add_string(&bb,"group", convert_to_ipaddr(table[idx].group));
|
||||
blobmsg_add_string(&bb,"mode", table[idx].mode);
|
||||
blobmsg_add_string(&bb,"rxgroup", convert_to_ipaddr(table[idx].RxGroup));
|
||||
blobmsg_add_string(&bb,"source", convert_to_ipaddr(table[idx].source));
|
||||
blobmsg_add_string(&bb,"reporter", convert_to_ipaddr(table[idx].reporter));
|
||||
blobmsg_add_u32(&bb,"timeout", table[idx].timeout);
|
||||
blobmsg_add_u32(&bb,"index", table[idx].Index);
|
||||
blobmsg_add_u32(&bb,"excludpt", table[idx].ExcludPt);
|
||||
blobmsg_close_table(&bb, t);
|
||||
}
|
||||
blobmsg_close_array(&bb, a);
|
||||
|
||||
ubus_send_reply(ctx, req, bb.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* igmp.h
|
||||
*
|
||||
* Created on: May 5, 2015
|
||||
* Author: stefan
|
||||
*/
|
||||
|
||||
#ifndef IGMP_H_
|
||||
#define IGMP_H_
|
||||
#ifndef NULL
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
|
||||
#define MAX_IGMP_ENTRY 128
|
||||
|
||||
int igmp_rpc(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
|
||||
|
||||
typedef struct igmp_table {
|
||||
bool exists;
|
||||
char bridge[32];
|
||||
char device[32];
|
||||
char srcdev[32];
|
||||
char tags[32];
|
||||
int lantci;
|
||||
int wantci;
|
||||
int group;
|
||||
char mode[32];
|
||||
int RxGroup;
|
||||
int source;
|
||||
int reporter;
|
||||
int timeout;
|
||||
int Index;
|
||||
int ExcludPt;
|
||||
|
||||
}IGMPtable;
|
||||
#endif /* IGMP_H_ */
|
||||
|
|
@ -1,507 +0,0 @@
|
|||
/*
|
||||
* ndisc.c - ICMPv6 neighbour discovery command line tool
|
||||
*
|
||||
* Author: Rémi Denis-Courmont
|
||||
* questd port: Sukru Senli sukru.senli@inteno.se
|
||||
*
|
||||
* Copyright © 2004-2007 Rémi Denis-Courmont.
|
||||
* This program is free software: you can redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, versions 2 of the license.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* div() */
|
||||
#include <inttypes.h> /* uint8_t */
|
||||
#include <limits.h> /* UINT_MAX */
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <errno.h> /* EMFILE */
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h> /* close() */
|
||||
#include <time.h> /* clock_gettime() */
|
||||
#include <poll.h> /* poll() */
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/times.h> /* times() fallback */
|
||||
|
||||
#include <netdb.h> /* getaddrinfo() */
|
||||
#include <arpa/inet.h> /* inet_ntop() */
|
||||
#include <net/if.h> /* if_nametoindex() */
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#ifndef IPV6_RECVHOPLIMIT
|
||||
/* Using obsolete RFC 2292 instead of RFC 3542 */
|
||||
# define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
|
||||
#endif
|
||||
|
||||
#ifndef AI_IDN
|
||||
# define AI_IDN 0
|
||||
#endif
|
||||
|
||||
enum ndisc_flags
|
||||
{
|
||||
NDISC_VERBOSE1=0x1,
|
||||
NDISC_VERBOSE2=0x2,
|
||||
NDISC_VERBOSE3=0x3,
|
||||
NDISC_VERBOSE =0x3,
|
||||
NDISC_NUMERIC =0x4,
|
||||
NDISC_SINGLE =0x8,
|
||||
};
|
||||
|
||||
#if defined (CLOCK_HIGHRES) && !defined (CLOCK_MONOTONIC)
|
||||
# define CLOCK_MONOTONIC CLOCK_HIGHRES
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
mono_gettime (struct timespec *ts)
|
||||
{
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
if (clock_gettime (CLOCK_MONOTONIC, ts))
|
||||
#endif
|
||||
{
|
||||
static long freq = 0;
|
||||
if (freq == 0)
|
||||
freq = sysconf (_SC_CLK_TCK);
|
||||
|
||||
struct tms dummy;
|
||||
clock_t t = times (&dummy);
|
||||
ts->tv_sec = t / freq;
|
||||
ts->tv_nsec = (t % freq) * (1000000000 / freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getipv6byname (const char *name, const char *ifname, int numeric, struct sockaddr_in6 *addr)
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
hints.ai_family = PF_INET6;
|
||||
hints.ai_socktype = SOCK_DGRAM; /* dummy */
|
||||
hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
|
||||
|
||||
int val = getaddrinfo (name, NULL, &hints, &res);
|
||||
if (val)
|
||||
{
|
||||
fprintf (stderr, "%s: %s\n", name, gai_strerror (val));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (addr, res->ai_addr, sizeof (struct sockaddr_in6));
|
||||
freeaddrinfo (res);
|
||||
|
||||
val = if_nametoindex (ifname);
|
||||
if (val == 0)
|
||||
{
|
||||
perror (ifname);
|
||||
return -1;
|
||||
}
|
||||
addr->sin6_scope_id = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
sethoplimit (int fd, int value)
|
||||
{
|
||||
return (setsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&value, sizeof (value))
|
||||
|| setsockopt (fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
&value, sizeof (value))) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static char MACADDR[24];
|
||||
|
||||
void
|
||||
clear_macaddr() {
|
||||
memset(MACADDR, '\0', sizeof(MACADDR));
|
||||
}
|
||||
|
||||
char *
|
||||
get_macaddr()
|
||||
{
|
||||
return MACADDR;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
printmacaddress (const uint8_t *ptr, size_t len)
|
||||
{
|
||||
char mac[4];
|
||||
while (len > 1)
|
||||
{
|
||||
sprintf(mac, "%02X:", *ptr);
|
||||
strcat(MACADDR, mac);
|
||||
ptr++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len == 1) {
|
||||
sprintf(mac, "%02X", *ptr);
|
||||
strcat(MACADDR, mac);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# ifdef __linux__
|
||||
# include <sys/ioctl.h>
|
||||
# endif
|
||||
|
||||
static int
|
||||
getmacaddress (const char *ifname, uint8_t *addr)
|
||||
{
|
||||
# ifdef SIOCGIFHWADDR
|
||||
struct ifreq req;
|
||||
memset (&req, 0, sizeof (req));
|
||||
|
||||
if (((unsigned)strlen (ifname)) >= (unsigned)IFNAMSIZ)
|
||||
return -1; /* buffer overflow = local root */
|
||||
strcpy (req.ifr_name, ifname);
|
||||
|
||||
int fd = socket (AF_INET6, SOCK_DGRAM, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
if (ioctl (fd, SIOCGIFHWADDR, &req))
|
||||
{
|
||||
perror (ifname);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
close (fd);
|
||||
|
||||
memcpy (addr, req.ifr_hwaddr.sa_data, 6);
|
||||
return 0;
|
||||
# else
|
||||
(void)ifname;
|
||||
(void)addr;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t nd_type_advert = ND_NEIGHBOR_ADVERT;
|
||||
static const unsigned nd_delay_ms = 1000;
|
||||
static const unsigned ndisc_default = NDISC_VERBOSE1 | NDISC_SINGLE;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct nd_neighbor_solicit hdr;
|
||||
struct nd_opt_hdr opt;
|
||||
uint8_t hw_addr[6];
|
||||
} solicit_packet;
|
||||
|
||||
|
||||
static ssize_t
|
||||
buildsol (solicit_packet *ns, struct sockaddr_in6 *tgt, const char *ifname)
|
||||
{
|
||||
/* builds ICMPv6 Neighbor Solicitation packet */
|
||||
ns->hdr.nd_ns_type = ND_NEIGHBOR_SOLICIT;
|
||||
ns->hdr.nd_ns_code = 0;
|
||||
ns->hdr.nd_ns_cksum = 0; /* computed by the kernel */
|
||||
ns->hdr.nd_ns_reserved = 0;
|
||||
memcpy (&ns->hdr.nd_ns_target, &tgt->sin6_addr, 16);
|
||||
|
||||
/* determines actual multicast destination address */
|
||||
memcpy (tgt->sin6_addr.s6_addr, "\xff\x02\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x01\xff", 13);
|
||||
|
||||
/* gets our own interface's link-layer address (MAC) */
|
||||
if (getmacaddress (ifname, ns->hw_addr))
|
||||
return sizeof (ns->hdr);
|
||||
|
||||
ns->opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
ns->opt.nd_opt_len = 1; /* 8 bytes */
|
||||
return sizeof (*ns);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parseadv (const uint8_t *buf, size_t len, const struct sockaddr_in6 *tgt, bool verbose)
|
||||
{
|
||||
const struct nd_neighbor_advert *na =
|
||||
(const struct nd_neighbor_advert *)buf;
|
||||
const uint8_t *ptr;
|
||||
|
||||
/* checks if the packet is a Neighbor Advertisement, and
|
||||
* if the target IPv6 address is the right one */
|
||||
if ((len < sizeof (struct nd_neighbor_advert))
|
||||
|| (na->nd_na_type != ND_NEIGHBOR_ADVERT)
|
||||
|| (na->nd_na_code != 0)
|
||||
|| memcmp (&na->nd_na_target, &tgt->sin6_addr, 16))
|
||||
return -1;
|
||||
|
||||
len -= sizeof (struct nd_neighbor_advert);
|
||||
|
||||
/* looks for Target Link-layer address option */
|
||||
ptr = buf + sizeof (struct nd_neighbor_advert);
|
||||
|
||||
while (len >= 8)
|
||||
{
|
||||
uint16_t optlen;
|
||||
|
||||
optlen = ((uint16_t)(ptr[1])) << 3;
|
||||
if (optlen == 0)
|
||||
break; /* invalid length */
|
||||
|
||||
if (len < optlen) /* length > remaining bytes */
|
||||
break;
|
||||
len -= optlen;
|
||||
|
||||
|
||||
/* skips unrecognized option */
|
||||
if (ptr[0] != ND_OPT_TARGET_LINKADDR)
|
||||
{
|
||||
ptr += optlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Found! displays link-layer address */
|
||||
ptr += 2;
|
||||
optlen -= 2;
|
||||
if (verbose)
|
||||
fputs ("Target link-layer address: ", stdout);
|
||||
|
||||
printmacaddress (ptr, optlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
static ssize_t
|
||||
recvfromLL (int fd, void *buf, size_t len, int flags, struct sockaddr_in6 *addr)
|
||||
{
|
||||
char cbuf[CMSG_SPACE (sizeof (int))];
|
||||
struct iovec iov =
|
||||
{
|
||||
.iov_base = buf,
|
||||
.iov_len = len
|
||||
};
|
||||
struct msghdr hdr =
|
||||
{
|
||||
.msg_name = addr,
|
||||
.msg_namelen = sizeof (*addr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cbuf,
|
||||
.msg_controllen = sizeof (cbuf)
|
||||
};
|
||||
|
||||
ssize_t val = recvmsg (fd, &hdr, flags);
|
||||
if (val == -1)
|
||||
return val;
|
||||
|
||||
/* ensures the hop limit is 255 */
|
||||
struct cmsghdr *cmsg;
|
||||
for (cmsg = CMSG_FIRSTHDR (&hdr);
|
||||
cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR (&hdr, cmsg))
|
||||
{
|
||||
if ((cmsg->cmsg_level == IPPROTO_IPV6)
|
||||
&& (cmsg->cmsg_type == IPV6_HOPLIMIT))
|
||||
{
|
||||
if (255 != *(int *)CMSG_DATA (cmsg))
|
||||
{
|
||||
// pretend to be a spurious wake-up
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
recvadv (int fd, const struct sockaddr_in6 *tgt, unsigned wait_ms, unsigned flags)
|
||||
{
|
||||
struct timespec now, end;
|
||||
unsigned responses = 0;
|
||||
|
||||
/* computes deadline time */
|
||||
mono_gettime (&now);
|
||||
{
|
||||
div_t d;
|
||||
|
||||
d = div (wait_ms, 1000);
|
||||
end.tv_sec = now.tv_sec + d.quot;
|
||||
end.tv_nsec = now.tv_nsec + (d.rem * 1000000);
|
||||
}
|
||||
|
||||
/* receive loop */
|
||||
for (;;)
|
||||
{
|
||||
/* waits for reply until deadline */
|
||||
ssize_t val = 0;
|
||||
if (end.tv_sec >= now.tv_sec)
|
||||
{
|
||||
val = (end.tv_sec - now.tv_sec) * 1000
|
||||
+ (int)((end.tv_nsec - now.tv_nsec) / 1000000);
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
}
|
||||
|
||||
val = poll (&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, val);
|
||||
if (val < 0)
|
||||
break;
|
||||
|
||||
if (val == 0)
|
||||
return responses;
|
||||
|
||||
/* receives an ICMPv6 packet */
|
||||
// TODO: use interface MTU as buffer size
|
||||
union
|
||||
{
|
||||
uint8_t b[1460];
|
||||
uint64_t align;
|
||||
} buf;
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
val = recvfromLL (fd, &buf, sizeof (buf), MSG_DONTWAIT, &addr);
|
||||
if (val == -1)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
perror ("Receiving ICMPv6 packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ensures the response came through the right interface */
|
||||
if (addr.sin6_scope_id
|
||||
&& (addr.sin6_scope_id != tgt->sin6_scope_id))
|
||||
continue;
|
||||
|
||||
if (parseadv (buf.b, val, tgt, (flags & NDISC_VERBOSE) != 0) == 0)
|
||||
{
|
||||
if (flags & NDISC_VERBOSE)
|
||||
{
|
||||
char str[INET6_ADDRSTRLEN];
|
||||
|
||||
if (inet_ntop (AF_INET6, &addr.sin6_addr, str,
|
||||
sizeof (str)) != NULL)
|
||||
printf (" from %s\n", str);
|
||||
}
|
||||
|
||||
if (responses < INT_MAX)
|
||||
responses++;
|
||||
|
||||
if (flags & NDISC_SINGLE)
|
||||
return 1 /* = responses */;
|
||||
}
|
||||
mono_gettime (&now);
|
||||
}
|
||||
|
||||
return -1; /* error */
|
||||
}
|
||||
|
||||
bool
|
||||
ndisc (const char *name, const char *ifname, unsigned flags, unsigned retry, unsigned wait_ms)
|
||||
{
|
||||
struct sockaddr_in6 tgt;
|
||||
|
||||
int fd = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
perror ("Raw IPv6 socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* set ICMPv6 filter */
|
||||
{
|
||||
struct icmp6_filter f;
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL (&f);
|
||||
ICMP6_FILTER_SETPASS (nd_type_advert, &f);
|
||||
setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER, &f, sizeof (f));
|
||||
}
|
||||
|
||||
setsockopt (fd, SOL_SOCKET, SO_DONTROUTE, &(int){ 1 }, sizeof (int));
|
||||
|
||||
/* sets Hop-by-hop limit to 255 */
|
||||
sethoplimit (fd, 255);
|
||||
setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
|
||||
&(int){ 1 }, sizeof (int));
|
||||
|
||||
/* resolves target's IPv6 address */
|
||||
if (getipv6byname (name, ifname, (flags & NDISC_NUMERIC) ? 1 : 0, &tgt))
|
||||
goto error;
|
||||
else
|
||||
{
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop (AF_INET6, &tgt.sin6_addr, s, sizeof (s));
|
||||
if (flags & NDISC_VERBOSE)
|
||||
printf ("Soliciting %s (%s) on %s...\n", name, s, ifname);
|
||||
}
|
||||
|
||||
{
|
||||
solicit_packet packet;
|
||||
struct sockaddr_in6 dst;
|
||||
ssize_t plen;
|
||||
|
||||
memcpy (&dst, &tgt, sizeof (dst));
|
||||
plen = buildsol (&packet, &dst, ifname);
|
||||
if (plen == -1)
|
||||
goto error;
|
||||
|
||||
while (retry > 0)
|
||||
{
|
||||
/* sends a Solitication */
|
||||
if (sendto (fd, &packet, plen, 0,
|
||||
(const struct sockaddr *)&dst,
|
||||
sizeof (dst)) != plen)
|
||||
{
|
||||
//perror ("Sending ICMPv6 packet");
|
||||
goto error;
|
||||
}
|
||||
retry--;
|
||||
|
||||
/* receives an Advertisement */
|
||||
ssize_t val = recvadv (fd, &tgt, wait_ms, flags);
|
||||
if (val > 0)
|
||||
{
|
||||
close (fd);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (val == 0)
|
||||
{
|
||||
if (flags & NDISC_VERBOSE)
|
||||
puts ("Timed out.");
|
||||
}
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
close (fd);
|
||||
if (flags & NDISC_VERBOSE)
|
||||
puts ("No response.");
|
||||
return false;
|
||||
|
||||
error:
|
||||
close (fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
* port -- collects port info for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
#include <linux/if_bridge.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define CHUNK 128
|
||||
|
||||
static long
|
||||
get_port_stat(char *dev, char *stat)
|
||||
{
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
sprintf(cmnd, "/sys/class/net/%s/statistics/%s", dev, stat);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
return atoi(result);
|
||||
}
|
||||
|
||||
void
|
||||
get_port_stats(Port *port)
|
||||
{
|
||||
port->stat.rx_bytes = get_port_stat(port->device, "rx_bytes");
|
||||
port->stat.rx_packets = get_port_stat(port->device, "rx_packets");
|
||||
port->stat.rx_errors = get_port_stat(port->device, "rx_errors");
|
||||
port->stat.tx_bytes = get_port_stat(port->device, "tx_bytes");
|
||||
port->stat.tx_packets =get_port_stat(port->device, "tx_packets");
|
||||
port->stat.tx_errors = get_port_stat(port->device, "tx_errors");
|
||||
}
|
||||
|
||||
void
|
||||
get_port_name(Port *port)
|
||||
{
|
||||
FILE *in;
|
||||
char buf[32];
|
||||
char cmnd[80];
|
||||
|
||||
sprintf(cmnd, ". /lib/network/config.sh && interfacename %s 2>/dev/null", port->device);
|
||||
if (!(in = popen(cmnd, "r")))
|
||||
exit(1);
|
||||
|
||||
fgets(buf, sizeof(buf), in);
|
||||
pclose(in);
|
||||
remove_newline(buf);
|
||||
strcpy(port->name, buf);
|
||||
|
||||
memset(cmnd, '\0', sizeof(cmnd));
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
|
||||
if(!strncmp(port->device, "wl", 2)) {
|
||||
sprintf(cmnd, "wlctl -i %s ssid | awk '{print$3}' | sed 's/\"//g' 2>/dev/null", port->device);
|
||||
if (!(in = popen(cmnd, "r")))
|
||||
exit(1);
|
||||
|
||||
fgets(buf, sizeof(buf), in);
|
||||
pclose(in);
|
||||
remove_newline(buf);
|
||||
strcpy(port->ssid, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
get_bridge_ports(char *bridge, char **ports)
|
||||
{
|
||||
FILE *in;
|
||||
char buf[64];
|
||||
char cmnd[128];
|
||||
|
||||
*ports = "";
|
||||
|
||||
sprintf(cmnd, "brctl showbr %s | awk '{print$NF}' | grep -v interfaces | tr '\n' ' '", bridge);
|
||||
if (!(in = popen(cmnd, "r")))
|
||||
exit(1);
|
||||
|
||||
fgets(buf, sizeof(buf), in);
|
||||
pclose(in);
|
||||
*ports = strdup(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_fdbs(const void *_f0, const void *_f1)
|
||||
{
|
||||
const struct fdb_entry *f0 = _f0;
|
||||
const struct fdb_entry *f1 = _f1;
|
||||
|
||||
return memcmp(f0->mac_addr, f1->mac_addr, 6);
|
||||
}
|
||||
|
||||
static inline void
|
||||
copy_fdb(struct fdb_entry *ent, const struct __fdb_entry *f)
|
||||
{
|
||||
memcpy(ent->mac_addr, f->mac_addr, 6);
|
||||
ent->port_no = f->port_no;
|
||||
ent->is_local = f->is_local;
|
||||
}
|
||||
|
||||
static int
|
||||
bridge_read_fdb(const char *bridge, struct fdb_entry *fdbs, unsigned long offset, int num)
|
||||
{
|
||||
FILE *f;
|
||||
int i, n;
|
||||
struct __fdb_entry fe[num];
|
||||
char path[256];
|
||||
|
||||
snprintf(path, 256, "/sys/class/net/%s/brforward", bridge);
|
||||
f = fopen(path, "r");
|
||||
if (f) {
|
||||
fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
|
||||
n = fread(fe, sizeof(struct __fdb_entry), num, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
copy_fdb(fdbs+i, fe+i);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
get_clients_onport(char *bridge, int portno, char **macaddr)
|
||||
{
|
||||
int i, n;
|
||||
struct fdb_entry *fdb = NULL;
|
||||
int offset = 0;
|
||||
char tmpmac[2400];
|
||||
char mac[24];
|
||||
|
||||
*macaddr = "";
|
||||
|
||||
for(;;) {
|
||||
fdb = realloc(fdb, (offset + CHUNK) * sizeof(struct fdb_entry));
|
||||
if (!fdb) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
n = bridge_read_fdb(bridge, fdb+offset, offset, CHUNK);
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "read of forward table failed: %s\n",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
}
|
||||
|
||||
qsort(fdb, offset, sizeof(struct fdb_entry), compare_fdbs);
|
||||
|
||||
for (i = 0; i < offset; i++) {
|
||||
const struct fdb_entry *f = fdb + i;
|
||||
if (f->port_no == portno && !f->is_local) {
|
||||
sprintf(mac, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]);
|
||||
strcat(tmpmac, " ");
|
||||
strcat(tmpmac, mac);
|
||||
}
|
||||
}
|
||||
*macaddr = strdup(tmpmac);
|
||||
|
||||
free(fdb);
|
||||
memset(tmpmac, '\0', sizeof(tmpmac));
|
||||
}
|
||||
2169
questd/src/questd.c
2169
questd/src/questd.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,219 +0,0 @@
|
|||
//#define _GNU_SOURCE
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <uci.h>
|
||||
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/ustream.h>
|
||||
#include <libubox/utils.h>
|
||||
|
||||
#include <libubus.h>
|
||||
|
||||
#include "dslstats.h"
|
||||
#include "igmp.h"
|
||||
|
||||
#define MAX_RADIO 4
|
||||
#define MAX_VIF 8
|
||||
#define MAX_NETWORK 16
|
||||
#define MAX_CLIENT 128
|
||||
#define MAX_PORT 8
|
||||
#define MAX_USB 18
|
||||
|
||||
typedef struct {
|
||||
const char *vif;
|
||||
const char *device;
|
||||
const char *ssid;
|
||||
const char *network;
|
||||
int noise;
|
||||
} Wireless;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *band;
|
||||
int frequency;
|
||||
const char *hwmodes[6];
|
||||
int channels[16];
|
||||
const char *pcid;
|
||||
int bwcaps[4];
|
||||
bool is_ac;
|
||||
} Radio;
|
||||
|
||||
typedef struct {
|
||||
int connum;
|
||||
int idle;
|
||||
int in_network;
|
||||
long tx_bytes;
|
||||
long rx_bytes;
|
||||
int tx_rate;
|
||||
int rx_rate;
|
||||
int snr;
|
||||
} Detail;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
bool local;
|
||||
bool dhcp;
|
||||
char leaseno[24];
|
||||
char macaddr[24];
|
||||
char ipaddr[24];
|
||||
char hostname[64];
|
||||
char network[32];
|
||||
char device[32];
|
||||
bool wireless;
|
||||
char wdev[8];
|
||||
bool connected;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
char macaddr[24];
|
||||
char wdev[8];
|
||||
int snr;
|
||||
} Sta;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
char ip6addr[128];
|
||||
char macaddr[24];
|
||||
char hostname[64];
|
||||
char duid[64];
|
||||
char device[32];
|
||||
bool wireless;
|
||||
char wdev[8];
|
||||
bool connected;
|
||||
} Client6;
|
||||
|
||||
typedef struct {
|
||||
unsigned long rx_bytes;
|
||||
unsigned long rx_packets;
|
||||
unsigned long rx_errors;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_packets;
|
||||
unsigned long tx_errors;
|
||||
} Statistic;
|
||||
|
||||
typedef struct {
|
||||
char name[16];
|
||||
char ssid[32];
|
||||
char device[32];
|
||||
Statistic stat;
|
||||
Client client[MAX_CLIENT];
|
||||
} Port;
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
bool is_lan;
|
||||
const char *name;
|
||||
const char *type;
|
||||
const char *proto;
|
||||
const char *ipaddr;
|
||||
const char *netmask;
|
||||
char ifname[128];
|
||||
Port port[MAX_PORT];
|
||||
bool ports_populated;
|
||||
} Network;
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
char *hardware;
|
||||
char *model;
|
||||
char *boardid;
|
||||
char *firmware;
|
||||
char *brcmver;
|
||||
char *filesystem;
|
||||
char *socmod;
|
||||
char *socrev;
|
||||
char *cfever;
|
||||
char *kernel;
|
||||
char *basemac;
|
||||
char *serialno;
|
||||
char uptime[64];
|
||||
unsigned int procs;
|
||||
unsigned int cpu;
|
||||
} Router;
|
||||
|
||||
typedef struct {
|
||||
unsigned long total;
|
||||
unsigned long used;
|
||||
unsigned long free;
|
||||
unsigned long shared;
|
||||
unsigned long buffers;
|
||||
} Memory;
|
||||
|
||||
typedef struct {
|
||||
char *auth;
|
||||
char *des;
|
||||
char *wpa;
|
||||
} Key;
|
||||
|
||||
typedef struct {
|
||||
bool wifi;
|
||||
bool adsl;
|
||||
bool vdsl;
|
||||
bool voice;
|
||||
bool dect;
|
||||
int vports;
|
||||
int eports;
|
||||
} Spec;
|
||||
|
||||
typedef struct {
|
||||
char mount[64];
|
||||
char product[64];
|
||||
char no[8];
|
||||
char name[8];
|
||||
unsigned long size;
|
||||
char *device;
|
||||
char *vendor;
|
||||
char *serial;
|
||||
char *speed;
|
||||
char *maxchild;
|
||||
} USB;
|
||||
|
||||
typedef struct jiffy_counts_t {
|
||||
unsigned long long usr, nic, sys, idle;
|
||||
unsigned long long iowait, irq, softirq, steal;
|
||||
unsigned long long total;
|
||||
unsigned long long busy;
|
||||
} jiffy_counts_t;
|
||||
|
||||
struct fdb_entry
|
||||
{
|
||||
u_int8_t mac_addr[6];
|
||||
u_int16_t port_no;
|
||||
unsigned char is_local;
|
||||
};
|
||||
|
||||
void recalc_sleep_time(bool calc, int toms);
|
||||
void init_db_hw_config(void);
|
||||
bool arping(char *target, char *device, int toms);
|
||||
void remove_newline(char *buf);
|
||||
void replace_char(char *buf, char a, char b);
|
||||
void runCmd(const char *pFmt, ...);
|
||||
const char *chrCmd(const char *pFmt, ...);
|
||||
void get_jif_val(jiffy_counts_t *p_jif);
|
||||
void dump_keys(Key *keys);
|
||||
void dump_specs(Spec *spec);
|
||||
void dump_static_router_info(Router *router);
|
||||
void dump_hostname(Router *router);
|
||||
void dump_sysinfo(Router *router, Memory *memory);
|
||||
void dump_cpuinfo(Router *router, jiffy_counts_t *prev_jif, jiffy_counts_t *cur_jif);
|
||||
void get_port_name(Port *port);
|
||||
void get_port_stats(Port *port);
|
||||
void get_bridge_ports(char *network, char **ifname);
|
||||
void get_clients_onport(char *bridge, int portno, char **macaddr);
|
||||
void dump_usb_info(USB *usb, char *usbno);
|
||||
void clear_macaddr(void);
|
||||
char *get_macaddr(void);
|
||||
bool ndisc (const char *name, const char *ifname, unsigned flags, unsigned retry, unsigned wait_ms);
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "questd.h"
|
||||
|
||||
void
|
||||
remove_newline(char *buf)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf) - 1;
|
||||
if (buf[len] == '\n')
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
replace_char(char *buf, char a, char b)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (buf[i]) {
|
||||
if (buf[i] == a)
|
||||
buf[i] = b;
|
||||
i++;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
runCmd(const char *pFmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char cmd[256] = {0};
|
||||
int len=0, maxLen;
|
||||
|
||||
maxLen = sizeof(cmd);
|
||||
|
||||
va_start(ap, pFmt);
|
||||
|
||||
if (len < maxLen)
|
||||
{
|
||||
maxLen -= len;
|
||||
vsnprintf(&cmd[len], maxLen, pFmt, ap);
|
||||
}
|
||||
|
||||
system(cmd);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
const char*
|
||||
chrCmd(const char *pFmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char cmd[256] = {0};
|
||||
int len=0, maxLen;
|
||||
|
||||
maxLen = sizeof(cmd);
|
||||
|
||||
va_start(ap, pFmt);
|
||||
|
||||
if (len < maxLen)
|
||||
{
|
||||
maxLen -= len;
|
||||
vsnprintf(&cmd[len], maxLen, pFmt, ap);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
FILE *pipe = 0;
|
||||
static char buffer[128] = {0};
|
||||
if ((pipe = popen(cmd, "r"))){
|
||||
fgets(buffer, sizeof(buffer), pipe);
|
||||
pclose(pipe);
|
||||
|
||||
remove_newline(buffer);
|
||||
if (strlen(buffer))
|
||||
return (const char*)buffer;
|
||||
else
|
||||
return "";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
131
questd/src/usb.c
131
questd/src/usb.c
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* usb -- collects usb info for questd
|
||||
*
|
||||
* Copyright (C) 2012-2013 Inteno Broadband Technology AB. All rights reserved.
|
||||
*
|
||||
* Author: sukru.senli@inteno.se
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "questd.h"
|
||||
#include <string.h>
|
||||
|
||||
static void
|
||||
remove_space(char *buf)
|
||||
{
|
||||
char *newbuf = malloc(strlen(buf)+1);
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
while (buf[i]) {
|
||||
newbuf[j] = buf[i];
|
||||
if (buf[i] != ' ')
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
newbuf[j] = '\0';
|
||||
strcpy(buf, newbuf);
|
||||
free(newbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
get_usb_infos(char **val, char *usbno, char *info) {
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
*val = "";
|
||||
|
||||
sprintf(cmnd, "/sys/bus/usb/devices/%s/%s", usbno, info);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
remove_newline(result);
|
||||
fclose(in);
|
||||
*val = strdup(result);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_usb_device(char **val, char *mount) {
|
||||
FILE *mounts;
|
||||
char line[128];
|
||||
char dev[16];
|
||||
char mnt[64];
|
||||
|
||||
*val = NULL;
|
||||
|
||||
if ((mounts = fopen("/var/usbmounts", "r"))) {
|
||||
while(fgets(line, sizeof(line), mounts) != NULL)
|
||||
{
|
||||
remove_newline(line);
|
||||
if (sscanf(line, "/dev/%s /mnt/%s", dev, mnt) == 2) {
|
||||
if (!strcmp(mnt, mount) || strstr(mount, mnt)) {
|
||||
*val = strdup(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(mounts);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_usb_size(unsigned long *val, char *device) {
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
*val = 0;
|
||||
|
||||
sprintf(cmnd, "/sys/class/block/%s/size", device);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
remove_newline(result);
|
||||
fclose(in);
|
||||
*val = (long)(atoi(result) / 2048);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_usb_info(USB *usb, char *usbno)
|
||||
{
|
||||
FILE *in;
|
||||
char cmnd[64];
|
||||
char result[32];
|
||||
|
||||
sprintf(cmnd, "/sys/bus/usb/devices/%s/product", usbno);
|
||||
if ((in = fopen(cmnd, "r"))) {
|
||||
fgets(result, sizeof(result), in);
|
||||
remove_newline(result);
|
||||
fclose(in);
|
||||
|
||||
strcpy(usb->product, result);
|
||||
sprintf(usb->no, "%s", usbno);
|
||||
sprintf(usb->name, "USB%s", strndup(usbno+2, strlen(usbno)));
|
||||
get_usb_infos(&usb->vendor, usb->no, "manufacturer");
|
||||
get_usb_infos(&usb->serial, usb->no, "serial");
|
||||
//get_usb_infos(&usb->speed, usb->no, "speed");
|
||||
get_usb_infos(&usb->maxchild, usb->no, "maxchild");
|
||||
sprintf(usb->mount, "%s%s", usb->vendor, usb->serial);
|
||||
remove_space(usb->mount);
|
||||
if(!strcmp(usb->mount, usb->serial)) {
|
||||
sprintf(usb->mount, "%s%s", usb->product, usb->serial);
|
||||
remove_space(usb->mount);
|
||||
}
|
||||
get_usb_device(&usb->device, usb->mount);
|
||||
get_usb_size(&usb->size, usb->device);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Reference in a new issue