How to do timeout less than 1 second? - expect

To write more robust scripts it is useful to "forget" contents of expect buffer to ensure the matching is done only on recently received input:
# this leaves expect buffer with unmatched history
# + accumulates incoming data over 1 sec
set timeout 1
expect
# match everything in the buffer ~"forget"
expect *
# subsequent expect commands will see only what appeared since now
Is it possible to have the timeout smaller than 1 second without patching the expect sources?
Note: set timeout 0 will not work as the first expect doesn't leave the newly incoming data in buffer.

I'm not sure about the how to flush the buffer in the tcl interpreter.
I'm not sure about your use case, but I have found that the most reliable format for remote-shell scripting over expect, that the easiest thing to do is to include a #randomnumber at the end of each send, expect for the #randomnumber, this makes sure that the buffer is synced to the last line that I send to the spawned process. Your mileage would vary if the spawned process doesn't echo the characters you send.
The pure python implementation from pexpect is great if you are ok with moving to python from the TCL implementation. The buffers work slightly differently so it will take some getting used to. If you are executing commands over remote shells I'd recommend python-remote (Which i wrote)
you could gas the buffer in the method you are using above by
import pexpect
spawn = pexpect.spawn(command)
stuff_inbuffer = spawn.read_nonblocking(size=100000, timeout=0.1)
sending random strings to sync the buffer before repsonse
import random, pexpect
spawn = pexpect.spawn(command)
rand = random.random()
spawn.sendline(command + " #%s" %(rand))
spawn.expect("%s\r\n" %(rand))
you could then either get the buffer with and expect, or read which will wait until the buffer has size, or timeout is exceeded.
results = spwan.read(size=100000, timeout=10)
spawn.expect("something")
results = spawn.buffer
or
results = spawn.before

Patching expect is easy... use negative timeouts for milliseconds (except -1, which is special):
# set timeout to 100 milliseconds
set timeout -100
The following if named milliExpect.patch... cd into expect5.45 directory and do
patch -Np1 -i milliExpect.patch.
Then the usual (may have to stipulate where tcl is in configure)...
./configure; make; sudo make install
--- milliExpect.patch ----
--- expect5.45_orig/exp_event.c 2010-06-30 17:53:49.000000000 -0700
+++ expect5.45/exp_event.c 2014-09-30 12:50:18.733698995 -0700
## -277,6 +277,117 ##
}
}
+/* returns status, one of EOF, TIMEOUT, ERROR or DATA */
+/* can now return RECONFIGURE, too */
+/*ARGSUSED*/
+int exp_get_next_event_d(interp,esPtrs,n,esPtrOut,timeout,key)
+Tcl_Interp *interp;
+ExpState *(esPtrs[]);
+int n; /* # of esPtrs */
+ExpState **esPtrOut; /* 1st ready esPtr, not set if none */
+double timeout; /* milliseconds */
+int key;
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ ExpState *esPtr;
+ int i; /* index into in-array */
+#ifdef HAVE_PTYTRAP
+ struct request_info ioctl_info;
+#endif
+
+ int old_configure_count = exp_configure_count;
+
+ int timerFired = FALSE;
+ Tcl_TimerToken timerToken = 0;/* handle to Tcl timehandler descriptor */
+ /* We must delete any timer before returning. Doing so throughout
+ * the code makes it unreadable; isolate the unreadable nonsense here.
+ */
+#define RETURN(x) { \
+ if (timerToken) Tcl_DeleteTimerHandler(timerToken); \
+ return(x); \
+ }
+
+ for (;;) {
+ /* if anything has been touched by someone else, report that */
+ /* an event has been received */
+
+ for (i=0;i<n;i++) {
+ tsdPtr->rr++;
+ if (tsdPtr->rr >= n) tsdPtr->rr = 0;
+
+ esPtr = esPtrs[tsdPtr->rr];
+
+ if (esPtr->key != key) {
+ esPtr->key = key;
+ esPtr->force_read = FALSE;
+ *esPtrOut = esPtr;
+ RETURN(EXP_DATA_OLD);
+ } else if ((!esPtr->force_read) && (!expSizeZero(esPtr))) {
+ *esPtrOut = esPtr;
+ RETURN(EXP_DATA_OLD);
+ } else if (esPtr->notified) {
+ /* this test of the mask should be redundant but SunOS */
+ /* raises both READABLE and EXCEPTION (for no */
+ /* apparent reason) when selecting on a plain file */
+ if (esPtr->notifiedMask & TCL_READABLE) {
+ *esPtrOut = esPtr;
+ esPtr->notified = FALSE;
+ RETURN(EXP_DATA_NEW);
+ }
+ /*
+ * at this point we know that the event must be TCL_EXCEPTION
+ * indicating either EOF or HP ptytrap.
+ */
+#ifndef HAVE_PTYTRAP
+ RETURN(EXP_EOF);
+#else
+ if (ioctl(esPtr->fdin,TIOCREQCHECK,&ioctl_info) < 0) {
+ expDiagLog("ioctl error on TIOCREQCHECK: %s", Tcl_PosixError(interp));
+ RETURN(EXP_TCLERROR);
+ }
+ if (ioctl_info.request == TIOCCLOSE) {
+ RETURN(EXP_EOF);
+ }
+ if (ioctl(esPtr->fdin, TIOCREQSET, &ioctl_info) < 0) {
+ expDiagLog("ioctl error on TIOCREQSET after ioctl or open on slave: %s", Tcl_ErrnoMsg(errno));
+ }
+ /* presumably, we trapped an open here */
+ /* so simply continue by falling thru */
+#endif /* !HAVE_PTYTRAP */
+ }
+ }
+
+ if (!timerToken) {
+ if (timeout >= 0) {
+ timerToken = Tcl_CreateTimerHandler((int)timeout,
+ exp_timehandler,
+ (ClientData)&timerFired);
+ }
+ }
+
+ /* make sure that all fds that should be armed are */
+ for (i=0;i<n;i++) {
+ esPtr = esPtrs[i];
+ /*printf("CreateChannelHandler: %s\r\n",esPtr->name);*/
+ Tcl_CreateChannelHandler(
+ esPtr->channel,
+ TCL_READABLE | TCL_EXCEPTION,
+ exp_channelhandler,
+ (ClientData)esPtr);
+ esPtr->fg_armed = TRUE;
+ }
+
+ Tcl_DoOneEvent(0); /* do any event */
+
+ if (timerFired) return(EXP_TIMEOUT);
+
+ if (old_configure_count != exp_configure_count) {
+ RETURN(EXP_RECONFIGURE);
+ }
+ }
+}
+
/* Having been told there was an event for a specific ExpState, get it */
/* This returns status, one of EOF, TIMEOUT, ERROR or DATA */
/*ARGSUSED*/
--- expect5.45_orig/expect.c 2010-10-26 15:09:36.000000000 -0700
+++ expect5.45/expect.c 2014-09-30 13:01:42.693800013 -0700
## -41,6 +41,12 ##
#include "tcldbg.h"
#endif
+#define TclUtfToUniChar(str, chPtr) \
+ ((((unsigned char) *(str)) < 0xC0) ? \
+ ((*(chPtr) = (Tcl_UniChar) *(str)), 1) \
+ : Tcl_UtfToUniChar(str, chPtr))
+
+
#include "retoglob.c" /* RE 2 GLOB translator C variant */
/* initial length of strings that we can guarantee patterns can match */
## -123,6 +129,7 ##
int duration; /* permanent or temporary */
int timeout_specified_by_flag; /* if -timeout flag used */
int timeout; /* timeout period if flag used */
+ double timeout_double; /* if timeout < -1 */
struct exp_cases_descriptor ecd;
struct exp_i *i_list;
} exp_cmds[4];
## -559,6 +566,11 ##
goto error;
}
eg->timeout_specified_by_flag = TRUE;
+ if (eg->timeout < -1) {
+ eg->timeout_double = (double)eg->timeout * -1.;
+ } else {
+ eg->timeout_double = (double)eg->timeout * 1000.;
+ }
break;
case EXP_ARG_NOBRACE:
/* nobrace does nothing but take up space */
## -1812,6 +1824,74 ##
return cc;
}
+/* returns # of bytes read or (non-positive) error of form EXP_XXX */
+/* returns 0 for end of file */
+/* If timeout is non-zero, set an alarm before doing the read, else assume */
+/* the read will complete immediately. */
+/*ARGSUSED*/
+static int
+expIRead_d( /* INTL */
+ Tcl_Interp *interp,
+ ExpState *esPtr,
+ double timeout,
+ int save_flags)
+{
+ int cc = EXP_TIMEOUT;
+ int size;
+
+ /* We drop one third when are at least 2/3 full */
+ /* condition is (size >= max*2/3) <=> (size*3 >= max*2) */
+ if (expSizeGet(esPtr)*3 >= esPtr->input.max*2)
+ exp_buffer_shuffle(interp,esPtr,save_flags,EXPECT_OUT,"expect");
+ size = expSizeGet(esPtr);
+
+#ifdef SIMPLE_EVENT
+ restart:
+
+ alarm_fired = FALSE;
+
+ if (timeout > -1) {
+ if (timeout > 0) {
+ usleep((int)timeout * 1000);
+ } else {
+ usleep(1000 * 1); /* ?? is 1 ms enough ??? */
+ }
+ }
+#endif
+
+ cc = Tcl_ReadChars(esPtr->channel, esPtr->input.newchars,
+ esPtr->input.max - esPtr->input.use,
+ 0 /* no append */);
+ i_read_errno = errno;
+
+ if (cc > 0) {
+ memcpy (esPtr->input.buffer + esPtr->input.use,
+ Tcl_GetUnicodeFromObj (esPtr->input.newchars, NULL),
+ cc * sizeof (Tcl_UniChar));
+ esPtr->input.use += cc;
+ }
+
+#ifdef SIMPLE_EVENT
+ alarm(0);
+
+ if (cc == -1) {
+ /* check if alarm went off */
+ if (i_read_errno == EINTR) {
+ if (alarm_fired) {
+ return EXP_TIMEOUT;
+ } else {
+ if (Tcl_AsyncReady()) {
+ int rc = Tcl_AsyncInvoke(interp,TCL_OK);
+ if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc));
+ }
+ goto restart;
+ }
+ }
+ }
+#endif
+ return cc;
+}
+
/*
* expRead() does the logical equivalent of a read() for the expect command.
* This includes figuring out which descriptor should be read from.
## -1932,6 +2012,126 ##
}
return(cc);
}
+/*
+ * expRead_d() does the logical equivalent of a read() for the expect command.
+ * This includes figuring out which descriptor should be read from.
+ *
+ * The result of the read() is left in a spawn_id's buffer rather than
+ * explicitly passing it back. Note that if someone else has modified a buffer
+ * either before or while this expect is running (i.e., if we or some event has
+ * called Tcl_Eval which did another expect/interact), expRead will also call
+ * this a successful read (for the purposes if needing to pattern match against
+ * it).
+ */
+
+/* if it returns a negative number, it corresponds to a EXP_XXX result */
+/* if it returns a non-negative number, it means there is data */
+/* (0 means nothing new was actually read, but it should be looked at again) */
+int
+expRead_d(
+ Tcl_Interp *interp,
+ ExpState *(esPtrs[]), /* If 0, then esPtrOut already known and set */
+ int esPtrsMax, /* number of esPtrs */
+ ExpState **esPtrOut, /* Out variable to leave new ExpState. */
+ double timeout,
+ int key)
+{
+ ExpState *esPtr;
+
+ int size;
+ int cc;
+ int write_count;
+ int tcl_set_flags; /* if we have to discard chars, this tells */
+ /* whether to show user locally or globally */
+
+ if (esPtrs == 0) {
+ /* we already know the ExpState, just find out what happened */
+ cc = exp_get_next_event_info(interp,*esPtrOut);
+ tcl_set_flags = TCL_GLOBAL_ONLY;
+ } else {
+ cc = exp_get_next_event_d(interp,esPtrs,esPtrsMax,esPtrOut,timeout,key);
+ tcl_set_flags = 0;
+ }
+
+ esPtr = *esPtrOut;
+
+ if (cc == EXP_DATA_NEW) {
+ /* try to read it */
+ cc = expIRead_d(interp,esPtr,timeout,tcl_set_flags);
+
+ /* the meaning of 0 from i_read means eof. Muck with it a */
+ /* little, so that from now on it means "no new data arrived */
+ /* but it should be looked at again anyway". */
+ if (cc == 0) {
+ cc = EXP_EOF;
+ } else if (cc > 0) {
+ /* successfully read data */
+ } else {
+ /* failed to read data - some sort of error was encountered such as
+ * an interrupt with that forced an error return
+ */
+ }
+ } else if (cc == EXP_DATA_OLD) {
+ cc = 0;
+ } else if (cc == EXP_RECONFIGURE) {
+ return EXP_RECONFIGURE;
+ }
+
+ if (cc == EXP_ABEOF) { /* abnormal EOF */
+ /* On many systems, ptys produce EIO upon EOF - sigh */
+ if (i_read_errno == EIO) {
+ /* Sun, Cray, BSD, and others */
+ cc = EXP_EOF;
+ } else if (i_read_errno == EINVAL) {
+ /* Solaris 2.4 occasionally returns this */
+ cc = EXP_EOF;
+ } else {
+ if (i_read_errno == EBADF) {
+ exp_error(interp,"bad spawn_id (process died earlier?)");
+ } else {
+ exp_error(interp,"i_read(spawn_id fd=%d): %s",esPtr->fdin,
+ Tcl_PosixError(interp));
+ if (esPtr->close_on_eof) {
+ exp_close(interp,esPtr);
+ }
+ }
+ return(EXP_TCLERROR);
+ /* was goto error; */
+ }
+ }
+
+ /* EOF, TIMEOUT, and ERROR return here */
+ /* In such cases, there is no need to update screen since, if there */
+ /* was prior data read, it would have been sent to the screen when */
+ /* it was read. */
+ if (cc < 0) return (cc);
+
+ /*
+ * update display
+ */
+
+ size = expSizeGet(esPtr);
+ if (size) write_count = size - esPtr->printed;
+ else write_count = 0;
+
+ if (write_count) {
+ /*
+ * Show chars to user if they've requested it, UNLESS they're seeing it
+ * already because they're typing it and tty driver is echoing it.
+ * Also send to Diag and Log if appropriate.
+ */
+ expLogInteractionU(esPtr,esPtr->input.buffer + esPtr->printed, write_count);
+
+ /*
+ * strip nulls from input, since there is no way for Tcl to deal with
+ * such strings. Doing it here lets them be sent to the screen, just
+ * in case they are involved in formatting operations
+ */
+ if (esPtr->rm_nulls) size = expNullStrip(&esPtr->input,esPtr->printed);
+ esPtr->printed = size; /* count'm even if not logging */
+ }
+ return(cc);
+}
/* when buffer fills, copy second half over first and */
/* continue, so we can do matches over multiple buffers */
## -2363,7 +2563,12 ##
/* "!e" means no case matched - transfer by default */
if (!e || e->transfer) {
- int remainder = numchars-match;
+ int remainder;
+ if (match > numchars) {
+ match = numchars;
+ eo->matchlen = match;
+ }
+ remainder = numchars-match;
/* delete matched chars from input buffer */
esPtr->printed -= match;
if (numchars != 0) {
## -2548,6 +2753,11 ##
time_t current_time = 0; /* current time (when we last looked)*/
time_t end_time; /* future time at which to give up */
+ double start_time_total_d; /* time at beginning of this procedure */
+ double start_time_d = 0.; /* time when restart label hit */
+ double current_time_d = 0.; /* current time (when we last looked)*/
+ double end_time_d; /* future time at which to give up */
+
ExpState *last_esPtr; /* for differentiating when multiple f's */
/* to print out better debugging messages */
int last_case; /* as above but for case */
## -2556,8 +2766,9 ##
int key; /* identify this expect command instance */
int configure_count; /* monitor exp_configure_count */
- int timeout; /* seconds */
+ int timeout; /* seconds (or milliseconds if less than -1) */
int remtime; /* remaining time in timeout */
+ double remtime_d; /* remaining time in timeout (milliseconds) */
int reset_timer; /* should timer be reset after continue? */
Tcl_Time temp_time;
Tcl_Obj* new_cmd = NULL;
## -2585,7 +2796,9 ##
Tcl_GetTime (&temp_time);
start_time_total = temp_time.sec;
+ start_time_total_d = temp_time.sec * 1000. + temp_time.usec / 1000.;
start_time = start_time_total;
+ start_time_d = start_time_total_d;
reset_timer = TRUE;
if (&StdinoutPlaceholder == (ExpState *)clientData) {
## -2641,6 +2854,7 ##
else {
Tcl_GetTime (&temp_time);
start_time = temp_time.sec;
+ start_time_d = temp_time.sec * 1000. + temp_time.usec / 1000.;
}
if (eg.timeout_specified_by_flag) {
## -2669,7 +2883,9 ##
if (reset_timer) {
Tcl_GetTime (&temp_time);
current_time = temp_time.sec;
+ current_time_d = temp_time.sec * 1000. + temp_time.usec / 1000.;
end_time = current_time + timeout;
+ end_time_d = current_time_d - timeout;
} else {
reset_timer = TRUE;
}
## -2677,12 +2893,20 ##
/* remtime and current_time updated at bottom of loop */
remtime = timeout;
+ remtime_d = timeout * -1.;
for (;;) {
- if ((timeout != EXP_TIME_INFINITY) && (remtime < 0)) {
+
+ if ((timeout > EXP_TIME_INFINITY) && (remtime < 0)) {
+ cc = EXP_TIMEOUT;
+ } else if ((timeout < EXP_TIME_INFINITY) && (remtime_d < 0.)) {
cc = EXP_TIMEOUT;
} else {
+ if (timeout >= EXP_TIME_INFINITY) {
cc = expRead(interp,esPtrs,mcount,&esPtr,remtime,key);
+ } else {
+ cc = expRead_d(interp,esPtrs,mcount,&esPtr,remtime_d,key);
+ }
}
/*SUPPRESS 530*/
## -2732,7 +2956,9 ##
if (timeout != EXP_TIME_INFINITY) {
Tcl_GetTime (&temp_time);
current_time = temp_time.sec;
+ current_time_d = temp_time.sec * 1000. + temp_time.usec / 1000.;
remtime = end_time - current_time;
+ remtime_d = end_time_d - current_time_d;
}
}

Related

eBPF Validation error when trying to hash a string (process name)

Hi I am trying to generate a 32bit hash for the full process name in ebpf. These process names can be long and will not fit on the stack hence the "heap" per cpu array. I am currently using libbpf bootstrap as a prototype from here: https://github.com/libbpf/libbpf-bootstrap.git I am having an issue with the verifier not validating the hash function. What is the problem here? I am stumped.
The meat of the code is:
uint32_t map_id = 0;
char *map_val = bpf_map_lookup_elem(&heap, &map_id);
if (!map_val)
return 0;
int bytes_read = bpf_probe_read_str(map_val, sizeof(e->filename), (void *)ctx + fname_off);
if (bytes_read > 0) {
map_val[ (bytes_read - 1) & (4096 -1) ] = 0;
uint32_t key = hash( (unsigned char*)map_val);
bpf_printk("process_exec count: %u, hash: %lu, full path: %s\n", bytes_read -1, key, map_val);
}
The hash function is:
uint32_t hash(unsigned char *str)
{
int c;
uint32_t hash = 5381;
while ( c = *str++ )
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
I get a validator error:
; hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
91: (27) r4 *= 33
; hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
92: (0f) r4 += r1
; while ( c = *str++ )
93: (71) r1 = *(u8 *)(r2 +0)
R0=inv(id=6,smin_value=-4096,smax_value=4095) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=4096,ks=4,vs=4096,imm=0) R4_w=inv(id=0) R6=ctx(id=0,off=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=map_value(id=0,off=0,ks=4,vs=4096,imm=0) R8=invP0 R10=fp0 fp-8=mmmm???? fp-16=mmmmmmmm fp-24=mmmm???? fp-32=mmmmmmmm
invalid access to map value, value_size=4096 off=4096 size=1
R2 min value is outside of the allowed memory range
processed 32861 insns (limit 1000000) max_states_per_insn 4 total_states 337 peak_states 337 mark_read 4
-- END PROG LOAD LOG --
libbpf: prog 'handle_exec': failed to load: -13
libbpf: failed to load object 'bootstrap_bpf'
libbpf: failed to load BPF skeleton 'bootstrap_bpf': -13
Failed to load and verify BPF skeleton
Here is the complete diff for my use case:
diff --git a/examples/c/bootstrap.bpf.c b/examples/c/bootstrap.bpf.c
index d0860c0..c93ed58 100644
--- a/examples/c/bootstrap.bpf.c
+++ b/examples/c/bootstrap.bpf.c
## -20,6 +20,13 ## struct {
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __uint(key_size, sizeof(u32));
+ __uint(max_entries, 1);
+ __uint(value_size, 4096);
+} heap SEC(".maps");
+
const volatile unsigned long long min_duration_ns = 0;
SEC("tp/sched/sched_process_exec")
## -58,6 +65,22 ## int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
/* successfully submit it to user-space for post-processing */
bpf_ringbuf_submit(e, 0);
+
+
+ uint32_t map_id = 0;
+ char *map_val = bpf_map_lookup_elem(&heap, &map_id);
+ if (!map_val)
+ return 0;
+
+ int bytes_read = bpf_probe_read_str(map_val, sizeof(e->filename), (void *)ctx + fname_off);
+ if (bytes_read > 0) {
+ // tell the validator bytes ready is between 0 and 4095
+ map_val[ (bytes_read - 1) & (4096 -1) ] = 0;
+
+ uint32_t key = hash( (unsigned char*)map_val);
+ bpf_printk("process_exec count: %u, hash: %u, full path: %s\n", bytes_read -1, key, map_val);
+ }
+
return 0;
}
## -109,4 +132,3 ## int handle_exit(struct trace_event_raw_sched_process_template* ctx)
bpf_ringbuf_submit(e, 0);
return 0;
}
-
diff --git a/examples/c/bootstrap.h b/examples/c/bootstrap.h
index b49e022..d268e56 100644
--- a/examples/c/bootstrap.h
+++ b/examples/c/bootstrap.h
## -4,7 +4,7 ##
#define __BOOTSTRAP_H
#define TASK_COMM_LEN 16
-#define MAX_FILENAME_LEN 127
+#define MAX_FILENAME_LEN 4096
struct event {
int pid;
## -16,4 +16,15 ## struct event {
bool exit_event;
};
+static inline
+uint32_t hash(unsigned char *str)
+{
+ int c;
+ uint32_t hash = 5381;
+ while ( c = *str++ )
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
+}
+
#endif /* __BOOTSTRAP_H */
TL;DR. You need to ensure that you are not reading past the end of the map value. So you need to check str never goes past the initial str value + 4095.
Verifier error explanation.
; while ( c = *str++ )
93: (71) r1 = *(u8 *)(r2 +0)
R0=inv(id=6,smin_value=-4096,smax_value=4095) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=4096,ks=4,vs=4096,imm=0) R4_w=inv(id=0) R6=ctx(id=0,off=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=map_value(id=0,off=0,ks=4,vs=4096,imm=0) R8=invP0 R10=fp0 fp-8=mmmm???? fp-16=mmmmmmmm fp-24=mmmm???? fp-32=mmmmmmmm
invalid access to map value, value_size=4096 off=4096 size=1
R2 min value is outside of the allowed memory range
The verifier here is telling you that your code may attempt to read one byte (size=1) from the map value, at offset 4096 (off=4096). Since the map value has a size of 4096 (value_size=4096), that would end up reading after the end of the map value, leading to an unbounded memory access. Hence, the verifier rejects it.

W5100 is sending garbage

I try to implement a web interface with a W5100 Ethernet Controller and an XMega, but my browser prints out this weird result:
Please take a look at my code:
SPIM_Config_t Config_SPIM = {
.Device = &SPIC,
.Mode = SPI_MODE_0,
.Prescaler = SPI_PRESCALER_64,
};
W5100_Config_t Config_Ethernet = {
.Submask = {255, 255, 0, 0},
.IP = {169, 254, 133, 121},
.Gateway = {169, 154, 133, 129},
.MAC = {0x00, 0x00, 0x00, 0x00, 0x00, 0xAA}
};
uint8_t Rx_Buffer[2048];
uint8_t Tx_Buffer[2048];
const char HTTP[] = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"
"<html>\r\n"
"<body>\r\n"
"<title>Title</title>\r\n"
"<p>Hello world</p>\r\n"
"</body>\r\n"
"</html>\r\n";
int main(void)
{
W5100_Init(&Config_SPIM, &Config_Ethernet);
while(1)
{
W5100_Status_t Status;
W5100_GetState(0, &Status);
switch(Status)
{
case W5100_SOCK_CLOSED:
{
if(W5100_Open(0, W5100_PROT_TCP, 80, W5100_MEM_2K, W5100_MEM_2K, 65535) == W5100_NO_ERROR)
{
W5100_Listen(0, ETHERNET_TIMEOUT);
}
break;
}
case W5100_SOCK_ESTABLISHED:
{
uint16_t Rx_Bytes;
if(W5100_GetBytes(0, &Rx_Bytes) == W5100_NO_ERROR)
{
if(Rx_Bytes)
{
W5100_Receive(0, Rx_Buffer, Rx_Bytes);
strcpy((char*)Tx_Buffer, HTTP);
W5100_Send(0, Tx_Buffer, strlen((char*)HTTP), ETHERNET_TIMEOUT);
}
else
{
}
}
W5100_Disconnect(0, ETHERNET_TIMEOUT);
break;
}
case W5100_SOCK_FIN_WAIT:
case W5100_SOCK_CLOSING:
case W5100_SOCK_TIME_WAIT:
case W5100_SOCK_CLOSE_WAIT:
case W5100_SOCK_LAST_ACK:
{
W5100_Close(0, ETHERNET_TIMEOUT);
break;
}
}
}
}
I think the error is somewhere in my W5100_Send function and it seems that the Controller is sending the content of different memory locations, but I can´t figure out the error. The code based on the datasheet of the Ethernet Controller:
W5100_ErrorCode_t W5100_Send(uint8_t Socket, uint8_t* Buffer, uint16_t Length, uint32_t Timeout)
{
uint8_t Temp[2];
uint8_t Mask;
uint16_t SocketBase;
uint16_t Offset;
uint16_t Free;
uint16_t SocketMemory;
uint32_t Timeout_Temp = Timeout;
if(!_W5100_IsInitialized)
{
return W5100_NOT_INITIALIZED;
}
else if((Socket > 0x04) || (Buffer == NULL) || (Length == 0x00))
{
return W5100_INVALID_PARAM;
}
// Get the memory mask for address calculation
W5100_ReadRegister(W5100_REGISTER_TMSR, &Mask);
Mask &= (0x03 << (Socket << 0x01));
// Check for invalid memory by comparing the memory mask for the given socket and the socket index
if(((Socket > 0) && (Mask == 3)) || ((Socket > 1) && (Mask == 2)))
{
return W5100_INVALID_PARAM;
}
SocketBase = W5100_SOCKET_ADDR(Socket);
SocketMemory = W5100_SOCKET_MEM_OFFSET << Mask;
// Wait while the buffer is full
do
{
// Get the free bytes
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_FSR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_FSR1, &Temp[1]);
Free = ((uint16_t)(Temp[0] << 0x08)) | Temp[1];
if(Timeout_Temp-- == 0x00)
{
W5100_Disconnect(Socket, Timeout);
return W5100_TIMEOUT;
}
_delay_ms(1);
}while(Free < Length);
// Get the write pointer address
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR1, &Temp[1]);
Offset = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]) & W5100_TX_MEM_MASK;
// Check for an overflow
if(Offset + Length > SocketMemory)
{
uint16_t Upper;
uint16_t Left;
Upper = SocketMemory - Offset;
Left = Length - Upper;
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Upper);
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket), Buffer, Left);
}
else
{
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Length);
}
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR0, Offset >> 0x08);
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR1, Offset & 0xFF);
return W5100_ExecuteCommand(Socket, W5100_CMD_SEND, Timeout);
}
You should fully rewrite your W5100_Send, because it is full of issues.
For example, calculation of Mask value has no sense.
The cycle which is waiting for Free value always delays at least 1 ms, even when good value obtained from the beginning. Also, when timed out, it breaks, even if received Free value is good.
Offset value is damaged by & operation:
Offset = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]) & W5100_TX_MEM_MASK;
This value is never increased by the written data size, and the damaged value is written back to W5100_OFFSET_TX_WR1:W5100_OFFSET_TX_WR0
The wrapping data writing has an error:
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Upper);
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket), Buffer, Left);
You're copying to both the parts from the start of Buffer. In the second line it should be &Buffer[Upper]
Etc etc...
First you need to determine size of sockets. I encourage you to set up the socket sizes from the beginning, thus avoiding offset and size calculation on the runtime.
But if you want to determine the socket size dynamically, then you can do it as follows:
uint16_t SocketBufAddr = W5100_TX_BUFFER_BASE; // Start of the socket memory block
SocketMemory = 0; // Size of the socket memory block
W5100_ReadRegister(W5100_REGISTER_TMSR, &Mask);
for (uint8_t i = 0 ; i <= Socket ; i++) {
SocketBufAddr += SocketMemory; // Increase the offset by the previous socket size
SocketMemory = 1024 << ((Mask >> (i * 2)) & 3);
}
now, the writing process should be something like this:
// Get the write pointer address
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR1, &Temp[1]);
uint16_t WrPointer = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]); // no & operation! It is the 16-bit pointer!!!
Offset = WrPointer & (SocketMemory - 1); // Offset inside the socket memory block. SocketMemory is always = 2^n
// Check for an overflow
if(Offset + Length > SocketMemory)
{
uint16_t Upper;
uint16_t Left;
Upper = SocketMemory - Offset ;
Left = Length - Upper;
W5100_WriteMemory(SocketBufAddr + Offset, Buffer, Upper);
W5100_WriteMemory(SocketBufAddr, &Buffer[Upper], Left);
}
else
{
W5100_WriteMemory(SocketBufAddr + Offset, Buffer, Length);
}
WrPointer += Length; // Increase full 16-bit pointer value
// Write the new pointer back
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR0, WrPointer >> 0x08);
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR1, WrPointer & 0xFF);
return W5100_ExecuteCommand(Socket, W5100_CMD_SEND, Timeout);

Looking for source code of __builtin_avr_delay_cycles called by _delay_ms in avr-gcc

I was investigating the delay_ms function of avr-gcc. In delay.h I found its definition:
void _delay_ms(double __ms)
{
double __tmp ;
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__) && \
!defined(__DELAY_BACKWARD_COMPATIBLE__) && \
__STDC_HOSTED__
uint32_t __ticks_dc;
extern void __builtin_avr_delay_cycles(unsigned long);
__tmp = ((F_CPU) / 1e3) * __ms;
#if defined(__DELAY_ROUND_DOWN__)
__ticks_dc = (uint32_t)fabs(__tmp);
#elif defined(__DELAY_ROUND_CLOSEST__)
__ticks_dc = (uint32_t)(fabs(__tmp)+0.5);
#else
//round up by default
__ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
#endif
__builtin_avr_delay_cycles(__ticks_dc);
#else
...
}
I am interested in how the __builtin_avr_delay_cycles function looks like internally and where it is defined? Where can I find the source?
As said in my comment to this very question on electronics.SE:
Compiler builtins are kinda funky to find, always, because they are not just C functions, but things that get inserted while parsing/compiling the code (at various levels of abstraction from the textual representation of the code itself. compiler theory stuff). What you're looking for is the function avr_expand_builtin in the GCC source tree. There's a case AVR_BUILTIN_DELAY_CYCLES in there. Look for what happens there.
Which is:
/* Implement `TARGET_EXPAND_BUILTIN'. */
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
(and in mode MODE if that's convenient).
SUBTARGET may be used as the target for computing one of EXP's operands.
IGNORE is nonzero if the value is to be ignored. */
static rtx
avr_expand_builtin (tree exp, rtx target,
rtx subtarget ATTRIBUTE_UNUSED,
machine_mode mode ATTRIBUTE_UNUSED,
int ignore)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
const char *bname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
unsigned int id = DECL_FUNCTION_CODE (fndecl);
const struct avr_builtin_description *d = &avr_bdesc[id];
tree arg0;
rtx op0;
gcc_assert (id < AVR_BUILTIN_COUNT);
switch (id)
{
case AVR_BUILTIN_NOP:
emit_insn (gen_nopv (GEN_INT (1)));
return 0;
case AVR_BUILTIN_DELAY_CYCLES:
{
arg0 = CALL_EXPR_ARG (exp, 0);
op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
if (!CONST_INT_P (op0))
error ("%s expects a compile time integer constant", bname);
else
avr_expand_delay_cycles (op0);
return NULL_RTX;
}
…
thus, the function you're looking for is avr_expand_delay_cycles in the same file:
static void
avr_expand_delay_cycles (rtx operands0)
{
unsigned HOST_WIDE_INT cycles = UINTVAL (operands0) & GET_MODE_MASK (SImode);
unsigned HOST_WIDE_INT cycles_used;
unsigned HOST_WIDE_INT loop_count;
if (IN_RANGE (cycles, 83886082, 0xFFFFFFFF))
{
loop_count = ((cycles - 9) / 6) + 1;
cycles_used = ((loop_count - 1) * 6) + 9;
emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode),
avr_mem_clobber()));
cycles -= cycles_used;
}
if (IN_RANGE (cycles, 262145, 83886081))
{
loop_count = ((cycles - 7) / 5) + 1;
if (loop_count > 0xFFFFFF)
loop_count = 0xFFFFFF;
cycles_used = ((loop_count - 1) * 5) + 7;
emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode),
avr_mem_clobber()));
cycles -= cycles_used;
}
if (IN_RANGE (cycles, 768, 262144))
{
loop_count = ((cycles - 5) / 4) + 1;
if (loop_count > 0xFFFF)
loop_count = 0xFFFF;
cycles_used = ((loop_count - 1) * 4) + 5;
emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode),
avr_mem_clobber()));
cycles -= cycles_used;
}
if (IN_RANGE (cycles, 6, 767))
{
loop_count = cycles / 3;
if (loop_count > 255)
loop_count = 255;
cycles_used = loop_count * 3;
emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode),
avr_mem_clobber()));
cycles -= cycles_used;
}
while (cycles >= 2)
{
emit_insn (gen_nopv (GEN_INT (2)));
cycles -= 2;
}
if (cycles == 1)
{
emit_insn (gen_nopv (GEN_INT (1)));
cycles--;
}
}
Of biggest interest here is that this modifies a node in the Abstract Syntax Tree, and emits instructions there.

running the publicly available PCL RANSAC code & saving the result not working

I am trying to use the publicly available code of RANSAC for PCL from here: http://pointclouds.org/documentation/tutorials/random_sample_consensus.php
However, I am omitting the 3D viewer portion. The problem I am facing is that I cant save the result & also when I check the final point cloud size, it`s showing zero. Here is the code:
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_plane.h>
#include <pcl/sample_consensus/sac_model_sphere.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
int main(int argc, char** argv)
{
// initialize PointClouds
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr final (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ> final_result = *final;
// populate our PointCloud with points
cloud->width = 500;
cloud->height = 1;
cloud->is_dense = false;
cloud->points.resize (cloud->width * cloud->height);
for (size_t i = 0; i < cloud->points.size (); ++i)
{
if (pcl::console::find_argument (argc, argv, "-s") >= 0 || pcl::console::find_argument (argc, argv, "-sf") >= 0)
{
cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
if (i % 5 == 0)
cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0);
else if(i % 2 == 0)
cloud->points[i].z = sqrt( 1 - (cloud->points[i].x * cloud->points[i].x)
- (cloud->points[i].y * cloud->points[i].y));
else
cloud->points[i].z = - sqrt( 1 - (cloud->points[i].x * cloud->points[i].x)
- (cloud->points[i].y * cloud->points[i].y));
}
else
{
cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
if( i % 2 == 0)
cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0);
else
cloud->points[i].z = -1 * (cloud->points[i].x + cloud->points[i].y);
}
}
std::vector<int> inliers;
// created RandomSampleConsensus object and compute the appropriated model
pcl::SampleConsensusModelSphere<pcl::PointXYZ>::Ptr
model_s(new pcl::SampleConsensusModelSphere<pcl::PointXYZ> (cloud));
pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr
model_p (new pcl::SampleConsensusModelPlane<pcl::PointXYZ> (cloud));
if(pcl::console::find_argument (argc, argv, "-f") >= 0)
{
pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model_p);
ransac.setDistanceThreshold (.01);
ransac.computeModel();
ransac.getInliers(inliers);
}
else if (pcl::console::find_argument (argc, argv, "-sf") >= 0 )
{
pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model_s);
ransac.setDistanceThreshold (.01);
ransac.computeModel();
ransac.getInliers(inliers);
}
// copies all inliers of the model computed to another PointCloud
pcl::copyPointCloud<pcl::PointXYZ>(*cloud, inliers, *final);
cout << final->size() << endl; // show the size
pcl::PointCloud<pcl::PointXYZ> final_result = *final;
pcl::io::savePCDFile ("final_result.pcd", final_result); // save
return 0;
}
any idea why this is not working?
You have to pass -s or -sf as argument when running the compiled program.

Encoding raw nv12 frames with ffmpeg

I am trying to encode raw frames in nv12 format. Frame rate is 15. I am using avcodec to encode. My capture device has a callback function which is activated when a raw viewfinder frame is available. I am copying the raw viewfinder frame and making a AVFrame from the data. Then I supply the frame to avcodec_encode_video as described in the api sample but somehow I am not getting expected result. I am using posix thread. I keep the raw frames on a buffer. Then my encoder thread collects data from the buffer and encodes it. The speed of encoding is too slow (h264 and mpeg1 -tested). Is it a problem with my threading or something else? I am at loss. The output is mysterious. The whole encoding process is a single function and single threaded but I find a bunch of frame encoded at a time. How exactly does the encoder function?Here is the code snippet for encoding:
while(cameraRunning)
{
pthread_mutex_lock(&lock_encoder);
if(vr->buffer->getTotalData()>0)
{
i++;
fprintf(stderr,"Encoding %d\n",i);
AVFrame *picture;
int y = 0,x;
picture = avcodec_alloc_frame();
av_image_alloc(picture->data, picture->linesize,c->width, c->height,c->pix_fmt, 1);
uint8_t* buf_source = new uint8_t[vr->width*vr->height*3/2];
uint8_t* data = vr->buffer->Read(vr->width*vr->height*3/2);
memcpy(buf_source,data,vr->width*vr->height*3/2);
//free(&vr->buffer->Buffer[vr->buffer->getRead()-1][0]);
/*for (y = 0; y < vr->height*vr->width; y++)
{
picture->data[0][(y/vr->width) * picture->linesize[0] + (y%vr->width)] = buf_source[(y/vr->width)+(y%vr->width)]x + y + i * 7;
if(y<vr->height*vr->width/4)
{
picture->data[1][(y/vr->width) * picture->linesize[1] + (y%vr->width)] = buf_source[vr->width*vr->height + 2 * ((y/vr->width)+(y%vr->width))]128 + y + i * 2;
picture->data[2][(y/vr->width) * picture->linesize[2] + (y%vr->width)] = buf_source[vr->width*vr->height + 2 * ((y/vr->width)+(y%vr->width)) + 1]64 + x + i * 5;
}
}
*/
for(y=0;y<c->height;y++) {
for(x=0;x<c->width;x++) {
picture->data[0][y * picture->linesize[0] + x] = x + y + i * 7;
}
}
/* Cb and Cr */
for(y=0;y<c->height/2;y++) {
for(x=0;x<c->width/2;x++) {
picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
}
}
free(buf_source);
fprintf(stderr,"Data ready\n");
outbuf_size = 100000 + c->width*c->height*3/2;
outbuf = (uint8_t*)malloc(outbuf_size);
fprintf(stderr,"Preparation done!!!\n");
out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
had_output |= out_size;
printf("encoding frame %3d (size=%5d)\n", i, out_size);
fwrite(outbuf, 1, out_size, f);
av_free(picture->data[0]);
av_free(picture);
}
pthread_mutex_unlock(&lock_encoder);
}
You can use sws_scale in libswscale for colorspace conversion. First create an SwsContext specifying the source (NV12) and destination (YUV420P) using sws_getContext.
m_pSwsCtx = sws_getContext(picture_width,
picture_height,
PIX_FMT_NV12,
picture_width,
picture_height,
PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
And then when you want to do the conversion each frame,
sws_scale(m_pSwsCtx, frameData, frameLineSize, 0, frameHeight,
outFrameData, outFrameLineSize);

Resources