int run_snap_poco(struct katcp_dispatch *d, void *data) { struct snap_poco *n; struct capture_poco *cp; uint32_t addr, ctrl[2]; int rr, wr, i, sr; void *payload; unsigned int total; n = data; if(need_current_mode_katcp(d, POCO_POCO_MODE) == NULL){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "left poco mode hence disabling %s snap", n->n_name); return -1; } #ifdef DEBUG if(n->n_magic != SNAP_MAGIC){ fprintf(stderr, "snap: bad magic: got 0x%x\n", n->n_magic); abort(); } #endif cp = n->n_capture; rr = read_pce(d, n->n_addr, &addr, 0, 4); if(rr != 4){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "unable to read snap address of %s", n->n_name); return -1; } if((addr + 1) < n->n_count){ log_message_katcp(d, KATCP_LEVEL_TRACE, NULL, "snap has %u waiting for %u", addr, n->n_count); return 0; } log_message_katcp(d, KATCP_LEVEL_TRACE, NULL, "snap got full %u+1 words", addr); total = n->n_count * 4; for(i = 0; i < total; i += n->n_chunk){ sr = i - total; if(sr > n->n_chunk){ sr = n->n_chunk; } payload = data_udp_poco(d, cp, i, sr); if(payload == NULL){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "snap: unable to acquire payload space of %d", sr); return -1; } /* TODO: add support to read from multiple blockrams */ if(n->n_blocks == 1){ rr = read_pce(d, n->n_bram[0], payload, i, sr); if(rr < sr){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "snap: blockram read failed"); return -1; } } else { #if 0 fprintf(stderr, "snap: multiple blocks read still to be implemented\n"); for(i = 0; i < n->n_blocks; i++){ rr = read_pce(d, n->n_bram[i], payload, i, sr); if(rr < sr){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "snap: blockram read failed"); return -1; } } } #endif } tx_udp_poco(d, cp); }
int run_generic_capture(struct katcp_dispatch *d, struct capture_poco *cp, int poke) { /* logic: */ /* zero poke means that we are being run from a timer, advance our state */ /* machine, by looking at state value (initial value zero, but never changed */ /* by subsequent api logic */ /* nonzero poke means that the user has changed a parameter */ #if 0 /* scary logic for client using the API: ping means that the user has changed some parameter - client has to figure out what to do on the basis of that, otherwise just run whatever client state machine, client can use c_state for that, where 0 is the starting condition (never gets reset by API logic, client responsible for that) */ #endif sane_capture(cp); log_message_katcp(d, KATCP_LEVEL_TRACE, NULL, "capture %s with notification %d and state %d", cp->c_name, poke, cp->c_state); switch(poke){ case CAPTURE_POKE_AUTO : /* automatic state machine runner */ switch(cp->c_state){ case IDLE_GENERIC_CAPTURE : log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "running capture timer while idle is unexpected"); return -1; case PREP_GENERIC_CAPTURE : log_message_katcp(d, KATCP_LEVEL_DEBUG, NULL, "capture-prepare %s", cp->c_name); if(cp->c_fd < 0){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "no valid destination, not starting capture %s", cp->c_name); return -1; } if(cp->c_start.tv_sec == 0){ log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "no valid start time while prepping"); cp->c_state = IDLE_GENERIC_CAPTURE; return -1; } if(cp->c_toggle){ log_message_katcp(d, KATCP_LEVEL_DEBUG, NULL, "toggling start for %s", cp->c_name); if((*(cp->c_toggle))(d, cp->c_dump, 1) < 0){ log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "unable to trigger data collection"); cp->c_state = IDLE_GENERIC_CAPTURE; return -1; } } register_at_tv_katcp(d, &(cp->c_start), &timer_generic_capture, cp); cp->c_start.tv_sec = 0; cp->c_start.tv_sec = 0; meta_udp_poco(d, cp, START_STREAM_CONTROL_POCO); tx_udp_poco(d, cp); cp->c_state = START_GENERIC_CAPTURE; break; case START_GENERIC_CAPTURE : /* MAYBE: change from log to #capture-start ? */ log_message_katcp(d, KATCP_LEVEL_INFO, NULL, "capture-start %s", cp->c_name); if(cp->c_stop.tv_sec){ log_message_katcp(d, KATCP_LEVEL_INFO, NULL, "scheduling stop at %lu.%06lu", cp->c_stop.tv_sec, cp->c_stop.tv_usec); register_at_tv_katcp(d, &(cp->c_stop), &timer_generic_capture, cp); } cp->c_state = RUN_GENERIC_CAPTURE; break; case RUN_GENERIC_CAPTURE : log_message_katcp(d, KATCP_LEVEL_INFO, NULL, "capture-stop %s", cp->c_name); if(cp->c_toggle){ if((*(cp->c_toggle))(d, cp->c_dump, 0) < 0){ log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "problems stopping %s", cp->c_name); } } else { log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "no switch to stop capture for %s", cp->c_name); } meta_udp_poco(d, cp, STOP_STREAM_CONTROL_POCO); tx_udp_poco(d, cp); cp->c_stop.tv_sec = 0; cp->c_stop.tv_usec = 0; cp->c_state = IDLE_GENERIC_CAPTURE; break; default : log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "bad state %d for capture %s", cp->c_state, cp->c_name); cp->c_state = IDLE_GENERIC_CAPTURE; return -1; } break; case CAPTURE_POKE_START : /* user notification start */ switch(cp->c_state){ case IDLE_GENERIC_CAPTURE : break; case PREP_GENERIC_CAPTURE : log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "overriding previously scheduled capture start for %s", cp->c_name); break; default : log_message_katcp(d, KATCP_LEVEL_ERROR, NULL, "capture for %s already running or scheduled to run", cp->c_name); return -1; } if(cp->c_prep.tv_sec == 0){ log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "no valid prep time given for %s", cp->c_name); return -1; } if(cmp_time_katcp(&(cp->c_prep), &(cp->c_start)) >= 0){ log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "prep time not before start time for %s", cp->c_name); return -1; } if((cp->c_stop.tv_sec != 0) && (cmp_time_katcp(&(cp->c_stop), &(cp->c_start)) < 0)){ log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "overriding stale stop carelessly scheduled for %lu.%06lus", cp->c_stop.tv_sec, cp->c_stop.tv_usec); cp->c_stop.tv_sec = 0; cp->c_stop.tv_usec = 0; } if(cp->c_fd < 0){ log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "hoping for that valid destination for %s will be set soon", cp->c_name); } register_at_tv_katcp(d, &(cp->c_prep), &timer_generic_capture, cp); cp->c_prep.tv_sec = 0; cp->c_prep.tv_usec = 0; cp->c_state = PREP_GENERIC_CAPTURE; break; case CAPTURE_POKE_STOP : /* user notification - stop */ if(cp->c_stop.tv_sec == 0){ log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "having no stop time set when requesting sto is a major logic failure"); } switch(cp->c_state){ case IDLE_GENERIC_CAPTURE : if(cp->c_start.tv_sec != 0) { log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "having a start time set in idle state is a major logic failure"); } log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "setting a stop at %lu.%lus while idle on %s despite having no start time", cp->c_stop.tv_sec, cp->c_stop.tv_usec, cp->c_name); break; case PREP_GENERIC_CAPTURE : if(cmp_time_katcp(&(cp->c_stop), &(cp->c_start)) <= 0){ log_message_katcp(d, KATCP_LEVEL_WARN, NULL, "cancelling capture on %s as stop time preceeds start time", cp->c_name); cp->c_stop.tv_sec = 0; cp->c_stop.tv_usec = 0; cp->c_start.tv_sec = 0; cp->c_start.tv_usec = 0; discharge_timer_katcp(d, cp); } break; case RUN_GENERIC_CAPTURE : register_at_tv_katcp(d, &(cp->c_stop), &timer_generic_capture, cp); break; } break; default : log_message_katcp(d, KATCP_LEVEL_FATAL, NULL, "unknown poke state %d", poke); return -1; break; } return 0; /* time registration functions look at this code, but only for periodic events */ }