Compare commits

..

7 commits

Author SHA1 Message Date
Stephan I. Böttcher
1bf29ce11e command version 2023-11-22 23:48:59 +01:00
Stephan I. Böttcher
faae72d243 more «cmd» help 2023-11-22 23:23:50 +01:00
Stephan I. Böttcher
e94349b466 process_cmd: explicit «cmd» help 2023-11-22 20:40:12 +01:00
Stephan I. Böttcher
5034f70af3 use keV for cuts, mV for high/low
also fix D3D channel numbers
2023-11-22 15:18:20 +01:00
Stephan I. Böttcher
5f6f578ff7 fix Version message at startup 2023-11-22 14:36:33 +01:00
Stephan I. Böttcher
8d9a142798 avoid error message for #comments, e.g., the #! line 2023-11-22 13:54:07 +01:00
Stephan I. Böttcher
9b2913bee1 add rc.local startup script 2023-11-21 22:56:27 +01:00
4 changed files with 194 additions and 59 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
irena
*~

View file

@ -1,5 +1,8 @@
VPLUS = $(shell git status | awk '/modified:/{print "+"; exit}')
VERSION = "$(shell git log -n 1 | awk '{print substr($$2,1,10);exit}')$(VPLUS)"
DONTWARN = dangling-else parentheses stringop-truncation
CFLAGS = -O3 -Wall -g -fno-exceptions $(patsubst %,-Wno-%,$(DONTWARN))
CFLAGS = -O3 -Wall -g -fno-exceptions $(patsubst %,-Wno-%,$(DONTWARN)) -DIRENA_VERSION='$(VERSION)'
LDLIBS = -lm
default: irena

221
irena.c
View file

@ -4,7 +4,10 @@
** Distribution: Gnu General Public License version 2 or later (GPLv2+).
*/
const char version[] = "$Id$";
#ifndef IRENA_VERSION
# define IRENA_VERSION "0"
#endif
const char version[] = IRENA_VERSION;
#include <stdio.h>
#include <stdlib.h>
@ -277,7 +280,21 @@ int config_file(struct file_format *f, int na, char **av)
int do_close = 0;
int do_open = 0;
if (na<1 || na>5) {
fprintf(mout, "usage: %s [«strftime» [«rotate» [«modulus» [«flags»]]]] [close|rotate]\n", av[0]);
fprintf(mout,
"usage: %s [«strftime» [«rotate» [«modulus» [«flags»]]]] [close|rotate]\n"
"- «strftime»: filename strftime format | stdout | stderr\n"
"- «rotate»: rotation interval, seconds (-1 for no change)\n"
"- «modulus»: rotation modulus, seconds (-1 for no change)\n"
"- «flags»: DO NOT CHANGE THIS!\n"
" * 1: `ERROR`, file has an error\n"
" * 2: `STDIO`, file is stdio FILE, else unix fd\n"
" * 4: `MOVE`, open file with `+` appended and rename on close\n"
" * 8: `APPEND`, appemd to existing file\n"
" * 16: `STDOUT`, file is stdout, fd=1\n"
" * 32: `STDERR`, file is stderr, fd=2\n"
"- option `close`: close the file now\n"
"- option `rotate`: rotate the file now\n",
av[0]);
return -1;
}
if (!strcmp(av[na-1], "close")) {
@ -295,15 +312,20 @@ int config_file(struct file_format *f, int na, char **av)
|| na>=3 && number(av[2], &rot))
return -1;
if (na>=2) {
if (strlen(av[1]) > MAX_FN-2) {
fprintf(mout, "filename format too long (>%d): %s\n", MAX_FN-2, av[1]);
return -1;
}
file_close(f);
strncpy(f->format, av[1], MAX_FN-1);
char *fnf = av[1];
if (rot != -1) f->rotate = rot;
if (mod != -1) f->rotate_modulus = mod;
if (flags != -1) f->flags = flags;
if (flags != -1) {
f->flags = flags & ~(FILE_STDERR|FILE_STDOUT);
if (flags & FILE_STDERR) fnf = "stderr";
if (flags & FILE_STDOUT) fnf = "stdout";
}
if (strlen(fnf) > MAX_FN-2) {
fprintf(mout, "filename format too long (>%d): %s\n", MAX_FN-2, fnf);
return -1;
}
strncpy(f->format, fnf, MAX_FN-1);
if (!do_close)
file_open(f, 0);
}
@ -312,7 +334,7 @@ int config_file(struct file_format *f, int na, char **av)
else if (do_open)
file_open(f, 0);
int io = is_open(f);
fprintf(mout, "%s %s %d %d 0x%x %s\n",
fprintf(mout, "%s '%s' %d %d 0x%x '%s'\n",
av[0], f->format, f->rotate, f->rotate_modulus, f->flags,
io ? f->filename : "CLOSED");
return io;
@ -511,7 +533,7 @@ void print_datarate(FILE *f)
int config_priority(int na, char **av)
{
int do_reset = 0;
if (!strcmp(av[na-1], "reset")) {
if (na && !strcmp(av[na-1], "reset")) {
do_reset = 1;
na--;
if (na==1) {
@ -523,8 +545,24 @@ int config_priority(int na, char **av)
print_datarate(mout);
return 0;
}
int fflags = 0;
if (na && !strcmp(av[na-1], "global")) {
fflags |= EMIT_GLOBAL_LIMIT;
na--;
}
if (na<2 || na>6) {
fprintf(mout, "usage: %s [«index» [«rate» [«instantanious» [«burst» [«flags»]]]]] [reset]\n", av[0]);
fprintf(mout,
"usage: %s [«index» [«rate» [«inst» [«burst» [«flags»]]]]] [global] [reset]\n"
"- configure data rate limits\n"
"- «index»: 0…%d: table index\n"
"- «rate»: bytes per second, long term data rate limit (-1 for no change)\n"
"- «inst»: short term data rate limit, (-1 for no change)\n"
"- «burst»: data burst volume limit, (-1 for no change)\n"
"- «flags»:\n"
" 1 : GLOBAL_LIMIT, obey the global data rate limit as well\n"
"- option `global`: set the GLOBAL_LIMIT flag\n"
"- option `reset`: zero the sent data volume\n",
av[0], NPRIO);
return -1;
}
int index, rate=-1, inst=-1, burst=-1, flags=-1;
@ -544,6 +582,7 @@ int config_priority(int na, char **av)
if (inst >= 0) ep->inst_rate = inst;
if (burst >= 0) ep->inst_burst = burst;
if (flags != -1) ep->flags = flags;
flags |= fflags;
fprintf(mout, "%s: %s %u %u %u %u 0x%x -> %llu(%llu)/%llu %u/%u\n",
ep->name, av[0], index, ep->rate, ep->inst_rate, ep->inst_burst, ep->flags,
ep->sent, ep->dropped, ep->allowed, ep->inst_sent, ep->inst_burst);
@ -905,7 +944,23 @@ int config_status(int na, char **av)
return 0;
}
if (na!=2 && (na<6 || na>9)) {
fprintf(mout, "usage: %s [«index» [«red» «yellow» «yellow» «red» [«tau» [«reset»] [«flags»]]]]\n", av[0]);
fprintf(mout,
"usage: %s [«index» [«red» «yellow» «yellow» «red» [«tau» [«reset»] [«flags»]]]]\n"
"- «index»: 0…%d, table index\n"
"- «red»: lower/upper error limit\n"
"- «yellow»: lower/upper warning limit\n"
"- «tau»: seconds, timescale of the average, exponentially weighed\n"
"- «reset»: `reset` | `noreset` | «seconds»\n"
" * `reset`: reset the µC when error persists\n"
" * `noreset`: do not reset on error\n"
" * «seconds»: reset the µC when error persists for this long\n"
"- «flags»: DO NOT CHANGE THIS!\n"
" * 1: Value type limit\n"
" * 2: Priority type limit\n"
" * 3: Time type limit\n"
" * 4: Trigger type limit\n"
" * 0x100: do reset on error\n",
av[0], NSTAT-1);
return -1;
}
int index;
@ -967,7 +1022,7 @@ void write_statusfile()
gmtime_r(&t, &gm);
char utc[32];
strftime(utc, 32, "%Y-%m-%dT%H:%M:%SZ", &gm);
fprintf(f, "irena status %ld %s\n", t, utc);
fprintf(f, "irena version %s status %ld %s\n", version, t, utc);
print_status(f, t);
print_datarate(f);
fflush(f);
@ -1468,10 +1523,10 @@ double high_low = 2896;
double let_scale = 0.34657359027997264;
unsigned int let_size = 18;
int high_gain_ch[NI] = { 0, 3, 4, 7, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
int low_gain_ch[NI] = { 1, 2, 5, 6, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
int coinc_ch[NI] = { 3, 0, 7, 4, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
double mV_calib[NC] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int high_gain_ch[NI] = { 1, 4, 7, 10, 13, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
int low_gain_ch[NI] = { 0, 3, 6, 9, 12, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
int coinc_ch[NI] = { 4, 1, 10, 7, 16, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
double mV_calib[NC] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int have_let(int c)
{
@ -1486,11 +1541,12 @@ static int have_let(int c)
void incr_histograms(struct event *ev)
{
double mV[NC];
double keV[NC];
for (int c=0; c<NC; c++)
if (ev->T[c] >= 2)
mV[c] = ev->A[c] / mVscale * mV_calib[c];
keV[c] = (mV[c] = ev->A[c] / mVscale) * mV_calib[c];
else
mV[c] = 0;
keV[c] = mV[c] = 0;
for (int i=0; i<NI; i++) {
int hg = high_gain_ch[i];
@ -1502,9 +1558,9 @@ void incr_histograms(struct event *ev)
if (lg < 0 || lg >= NC)
low_gain_ch[i] = lg = -1;
if (lg >= 0 && mV[hg] >= high_low)
hists.dose[lg] += mV[lg];
else if (mV[hg] >= dose_min)
hists.dose[hg] += mV[hg];
hists.dose[lg] += keV[lg];
else if (keV[hg] >= dose_min)
hists.dose[hg] += keV[hg];
int ohg = coinc_ch[i];
if (ohg < 0 || ohg >= NC)
@ -1519,10 +1575,10 @@ void incr_histograms(struct event *ev)
}
if (olg < 0)
olg = ohg;
double h1 = mV[hg];
double h2 = mV[ohg];
double l1 = mV[lg];
double l2 = mV[olg];
double h1 = keV[hg];
double h2 = keV[ohg];
double l1 = keV[lg];
double l2 = keV[olg];
if (h1 < let_min || h2 < let_min)
continue;
if (h2*let_ratio < h1)
@ -1530,9 +1586,9 @@ void incr_histograms(struct event *ev)
if (h1*let_ratio < h2)
continue;
if (lg != hg) {
if (h1 >= high_low && l2*let_ratio < l1)
if (mV[hg] >= high_low && l2*let_ratio < l1)
continue;
if (h2 >= high_low && l1*let_ratio < l2)
if (mV[ohg] >= high_low && l1*let_ratio < l2)
continue;
}
int binh = (int)floor(log(h1/let_min_hg)/let_scale);
@ -2642,10 +2698,10 @@ struct numbers {
};
} numbers[] = {
{.name="mVscale", .doc="A/mV", .d=&mVscale, .flags=NU_DOUBLE},
{.name="dose_min_mV", .doc="mV", .d=&dose_min, .flags=NU_DOUBLE},
{.name="let_min_mV", .doc="mV", .d=&let_min, .flags=NU_DOUBLE},
{.name="let_min_lg_mV", .doc="mV", .d=&let_min_lg, .flags=NU_DOUBLE},
{.name="let_min_hg_mV", .doc="mV", .d=&let_min_hg, .flags=NU_DOUBLE},
{.name="dose_min", .doc="keV", .d=&dose_min, .flags=NU_DOUBLE},
{.name="let_min", .doc="keV", .d=&let_min, .flags=NU_DOUBLE},
{.name="let_min_lg", .doc="keV", .d=&let_min_lg, .flags=NU_DOUBLE},
{.name="let_min_hg", .doc="keV", .d=&let_min_hg, .flags=NU_DOUBLE},
{.name="let_ratio_cut",.doc="ratio",.d=&let_ratio, .flags=NU_DOUBLE},
{.name="high_low_cut", .doc="mV", .d=&high_low, .flags=NU_DOUBLE},
{.name="let_scale", .doc="ln(2)/bpo", .d=&let_scale, .flags=NU_DOUBLE},
@ -2654,7 +2710,7 @@ struct numbers {
{.name="Vref", .doc="V", .d=&Vref, .flags=NU_DOUBLE},
{.name="let_cadence", .doc="seconds", .u=&let_cadence, .flags=NU_INT},
{.name="dose_cadence", .doc="seconds", .u=&dose_cadence, .flags=NU_INT},
{.name="fct", .doc="fcts", .i=&fct_size, .flags=NU_INT},
{.name="fct", .doc="lines", .i=&fct_size, .flags=NU_INT},
{.name="fct_max_cadence", .doc="seconds", .i=&fct_max_cadence, .flags=NU_INT},
{.name="fct_min_data", .doc="packets", .i=&fct_min_data, .flags=NU_INT},
{.name="fct_sent", .doc="fcts", .i=&fct_sent, .flags=NU_INT},
@ -2670,7 +2726,7 @@ struct numbers {
{.name="highgain", .doc="ch#", .i=high_gain_ch, .flags=NU_INT, .size=NI},
{.name="lowgain", .doc="ch#", .i=low_gain_ch, .flags=NU_INT, .size=NI},
{.name="coincidence", .doc="ch#", .i=coinc_ch, .flags=NU_INT, .size=NI},
{.name="calibration", .doc="E/mV", .d=mV_calib, .flags=NU_DOUBLE, .size=NC},
{.name="calibration", .doc="keV/mV", .d=mV_calib, .flags=NU_DOUBLE, .size=NC},
{.name="verbosity", .doc="int", .i=verbosity, .flags=NU_INT, .size=2},
{.name="maintainance", .doc="int", .i=&maintainance, .flags=NU_INT},
{.name=0}
@ -2756,7 +2812,7 @@ int process_cmd(char *l)
char *av[10];
int na = split(l, 10, av);
if (!na)
if (!na || av[0][0]=='#')
return 0;
check_prompt();
if (verbose(2) || !strcmp(av[0], "echo")) {
@ -2768,10 +2824,19 @@ int process_cmd(char *l)
if (!strcmp(av[0], "echo")) {
return 0;
}
if (!strcmp(av[0], "version")) {
fprintf(mout, "irena version %s\n", version);
return 0;
}
int help = na>=2 && !strcmp(av[1], "help");
if (!strcmp(av[0], "help")) {
fprintf(mout, "available commands\n"
"commands:\n"
"\thelp\n"
"\tversion\n"
"\tnumbers\n"
"\texit «code»\n"
"\tsleep «seconds»\n"
@ -2817,12 +2882,12 @@ int process_cmd(char *l)
aa++;
na--;
}
if (ii<0 || na+ii > nn) {
if (help || ii<0 || na+ii > nn) {
if (nn>1)
fprintf(mout, "usage: %s [[«i»]] «%s» [… %d items]\n", n->name, n->doc, nn);
else
fprintf(mout, "usage: %s «%s»\n", n->name, n->doc);
return -1;
na = 0;
}
for (; na && ii<nn; ii++, aa++, na--) {
@ -2849,19 +2914,21 @@ int process_cmd(char *l)
}
if (!strcmp(av[0], "exit")) {
int code = 0;
if (help || na>2 || na==2 && number(av[1], &code)) {
fprintf(mout, "usage: exit [«status»]\n");
return -1;
}
file_close(&data_file);
file_close(&counter_file);
file_close(&status_file);
close_cmd_socket();
int code;
if (na==2 && !number(av[1], &code))
exit(code);
exit(0);
exit(code);
}
if (!strcmp(av[0], "sleep")) {
int sec;
if (na!=2 || number(av[1], &sec)) {
if (help || na!=2 || number(av[1], &sec)) {
fprintf(mout, "usage: sleep «seconds»\n");
return -1;
}
@ -2870,7 +2937,7 @@ int process_cmd(char *l)
}
if (!strcmp(av[0], "script")) {
if (na!=2) {
if (help || na!=2) {
fprintf(mout, "usage: script «filename»\n");
return -1;
}
@ -2881,6 +2948,14 @@ int process_cmd(char *l)
char *cmd = 0;
int drop = 0;
int i = 2;
if (help) {
fprintf(mout, "usage: sendfile [drop] «filename» [«command»]\n"
"- send contents of «filename» as 512 Byte blocks into the flashbuffer,\n"
"- optionally, send irena «command»,\n"
"- execute any cron items flagged `buffer`.\n"
"- option `drop`: do not send data blocks of all 0xff\n");
return -1;
}
if (na>2 && !strcmp(av[2], "drop")) {
drop = 1;
i++;
@ -2918,14 +2993,36 @@ int process_cmd(char *l)
return -1;
}
}
if (na<2 || na>4 || na==4 && !do_reset) {
fprintf(mout, "usage: uart «tty» [«baudrate»] [reset|rs232|rs422]\n");
if (help || na<2 || na>4 || na==4 && !do_reset) {
fprintf(mout,
"usage: uart «tty» [«baudrate»] [«reset»]\n"
"- open the serial port,\n"
"- optionally reset the µC, and\n"
"- configure the mode of reset for error recovery.\n"
"- «tty»: serial port device, /dev/tty…\n"
"- «baudrate»: 9600 | 38400 | 57600 | 115200 | 921600 | 1000000 | 1500000\n"
"- «reset»: on error, reset the µC via\n"
" * `reset`: RTS/CTS default polarity\n"
" * `rs232`: RS232 levels\n"
" * `rs422`: RS422 levels\n"
" * `gpio`: GPIO high active reset\n"
" * `gpio0`: GPIO low active reset\n"
);
return -1;
}
return init_serial_port(av[1], baud, do_reset);
}
if (!strcmp(av[0], "irena") || !strcmp(av[0],"var")) {
if (help) {
fprintf(mout,
"usage: irena «command»\n"
"usage: var «variable command»\n"
" (short for `irena var «command»`)\n"
"- send «command» to the irena µC\n"
);
return -1;
}
int i = *av[0]=='i';
unsplit(l, na);
int n;
@ -2948,8 +3045,15 @@ int process_cmd(char *l)
else do_sleep = -1;
if (na>3 || na>2 && (!do_sleep || strcmp(av[2], "config")))
do_sleep = -1;
if (do_sleep < 0) {
fprintf(mout, "usage: set_clock [sleep|drift] [config]\n");
if (help || do_sleep < 0) {
fprintf(mout,
"usage: set_clock [sleep|drift] [config]\n"
"- set the µC RTC to the current host time.\n"
"option `sleep`: Wait until the end of the current second.\n"
"option `drift`: Sleep, and ask the µC to adjust the clock speed.\n"
"option `config`: configure the sleep mode of the periodic clock setting,\n"
" (does not set the µC clock).\n"
);
return -1;
}
if (config) {
@ -2959,30 +3063,32 @@ int process_cmd(char *l)
}
return set_clock(do_sleep);
}
int na0 = help ? 0 : na;
if (!strcmp(av[0], "datafile"))
return config_file(&data_file, na, av);
return config_file(&data_file, na0, av);
if (!strcmp(av[0], "counterfile"))
return config_file(&counter_file, na, av);
return config_file(&counter_file, na0, av);
if (!strcmp(av[0], "statusfile"))
return config_file(&status_file, na, av);
return config_file(&status_file, na0, av);
if (!strcmp(av[0], "datarate"))
return config_priority(na, av);
return config_priority(na0, av);
if (!strcmp(av[0], "limits"))
return config_status(na, av);
return config_status(na0, av);
if (!strcmp(av[0], "socket"))
return open_cmd_socket(na, av);
return open_cmd_socket(na0, av);
if (!strcmp(av[0], "test_uart_buffer"))
return test_serial_read_buffer(na, av);
return test_serial_read_buffer(na0, av);
if (!strcmp(av[0], "cron")) {
if (config_cron(na, av) == -1)
if (help || config_cron(na, av) == -1)
fprintf(mout, "usage:\tcron [«index» [«flags»… [«delay» «cmd»]]]\n"
"\tcron force «flags»… [«times»]\n"
"\tcron «index» delete\n");
@ -3003,7 +3109,7 @@ int process_cmd(char *l)
if (na>1)
break;
}
if (na>3 || na>1 && !pp->name)
if (help || na>3 || na>1 && !pp->name)
fprintf(mout, "usage:\tpath [«name» [«value»]]\n");
return 0;
}
@ -3185,8 +3291,7 @@ int main(int argc, char **argv)
mout = stderr;
fprintf(mout,
"irena data acquisition via uart\n"
"%s\n", version);
"irena data acquisition via uart, git %s\n", version);
epoll_fd = epoll_create(1);
if (epoll_fd < 0) {

26
rc.local Executable file
View file

@ -0,0 +1,26 @@
#!/bin/bash -vx
## call this script from /etc/rc.local
# chmod -v a+x /etc/rc.local
# echo $0 >> /etc/rc.local
D3D="$(dirname $0)"
IRENA=$D3D/d3d.rc
IMON=$D3D/imonitor.py
U=$(stat "$0" -c "%U")
## disable getty on $T
# sed -i 's/^2:/#2:/' /etc/inittab
T=/dev/tty2
if [ -x "$IRENA" ]
then
cd $D3D
sudo -inu $U screen -S IRENA -d -m $IRENA
[ -x "$IMON" ] && sudo -inu $U screen -S IRENA -X screen $IMON
chown $U $T
sudo -inu $U setsid <$T >$T 2>&1 screen -S IRENA -x &
fi
exit 0