Commit ae5dcb63 authored by Jeroen Vreeken's avatar Jeroen Vreeken
Browse files

Merge branch 'build' into sercos

Conflicts:
	controller/Makefile
	controller/controller/controller_setpoint_command.c
	controller/ec/Makefile
parents 3bd8b0bf 295c8add
......@@ -13,4 +13,3 @@
.libs
bin
include
lib
.PHONY: clean all rel_mktemp_dir console controller help
.PHONY: clean all rel_mktemp_dir console help
include build.mk
CONTROLLER_REL_TAR:=$(CURDIR)/controller_$(shell date +%Y%m%d%H%M).tar.gz
CONSOLE_REL_TAR:=$(CURDIR)/console_$(shell date +%Y%m%d%H%M).tar.gz
all:
$(MAKE) -C common/utils
$(MAKE) -C common/trace
$(MAKE) -C common/log
$(MAKE) -C controller
cd libnova-0.13.0 ; ./configure -enable-static -disable-shared --prefix=${CURDIR} ; make; make install
$(MAKE) -C console
all: common controller console
help:
@echo "Available build rules"; \
......@@ -33,26 +29,13 @@ help:
echo "golden repository (on eris.camras.nl)."
controller:
$(MAKE) -C common/log
$(MAKE) -C common/utils
$(MAKE) -C common/trace
$(MAKE) -C controller
console:
$(MAKE) -C common/log
$(MAKE) -C common/utils
$(MAKE) -C common/trace
libnova.la:
cd libnova-0.13.0 ; ./configure -enable-static -disable-shared --prefix=${CURDIR} ; make; make install
$(MAKE) -C console
clean:
$(MAKE) -C common/log clean
$(MAKE) -C common/utils clean
$(MAKE) -C common/trace clean
$(MAKE) -C controller clean
clean: subdirs_CLEAN
rm -rf common/lib/*
cd libnova-0.13.0 ; make clean || true
$(MAKE) -C console clean
# Rules for building a release
......@@ -75,12 +58,17 @@ rel_trace: rel_utils
$(MAKE) -C $(REL_BUILD_DIR)/common/trace >/dev/null; \
echo " Done"
rel_command: rel_utils
@echo "****** Building common/command"; \
$(MAKE) -C $(REL_BUILD_DIR)/common/command >/dev/null; \
echo " Done"
rel_log:
@echo "****** Building common/log"; \
$(MAKE) -C $(REL_BUILD_DIR)/common/log >/dev/null; \
echo " Done"
rel_ctrl: rel_trace rel_log
rel_ctrl: rel_trace rel_log rel_command
@echo "****** Building controller"; \
$(MAKE) -C $(REL_BUILD_DIR)/controller >/dev/null; \
echo " Done"
......@@ -92,7 +80,7 @@ rel_libnova: rel_clone_dir
echo " Done"
rel_cons: rel_trace rel_libnova rel_log
rel_cons: rel_trace rel_libnova rel_log rel_command
@echo "****** Building console"; \
$(MAKE) -C $(REL_BUILD_DIR)/console >/dev/null; \
echo " Done"
......@@ -110,3 +98,54 @@ $(CONTROLLER_REL_TAR): rel_ctrl
release: $(CONSOLE_REL_TAR) $(CONTROLLER_REL_TAR)
release_console: $(CONSOLE_REL_TAR)
release_controller: $(CONTROLLER_REL_TAR)
DIR := .
SRCS :=
TARGETS :=
CLEAN :=
define SUBDIR
ifeq ($(DIR),.)
DIR := $1
else
DIR := $(DIR)/$1
endif
include $(DIR)/$1/build.mk
DIR := $(DIR)
endef
TARGETS:=
$(eval $(call SUBDIR,common))
common: $(TARGETS)
TARGETS:=
$(eval $(call SUBDIR,controller))
controller: $(TARGETS)
TARGETS:=
$(eval $(call SUBDIR,console))
console: $(TARGETS)
CFLAGS := -Icommon -Icommon/include -Icontroller -Iconsole/console -Iinclude
LDFLAGS := -Lcommon/lib -Lcontroller/lib -Lconsole/console/lib -Llib -Wl,--as-needed
VPATH += common/lib controller/lib console/console/lib lib
SRCS_TMP:=$(SRCS:.il=.il2c.d)
DEPS:=$(SRCS_TMP:.c=.d)
DEPSLIBS:=$(foreach DEP,$(DEPS),$(dir $(DEP)).libs/$(notdir $(DEP)))
-include $(DEPS) $(DEPSLIBS)
CLEAN += $(DEPS) $(DEPSLIBS)
SRCS_IL = $(filter %.il,$(SRCS))
$(SRCS_IL): $(IL2C)
subdirs_CLEAN:
$(foreach CLEANITEM,$(CLEAN), rm -rf $(CLEANITEM);)
# Some make rules to make output pretty....
# default ARFLAGS also has 'v', but we don't want it to be verbose.
ARFLAGS= -r
# make sure libs from /usr/local/lib are found
VPATH= /lib64 /usr/lib64 /usr/local/lib64 /lib /usr/lib /usr/local/lib
LIBTOOL=libtool
OS= $(shell uname -s)
ifneq ($(OS), FreeBSD)
FLEX=flex
else
FLEX=/usr/local/bin/flex
endif
%.o : %.c
@echo " CC $<"
@$(CC) -MMD $(CFLAGS) -c $< -o $@
%.o : %.il2c.c
@echo "LT CCil $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $< -o $@
@sed -e "s:\.il2c.c:\.il:" -i -i $*.il2c.d
%: %.o
@echo " LD $@"
@${LIBTOOL} --quiet --mode=link --tag=CC $(LINK.o) $(filter %.o,$^) $(LOADLIBS) $(LDLIBS) $($@_LDFLAGS) -o $@
%.lo: %.c
@echo "LT CC $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $< -o $@
@cat $(dir $*).libs/$(*F).d | sed -e "s:\.libs/::" -e "s:\.o:\.lo:" > $*.d
%.lo: %.il2c.c
@echo "LT ilCC $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $<
@cat $(dir $*).libs/$(*F).d | sed -e "s:\.libs/::" -e "s:\.o:\.lo:" -e "s:\.il2c.c:\.il:" > $*.d
define LIB_LINK
@echo "LT LD $@"
@${LIBTOOL} --quiet --mode=link gcc $(filter %.lo,$^) -o $@ $(LDFLAGS) $($@_LDFLAGS) -static-libtool-libs -rpath $(abspath $(@D))
@echo "LT INST $@"
@${LIBTOOL} --quiet --mode=install install $@ $(abspath $(@D))
endef
%.so:
@echo "LT soLD $@"
@${LIBTOOL} --quiet --mode=link gcc $(filter %.lo,$^) -o $@ $(LDFLAGS) $($@_LDFLAGS)
(%): %
@echo " AR $^ in $@"
@$(AR) $(ARFLAGS) $@ $^
%.tab.c %.tab.h: %.y
@echo "BISON $<"
@bison --defines=$*.tab.h $< -o $*.tab.c
%.yy.c %.yy.h: %.l %.tab.h
@echo " FLEX $<"
@$(FLEX) --header-file=$*.yy.h -o $*.yy.c $<
# il2c: instruction list 2 c 'compiler'
%.il2c.c: %.il
@echo " IL2C $<"
@$(IL2C) $<
# dot -> pdf
%.pdf: %.dot
@echo " DOT $<"
@dot $< -o $@ -Tpdf
# Some make rules to make output pretty....
# default ARFLAGS also has 'v', but we don't want it to be verbose.
ARFLAGS= -r
LIBDIR:=$(DIR)/lib
# make sure libs from /usr/local/lib are found
VPATH= /lib64 /usr/lib64 /usr/local/lib64 /lib /usr/lib /usr/local/lib
LIBTOOL=libtool
%.o : %.c
@echo " CC $<"
@$(CC) -MMD $(CFLAGS) -c $<
%: %.o
@echo " LD $@"
@${LIBTOOL} --quiet --mode=link --tag=CC $(LINK.o) $(filter %.o,$^) $(LOADLIBS) $(LDLIBS) $($@_LDFLAGS) -o $@
%.lo: %.c
@echo "LT CC $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $<
%.la:
@echo "LIBTOOL $@"
@${LIBTOOL} --quiet --mode=link gcc $^ -o $@ $(LDFLAGS) $($@_LDFLAGS) -static-libtool-libs
(%): %
@echo " AR $^ in $@"
@$(AR) $(ARFLAGS) $@ $^
%.tab.c %.tab.h: %.y
@echo "BISON $<"
@bison -d $<
%.yy.h: %.l %.tab.h
@echo " FLEX $<"
@flex --header-file=$*.yy.h $<
%.yy.c: %.l %.tab.h
@echo " FLEX $<"
@flex -o $@ $<
# il2c: instruction list 2 c 'compiler'
%.c %.h: %.il
@echo " IL2C $<"
@$(IL2C) $<
# dot -> pdf
%.pdf: %.dot
@echo " DOT $<"
@dot $< -o $@ -Tpdf
-include $(SRCS:.c=.d)
$(eval $(call SUBDIR,log))
$(eval $(call SUBDIR,utils))
$(eval $(call SUBDIR,command))
$(eval $(call SUBDIR,trace))
COMMAND_TARGETS += $(LIBDIR)/libcommand.la
COMMAND_TARGETS += $(DIR)/command_list
ARCHSRCS := $(DIR)/command.c $(DIR)/command_tcp.c
ARCHOBJS := $(ARCHSRCS:.c=.lo)
$(ARCHOBJS) += -Wall -O3 -fPIC
$(LIBDIR)/libcommand.la: libutils.la liblog.la
$(LIBDIR)/libcommand.la_LDFLAGS += -lutils -lm -llog
$(LIBDIR)/libcommand.la: $(ARCHOBJS)
$(LIB_LINK)
COMMAND_LIST_SRCS := $(DIR)/command_list.c
COMMAND_LIST_OBJS := $(COMMAND_LIST_SRCS:.c=.o)
$(DIR)/command_list: libcommand.la
$(DIR)/command_list_LDFLAGS += -lcommand
$(DIR)/command_list: $(COMMAND_LIST_OBJS)
SRCS += $(ARCHSRCS) $(COMMAND_LIST_SRCS)
TARGETS += $(COMMAND_TARGETS)
CLEAN += $(COMMAND_TARGETS) $(ARCHOBJS) $(COMMAND_LIST_OBJS)
/*
Command support
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2014
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <command/command.h>
#include <command/command_def.h>
#include <utils/tcp_connect.h>
#include <log/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/ioctl.h>
#include <pthread.h>
void command_initialize(struct command *command, size_t buffer)
{
memset(command, 0, sizeof(struct command));
command->rx_buffer = malloc(buffer);
command->rx_buf_size = buffer;
command->fd = -1;
}
void command_packet_initialize(struct command_pkt *pkt)
{
memset(pkt, 0, sizeof(struct command_pkt));
}
#define PACKET_BUFLEN 256
#define PACKET_POOL_CHUNK 16
static struct command_pkt **packet_pool;
static int packet_pool_size = 0;
static int packet_pool_cur = 0;
static pthread_mutex_t command_pkt_mutex = PTHREAD_MUTEX_INITIALIZER;
struct command_pkt *command_packet_new(void)
{
struct command_pkt *pkt = NULL;
pthread_mutex_lock(&command_pkt_mutex);
if (packet_pool_cur) {
pkt = packet_pool[packet_pool_cur-1];
packet_pool_cur--;
}
pthread_mutex_unlock(&command_pkt_mutex);
if (!pkt) {
pkt = calloc(1, sizeof(struct command_pkt));
pkt->data = malloc(PACKET_BUFLEN);
pkt->buflen = PACKET_BUFLEN;
}
return pkt;
}
int command_packet_resize(struct command_pkt *pkt, size_t len)
{
if (len <= pkt->buflen)
return 0;
pkt->data = realloc(pkt->data, len);
pkt->buflen = len;
return 0;
}
void command_packet_put(struct command_pkt *pkt)
{
if (pkt->buflen > PACKET_BUFLEN) {
free(pkt->data);
free(pkt);
return;
}
pthread_mutex_lock(&command_pkt_mutex);
if (packet_pool_cur >= packet_pool_size) {
packet_pool_size += PACKET_POOL_CHUNK;
packet_pool = realloc(packet_pool,
sizeof(struct command_pkt *) * packet_pool_size);
}
packet_pool[packet_pool_cur] = pkt;
pkt->len = 0;
packet_pool_cur++;
pthread_mutex_unlock(&command_pkt_mutex);
}
int command_packet_list_add(struct command_pkt *pkt,
char *name, enum command_value_type type, char *unit,
int typec, enum command_ptype typev[])
{
size_t entry_size = strlen(name)+1 + 1 + strlen(unit) + 1 + typec + 1;
unsigned char *entry;
int i;
if (!pkt->len) {
command_packet_resize(pkt, 1);
pkt->len = 1;
pkt->data[0] = COMMAND_PTYPE_LIST;
}
command_packet_resize(pkt, pkt->len + entry_size);
entry = pkt->data + pkt->len;
strcpy((char *)entry, name);
entry += strlen(name) + 1;
*entry = type;
entry++;
strcpy((char *)entry, unit);
entry += strlen(unit) + 1;
for (i = 0; i < typec; i++) {
*entry = typev[i];
entry++;
}
*entry = COMMAND_PTYPE_NULL;
entry++;
pkt->len += entry_size;
return 0;
}
int command_packet_name_set(struct command_pkt *pkt, char *name)
{
if (pkt->len < sizeof(struct command_header) + strlen(name) + 1) {
pkt->len = strlen(name) + 1 + sizeof(struct command_header);
command_packet_resize(pkt, pkt->len);
pkt->data[0] = COMMAND_PTYPE_NAME;
}
strcpy((char *)pkt->data + 1, name);
return 0;
}
int command_packet_id_set(struct command_pkt *pkt, char *id)
{
if (pkt->len < sizeof(struct command_header) + strlen(id) + 1) {
pkt->len = strlen(id) + 1 + sizeof(struct command_header);
command_packet_resize(pkt, pkt->len);
pkt->data[0] = COMMAND_PTYPE_ID;
}
strcpy((char *)pkt->data + 1, id);
return 0;
}
int command_packet_entry_set(struct command_pkt *pkt,
struct command_entry *entry, enum command_value_type type)
{
size_t vsize;
size_t size;
unsigned char *p;
switch (type) {
default:
case COMMAND_VALUE_TYPE_FLOAT:
case COMMAND_VALUE_TYPE_UINT32:
case COMMAND_VALUE_TYPE_SINT32:
vsize = 4;
break;
case COMMAND_VALUE_TYPE_BOOL:
case COMMAND_VALUE_TYPE_UINT8:
case COMMAND_VALUE_TYPE_SINT8:
vsize = 1;
break;
case COMMAND_VALUE_TYPE_UINT16:
case COMMAND_VALUE_TYPE_SINT16:
vsize = 2;
break;
}
if (entry->type == COMMAND_PTYPE_SETPOINT_TIME) {
size = 8 + 4 + vsize;
} else {
size = vsize;
}
pkt->len = size + sizeof(struct command_header);
command_packet_resize(pkt, pkt->len);
pkt->data[0] = entry->type;
p = &pkt->data[1];
if (entry->type == COMMAND_PTYPE_SETPOINT_TIME) {
struct command_timestamp *t = (void *)p;
t->sec = htobe64(entry->t.tv_sec);
t->nsec = htobe32(entry->t.tv_nsec);
p += sizeof(struct command_timestamp);
}
switch (vsize) {
case 1:
*p = entry->value.u8;
break;
case 2: {
struct command_ptype_value *pv;
pv = (void *)p;
pv->u.u16 = htobe16(entry->value.u16);
break;
}
case 4: {
struct command_ptype_value *pv;
pv = (void *)p;
pv->u.u32 = htobe32(entry->value.u32);
break;
}
}
return 0;
}
bool command_fd_set(struct command *command, fd_set *set, int *high)
{
if (command->fd < 0) {
if (!command->recover)
return false;
if (command->recovertime >= time(NULL))
return false;
command->recovertime = time(NULL);
log_send(LOG_T_DEBUG, "Attempt to recover command %s",
command->name);
command->fd = tcp_connect(command->host, command->port);
if (command->fd >= 0) {
struct command_pkt *pkt;
ioctl(command->fd, FIONBIO, &(int){1});
if (command->name) {
pkt = command_packet_new();
command_packet_name_set(pkt, command->name);
command_packet_write(command, pkt);
command_packet_put(pkt);
}
if (command->id) {
pkt = command_packet_new();
command_packet_id_set(pkt, command->id);
command_packet_write(command, pkt);
command_packet_put(pkt);
}
}
if (command->fd < 0) {
log_send(LOG_T_DEBUG, "Failed to recover command connection");
return false;
}
log_send(LOG_T_DEBUG, "Reconnected command");
}
FD_SET(command->fd, set);
if (command->fd > *high)
*high = command->fd;
return true;
}
int command_handle(struct command *command, fd_set *set)
{
if (FD_ISSET(command->fd, set)) {
while (command_fd_read(command)) {
struct command_pkt *pkt;
struct command_entry entry;
size_t pos = 1;
pkt = command_packet_get(command);
if (!pkt)
break;
switch (pkt->data[0]) {
case COMMAND_PTYPE_LIST: {
unsigned char *listentry;
while (pos < pkt->len) {
char *name;
enum command_value_type type;
char *unit;
enum command_ptype ptypev[COMMAND_PTYPE_MAX] = { 0 };
int i;
int j;
listentry = pkt->data + pos;
name = (char *)listentry;
type = listentry[strlen(name) + 1];
unit = (char *)listentry+strlen(name) + 2;
for (i = strlen(name) + strlen(unit) + 3, j = 0;
j < COMMAND_PTYPE_MAX && listentry[i] != COMMAND_PTYPE_NULL;
i++, j++)
ptypev[j] = listentry[i];
if (command->handler_list_entry) {
command->handler_list_entry(command,
name, type, unit, j, ptypev);
}
pos += strlen(name) + strlen(unit) + 3 + j + 1;