From ef6fedfc16c65147855caf63570b22a6d94cf0f1 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sat, 14 Oct 2017 21:21:50 -0700 Subject: [PATCH 01/10] libutil/hash: add Chris Dunlap's hash module Add hash module plus thread module it requires. --- src/common/libutil/Makefile.am | 6 +- src/common/libutil/hash.c | 433 +++++++++++++++++++++++++++++++++ src/common/libutil/hash.h | 177 ++++++++++++++ src/common/libutil/thread.c | 50 ++++ src/common/libutil/thread.h | 106 ++++++++ 5 files changed, 771 insertions(+), 1 deletion(-) create mode 100644 src/common/libutil/hash.c create mode 100644 src/common/libutil/hash.h create mode 100644 src/common/libutil/thread.c create mode 100644 src/common/libutil/thread.h diff --git a/src/common/libutil/Makefile.am b/src/common/libutil/Makefile.am index b968bcd..0d0e5bb 100644 --- a/src/common/libutil/Makefile.am +++ b/src/common/libutil/Makefile.am @@ -15,4 +15,8 @@ libutil_la_SOURCES = \ color.c \ color.h \ list.c \ - list.h + list.h \ + hash.c \ + hash.h \ + thread.c \ + thread.h diff --git a/src/common/libutil/hash.c b/src/common/libutil/hash.c new file mode 100644 index 0000000..352551f --- /dev/null +++ b/src/common/libutil/hash.c @@ -0,0 +1,433 @@ +/***************************************************************************** + * $Id: hash.c 2950 2005-01-18 20:09:32Z dun $ + ***************************************************************************** + * Copyright (C) 2003-2005 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Chris Dunlap . + * + * This file is from LSD-Tools, the LLNL Software Development Toolbox. + * + * This 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 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; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA. + ***************************************************************************** + * Refer to "hash.h" for documentation on public functions. + *****************************************************************************/ + + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "thread.h" +#include "hash.h" + + +/***************************************************************************** + * Constants + *****************************************************************************/ + +#define HASH_ALLOC 1024 +#define HASH_DEF_SIZE 1213 +#define HASH_MAGIC 0xDEADBEEF + + +/***************************************************************************** + * Data Types + *****************************************************************************/ + +struct hash_node { + struct hash_node *next; /* next node in list */ + void *data; /* ptr to hashed item */ + const void *hkey; /* ptr to hashed item's key */ +}; + +struct hash { + int count; /* number of items in hash table */ + int size; /* num slots allocated in hash table */ + struct hash_node **table; /* hash table array of node ptrs */ + hash_cmp_f cmp_f; /* key comparison function */ + hash_del_f del_f; /* item deletion function */ + hash_key_f key_f; /* key hash function */ +#if WITH_PTHREADS + pthread_mutex_t mutex; /* mutex to protect access to hash */ +#endif /* WITH_PTHREADS */ +#ifndef NDEBUG + unsigned int magic; /* sentinel for asserting validity */ +#endif /* NDEBUG */ +}; + + +/***************************************************************************** + * Prototypes + *****************************************************************************/ + +static struct hash_node * hash_node_alloc (void); + +static void hash_node_free (struct hash_node *node); + + +/***************************************************************************** + * Variables + *****************************************************************************/ + +static struct hash_node *hash_free_list = NULL; + +#if WITH_PTHREADS +static pthread_mutex_t hash_free_lock = PTHREAD_MUTEX_INITIALIZER; +#endif /* WITH_PTHREADS */ + + +/***************************************************************************** + * Macros + *****************************************************************************/ + +#ifdef WITH_LSD_FATAL_ERROR_FUNC +# undef lsd_fatal_error + extern void lsd_fatal_error (char *file, int line, char *mesg); +#else /* !WITH_LSD_FATAL_ERROR_FUNC */ +# ifndef lsd_fatal_error +# define lsd_fatal_error(file, line, mesg) (abort ()) +# endif /* !lsd_fatal_error */ +#endif /* !WITH_LSD_FATAL_ERROR_FUNC */ + +#ifdef WITH_LSD_NOMEM_ERROR_FUNC +# undef lsd_nomem_error + extern void * lsd_nomem_error (char *file, int line, char *mesg); +#else /* !WITH_LSD_NOMEM_ERROR_FUNC */ +# ifndef lsd_nomem_error +# define lsd_nomem_error(file, line, mesg) (NULL) +# endif /* !lsd_nomem_error */ +#endif /* !WITH_LSD_NOMEM_ERROR_FUNC */ + + +/***************************************************************************** + * Functions + *****************************************************************************/ + +hash_t +hash_create (int size, hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f) +{ + hash_t h; + + if (!cmp_f || !key_f) { + errno = EINVAL; + return (NULL); + } + if (size <= 0) { + size = HASH_DEF_SIZE; + } + if (!(h = malloc (sizeof (*h)))) { + return (lsd_nomem_error (__FILE__, __LINE__, "hash_create")); + } + if (!(h->table = calloc (size, sizeof (struct hash_node *)))) { + free (h); + return (lsd_nomem_error (__FILE__, __LINE__, "hash_create")); + } + h->count = 0; + h->size = size; + h->cmp_f = cmp_f; + h->del_f = del_f; + h->key_f = key_f; + lsd_mutex_init (&h->mutex); + assert (h->magic = HASH_MAGIC); /* set magic via assert abuse */ + return (h); +} + + +void +hash_destroy (hash_t h) +{ + int i; + struct hash_node *p, *q; + + if (!h) { + errno = EINVAL; + return; + } + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + for (i = 0; i < h->size; i++) { + for (p = h->table[i]; p != NULL; p = q) { + q = p->next; + if (h->del_f) + h->del_f (p->data); + hash_node_free (p); + } + } + assert (h->magic = ~HASH_MAGIC); /* clear magic via assert abuse */ + lsd_mutex_unlock (&h->mutex); + lsd_mutex_destroy (&h->mutex); + free (h->table); + free (h); + return; +} + + +int +hash_is_empty (hash_t h) +{ + int n; + + if (!h) { + errno = EINVAL; + return (0); + } + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + n = h->count; + lsd_mutex_unlock (&h->mutex); + return (n == 0); +} + + +int +hash_count (hash_t h) +{ + int n; + + if (!h) { + errno = EINVAL; + return (0); + } + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + n = h->count; + lsd_mutex_unlock (&h->mutex); + return (n); +} + + +void * +hash_find (hash_t h, const void *key) +{ + unsigned int slot; + struct hash_node *p; + void *data = NULL; + + if (!h || !key) { + errno = EINVAL; + return (NULL); + } + errno = 0; + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + slot = h->key_f (key) % h->size; + for (p = h->table[slot]; p != NULL; p = p->next) { + if (!h->cmp_f (p->hkey, key)) { + data = p->data; + break; + } + } + lsd_mutex_unlock (&h->mutex); + return (data); +} + + +void * +hash_insert (hash_t h, const void *key, void *data) +{ + struct hash_node *p; + unsigned int slot; + + if (!h || !key || !data) { + errno = EINVAL; + return (NULL); + } + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + slot = h->key_f (key) % h->size; + for (p = h->table[slot]; p != NULL; p = p->next) { + if (!h->cmp_f (p->hkey, key)) { + errno = EEXIST; + data = NULL; + goto end; + } + } + if (!(p = hash_node_alloc ())) { + data = lsd_nomem_error (__FILE__, __LINE__, "hash_insert"); + goto end; + } + p->hkey = key; + p->data = data; + p->next = h->table[slot]; + h->table[slot] = p; + h->count++; + +end: + lsd_mutex_unlock (&h->mutex); + return (data); +} + + +void * +hash_remove (hash_t h, const void *key) +{ + struct hash_node **pp; + struct hash_node *p; + unsigned int slot; + void *data = NULL; + + if (!h || !key) { + errno = EINVAL; + return (NULL); + } + errno = 0; + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + slot = h->key_f (key) % h->size; + for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &((*pp)->next)) { + if (!h->cmp_f (p->hkey, key)) { + data = p->data; + *pp = p->next; + hash_node_free (p); + h->count--; + break; + } + } + lsd_mutex_unlock (&h->mutex); + return (data); +} + + +int +hash_delete_if (hash_t h, hash_arg_f arg_f, void *arg) +{ + int i; + struct hash_node **pp; + struct hash_node *p; + int n = 0; + + if (!h || !arg_f) { + errno = EINVAL; + return (-1); + } + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + for (i = 0; i < h->size; i++) { + pp = &(h->table[i]); + while ((p = *pp) != NULL) { + if (arg_f (p->data, p->hkey, arg) > 0) { + if (h->del_f) + h->del_f (p->data); + *pp = p->next; + hash_node_free (p); + h->count--; + n++; + } + else { + pp = &(p->next); + } + } + } + lsd_mutex_unlock (&h->mutex); + return (n); +} + + +int +hash_for_each (hash_t h, hash_arg_f arg_f, void *arg) +{ + int i; + struct hash_node *p; + int n = 0; + + if (!h || !arg_f) { + errno = EINVAL; + return (-1); + } + lsd_mutex_lock (&h->mutex); + assert (h->magic == HASH_MAGIC); + for (i = 0; i < h->size; i++) { + for (p = h->table[i]; p != NULL; p = p->next) { + if (arg_f (p->data, p->hkey, arg) > 0) { + n++; + } + } + } + lsd_mutex_unlock (&h->mutex); + return (n); +} + + +/***************************************************************************** + * Hash Functions + *****************************************************************************/ + +unsigned int +hash_key_string (const char *str) +{ + unsigned char *p; + unsigned int hval = 0; + const unsigned int multiplier = 31; + + for (p = (unsigned char *) str; *p != '\0'; p++) { + hval += (multiplier * hval) + *p; + } + return (hval); +} + + +/***************************************************************************** + * Internal Functions + *****************************************************************************/ + +static struct hash_node * +hash_node_alloc (void) +{ +/* Allocates a hash node from the freelist. + * Memory is allocated in chunks of HASH_ALLOC. + * Returns a ptr to the object, or NULL if memory allocation fails. + */ + int i; + struct hash_node *p = NULL; + + assert (HASH_ALLOC > 0); + lsd_mutex_lock (&hash_free_lock); + if (!hash_free_list) { + if ((hash_free_list = malloc (HASH_ALLOC * sizeof (*p)))) { + for (i = 0; i < HASH_ALLOC - 1; i++) + hash_free_list[i].next = &hash_free_list[i+1]; + hash_free_list[i].next = NULL; + } + } + if (hash_free_list) { + p = hash_free_list; + hash_free_list = p->next; + } + else { + errno = ENOMEM; + } + lsd_mutex_unlock (&hash_free_lock); + return (p); +} + + +static void +hash_node_free (struct hash_node *node) +{ +/* De-allocates the object [node], returning it to the freelist. + */ + assert (node != NULL); + memset (node, 0, sizeof (*node)); + lsd_mutex_lock (&hash_free_lock); + node->next = hash_free_list; + hash_free_list = node; + lsd_mutex_unlock (&hash_free_lock); + return; +} diff --git a/src/common/libutil/hash.h b/src/common/libutil/hash.h new file mode 100644 index 0000000..e8e27e5 --- /dev/null +++ b/src/common/libutil/hash.h @@ -0,0 +1,177 @@ +/***************************************************************************** + * $Id: hash.h 2950 2005-01-18 20:09:32Z dun $ + ***************************************************************************** + * Copyright (C) 2003-2005 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Chris Dunlap . + * + * This file is from LSD-Tools, the LLNL Software Development Toolbox. + * + * This 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 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; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + + +#ifndef LSD_HASH_H +#define LSD_HASH_H + + +/***************************************************************************** + * Notes + *****************************************************************************/ +/* + * If an item's key is modified after insertion, the hash will be unable to + * locate it if the new key should hash to a different slot in the table. + * + * If NDEBUG is not defined, internal debug code will be enabled; this is + * intended for development use only. Production code should define NDEBUG. + * + * If WITH_LSD_FATAL_ERROR_FUNC is defined, the linker will expect to + * find an external lsd_fatal_error(file,line,mesg) function. By default, + * lsd_fatal_error(file,line,mesg) is a macro definition that aborts. + * This macro may be redefined to invoke another routine instead. + * + * If WITH_LSD_NOMEM_ERROR_FUNC is defined, the linker will expect to + * find an external lsd_nomem_error(file,line,mesg) function. By default, + * lsd_nomem_error(file,line,mesg) is a macro definition that returns NULL. + * This macro may be redefined to invoke another routine instead. + * + * If WITH_PTHREADS is defined, these routines will be thread-safe. + */ + + +/***************************************************************************** + * Data Types + *****************************************************************************/ + +typedef struct hash * hash_t; +/* + * Hash table opaque data type. + */ + +typedef unsigned int (*hash_key_f) (const void *key); +/* + * Function prototype for the hash function responsible for converting + * the data's [key] into an unsigned integer hash value. + */ + +typedef int (*hash_cmp_f) (const void *key1, const void *key2); +/* + * Function prototype for comparing two keys. + * Returns zero if both keys are equal; o/w, returns nonzero. + */ + +typedef void (*hash_del_f) (void *data); +/* + * Function prototype for de-allocating a data item stored within a hash. + * This function is responsible for freeing all memory associated with + * the [data] item, including any subordinate items. + */ + +typedef int (*hash_arg_f) (void *data, const void *key, void *arg); +/* + * Function prototype for operating on each element in the hash table. + * The function will be invoked once for each [data] item in the hash, + * with the item's [key] and the specified [arg] being passed in as args. + */ + + +/***************************************************************************** + * Functions + *****************************************************************************/ + +hash_t hash_create (int size, + hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f); +/* + * Creates and returns a new hash table on success. + * Returns lsd_nomem_error() with errno=ENOMEM if memory allocation fails. + * Returns NULL with errno=EINVAL if [keyf] or [cmpf] is not specified. + * The [size] is the number of slots in the table; a larger table requires + * more memory, but generally provide quicker access times. If set <= 0, + * the default size is used. + * The [keyf] function converts a key into a hash value. + * The [cmpf] function determines whether two keys are equal. + * The [delf] function de-allocates memory used by items in the hash; + * if set to NULL, memory associated with these items will not be freed + * when the hash is destroyed. + */ + +void hash_destroy (hash_t h); +/* + * Destroys hash table [h]. If a deletion function was specified when the + * hash was created, it will be called for each item contained within. + * Abadoning a hash without calling hash_destroy() will cause a memory leak. + */ + +int hash_is_empty (hash_t h); +/* + * Returns non-zero if hash table [h] is empty; o/w, returns zero. + */ + +int hash_count (hash_t h); +/* + * Returns the number of items in hash table [h]. + */ + +void * hash_find (hash_t h, const void *key); +/* + * Searches for the item corresponding to [key] in hash table [h]. + * Returns a ptr to the found item's data on success. + * Returns NULL with errno=0 if no matching item is found. + * Returns NULL with errno=EINVAL if [key] is not specified. + */ + +void * hash_insert (hash_t h, const void *key, void *data); +/* + * Inserts [data] with the corresponding [key] into hash table [h]; + * note that it is permissible for [key] to be set equal to [data]. + * Returns a ptr to the inserted item's data on success. + * Returns NULL with errno=EEXIST if [key] already exists in the hash. + * Returns NULL with errno=EINVAL if [key] or [data] is not specified. + * Returns lsd_nomem_error() with errno=ENOMEM if memory allocation fails. + */ + +void * hash_remove (hash_t h, const void *key); +/* + * Removes the item corresponding to [key] from hash table [h]. + * Returns a ptr to the removed item's data on success. + * Returns NULL with errno=0 if no matching item is found. + * Returns NULL with errno=EINVAL if [key] is not specified. + */ + +int hash_delete_if (hash_t h, hash_arg_f argf, void *arg); +/* + * Conditionally deletes (and de-allocates) items from hash table [h]. + * The [argf] function is invoked once for each item in the hash, with + * [arg] being passed in as an argument. Items for which [argf] returns + * greater-than-zero are deleted. + * Returns the number of items deleted. + * Returns -1 with errno=EINVAL if [argf] is not specified. + */ + +int hash_for_each (hash_t h, hash_arg_f argf, void *arg); +/* + * Invokes the [argf] function once for each item in hash table [h], + * with [arg] being passed in as an argument. + * Returns the number of items for which [argf] returns greater-than-zero. + * Returns -1 with errno=EINVAL if [argf] is not specified. + */ + +unsigned int hash_key_string (const char *str); +/* + * A hash_key_f function that hashes the string [str]. + */ + + +#endif /* !LSD_HASH_H */ diff --git a/src/common/libutil/thread.c b/src/common/libutil/thread.c new file mode 100644 index 0000000..110f24a --- /dev/null +++ b/src/common/libutil/thread.c @@ -0,0 +1,50 @@ +/***************************************************************************** + * $Id: thread.c 2918 2003-09-11 21:09:45Z dun $ + ***************************************************************************** + * Copyright (C) 2003 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Chris Dunlap . + * + * This file is from LSD-Tools, the LLNL Software Development Toolbox. + * + * LSD-Tools 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. + * + * LSD-Tools 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 LSD-Tools; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include "thread.h" + + +#if WITH_PTHREADS +#ifndef NDEBUG +int +lsd_mutex_is_locked (pthread_mutex_t *mutex) +{ +/* Returns true if the mutex is locked; o/w, returns false. + */ + int rc; + + assert (mutex != NULL); + rc = pthread_mutex_trylock (mutex); + return (rc == EBUSY ? 1 : 0); +} +#endif /* !NDEBUG */ +#endif /* WITH_PTHREADS */ diff --git a/src/common/libutil/thread.h b/src/common/libutil/thread.h new file mode 100644 index 0000000..ada38b6 --- /dev/null +++ b/src/common/libutil/thread.h @@ -0,0 +1,106 @@ +/***************************************************************************** + * $Id: thread.h 2938 2003-11-26 23:01:18Z dun $ + ***************************************************************************** + * Copyright (C) 2003 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Chris Dunlap . + * + * This file is from LSD-Tools, the LLNL Software Development Toolbox. + * + * LSD-Tools 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. + * + * LSD-Tools 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 LSD-Tools; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + + +#ifndef LSD_THREAD_H +#define LSD_THREAD_H + +#if WITH_PTHREADS +# include +# include +# include +#endif /* WITH_PTHREADS */ + + +/***************************************************************************** + * Macros + *****************************************************************************/ + +#if WITH_PTHREADS + +# ifdef WITH_LSD_FATAL_ERROR_FUNC +# undef lsd_fatal_error + extern void lsd_fatal_error (char *file, int line, char *mesg); +# else /* !WITH_LSD_FATAL_ERROR_FUNC */ +# ifndef lsd_fatal_error +# define lsd_fatal_error(file, line, mesg) (abort ()) +# endif /* !lsd_fatal_error */ +# endif /* !WITH_LSD_FATAL_ERROR_FUNC */ + +# define lsd_mutex_init(pmutex) \ + do { \ + int e = pthread_mutex_init (pmutex, NULL); \ + if (e != 0) { \ + errno = e; \ + lsd_fatal_error (__FILE__, __LINE__, "mutex_init"); \ + abort (); \ + } \ + } while (0) + +# define lsd_mutex_lock(pmutex) \ + do { \ + int e = pthread_mutex_lock (pmutex); \ + if (e != 0) { \ + errno = e; \ + lsd_fatal_error (__FILE__, __LINE__, "mutex_lock"); \ + abort (); \ + } \ + } while (0) + +# define lsd_mutex_unlock(pmutex) \ + do { \ + int e = pthread_mutex_unlock (pmutex); \ + if (e != 0) { \ + errno = e; \ + lsd_fatal_error (__FILE__, __LINE__, "mutex_unlock"); \ + abort (); \ + } \ + } while (0) + +# define lsd_mutex_destroy(pmutex) \ + do { \ + int e = pthread_mutex_destroy (pmutex); \ + if (e != 0) { \ + errno = e; \ + lsd_fatal_error (__FILE__, __LINE__, "mutex_destroy"); \ + abort (); \ + } \ + } while (0) + +# ifndef NDEBUG + int lsd_mutex_is_locked (pthread_mutex_t *pmutex); +# endif /* !NDEBUG */ + +#else /* !WITH_PTHREADS */ + +# define lsd_mutex_init(mutex) +# define lsd_mutex_lock(mutex) +# define lsd_mutex_unlock(mutex) +# define lsd_mutex_destroy(mutex) +# define lsd_mutex_is_locked(mutex) (1) + +#endif /* !WITH_PTHREADS */ + + +#endif /* !LSD_THREAD_H */ From 1fb3648fb993038dcfbf7fffb449fd25dee66362 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sat, 14 Oct 2017 22:46:04 -0700 Subject: [PATCH 02/10] libutil/xzmalloc: add xasprintf() --- src/common/libutil/xzmalloc.c | 21 +++++++++++++++++++++ src/common/libutil/xzmalloc.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/src/common/libutil/xzmalloc.c b/src/common/libutil/xzmalloc.c index 476c23b..99f49c0 100644 --- a/src/common/libutil/xzmalloc.c +++ b/src/common/libutil/xzmalloc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "log.h" #include "xzmalloc.h" @@ -52,6 +53,26 @@ char *xstrdup (const char *s) return cpy; } +char *xvasprintf(const char *fmt, va_list ap) +{ + char *s; + + if (vasprintf (&s, fmt, ap) < 0) + oom (); + return s; +} + +char *xasprintf (const char *fmt, ...) +{ + va_list ap; + char *s; + + va_start (ap, fmt); + s = xvasprintf (fmt, ap); + va_end (ap); + return s; +} + /* * vi:tabstop=4 shiftwidth=4 expandtab */ diff --git a/src/common/libutil/xzmalloc.h b/src/common/libutil/xzmalloc.h index f1b0c75..bc80fc5 100644 --- a/src/common/libutil/xzmalloc.h +++ b/src/common/libutil/xzmalloc.h @@ -1,10 +1,14 @@ #ifndef _UTIL_XZMALLOC_H #define _UTIL_XZMALLOC_H +#include + /* Memory allocation functions that call oom() on allocation error. */ void *xzmalloc (size_t size); char *xstrdup (const char *s); +char *xasprintf (const char *fmt, ...); +char *xvasprintf(const char *fmt, va_list ap); #endif /* !_UTIL_XZMALLOC_H */ /* From 405afc377ca5cf40351f11dae2effea7bc8d3a7d Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sun, 15 Oct 2017 13:54:56 -0700 Subject: [PATCH 03/10] libsbig/temp: [cleanup] drop trailing whitespace --- src/common/libsbig/temp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/libsbig/temp.c b/src/common/libsbig/temp.c index c0773ab..5aae157 100644 --- a/src/common/libsbig/temp.c +++ b/src/common/libsbig/temp.c @@ -35,14 +35,14 @@ int sbig_temp_set (sbig_t *sb, TEMPERATURE_REGULATION reg, double ccdSetpoint) { SetTemperatureRegulationParams2 in = { .regulation = reg, .ccdSetpoint = ccdSetpoint }; - - return sb->fun (CC_SET_TEMPERATURE_REGULATION2, &in, NULL); + + return sb->fun (CC_SET_TEMPERATURE_REGULATION2, &in, NULL); } int sbig_temp_get_info (sbig_t *sb, QueryTemperatureStatusResults2 *info) { QueryTemperatureStatusParams in = { .request = TEMP_STATUS_ADVANCED2}; - return sb->fun (CC_QUERY_TEMPERATURE_STATUS, &in, info); + return sb->fun (CC_QUERY_TEMPERATURE_STATUS, &in, info); } /* From ed775a7a430523d8850c037b4e1350b0fcf12486 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sat, 14 Oct 2017 21:26:05 -0700 Subject: [PATCH 04/10] cmd/sbig-ctl: new --- src/cmd/Makefile.am | 3 +- src/cmd/sbig-ctl.c | 594 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 596 insertions(+), 1 deletion(-) create mode 100644 src/cmd/sbig-ctl.c diff --git a/src/cmd/Makefile.am b/src/cmd/Makefile.am index ac092e4..f693691 100644 --- a/src/cmd/Makefile.am +++ b/src/cmd/Makefile.am @@ -14,7 +14,8 @@ sbigbin_PROGRAMS = \ sbig-snap \ sbig-cooler \ sbig-focus \ - sbig-find + sbig-find \ + sbig-ctl LDADD = \ $(top_builddir)/src/common/libsbig/libsbig.la \ diff --git a/src/cmd/sbig-ctl.c b/src/cmd/sbig-ctl.c new file mode 100644 index 0000000..cd96983 --- /dev/null +++ b/src/cmd/sbig-ctl.c @@ -0,0 +1,594 @@ +/***************************************************************************** + * Copyright (c) 2017 Jim Garlick All rights reserved. + * + * This file is part of the sbig-util. + * For details, see https://github.com/garlick/sbig-util. + * + * 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. + * + * sbig-util 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 terms and conditions of 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. + * See also: http://www.gnu.org/licenses/ +\*****************************************************************************/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/common/libsbig/sbig.h" +#include "src/common/libutil/xzmalloc.h" +#include "src/common/libutil/log.h" +#include "src/common/libutil/bcd.h" +#include "src/common/libutil/hash.h" +#include "src/common/libutil/list.h" + +#define MAX_KEYLEN 128 + +struct xhash { + hash_t hash; + List keys; +}; + +void get_driver_info (sbig_t *sb, const char *key_prefix, struct xhash *h); +void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, + const char *key_prefix, struct xhash *h); +void get_cfw_info (sbig_t *sb, const char *key_prefix, struct xhash *h); +void get_ccd_info (sbig_t *sb, const char *key_prefix, struct xhash *h); + +void xhash_insert (struct xhash *h, const char *prefix, const char *name, + const char *fmt, ...); +struct xhash *xhash_create (void); +void xhash_destroy (struct xhash *h); +void xhash_sort (struct xhash *h); + +void ctl_list_value (struct xhash *h, const char *key_match); +void ctl_set_value (struct xhash *h, const char *key_value); + + +#define OPTIONS "ah" +static const struct option longopts[] = { + {"all", no_argument, 0, 'a'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}, +}; + +void usage (void) +{ + fprintf (stderr, +"Usage: sbig ctl key[=val]\n" +" sbig ctl -a\n" +); + exit (1); +} + +int main (int argc, char *argv[]) +{ + const char *sbig_udrv = getenv ("SBIG_UDRV"); + const char *sbig_device = getenv ("SBIG_DEVICE"); + int ch; + bool list_all = false; + int e; + sbig_t *sb; + CAMERA_TYPE camera_type; + struct xhash *h; + + log_init ("sbig-ctl"); + + while ((ch = getopt_long (argc, argv, OPTIONS, longopts, NULL)) != -1) { + switch (ch) { + case 'a': /* --all */ + list_all = true; + break; + case 'h': /* --help */ + default: + usage (); + } + } + if (list_all && optind < argc) + usage (); + if (!list_all && optind == argc) + usage (); + + if (!sbig_device) + msg_exit ("SBIG_DEVICE is not set"); + + /* Initialize driver + */ + if (!(sb = sbig_new ())) + err_exit ("sbig_new"); + if (sbig_dlopen (sb, sbig_udrv) != 0) + msg_exit ("%s", dlerror ()); + if ((e = sbig_open_driver (sb)) != 0) + msg_exit ("sbig_open_driver: %s", sbig_get_error_string (sb, e)); + + /* Link to camera + */ + if ((e = sbig_open_device (sb, sbig_device) != 0)) + msg_exit ("%s: %s", sbig_device, sbig_get_error_string (sb, e)); + if ((e = sbig_establish_link (sb, &camera_type)) != 0) + msg_exit ("sbig_establish_link: %s", sbig_get_error_string (sb, e)); + + /* Populate hash + */ + h = xhash_create (); + xhash_insert (h, NULL, "model", "%s", sbig_strcam (camera_type)); + + get_driver_info (sb, "driver", h); + get_cooling_info (sb, camera_type, "cooling", h); + get_cfw_info (sb, "cfw", h); + get_ccd_info (sb, "ccd", h); + + xhash_sort (h); + if (list_all) { + ctl_list_value (h, ""); + } + else { + char kv[2*MAX_KEYLEN]; + int i, n, used; + kv[0] = '\0'; + for (i = optind; i < argc; i++) { + used = strlen (kv); + n = snprintf (kv + used, sizeof (kv) - used, "%s", argv[i]); + if (n >= sizeof (kv) - used) + errn_exit (EINVAL, "buffer exceeded"); + } + if (strchr (kv, '=')) + ctl_set_value (h, kv); + else + ctl_list_value (h, kv); + } + + xhash_destroy (h); + + /* Disconnect from camera + */ + if ((e = sbig_close_device (sb)) != 0) + msg_exit ("sbig_close_device: %s", sbig_get_error_string (sb, e)); + + /* Finalize driver + */ + sbig_destroy (sb); + + log_fini (); + return 0; +} + +/* List all keys that match "^key_match" + */ +void ctl_list_value (struct xhash *h, const char *key_match) +{ + ListIterator itr = list_iterator_create (h->keys); + const char *key, *val; + while ((key = list_next (itr))) { + val = hash_find (h->hash, key); + if (!strncmp (key, key_match, strlen (key_match))) + printf ("%s = %s\n", key, val); + } + list_iterator_destroy (itr); +} + +void ctl_set_value (struct xhash *h, const char *key_value) +{ + char key[MAX_KEYLEN*2]; + char *val; + + /* Parse out key=value + */ + while (isspace (*key_value)) + key_value++; + if (snprintf (key, sizeof (key), "%s", key_value) >= sizeof (key)) + errn_exit (EINVAL, "input buffer exceeded"); + val = strchr (key, '='); + if (!val) + errn_exit (EINVAL, "missing =value"); + do { + *val++ = '\0'; + } while (isspace (*val)); + if (strlen (val) == 0) + errn_exit (EINVAL, "missing =value"); + while (isspace (key[strlen (key) - 1])) + key[strlen (key) - 1] = '\0'; + if (strlen (key) == 0) + errn_exit (EINVAL, "missing key="); + /* Try to set it + */ + msg ("set '%s' to '%s'", key, val); +} + +void xhash_sort (struct xhash *h) +{ + list_sort (h->keys, (ListCmpF)strcmp); +} + +void xhash_destroy (struct xhash *h) +{ + if (h) { + list_destroy (h->keys); + hash_destroy (h->hash); + free (h); + } +} + + +struct xhash *xhash_create (void) +{ + struct xhash *h = xzmalloc (sizeof (*h)); + h->hash = hash_create (0, (hash_key_f)hash_key_string, + (hash_cmp_f)strcmp, + (hash_del_f)free); + h->keys = list_create ((ListDelF)free); + return h; +} + +void xhash_insert (struct xhash *h, const char *prefix, const char *name, + const char *fmt, ...) +{ + char *key; + va_list ap; + char *val; + + if (prefix) + key = xasprintf ("%s.%s", prefix, name); + else + key = xstrdup (name); + va_start (ap, fmt); + val = xvasprintf (fmt, ap); + va_end (ap); + hash_insert (h->hash, key, val); + list_append (h->keys, key); +} + +bool has_int_tracking (sbig_t *sb) +{ + sbig_ccd_t *ccd; + + if (sbig_ccd_create (sb, CCD_TRACKING, &ccd) != CE_NO_ERROR) + return false; + sbig_ccd_destroy (ccd); + return true; +} + +bool has_ext_tracking_capability (sbig_t *sb) +{ + sbig_ccd_t *ccd; + GetCCDInfoResults4 info4; + bool result = false; + + if (sbig_ccd_create (sb, CCD_TRACKING, &ccd) != CE_NO_ERROR) + goto done; + if (sbig_ccd_get_info4 (ccd, &info4) != CE_NO_ERROR) + goto done_destroy; + if ((info4.capabilitiesBits & CB_CCD_EXT_TRACKER_MASK) + == CB_CCD_EXT_TRACKER_YES) + result = true; +done_destroy: + sbig_ccd_destroy (ccd); +done: + return result; +} + +bool has_fan (sbig_t *sb) +{ + sbig_ccd_t *ccd; + GetCCDInfoResults0 info0; + bool result = true; + + if (sbig_ccd_create (sb, CCD_IMAGING, &ccd) != CE_NO_ERROR) + goto done; + if (sbig_ccd_get_info0 (ccd, &info0) != CE_NO_ERROR) + goto done_destroy; + if (info0.cameraType == ST5C_CAMERA) + result = false; +done_destroy: + sbig_ccd_destroy (ccd); +done: + return result; +} + +void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, + const char *key_prefix, struct xhash *h) +{ + QueryTemperatureStatusResults2 info; + int e; + bool have_int_tracking = has_int_tracking (sb); + bool have_ext_tracking = has_ext_tracking_capability (sb); + bool have_fan = has_fan (sb); + + if ((e = sbig_temp_get_info (sb, &info)) != CE_NO_ERROR) + msg_exit ("sbig_temp_get_info: %s", sbig_get_error_string (sb, e)); + + /* Main cooling status + */ + xhash_insert (h, key_prefix, "enabled", "%d", info.coolingEnabled); + xhash_insert (h, key_prefix, "ambient", "%.2f", info.ambientTemperature); + xhash_insert (h, key_prefix, "heatsink", "%.2f", info.heatsinkTemperature); + + xhash_insert (h, key_prefix, "imaging.setpoint", "%.2f", info.ccdSetpoint); + xhash_insert (h, key_prefix, "imaging.temperature", "%.2f", + info.imagingCCDTemperature); + xhash_insert (h, key_prefix, "imaging.power", "%.0f", + info.imagingCCDPower); + + /* Internal guide chip cooling status + */ + if (have_int_tracking) { + xhash_insert (h, key_prefix, "tracking.setpoint", "%.2f", + info.trackingCCDSetpoint); + xhash_insert (h, key_prefix, "tracking.temperature", "%.2f", + info.trackingCCDTemperature); + xhash_insert (h, key_prefix, "tracking.power", "%.0f", + info.trackingCCDPower); + } + + /* Remote guide head cooling status + * N.B. where is the 'setpoint'? + */ + if (have_ext_tracking) { + xhash_insert (h, key_prefix, "tracking-ext.temperature", "%.2f", + info.externalTrackingCCDTemperature); + xhash_insert (h, key_prefix, "tracking-ext.power", "%.0f", + info.externalTrackingCCDPower); + } + + /* Fan status + */ + if (have_fan) { + xhash_insert (h, key_prefix, "fan.enabled", "%s", + info.fanEnabled == FS_OFF ? "off" : + info.fanEnabled == FS_ON ? "manual" : "auto"); + xhash_insert (h, key_prefix, "fan.power", "%.0f", info.fanPower); + xhash_insert (h, key_prefix, "fan.rpm", "%.0f", info.fanSpeed); + } +} + +void get_driver_info (sbig_t *sb, const char *key_prefix, struct xhash *h) +{ + GetDriverInfoResults0 info; + int e; + char version[16]; + + if ((e = sbig_get_driver_info (sb, DRIVER_STD, &info)) != 0) + msg_exit ("sbig_get_driver_info: %s", sbig_get_error_string (sb, e)); + bcd4str (info.version, version, sizeof (version)); + + xhash_insert (h, key_prefix, "version", "%s", version); + xhash_insert (h, key_prefix, "name", "%s", info.name); + xhash_insert (h, key_prefix, "maxreq", "%d", info.maxRequest); +} + +void get_cfw_info (sbig_t *sb, const char *key_prefix, struct xhash *h) +{ + int e; + ulong fwrev, numpos; + CFW_MODEL_SELECT model; + char version[16]; + CFW_STATUS status; + CFW_POSITION position; + + if ((e = sbig_cfw_get_info (sb, &model, &fwrev, &numpos)) != 0) + msg_exit ("sbig_cfw_get_info: %s", sbig_get_error_string (sb, e)); + bcd4str (fwrev, version, sizeof (version)); + + xhash_insert (h, key_prefix, "model", "%s", sbig_strcfw (model)); + xhash_insert (h, key_prefix, "firmware-revision", "%s", version); + xhash_insert (h, key_prefix, "slots", "%d", numpos); + + if ((e = sbig_cfw_query (sb, &status, &position)) != CE_NO_ERROR) + msg_exit ("sbig_cfw_query: %s", sbig_get_error_string (sb, e)); + + xhash_insert (h, key_prefix, "status", "%s", + status == CFWS_UNKNOWN ? "unknown" : + status == CFWS_IDLE ? "idle" : "busy"); + if (position == CFWP_UNKNOWN) + xhash_insert (h, key_prefix, "position", "%s", "unknown"); + else + xhash_insert (h, key_prefix, "position", "%d", position); +} + +/* Query 0 obtains Results0 for imaging ccd + * Query 1 obtains Results0 for tracking ccd + * 'ccd' parameter will already be tied to imaging or tracking. + */ +static void get_ccd_info0 (sbig_t *sb, sbig_ccd_t *ccd, + const char *key_prefix, struct xhash *h) +{ + GetCCDInfoResults0 info0; + int i, e; + char version[16]; + + e = sbig_ccd_get_info0 (ccd, &info0); + if (e != CE_NO_ERROR) + msg_exit ("sbig_ccd_get_info: %s", sbig_get_error_string (sb, e)); + + bcd4str (info0.firmwareVersion, version, sizeof (version)); + xhash_insert (h, key_prefix, "firmware-revision", "%s", version); + + for (i = 0; i < info0.readoutModes; i++) { + char mode[128]; + snprintf (mode, sizeof (mode), "%s.mode.%d", + key_prefix, info0.readoutInfo[i].mode); + xhash_insert (h, mode, "width", "%d", info0.readoutInfo[i].width); + xhash_insert (h, mode, "height", "%d", info0.readoutInfo[i].height); + xhash_insert (h, mode, "gain", "%2.2f", + bcd2_2 (info0.readoutInfo[i].gain)); + xhash_insert (h, mode, "pixel-width", "%3.2f", + bcd6_2 (info0.readoutInfo[i].pixelWidth)); + xhash_insert (h, mode, "pixel-height", "%3.2f", + bcd6_2 (info0.readoutInfo[i].pixelHeight)); + } +} + +/* Query 2 obtains Results2 for imaging ccd on all but ST-5C and ST-237 + */ +static void get_ccd_info2 (sbig_t *sb, sbig_ccd_t *ccd, + const char *key_prefix, struct xhash *h) +{ + GetCCDInfoResults2 info2; + int e; + + e = sbig_ccd_get_info2 (ccd, &info2); + if (e != CE_NO_ERROR) { + if (e == CE_BAD_PARAMETER) + return; + msg_exit ("sbig_ccd_get_info2: %s", sbig_get_error_string (sb, e)); + } + xhash_insert (h, key_prefix, "badcolumns", "%d", info2.badColumns); + xhash_insert (h, key_prefix, "abg", "%d", + info2.imagingABG == ABG_PRESENT ? 1 : 0); + xhash_insert (h, key_prefix, "serial-number", "%s", info2.serialNumber); +} + +/* Query 3 obtains Results3 for imaging chip on ST-5C and ST-237 + */ +static void get_ccd_info3 (sbig_t *sb, sbig_ccd_t *ccd, + const char *key_prefix, struct xhash *h) +{ + GetCCDInfoResults3 info3; + int e; + + e = sbig_ccd_get_info3 (ccd, &info3); + if (e != CE_NO_ERROR) { + if (e == CE_BAD_PARAMETER) + return; + msg_exit ("sbig_ccd_get_info3: %s", sbig_get_error_string (sb, e)); + } + xhash_insert (h, key_prefix, "adsize", "%d", + info3.adSize == AD_12_BITS ? 12 : + info3.adSize == AD_16_BITS ? 16 : + info3.adSize == AD_UNKNOWN ? 0 : 0); + + // redundant with cfw + //xhash_insert (h, key_prefix, "filtertype", "%s", + // info3.filterType == FW_EXTERNAL ? "external" : + // info3.filterType == FW_VANE ? "2 position" : + // info3.filterType == FW_FILTER_WHEEL ? "5 position" : + // info3.filterType == FW_UNKNOWN ? "unknown" : "unknown"); +} + +/* Query 4 obtains Results4 for imaging ccd + * Query 5 obtains Results4 for tracking ccd + * 'ccd' paramter will already be tied to imaging or tracking. + */ +static void get_ccd_info4 (sbig_t *sb, sbig_ccd_t *ccd, + const char *key_prefix, struct xhash *h) +{ + GetCCDInfoResults4 info4; + int e; + + e = sbig_ccd_get_info4 (ccd, &info4); + if (e != CE_NO_ERROR) + msg_exit ("sbig_get_ccd_xinfo4: %s", sbig_get_error_string (sb, e)); + + int ccd_type = info4.capabilitiesBits & CB_CCD_TYPE_MASK; + int eshutter = info4.capabilitiesBits & CB_CCD_ESHUTTER_MASK; + int ext_tracker = info4.capabilitiesBits & CB_CCD_EXT_TRACKER_MASK; + int btdi = info4.capabilitiesBits & CB_CCD_BTDI_MASK; + int ao8 = info4.capabilitiesBits & CB_AO8_MASK; + int framebuf = info4.capabilitiesBits & CB_FRAME_BUFFER_MASK; + //int sex2 = info4.capabilitiesBits & CB_REQUIRES_STARTEXP2_MASK; + + xhash_insert (h, key_prefix, "type", "%s", + ccd_type == CB_CCD_TYPE_FULL_FRAME ? "full-frame" : + "frame-transfer"); + xhash_insert (h, key_prefix, "eshutter", "%d", + eshutter == CB_CCD_ESHUTTER_YES ? 1 : 0); + xhash_insert (h, key_prefix, "ext-tracker", "%d", + ext_tracker == CB_CCD_EXT_TRACKER_YES ? 1 : 0); + xhash_insert (h, key_prefix, "bdti", "%d", + btdi == CB_CCD_BTDI_YES ? 1 : 0); + xhash_insert (h, key_prefix, "ao8", "%d", + ao8 == CB_AO8_YES ? 1 : 0); + xhash_insert (h, key_prefix, "framebuffer", "%d", + framebuf == CB_FRAME_BUFFER_YES ? 1 : 0); + // not useful to expose externally + //xhash_insert (h, key_prefix, "use-startexp2", "%d", + // sex2 == CB_REQUIRES_STARTEXP2_YES ? 1 : 0); +} + +/* Query 6 obtains Results6 for imaging chip + */ +static void get_ccd_info6 (sbig_t *sb, sbig_ccd_t *ccd, + const char *key_prefix, struct xhash *h) +{ + GetCCDInfoResults6 info6; + int e; + int color; + + e = sbig_ccd_get_info6 (ccd, &info6); + if (e != CE_NO_ERROR) { + if (e == CE_BAD_PARAMETER) + return; + msg_exit ("sbig_ccd_get_info6: %s", sbig_get_error_string (sb, e)); + } + + // XXX cameraBits + + xhash_insert (h, key_prefix, "mech-shutter", "%d", + !(info6.cameraBits & 2) ? 1 : 0); + + color = (info6.ccdBits & 1) ? 1: 0; + xhash_insert (h, key_prefix, "color", "%d", color); + if (color) { + xhash_insert (h, key_prefix, "color-mask", "%s", + !(info6.ccdBits & 2) ? "bayer" : "truesense"); + } +} + +void get_ccd_info (sbig_t *sb, const char *key_prefix, struct xhash *h) +{ + int e; + sbig_ccd_t *ccd; + char key[MAX_KEYLEN]; + + /* Get imaging chip info + */ + e = sbig_ccd_create (sb, CCD_IMAGING, &ccd); + if (e != CE_NO_ERROR) + msg_exit ("sbig_ccd_create: %s", sbig_get_error_string (sb, e)); + snprintf (key, sizeof (key), "%s.%s", key_prefix, "imaging"); + + get_ccd_info0 (sb, ccd, key, h); + get_ccd_info2 (sb, ccd, key, h); + get_ccd_info3 (sb, ccd, key, h); + get_ccd_info4 (sb, ccd, key, h); + get_ccd_info6 (sb, ccd, key, h); + + sbig_ccd_destroy (ccd); + + /* Get tracking chip info + * Query will fail if there is none. + */ + e = sbig_ccd_create (sb, CCD_TRACKING, &ccd); + if (e == CE_NO_ERROR) { + snprintf (key, sizeof (key), "%s.%s", key_prefix, "tracking"); + + get_ccd_info0 (sb, ccd, key, h); + get_ccd_info3 (sb, ccd, key, h); + get_ccd_info4 (sb, ccd, key, h); + + sbig_ccd_destroy (ccd); + } +} + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ From 6ce5bb31e005f790bee1741bc5729428e8428c13 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 20 Oct 2017 20:41:04 -0700 Subject: [PATCH 05/10] cmd/sbig-ctl: set cooling.enable, setpoint --- src/cmd/sbig-ctl.c | 156 +++++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 76 deletions(-) diff --git a/src/cmd/sbig-ctl.c b/src/cmd/sbig-ctl.c index cd96983..2199c34 100644 --- a/src/cmd/sbig-ctl.c +++ b/src/cmd/sbig-ctl.c @@ -49,9 +49,15 @@ struct xhash { }; void get_driver_info (sbig_t *sb, const char *key_prefix, struct xhash *h); + +void set_cooling_info (const char *key_prefix, const char *key, + const char *val, struct xhash *h, int *update); void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, const char *key_prefix, struct xhash *h); +void update_cooling_info (sbig_t *sb, struct xhash *h); + void get_cfw_info (sbig_t *sb, const char *key_prefix, struct xhash *h); + void get_ccd_info (sbig_t *sb, const char *key_prefix, struct xhash *h); void xhash_insert (struct xhash *h, const char *prefix, const char *name, @@ -61,8 +67,13 @@ void xhash_destroy (struct xhash *h); void xhash_sort (struct xhash *h); void ctl_list_value (struct xhash *h, const char *key_match); -void ctl_set_value (struct xhash *h, const char *key_value); +void ctl_set_value (struct xhash *h, const char *key_value, int *update); +enum { + UPDATE_NONE = 0, + UPDATE_COOLING = 1, + UPDATE_CFW = 2, +}; #define OPTIONS "ah" static const struct option longopts[] = { @@ -90,6 +101,7 @@ int main (int argc, char *argv[]) sbig_t *sb; CAMERA_TYPE camera_type; struct xhash *h; + int update = UPDATE_NONE; log_init ("sbig-ctl"); @@ -142,19 +154,19 @@ int main (int argc, char *argv[]) ctl_list_value (h, ""); } else { - char kv[2*MAX_KEYLEN]; - int i, n, used; - kv[0] = '\0'; - for (i = optind; i < argc; i++) { - used = strlen (kv); - n = snprintf (kv + used, sizeof (kv) - used, "%s", argv[i]); - if (n >= sizeof (kv) - used) - errn_exit (EINVAL, "buffer exceeded"); + while (optind < argc) { + if (strchr (argv[optind], '=')) + ctl_set_value (h, argv[optind], &update); + else + ctl_list_value (h, argv[optind]); + optind++; } - if (strchr (kv, '=')) - ctl_set_value (h, kv); - else - ctl_list_value (h, kv); + } + + /* Perform updates, if needed + */ + if ((update & UPDATE_COOLING)) { + update_cooling_info (sb, h); } xhash_destroy (h); @@ -186,7 +198,7 @@ void ctl_list_value (struct xhash *h, const char *key_match) list_iterator_destroy (itr); } -void ctl_set_value (struct xhash *h, const char *key_value) +void ctl_set_value (struct xhash *h, const char *key_value, int *update) { char key[MAX_KEYLEN*2]; char *val; @@ -209,9 +221,12 @@ void ctl_set_value (struct xhash *h, const char *key_value) key[strlen (key) - 1] = '\0'; if (strlen (key) == 0) errn_exit (EINVAL, "missing key="); - /* Try to set it - */ - msg ("set '%s' to '%s'", key, val); + + if (!strncmp (key, "cooling.", 8)) { + set_cooling_info ("cooling", key + 8, val, h, update); + } + else + msg_exit ("%s cannot be set", key); } void xhash_sort (struct xhash *h) @@ -253,37 +268,11 @@ void xhash_insert (struct xhash *h, const char *prefix, const char *name, va_start (ap, fmt); val = xvasprintf (fmt, ap); va_end (ap); + if (hash_find (h->hash, key)) { + hash_remove (h->hash, key); + } else + list_append (h->keys, key); hash_insert (h->hash, key, val); - list_append (h->keys, key); -} - -bool has_int_tracking (sbig_t *sb) -{ - sbig_ccd_t *ccd; - - if (sbig_ccd_create (sb, CCD_TRACKING, &ccd) != CE_NO_ERROR) - return false; - sbig_ccd_destroy (ccd); - return true; -} - -bool has_ext_tracking_capability (sbig_t *sb) -{ - sbig_ccd_t *ccd; - GetCCDInfoResults4 info4; - bool result = false; - - if (sbig_ccd_create (sb, CCD_TRACKING, &ccd) != CE_NO_ERROR) - goto done; - if (sbig_ccd_get_info4 (ccd, &info4) != CE_NO_ERROR) - goto done_destroy; - if ((info4.capabilitiesBits & CB_CCD_EXT_TRACKER_MASK) - == CB_CCD_EXT_TRACKER_YES) - result = true; -done_destroy: - sbig_ccd_destroy (ccd); -done: - return result; } bool has_fan (sbig_t *sb) @@ -304,13 +293,52 @@ bool has_fan (sbig_t *sb) return result; } +void set_cooling_info (const char *key_prefix, const char *key, + const char *val, struct xhash *h, int *update) +{ + + if (!strcmp (key, "enabled")) { + xhash_insert (h, key_prefix, key, "%s", val); + *update |= UPDATE_COOLING; + } + else if (!strcmp (key, "setpoint")) { + xhash_insert (h, key_prefix, key, "%s", val); + *update |= UPDATE_COOLING; + } + else + msg_exit ("cannot set %s", key); +} + +void update_cooling_info (sbig_t *sb, struct xhash *h) +{ + double setpoint; + TEMPERATURE_REGULATION mode; + int e; + const char *s; + + if (!(s = hash_find (h->hash, "cooling.setpoint"))) + msg_exit ("cannot get cooling.setpoint"); + setpoint = strtod (s, NULL); + + if (!(s = hash_find (h->hash, "cooling.enabled"))) + msg_exit ("cannot get cooling.setpoint"); + if (!strcmp (s, "0")) + mode = REGULATION_OFF; + else + mode = REGULATION_ON; + + if ((e = sbig_temp_set (sb, mode, setpoint)) != CE_NO_ERROR) + msg_exit ("sbig_temp_set: %s", sbig_get_error_string (sb, e)); +} + +/* FIXME: tracking and ext-tracking do not appear to have any way to + * adjust the setpoint? Just report the main cooling status for now. + */ void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, const char *key_prefix, struct xhash *h) { QueryTemperatureStatusResults2 info; int e; - bool have_int_tracking = has_int_tracking (sb); - bool have_ext_tracking = has_ext_tracking_capability (sb); bool have_fan = has_fan (sb); if ((e = sbig_temp_get_info (sb, &info)) != CE_NO_ERROR) @@ -322,35 +350,11 @@ void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, xhash_insert (h, key_prefix, "ambient", "%.2f", info.ambientTemperature); xhash_insert (h, key_prefix, "heatsink", "%.2f", info.heatsinkTemperature); - xhash_insert (h, key_prefix, "imaging.setpoint", "%.2f", info.ccdSetpoint); - xhash_insert (h, key_prefix, "imaging.temperature", "%.2f", + xhash_insert (h, key_prefix, "setpoint", "%.2f", info.ccdSetpoint); + xhash_insert (h, key_prefix, "temperature", "%.2f", info.imagingCCDTemperature); - xhash_insert (h, key_prefix, "imaging.power", "%.0f", - info.imagingCCDPower); + xhash_insert (h, key_prefix, "power", "%.0f", info.imagingCCDPower); - /* Internal guide chip cooling status - */ - if (have_int_tracking) { - xhash_insert (h, key_prefix, "tracking.setpoint", "%.2f", - info.trackingCCDSetpoint); - xhash_insert (h, key_prefix, "tracking.temperature", "%.2f", - info.trackingCCDTemperature); - xhash_insert (h, key_prefix, "tracking.power", "%.0f", - info.trackingCCDPower); - } - - /* Remote guide head cooling status - * N.B. where is the 'setpoint'? - */ - if (have_ext_tracking) { - xhash_insert (h, key_prefix, "tracking-ext.temperature", "%.2f", - info.externalTrackingCCDTemperature); - xhash_insert (h, key_prefix, "tracking-ext.power", "%.0f", - info.externalTrackingCCDPower); - } - - /* Fan status - */ if (have_fan) { xhash_insert (h, key_prefix, "fan.enabled", "%s", info.fanEnabled == FS_OFF ? "off" : From 88e567dd9dc6f9d94dd16b075fdc5a7e97741024 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 20 Oct 2017 21:21:57 -0700 Subject: [PATCH 06/10] cmd/sbig-ctl: set cfw.position --- src/cmd/sbig-ctl.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/cmd/sbig-ctl.c b/src/cmd/sbig-ctl.c index 2199c34..c524d49 100644 --- a/src/cmd/sbig-ctl.c +++ b/src/cmd/sbig-ctl.c @@ -23,6 +23,7 @@ #if HAVE_CONFIG_H #include "config.h" #endif +#include #include #include #include @@ -57,6 +58,9 @@ void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, void update_cooling_info (sbig_t *sb, struct xhash *h); void get_cfw_info (sbig_t *sb, const char *key_prefix, struct xhash *h); +void set_cfw_info (const char *key_profile, const char *key, + const char *val, struct xhash *h, int *update); +void update_cfw_info (sbig_t *sb, struct xhash *h); void get_ccd_info (sbig_t *sb, const char *key_prefix, struct xhash *h); @@ -168,6 +172,9 @@ int main (int argc, char *argv[]) if ((update & UPDATE_COOLING)) { update_cooling_info (sb, h); } + if ((update & UPDATE_CFW)) { + update_cfw_info (sb, h); + } xhash_destroy (h); @@ -225,6 +232,9 @@ void ctl_set_value (struct xhash *h, const char *key_value, int *update) if (!strncmp (key, "cooling.", 8)) { set_cooling_info ("cooling", key + 8, val, h, update); } + else if (!strncmp (key, "cfw.", 4)) { + set_cfw_info ("cfw", key + 4, val, h, update); + } else msg_exit ("%s cannot be set", key); } @@ -379,6 +389,39 @@ void get_driver_info (sbig_t *sb, const char *key_prefix, struct xhash *h) xhash_insert (h, key_prefix, "maxreq", "%d", info.maxRequest); } +void set_cfw_info (const char *key_prefix, const char *key, + const char *val, struct xhash *h, int *update) +{ + + if (!strcmp (key, "position")) { + xhash_insert (h, key_prefix, key, "%s", val); + *update |= UPDATE_CFW; + } + else + msg_exit ("cannot set %s", key); +} + +void update_cfw_info (sbig_t *sb, struct xhash *h) +{ + CFW_POSITION position, actual; + CFW_STATUS status; + int e; + const char *s; + + if (!(s = hash_find (h->hash, "cfw.position"))) + msg_exit ("cannot get cooling.setpoint"); + position = strtoul (s, NULL, 10); + + if ((e = sbig_cfw_goto (sb, position)) != CE_NO_ERROR) + msg_exit ("sbig_cfw_goto: %s", sbig_get_error_string (sb, e)); + do { + if ((e = sbig_cfw_query (sb, &status, &actual)) != CE_NO_ERROR) + msg_exit ("sbig_cfw_query: %s", sbig_get_error_string (sb, e)); + if (status == CFWS_BUSY) + usleep (1000*100); + } while (status == CFWS_BUSY); +} + void get_cfw_info (sbig_t *sb, const char *key_prefix, struct xhash *h) { int e; From 2b9d05777cc9a56e4aba30ac7adb228b5217bcd9 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sun, 11 Feb 2018 13:20:33 -0800 Subject: [PATCH 07/10] sbig-ctl: don't abort if CFW query fails On STF-8300C, sbig-ctl -a would fail due to missing CFW. Presumably earlier testing was on the ST-5C which has a built-in CFW. --- src/cmd/sbig-ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/sbig-ctl.c b/src/cmd/sbig-ctl.c index c524d49..2a74db4 100644 --- a/src/cmd/sbig-ctl.c +++ b/src/cmd/sbig-ctl.c @@ -432,7 +432,7 @@ void get_cfw_info (sbig_t *sb, const char *key_prefix, struct xhash *h) CFW_POSITION position; if ((e = sbig_cfw_get_info (sb, &model, &fwrev, &numpos)) != 0) - msg_exit ("sbig_cfw_get_info: %s", sbig_get_error_string (sb, e)); + return; // no CFW installed bcd4str (fwrev, version, sizeof (version)); xhash_insert (h, key_prefix, "model", "%s", sbig_strcfw (model)); From 2badbe46542206f35544845aec69e13fffd50905 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sun, 11 Feb 2018 13:26:58 -0800 Subject: [PATCH 08/10] sbig-ctl: show fan.enabled = off/on/auto This is better than off/manual/auto. --- src/cmd/sbig-ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/sbig-ctl.c b/src/cmd/sbig-ctl.c index 2a74db4..e9c659e 100644 --- a/src/cmd/sbig-ctl.c +++ b/src/cmd/sbig-ctl.c @@ -368,7 +368,7 @@ void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, if (have_fan) { xhash_insert (h, key_prefix, "fan.enabled", "%s", info.fanEnabled == FS_OFF ? "off" : - info.fanEnabled == FS_ON ? "manual" : "auto"); + info.fanEnabled == FS_ON ? "on" : "auto"); xhash_insert (h, key_prefix, "fan.power", "%.0f", info.fanPower); xhash_insert (h, key_prefix, "fan.rpm", "%.0f", info.fanSpeed); } From d51cff512f62b86195b151db8f534cab817c3d21 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Mon, 12 Feb 2018 07:12:51 -0800 Subject: [PATCH 09/10] libsbig: add sbig_misc_set() --- src/common/libsbig/Makefile.am | 4 +++- src/common/libsbig/misc.c | 41 ++++++++++++++++++++++++++++++++++ src/common/libsbig/misc.h | 13 +++++++++++ src/common/libsbig/sbig.h | 1 + 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/common/libsbig/misc.c create mode 100644 src/common/libsbig/misc.h diff --git a/src/common/libsbig/Makefile.am b/src/common/libsbig/Makefile.am index df04d77..2a0ee70 100644 --- a/src/common/libsbig/Makefile.am +++ b/src/common/libsbig/Makefile.am @@ -20,4 +20,6 @@ libsbig_la_SOURCES = \ temp.h \ sbfits.c \ sbfits.h \ - sbig.h + sbig.h \ + misc.c \ + misc.h diff --git a/src/common/libsbig/misc.c b/src/common/libsbig/misc.c new file mode 100644 index 0000000..2d86e97 --- /dev/null +++ b/src/common/libsbig/misc.c @@ -0,0 +1,41 @@ +/*****************************************************************************\ + * Copyright (c) 2014 Jim Garlick All rights reserved. + * + * This file is part of the sbig-util. + * For details, see https://github.com/garlick/sbig-util. + * + * 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. + * + * sbig-util 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 terms and conditions of 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. + * See also: http://www.gnu.org/licenses/ +\*****************************************************************************/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include "handle.h" +#include "handle_impl.h" +#include "sbigudrv.h" +#include "misc.h" + +int sbig_misc_set (sbig_t *sb, MiscellaneousControlParams *misc) +{ + return sb->fun (CC_MISCELLANEOUS_CONTROL, misc, NULL); +} + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ diff --git a/src/common/libsbig/misc.h b/src/common/libsbig/misc.h new file mode 100644 index 0000000..137528f --- /dev/null +++ b/src/common/libsbig/misc.h @@ -0,0 +1,13 @@ +#ifndef _SBIG_MISC_H +#define _SBIG_MISC_H + +#include "handle.h" +#include "sbigudrv.h" + +int sbig_misc_set (sbig_t *sb, MiscellaneousControlParams *misc); + +#endif + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ diff --git a/src/common/libsbig/sbig.h b/src/common/libsbig/sbig.h index 438bf6e..e6763ad 100644 --- a/src/common/libsbig/sbig.h +++ b/src/common/libsbig/sbig.h @@ -8,6 +8,7 @@ #include "cfw.h" #include "ao.h" #include "temp.h" +#include "misc.h" #endif From 3824b2d0dba15c9e8eb3253d730e3516eeb0ae6f Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Mon, 12 Feb 2018 06:50:45 -0800 Subject: [PATCH 10/10] sbig-ctl: allow cooling.fan.enabled to be set The cooling.fan.enabled value for get comes from QueryTemperatureStatusResults2.fanEnabled and may have a value of: FS_OFF FS_ON (on, manual control) FS_AUTOCONTROL (on, auto speed control) The fan is controlled through MiscellaneousControlParams.fanEnable and may be set to 0 Off 1 On 2-100 Fan speed (percent, STX/STT only) --- src/cmd/sbig-ctl.c | 73 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/src/cmd/sbig-ctl.c b/src/cmd/sbig-ctl.c index e9c659e..f6acac6 100644 --- a/src/cmd/sbig-ctl.c +++ b/src/cmd/sbig-ctl.c @@ -62,6 +62,10 @@ void set_cfw_info (const char *key_profile, const char *key, const char *val, struct xhash *h, int *update); void update_cfw_info (sbig_t *sb, struct xhash *h); +void set_cooling_fan_enabled (const char *key_prefix, const char *key, + const char *val, struct xhash *h, int *update); +void update_misc (sbig_t *sb, struct xhash *h); + void get_ccd_info (sbig_t *sb, const char *key_prefix, struct xhash *h); void xhash_insert (struct xhash *h, const char *prefix, const char *name, @@ -77,6 +81,7 @@ enum { UPDATE_NONE = 0, UPDATE_COOLING = 1, UPDATE_CFW = 2, + UPDATE_MISC = 4, }; #define OPTIONS "ah" @@ -169,6 +174,9 @@ int main (int argc, char *argv[]) /* Perform updates, if needed */ + if ((update & UPDATE_MISC)) { + update_misc (sb, h); + } if ((update & UPDATE_COOLING)) { update_cooling_info (sb, h); } @@ -229,7 +237,10 @@ void ctl_set_value (struct xhash *h, const char *key_value, int *update) if (strlen (key) == 0) errn_exit (EINVAL, "missing key="); - if (!strncmp (key, "cooling.", 8)) { + if (!strcmp (key, "cooling.fan.enabled")) { + set_cooling_fan_enabled ("cooling.fan", "enabled", val, h, update); + } + else if (!strncmp (key, "cooling.", 8)) { set_cooling_info ("cooling", key + 8, val, h, update); } else if (!strncmp (key, "cfw.", 4)) { @@ -303,6 +314,13 @@ bool has_fan (sbig_t *sb) return result; } +void set_cooling_fan_enabled (const char *key_prefix, const char *key, + const char *val, struct xhash *h, int *update) +{ + xhash_insert (h, key_prefix, key, "%s", val); + *update |= UPDATE_MISC; +} + void set_cooling_info (const char *key_prefix, const char *key, const char *val, struct xhash *h, int *update) { @@ -319,6 +337,53 @@ void set_cooling_info (const char *key_prefix, const char *key, msg_exit ("cannot set %s", key); } +bool has_fan_speed_control (sbig_t *sb) +{ + sbig_ccd_t *ccd; + GetCCDInfoResults0 info0; + bool result = false; + + if (sbig_ccd_create (sb, CCD_IMAGING, &ccd) != CE_NO_ERROR) + goto done; + if (sbig_ccd_get_info0 (ccd, &info0) != CE_NO_ERROR) + goto done_destroy; + if (info0.cameraType == STT_CAMERA || info0.cameraType == STX_CAMERA) + result = true; +done_destroy: + sbig_ccd_destroy (ccd); +done: + return result; +} + +/* cooling.fan.enabled: + * info2.fanEnabled: FS_OFF (0), FS_ON (1), or FS_AUTOCONTROL (2). + * misc.fanEnable on non-STX/STT: off (0), or on (1). + * misc.fanEanble on STX/STT: off (0), auto (1), pct max speed (20-100). + */ +void update_misc (sbig_t *sb, struct xhash *h) +{ + MiscellaneousControlParams misc; + const char *s; + unsigned long value; + int e; + + misc.shutterCommand = SC_LEAVE_SHUTTER; // ignore shutter + misc.ledState = LED_ON; // restores LED to default (non-integrating) value + + if (!(s = hash_find (h->hash, "cooling.fan.enabled"))) + msg_exit ("cannot get cooling.fan.enabled"); + value = strtoul (s, NULL, 10); + + if (has_fan_speed_control (sb)) + misc.fanEnable = (value == 0 || value >= 20) ? value : 1; + else + misc.fanEnable = value ? TRUE : FALSE; + msg ("XXX setting misc.fanEnable=%d", misc.fanEnable); + + if ((e = sbig_misc_set (sb, &misc)) != CE_NO_ERROR) + msg_exit ("sbig_misc_set: %s", sbig_get_error_string (sb, e)); +} + void update_cooling_info (sbig_t *sb, struct xhash *h) { double setpoint; @@ -331,7 +396,7 @@ void update_cooling_info (sbig_t *sb, struct xhash *h) setpoint = strtod (s, NULL); if (!(s = hash_find (h->hash, "cooling.enabled"))) - msg_exit ("cannot get cooling.setpoint"); + msg_exit ("cannot get cooling.enabled"); if (!strcmp (s, "0")) mode = REGULATION_OFF; else @@ -366,9 +431,7 @@ void get_cooling_info (sbig_t *sb, CAMERA_TYPE camera_type, xhash_insert (h, key_prefix, "power", "%.0f", info.imagingCCDPower); if (have_fan) { - xhash_insert (h, key_prefix, "fan.enabled", "%s", - info.fanEnabled == FS_OFF ? "off" : - info.fanEnabled == FS_ON ? "on" : "auto"); + xhash_insert (h, key_prefix, "fan.enabled", "%d", info.fanEnabled); xhash_insert (h, key_prefix, "fan.power", "%.0f", info.fanPower); xhash_insert (h, key_prefix, "fan.rpm", "%.0f", info.fanSpeed); }