Add lots of profiling to assist in debugging

- made some debug output conditional.
- make it possible to debug slip decoding without getting swamped by other output.
- Improve reporting of unnamed schedule() calls.
- always collect performance statistics, and report on any excess
  use (>1sec in every 3), even if debug.timing is not enabled.
- include file size information in Rhizome transfer messages.
- reduce output when debug.rhizome_rx is set.
This commit is contained in:
gardners 2013-02-16 06:51:33 +10:30 committed by Jeremy Lakeman
parent 80168e3530
commit f465f3a9ee
11 changed files with 144 additions and 88 deletions

@ -657,6 +657,7 @@ int app_dna_lookup(const struct cli_parsed *parsed, void *context)
int app_server_start(const struct cli_parsed *parsed, void *context)
{
IN();
if (config.debug.verbose)
DEBUG_cli_parsed(parsed);
/* Process optional arguments */
@ -680,7 +681,7 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
status=server_probe(&pid);
if (status!=SERVER_NOTRUNNING) {
WHY("Tried to stop stuck servald process, but attempt failed.");
return -1;
RETURN(-1);
}
WHY("Killed stuck servald process, so will try to start");
pid=-1;
@ -702,23 +703,23 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
int foregroundP = parsed->argc >= 2 && !strcasecmp(parsed->args[1], "foreground");
if (cli_arg(parsed, "instance path", &instancepath, cli_absolute_path, NULL) == -1
|| cli_arg(parsed, "exec path", &execpath, cli_absolute_path, NULL) == -1)
return -1;
RETURN(-1);
if (instancepath != NULL)
serval_setinstancepath(instancepath);
if (execpath == NULL) {
#ifdef HAVE_JNI_H
if (jni_env)
return WHY("Must supply <exec path> argument when invoked via JNI");
RETURN(WHY("Must supply <exec path> argument when invoked via JNI"));
#endif
if ((tmp = malloc(PATH_MAX)) == NULL)
return WHY("Out of memory");
if (get_self_executable_path(tmp, PATH_MAX) == -1)
return WHY("unable to determine own executable name");
RETURN(WHY("unable to determine own executable name"));
execpath = tmp;
}
/* Create the instance directory if it does not yet exist */
if (create_serval_instance_dir() == -1)
return -1;
RETURN(-1);
/* Now that we know our instance path, we can ask for the default set of
network interfaces that we will take interest in. */
if (config.interfaces.ac == 0)
@ -726,7 +727,7 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
if (pid == -1)
pid = server_pid();
if (pid < 0)
return -1;
RETURN(-1);
int ret = -1;
// If the pidfile identifies this process, it probably means we are re-spawning after a SEGV, so
// go ahead and do the fork/exec.
@ -741,17 +742,17 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
/* Start the Serval process. All server settings will be read by the server process from the
instance directory when it starts up. */
if (server_remove_stopfile() == -1)
return -1;
RETURN(-1);
overlayMode = 1;
if (foregroundP)
return server(NULL);
RETURN(server(NULL));
const char *dir = getenv("SERVALD_SERVER_CHDIR");
if (!dir)
dir = config.server.chdir;
switch (cpid = fork()) {
case -1:
/* Main process. Fork failed. There is no child process. */
return WHY_perror("fork");
RETURN(WHY_perror("fork"));
case 0: {
/* Child process. Fork then exit, to disconnect daemon from parent process, so that
when daemon exits it does not live on as a zombie. N.B. Do not return from within this
@ -800,9 +801,9 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
sleep_ms(200); // 5 Hz
} while ((pid = server_pid()) == 0 && gettime_ms() < timeout);
if (pid == -1)
return -1;
RETURN(-1);
if (pid == 0)
return WHY("Server process did not start");
RETURN(WHY("Server process did not start"));
ret = 0;
}
cli_puts("instancepath");
@ -826,7 +827,7 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
sleep_ms(milliseconds);
}
}
return ret;
RETURN(ret);
}
int app_server_stop(const struct cli_parsed *parsed, void *context)

@ -203,6 +203,7 @@ ATOM(char, packetrx, 0, cf_opt_char_boolean,, "")
ATOM(char, packetradio, 0, cf_opt_char_boolean,, "")
ATOM(char, rejecteddata, 0, cf_opt_char_boolean,, "")
ATOM(char, slip, 0, cf_opt_char_boolean,, "")
ATOM(char, slipdecode, 0, cf_opt_char_boolean,, "")
ATOM(char, packetconstruction, 0, cf_opt_char_boolean,, "")
ATOM(char, rhizome, 0, cf_opt_char_boolean,, "")
ATOM(char, rhizome_tx, 0, cf_opt_char_boolean,, "")

@ -92,7 +92,6 @@ int _schedule(struct __sourceloc __whence, struct sched_ent *alarm)
__whence.function,__whence.file,__whence.line);
if (!alarm->stats)
WARNF("schedule() called from %s() %s:%d without supplying an alarm name",
alloca_alarm_name(alarm),
__whence.function,__whence.file,__whence.line);
struct sched_ent *node = next_alarm, *last = NULL;
@ -159,6 +158,9 @@ int _watch(struct __sourceloc __whence, struct sched_ent *alarm)
{
if (config.debug.io)
DEBUGF("watch(alarm=%s)", alloca_alarm_name(alarm));
if (!alarm->stats)
WARNF("watch() called from %s() %s:%d without supplying an alarm name",
__whence.function,__whence.file,__whence.line);
if (!alarm->function)
return WHY("Can't watch if you haven't set the function pointer");
@ -208,9 +210,13 @@ int _unwatch(struct __sourceloc __whence, struct sched_ent *alarm)
static void call_alarm(struct sched_ent *alarm, int revents)
{
IN();
struct call_stats call_stats;
call_stats.totals = alarm->stats;
if (config.debug.io) DEBUGF("Calling alarm/callback %p ('%s')",
alarm, alloca_alarm_name(alarm));
if (call_stats.totals)
fd_func_enter(__HERE__, &call_stats);
@ -219,16 +225,21 @@ static void call_alarm(struct sched_ent *alarm, int revents)
if (call_stats.totals)
fd_func_exit(__HERE__, &call_stats);
if (config.debug.io) DEBUGF("Alarm %p returned",alarm);
OUT();
}
int fd_poll()
{
IN();
int i, r=0;
int ms=60000;
time_ms_t now = gettime_ms();
if (!next_alarm && !next_deadline && fdcount==0)
return 0;
RETURN(0);
/* move alarms that have elapsed to the deadline queue */
while (next_alarm!=NULL&&next_alarm->alarm <=now){
@ -258,6 +269,7 @@ int fd_poll()
else
usleep(ms*1000);
}else{
if (config.debug.io) DEBUGF("poll(X,%d,%d)",fdcount,ms);
r = poll(fds, fdcount, ms);
if (config.debug.io) {
strbuf b = strbuf_alloca(1024);
@ -298,5 +310,5 @@ int fd_poll()
set_block(fds[i].fd);
}
}
return 1;
RETURN(1);
}

@ -79,6 +79,8 @@ keyring_file *keyring=NULL;
int overlayServerMode()
{
IN();
/* In overlay mode we need to listen to all of our sockets, and also to
send periodic traffic. This means we need to */
INFO("Running in overlay mode.");
@ -152,15 +154,13 @@ schedule(&_sched_##X); }
/* Periodically advertise bundles */
SCHEDULE(overlay_rhizome_advertise, 1000, 10000);
/* Show CPU usage stats periodically */
if (config.debug.timing){
SCHEDULE(fd_periodicstats, 3000, 500);
}
/* Calculate (and possibly show) CPU usage stats periodically */
SCHEDULE(fd_periodicstats, 3000, 500);
#undef SCHEDULE
/* Check for activitiy and respond to it */
while(fd_poll());
return 0;
RETURN(0);
}

@ -627,9 +627,10 @@ static void interface_read_stream(struct overlay_interface *interface){
struct slip_decode_state *state=&interface->slip_decode_state;
if (config.debug.slip)
dump("RX bytes",&state->src[state->src_offset],
state->src_size-state->src_offset);
if (config.debug.slip) {
dump("RX bytes",&state->src[state->src_offset],
state->src_size-state->src_offset);
}
state->src=buffer;
state->src_size=nread;

@ -316,8 +316,9 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
// TODO stop when the packet is nearly full?
while(frame){
if (frame->enqueued_at + queue->latencyTarget < now){
DEBUGF("Dropping frame type %x for %s due to expiry timeout",
frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
if (config.debug.rejecteddata)
DEBUGF("Dropping frame type %x for %s due to expiry timeout",
frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
frame = overlay_queue_remove(queue, frame);
continue;
}

@ -18,6 +18,7 @@
*/
#include "serval.h"
#include "conf.h"
struct profile_total *stats_head=NULL;
struct call_stats *current_call=NULL;
@ -148,17 +149,31 @@ int fd_showstats()
stats = stats->_next;
}
INFOF("servald time usage stats:");
stats = stats_head;
while(stats!=NULL){
/* Get total time spent doing everything */
if (stats->calls)
fd_showstat(&total,stats);
stats = stats->_next;
// Report any functions that take too much time
if (!config.debug.timing)
{
stats = stats_head;
while(stats!=NULL){
/* If a function spends more than 1 second in any
notionally 3 second period, then dob on it */
if (stats->total_time>1000
&&strcmp(stats->name,"Idle (in poll)"))
fd_showstat(&total,stats);
stats = stats->_next;
}
}
else {
INFOF("servald time usage stats:");
stats = stats_head;
while(stats!=NULL){
/* Get total time spent doing everything */
if (stats->calls)
fd_showstat(&total,stats);
stats = stats->_next;
}
fd_showstat(&total,&total);
}
fd_showstat(&total,&total);
return 0;
}

@ -1115,11 +1115,11 @@ cleanup:
int64_t rhizome_database_create_blob_for(const char *hashhex,int64_t fileLength,
int priority)
{
IN();
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;") != SQLITE_OK)
return WHY("Failed to begin transaction");
RETURN(WHY("Failed to begin transaction"));
/* INSERT INTO FILES(id as text, data blob, length integer, highestpriority integer).
BUT, we have to do this incrementally so that we can handle blobs larger than available memory.
@ -1155,7 +1155,7 @@ int64_t rhizome_database_create_blob_for(const char *hashhex,int64_t fileLength,
insert_row_fail:
WHYF("Failed to insert row for fileid=%s", hashhex);
sqlite_exec_void_retry(&retry, "ROLLBACK;");
return -1;
RETURN(-1);
}
/* Get rowid for inserted row, so that we can modify the blob */
@ -1164,10 +1164,10 @@ insert_row_fail:
ret = sqlite_exec_void_retry(&retry, "COMMIT;");
if (ret!=SQLITE_OK){
sqlite_exec_void_retry(&retry, "ROLLBACK;");
return WHYF("Failed to commit transaction");
RETURN(WHYF("Failed to commit transaction"));
}
DEBUGF("Got rowid %lld for %s", rowid, hashhex);
return rowid;
RETURN(rowid);
}
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount)

@ -524,6 +524,7 @@ static int rhizome_import_received_bundle(struct rhizome_manifest *m)
static int schedule_fetch(struct rhizome_fetch_slot *slot)
{
IN();
int sock = -1;
/* TODO Don't forget to implement resume */
/* TODO We should stream file straight into the database */
@ -601,7 +602,7 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
slot->alarm.alarm = gettime_ms() + RHIZOME_IDLE_TIMEOUT;
slot->alarm.deadline = slot->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
schedule(&slot->alarm);
return 0;
RETURN(0);
}
bail_http:
@ -609,7 +610,7 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
the connection/attempt to fetch via HTTP failed. */
slot->state=RHIZOME_FETCH_RXFILEMDP;
rhizome_fetch_switch_to_mdp(slot);
return 0;
RETURN(0);
}
/* Start fetching a bundle's payload ready for importing.
@ -675,12 +676,12 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct
if (config.debug.rhizome_rx)
DEBUGF("Fetching bundle slot=%d bid=%s version=%lld size=%lld peerip=%s",
slotno(slot),
bid,
m->version,
m->fileLength,
alloca_sockaddr(peerip)
);
slotno(slot),
bid,
m->version,
m->fileLength,
alloca_sockaddr(peerip)
);
// If the payload is empty, no need to fetch, so import now.
if (m->fileLength == 0) {
@ -828,6 +829,7 @@ rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip,
*/
static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
{
IN();
struct rhizome_fetch_queue *q;
for (q = (struct rhizome_fetch_queue *) slot; q >= rhizome_fetch_queues; --q) {
int i = 0;
@ -836,11 +838,11 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
int result = rhizome_fetch(slot, c->manifest, &c->peer_ipandport,c->peer_sid);
switch (result) {
case SLOTBUSY:
return;
OUT(); return;
case STARTED:
c->manifest = NULL;
rhizome_fetch_unqueue(q, i);
return;
OUT(); return;
case IMPORTED:
case SAMEBUNDLE:
case SAMEPAYLOAD:
@ -858,6 +860,7 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
}
}
}
OUT();
}
/* Called soon after any fetch candidate is queued, to start any queued fetches.
@ -866,9 +869,11 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
*/
static void rhizome_start_next_queued_fetches(struct sched_ent *alarm)
{
IN();
int i;
for (i = 0; i < NQUEUES; ++i)
rhizome_start_next_queued_fetch(&rhizome_fetch_queues[i].active);
OUT();
}
/* Search all fetch slots, including active downloads, for a matching manifest */
@ -908,6 +913,9 @@ rhizome_manifest * rhizome_fetch_search(unsigned char *id, int prefix_length){
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
struct profile_total rsnqf_stats={.name="rhizome_start_next_queued_fetches"};
struct profile_total rfmsc_stats={.name="rhizome_fetch_mdp_slot_callback"};
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip,const unsigned char peersid[SID_SIZE])
{
IN();
@ -1029,7 +1037,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock
if (!is_scheduled(&sched_activate)) {
sched_activate.function = rhizome_start_next_queued_fetches;
sched_activate.stats = NULL;
sched_activate.stats = &rsnqf_stats;
sched_activate.alarm = gettime_ms() + rhizome_fetch_delay_ms();
sched_activate.deadline = sched_activate.alarm + 5000;
schedule(&sched_activate);
@ -1074,28 +1082,33 @@ static int rhizome_fetch_close(struct rhizome_fetch_slot *slot)
static void rhizome_fetch_mdp_slot_callback(struct sched_ent *alarm)
{
IN();
struct rhizome_fetch_slot *slot=(struct rhizome_fetch_slot*)alarm;
if (slot->state!=5) {
DEBUGF("Stale alarm triggered on idle/reclaimed slot. Ignoring");
unschedule(alarm);
OUT();
return;
}
long long now=gettime_ms();
if (now-slot->last_write_time>slot->mdpIdleTimeout) {
DEBUGF("MDP connection timed out: last RX %lldms ago",
now-slot->last_write_time);
DEBUGF("MDP connection timed out: last RX %lldms ago (read %d of %d bytes)",
now-slot->last_write_time,
slot->file_ofs,slot->file_len);
rhizome_fetch_close(slot);
OUT();
return;
}
if (config.debug.rhizome_rx)
DEBUGF("Timeout waiting for blocks. Resending request for slot=0x%p",
slot);
DEBUGF("Timeout: Resending request for slot=0x%p (%d of %d received)",
slot,slot->file_ofs,slot->file_len);
if (slot->bidP)
rhizome_fetch_mdp_requestblocks(slot);
else
rhizome_fetch_mdp_requestmanifest(slot);
OUT();
}
static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
@ -1138,6 +1151,7 @@ static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
slot->mdpResponsesOutstanding=32; // TODO: set according to bitmap
unschedule(&slot->alarm);
slot->alarm.stats=&rfmsc_stats;
slot->alarm.function = rhizome_fetch_mdp_slot_callback;
// 266ms @ 1mbit (WiFi broadcast speed) = 32x1024 byte packets.
slot->alarm.alarm=gettime_ms()+266;
@ -1205,7 +1219,8 @@ static int rhizome_fetch_switch_to_mdp(struct rhizome_fetch_slot *slot)
}
if (config.debug.rhizome_rx)
DEBUGF("Trying to switch to MDP for Rhizome fetch: slot=0x%p",slot);
DEBUGF("Trying to switch to MDP for Rhizome fetch: slot=0x%p (%d bytes)",
slot,slot->file_len);
/* close socket and stop watching it */
if (slot->alarm.poll.fd>=0) {
@ -1365,7 +1380,7 @@ int rhizome_write_content(struct rhizome_fetch_slot *slot, char *buffer, int byt
if (config.debug.rhizome_rx) {
DEBUGF("slot->blob_buffer_bytes=%d, slot->file_ofs=%d",
slot->blob_buffer_bytes,slot->file_ofs);
dump("buffer",buffer,bytes);
// dump("buffer",buffer,bytes);
}
if (!slot->blob_buffer_size) {

@ -87,6 +87,7 @@ void server_save_argv(int argc, const char *const *argv)
int server(char *backing_file)
{
IN();
/* For testing, it can be very helpful to delay the start of the server process, for example to
* check that the start/stop logic is robust.
*/
@ -121,11 +122,11 @@ int server(char *backing_file)
/* Record PID to advertise that the server is now running */
char filename[1024];
if (!FORM_SERVAL_INSTANCE_PATH(filename, PIDFILE_NAME))
return -1;
RETURN(-1);
FILE *f=fopen(filename,"w");
if (!f) {
WHY_perror("fopen");
return WHYF("Could not write to PID file %s", filename);
RETURN(WHYF("Could not write to PID file %s", filename));
}
server_getpid = getpid();
fprintf(f,"%d\n", server_getpid);
@ -133,7 +134,7 @@ int server(char *backing_file)
overlayServerMode();
return 0;
RETURN(0);
}
/* Called periodically by the server process in its main loop.

67
slip.c

@ -193,22 +193,24 @@ int parse_rfd900_rssi(char *s)
#define UPPER7_STATE_D7 15
int upper7_decode(struct slip_decode_state *state,unsigned char byte)
{
if (0&&config.debug.slip)
IN()
if (config.debug.slipdecode)
DEBUGF("state=%d, byte=0x%02x",state->state,byte);
// Parse out inline RSSI reports
if (byte=='{') {
state->state=UPPER7_STATE_L1;
state->packet_length=0;
return 0;
RETURN(0);
} else if (byte=='}') {
// End of packet marker -- report end of received packet to caller
// for CRC verification etc.
state->state=UPPER7_STATE_NOTINPACKET; return 1;
state->state=UPPER7_STATE_NOTINPACKET; RETURN(1);
} else if (byte>=' '&&byte<=0x7f) {
if (state->rssi_len<0) state->rssi_len=0;
if (state->rssi_len<RSSI_TEXT_SIZE)
state->rssi_text[state->rssi_len++]=byte;
return 0;
RETURN(0);
} else if (byte=='\r'||byte=='\n') {
if (state->rssi_len>=RSSI_TEXT_SIZE) state->rssi_len=RSSI_TEXT_SIZE-1;
if (state->rssi_len<0) state->rssi_len=0;
@ -220,17 +222,21 @@ int upper7_decode(struct slip_decode_state *state,unsigned char byte)
// Non-data bytes (none currently used, but we need to catch them before
// moving onto processing data bytes)
if (byte<0x80) {
switch (byte) {
default:
return 0;
}
RETURN(0);
}
// Data bytes and packet fields
byte&=0x7f;
if (state->packet_length>=OVERLAY_INTERFACE_RX_BUFFER_SIZE
||(state->dst_offset+7)>=OVERLAY_INTERFACE_RX_BUFFER_SIZE
||state->dst_offset<0)
{
WARNF("state->dst_offset=%d, ->packet_length=%d, ->state=%d",
state->dst_offset,state->packet_length,state->state);
}
switch(state->state) {
case UPPER7_STATE_NOTINPACKET: return 0;
case UPPER7_STATE_L1: state->packet_length=byte<<7; state->state++; return 0;
case UPPER7_STATE_NOTINPACKET: RETURN(0);
case UPPER7_STATE_L1: state->packet_length=byte<<7; state->state++; RETURN(0);
case UPPER7_STATE_L2: state->packet_length|=byte;
// Make sure packet length can fit in RX buffer, including that we might
// need upto 7 bytes extra temporary space due to blocking
@ -242,57 +248,57 @@ int upper7_decode(struct slip_decode_state *state,unsigned char byte)
DEBUGF("Ignoring jumbo packet of %d bytes",state->packet_length);
state->state=UPPER7_STATE_NOTINPACKET;
}
return 0;
case UPPER7_STATE_C1: state->crc=byte<<25; state->state++; return 0;
case UPPER7_STATE_C2: state->crc|=byte<<(25-7); state->state++; return 0;
case UPPER7_STATE_C3: state->crc|=byte<<(25-7-7); state->state++; return 0;
case UPPER7_STATE_C4: state->crc|=byte<<(25-7-7-7); state->state++; return 0;
case UPPER7_STATE_C5: state->crc|=byte<<0; state->state++; return 0;
RETURN(0);
case UPPER7_STATE_C1: state->crc=byte<<25; state->state++; RETURN(0);
case UPPER7_STATE_C2: state->crc|=byte<<(25-7); state->state++; RETURN(0);
case UPPER7_STATE_C3: state->crc|=byte<<(25-7-7); state->state++; RETURN(0);
case UPPER7_STATE_C4: state->crc|=byte<<(25-7-7-7); state->state++; RETURN(0);
case UPPER7_STATE_C5: state->crc|=byte<<0; state->state++; RETURN(0);
case UPPER7_STATE_D0:
// Prevent buffer overruns
if (state->dst_offset+7>OVERLAY_INTERFACE_RX_BUFFER_SIZE)
state=UPPER7_STATE_NOTINPACKET;
state->dst[state->dst_offset]=byte<<1;
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D1:
state->dst[state->dst_offset+0]|=(byte>>6)&0x01;
state->dst[state->dst_offset+1]=(byte<<2);
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D2:
state->dst[state->dst_offset+1]|=(byte>>5)&0x03;
state->dst[state->dst_offset+2]=(byte<<3);
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D3:
state->dst[state->dst_offset+2]|=(byte>>4)&0x07;
state->dst[state->dst_offset+3]=(byte<<4);
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D4:
state->dst[state->dst_offset+3]|=(byte>>3)&0x0f;
state->dst[state->dst_offset+4]=(byte<<5);
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D5:
state->dst[state->dst_offset+4]|=(byte>>2)&0x1f;
state->dst[state->dst_offset+5]=(byte<<6);
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D6:
state->dst[state->dst_offset+5]|=(byte>>1)&0x3f;
state->dst[state->dst_offset+6]=(byte<<7);
state->state++;
return 0;
RETURN(0);
case UPPER7_STATE_D7:
state->dst[state->dst_offset+6]|=(byte>>0)&0x7f;
state->dst_offset+=7;
state->state=UPPER7_STATE_D0;
return 0;
RETURN(0);
default:
state->state=UPPER7_STATE_NOTINPACKET;
return 0;
RETURN(0);
}
}
@ -387,13 +393,15 @@ int slip_decode(struct slip_decode_state *state)
if (state->rssi_len<0) state->rssi_len=0;
if (state->rssi_len>=RSSI_TEXT_SIZE) state->rssi_len=RSSI_TEXT_SIZE-1;
state->rssi_text[state->rssi_len]=0;
DEBUGF("RX state=%d, rssi_len=%d, rssi_text='%s'",
state->state,state->rssi_len,state->rssi_text);
DEBUGF("RX state=%d, rssi_len=%d, rssi_text='%s',src=%p, src_size=%d",
state->state,state->rssi_len,state->rssi_text,
state->src,state->src_size);
}
while(state->src_offset<state->src_size)
while(state->src_offset<state->src_size) {
if (upper7_decode(state,state->src[state->src_offset++])==1) {
if (config.debug.slip)
if (config.debug.slip) {
dump("de-slipped packet",state->dst,state->packet_length);
}
// Check that CRC matches
uint32_t crc=Crc32_ComputeBuf( 0, state->dst, state->packet_length);
@ -410,6 +418,7 @@ int slip_decode(struct slip_decode_state *state)
return 1;
}
}
}
}
return 0;
default: