// // Created by MightyPork on 2017/11/25. // #include "unit_base.h" #include "unit_adc.h" #define ADC_INTERNAL #include "_adc_internal.h" // ------------------------------------------------------------------------ enum TplCmd_ { CMD_READ_RAW = 0, CMD_READ_SMOOTHED = 1, CMD_GET_ENABLED_CHANNELS = 10, CMD_SETUP_TRIGGER = 20, CMD_ARM = 21, CMD_DISARM = 22, CMD_ABORT = 23, // abort any ongoing capture or stream CMD_FORCE_TRIGGER = 24, CMD_BLOCK_CAPTURE = 25, CMD_STREAM_START = 26, CMD_STREAM_STOP = 27, }; /** Handle a request message */ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { struct priv *priv = unit->data; PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); switch (command) { case CMD_GET_ENABLED_CHANNELS: dbg("> Query channels"); for (uint8_t i = 0; i < 18; i++) { if (priv->extended_channels_mask & (1 << i)) { pb_u8(&pb, i); } } com_respond_pb(frame_id, MSG_SUCCESS, &pb); return E_SUCCESS; case CMD_READ_RAW: dbg("> Read raw"); if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) { return E_BUSY; } for (uint8_t i = 0; i < 18; i++) { if (priv->extended_channels_mask & (1 << i)) { pb_u8(&pb, i); pb_u16(&pb, priv->last_samples[i]); } } assert_param(pb.ok); com_respond_pb(frame_id, MSG_SUCCESS, &pb); return E_SUCCESS; case CMD_READ_SMOOTHED: dbg("> Read smoothed"); if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) { return E_BUSY; } for (uint8_t i = 0; i < 18; i++) { if (priv->extended_channels_mask & (1 << i)) { pb_u8(&pb, i); pb_float(&pb, priv->averaging_bins[i]); } } assert_param(pb.ok); com_respond_pb(frame_id, MSG_SUCCESS, &pb); return E_SUCCESS; case CMD_SETUP_TRIGGER: dbg("> Setup trigger"); if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; { uint8_t source = pp_u8(pp); uint16_t level = pp_u16(pp); uint8_t edge = pp_u8(pp); uint16_t pretrig = pp_u16(pp); uint32_t count = pp_u32(pp); uint16_t holdoff = pp_u16(pp); bool auto_rearm = pp_bool(pp); if (source > 17) { com_respond_str(MSG_ERROR, frame_id, "Invalid trig source"); return E_FAILURE; } if (0 == (priv->extended_channels_mask & (1 << source))) { com_respond_str(MSG_ERROR, frame_id, "Channel not enabled"); return E_FAILURE; } if (level > 4095) { com_respond_str(MSG_ERROR, frame_id, "Level out of range (0-4095)"); return E_FAILURE; } if (edge == 0 || edge > 3) { com_respond_str(MSG_ERROR, frame_id, "Bad edge"); return E_FAILURE; } // XXX the max size may be too much uint16_t max_pretrig = (priv->dma_buffer_itemcount / priv->nb_channels); if (pretrig > max_pretrig) { com_respond_snprintf(frame_id, MSG_ERROR, "Pretrig too large (max %d)", (int) max_pretrig); return E_FAILURE; } priv->trigger_source = source; priv->trig_level = level; priv->trig_prev_level = priv->last_samples[source]; priv->trig_edge = edge; priv->pretrig_len = pretrig; priv->trig_len = count; priv->trig_holdoff = holdoff; priv->auto_rearm = auto_rearm; } return E_SUCCESS; case CMD_ARM: dbg("> Arm"); if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; if (priv->trig_len == 0) { com_respond_str(MSG_ERROR, frame_id, "Trigger not configured."); return E_FAILURE; } UADC_SwitchMode(unit, ADC_OPMODE_ARMED); return E_SUCCESS; case CMD_DISARM: dbg("> Disarm"); if(priv->opmode == ADC_OPMODE_IDLE) { return E_SUCCESS; // already idle, success - no work to do } // capture in progress if(priv->opmode != ADC_OPMODE_ARMED) return E_BUSY; UADC_SwitchMode(unit, ADC_OPMODE_IDLE); return E_SUCCESS; case CMD_ABORT:; dbg("> Abort capture"); enum uadc_opmode old_opmode = priv->opmode; UADC_SwitchMode(unit, ADC_OPMODE_IDLE); if (old_opmode == ADC_OPMODE_FIXCAPT || old_opmode == ADC_OPMODE_STREAM || old_opmode == ADC_OPMODE_TRIGD) { UADC_ReportEndOfStream(unit); } return E_SUCCESS; case CMD_FORCE_TRIGGER: dbg("> Force trigger"); if(priv->opmode == ADC_OPMODE_IDLE) { com_respond_str(MSG_ERROR, frame_id, "Not armed"); return E_FAILURE; } if(priv->opmode != ADC_OPMODE_ARMED) return E_BUSY; UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime()); return E_SUCCESS; case CMD_BLOCK_CAPTURE: dbg("> Block cpt"); if(priv->opmode != ADC_OPMODE_ARMED && priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; uint32_t count = pp_u32(pp); UADC_StartBlockCapture(unit, count, frame_id); return E_SUCCESS; case CMD_STREAM_START: dbg("> Stream ON"); if(priv->opmode != ADC_OPMODE_ARMED && priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; UADC_StartStream(unit, frame_id); return E_SUCCESS; case CMD_STREAM_STOP: dbg("> Stream OFF"); if(priv->opmode != ADC_OPMODE_STREAM) { com_respond_str(MSG_ERROR, frame_id, "Not streaming"); return E_FAILURE; } UADC_StopStream(unit); return E_SUCCESS; default: return E_UNKNOWN_COMMAND; } } // ------------------------------------------------------------------------ /** Unit template */ const UnitDriver UNIT_ADC = { .name = "ADC", .description = "Analog/Digital converter", // Settings .preInit = UADC_preInit, .cfgLoadBinary = UADC_loadBinary, .cfgWriteBinary = UADC_writeBinary, .cfgLoadIni = UADC_loadIni, .cfgWriteIni = UADC_writeIni, // Init .init = UADC_init, .deInit = UADC_deInit, // Function .handleRequest = UADC_handleRequest, .updateTick = UADC_updateTick, };