From: Bert Vermeulen Date: Wed, 12 Jun 2013 11:10:56 +0000 (+0200) Subject: cem-dt-885x: Live SPL acquisition X-Git-Tag: libsigrok-0.2.1~64 X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=commitdiff_plain;h=e37c4b3959052691a9e9d9ec4cfcdf0f8c6e36e1 cem-dt-885x: Live SPL acquisition --- diff --git a/hardware/cem-dt-885x/api.c b/hardware/cem-dt-885x/api.c index 68e2f023..b69456d9 100644 --- a/hardware/cem-dt-885x/api.c +++ b/hardware/cem-dt-885x/api.c @@ -92,7 +92,7 @@ static GSList *scan(GSList *options) sdi->inst_type = SR_INST_SERIAL; sdi->priv = devc; sdi->driver = di; - if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1"))) + if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "SPL"))) return NULL; sdi->probes = g_slist_append(sdi->probes, probe); drvc->instances = g_slist_append(drvc->instances, sdi); @@ -223,17 +223,31 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) return ret; } -static int dev_acquisition_start(const struct sr_dev_inst *sdi, - void *cb_data) +static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { - (void)sdi; - (void)cb_data; + struct dev_context *devc; + struct sr_serial_dev_inst *serial; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; - /* TODO: configure hardware, reset acquisition state, set up - * callbacks and send header packet. */ + if (!(devc = sdi->priv)) { + sr_err("sdi->priv was NULL."); + return SR_ERR_BUG; + } + + devc->cb_data = cb_data; + devc->state = ST_INIT; + devc->num_samples = 0; + devc->buf_len = 0; + + /* Send header packet to the session bus. */ + std_session_send_df_header(cb_data, LOG_PREFIX); + + /* Poll every 100ms, or whenever some data comes in. */ + serial = sdi->conn; + sr_source_add(serial->fd, G_IO_IN, 150, cem_dt_885x_receive_data, + (void *)sdi); return SR_OK; } @@ -245,7 +259,8 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; - /* TODO: stop acquisition. */ + return std_dev_acquisition_stop_serial(sdi, cb_data, dev_close, + sdi->conn, LOG_PREFIX); return SR_OK; } diff --git a/hardware/cem-dt-885x/protocol.c b/hardware/cem-dt-885x/protocol.c index 0e4f93b2..8b09d324 100644 --- a/hardware/cem-dt-885x/protocol.c +++ b/hardware/cem-dt-885x/protocol.c @@ -17,23 +17,233 @@ * along with this program. If not, see . */ +#include #include "protocol.h" -SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data) +/* Length of expected payload for each token. */ +static int token_payloads[][2] = { + { TOKEN_WEIGHT_TIME_FAST, 0 }, + { TOKEN_WEIGHT_TIME_SLOW, 0 }, + { TOKEN_HOLD_MAX, 0 }, + { TOKEN_HOLD_MIN, 0 }, + { TOKEN_TIME, 3 }, + { TOKEN_MEAS_RANGE_OVER, 0 }, + { TOKEN_MEAS_RANGE_UNDER, 0 }, + { TOKEN_STORE_FULL, 0 }, + { TOKEN_RECORDING_ON, 0 }, + { TOKEN_MEAS_WAS_READOUT, 1 }, + { TOKEN_MEAS_WAS_BARGRAPH, 0 }, + { TOKEN_MEASUREMENT, 2 }, + { TOKEN_HOLD_NONE, 0 }, + { TOKEN_BATTERY_LOW, 0 }, + { TOKEN_MEAS_RANGE_OK, 0 }, + { TOKEN_STORE_OK, 0 }, + { TOKEN_RECORDING_OFF, 0 }, + { TOKEN_WEIGHT_FREQ_A, 1 }, + { TOKEN_WEIGHT_FREQ_C, 1 }, + { TOKEN_BATTERY_OK, 0 }, + { TOKEN_MEAS_RANGE_30_80, 0 }, + { TOKEN_MEAS_RANGE_30_130, 0 }, + { TOKEN_MEAS_RANGE_50_100, 0 }, + { TOKEN_MEAS_RANGE_80_130, 0 }, +}; + +static int find_token_payload_len(unsigned char c) { - (void)fd; + unsigned int i; - const struct sr_dev_inst *sdi; + for (i = 0; i < ARRAY_SIZE(token_payloads); i++) { + if (token_payloads[i][0] == c) + return token_payloads[i][1]; + } + + return -1; +} + +/* Process measurement or setting (0xa5 command). */ +static void process_mset(const struct sr_dev_inst *sdi) +{ struct dev_context *devc; + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + GString *dbg; + float fvalue; + int i; - if (!(sdi = cb_data)) - return TRUE; + devc = sdi->priv; + if (sr_log_loglevel_get() >= SR_LOG_SPEW) { + dbg = g_string_sized_new(128); + g_string_printf(dbg, "got command 0x%.2x token 0x%.2x", + devc->cmd, devc->token); + if (devc->buf_len) { + g_string_append_printf(dbg, " payload"); + for (i = 0; i < devc->buf_len; i++) + g_string_append_printf(dbg, " %.2x", devc->buf[i]); + } + sr_spew("%s", dbg->str); + g_string_free(dbg, TRUE); + } + + switch(devc->token) { + case TOKEN_WEIGHT_TIME_FAST: + devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F; + devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_S; + break; + case TOKEN_WEIGHT_TIME_SLOW: + devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S; + devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_F; + break; + case TOKEN_WEIGHT_FREQ_A: + devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A; + devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_C; + break; + case TOKEN_WEIGHT_FREQ_C: + devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C; + devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_A; + break; + case TOKEN_HOLD_MAX: + devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MAX; + devc->cur_mqflags &= ~SR_MQFLAG_MIN; + break; + case TOKEN_HOLD_MIN: + devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MIN; + devc->cur_mqflags &= ~SR_MQFLAG_MAX; + break; + case TOKEN_HOLD_NONE: + devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_HOLD); + break; + case TOKEN_MEASUREMENT: + fvalue = ((devc->buf[0] & 0xf0) >> 4) * 100; + fvalue += (devc->buf[0] & 0x0f) * 10; + fvalue += ((devc->buf[1] & 0xf0) >> 4); + fvalue += (devc->buf[1] & 0x0f) / 10.0; + memset(&analog, 0, sizeof(struct sr_datafeed_analog)); + analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL; + analog.mqflags = devc->cur_mqflags; + analog.unit = SR_UNIT_DECIBEL_SPL; + analog.probes = sdi->probes; + analog.num_samples = 1; + analog.data = &fvalue; + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(devc->cb_data, &packet); + + devc->num_samples++; + if (devc->limit_samples && devc->num_samples >= devc->limit_samples) + sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi, + devc->cb_data); + break; + case TOKEN_TIME: + case TOKEN_STORE_OK: + case TOKEN_STORE_FULL: + case TOKEN_RECORDING_ON: + case TOKEN_RECORDING_OFF: + case TOKEN_MEAS_WAS_READOUT: + case TOKEN_MEAS_WAS_BARGRAPH: + case TOKEN_BATTERY_OK: + case TOKEN_BATTERY_LOW: + case TOKEN_MEAS_RANGE_OK: + case TOKEN_MEAS_RANGE_OVER: + case TOKEN_MEAS_RANGE_UNDER: + case TOKEN_MEAS_RANGE_30_80: + case TOKEN_MEAS_RANGE_30_130: + case TOKEN_MEAS_RANGE_50_100: + case TOKEN_MEAS_RANGE_80_130: + /* Not useful, or not expressable in sigrok. */ + break; + } + +} + +static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c) +{ + struct dev_context *devc; + int len; if (!(devc = sdi->priv)) + return; + + if (c == 0xff) { + /* Device is in hold mode */ + devc->cur_mqflags |= SR_MQFLAG_HOLD; + + /* TODO: send out the last measurement at the same + * rate as it normally gets sent */ + + /* When the device leaves hold mode, it starts from scratch. */ + devc->state = ST_INIT; + return; + } + devc->cur_mqflags &= ~SR_MQFLAG_HOLD; + + if (devc->state == ST_INIT) { + if (c == 0xa5) { + devc->cmd = c; + devc->token = 0x00; + devc->state = ST_GET_TOKEN; + } else if (c == 0xbb) { + devc->cmd = c; + devc->buf_len = 0; + devc->state = ST_GET_LOG; + } + } else if (devc->state == ST_GET_TOKEN) { + devc->token = c; + devc->buf_len = 0; + len = find_token_payload_len(devc->token); + if (len == -1 || len > 0) { + devc->buf_len = 0; + devc->state = ST_GET_DATA; + } else { + process_mset(sdi); + devc->state = ST_INIT; + } + } else if (devc->state == ST_GET_DATA) { + len = find_token_payload_len(devc->token); + if (len == -1) { + /* We don't know this token. */ + sr_dbg("Unknown 0xa5 token 0x%.2x", devc->token); + if (c == 0xa5 || c == 0xbb) { + /* Looks like a new command however. */ + process_mset(sdi); + devc->state = ST_INIT; + } else { + devc->buf[devc->buf_len++] = c; + if (devc->buf_len > BUF_SIZE) { + /* Shouldn't happen, ignore. */ + devc->state = ST_INIT; + } + } + } else { + devc->buf[devc->buf_len++] = c; + if (devc->buf_len == len) { + process_mset(sdi); + devc->state = ST_INIT; + } else if (devc->buf_len > BUF_SIZE) { + /* Shouldn't happen, ignore. */ + devc->state = ST_INIT; + } + } + } else if (devc->state == ST_GET_LOG) { + } + +} + +SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data) +{ + const struct sr_dev_inst *sdi; + struct sr_serial_dev_inst *serial; + unsigned char c; + + (void)fd; + + if (!(sdi = cb_data)) return TRUE; + serial = sdi->conn; if (revents == G_IO_IN) { - /* TODO */ + if (serial_read(serial, &c, 1) != 1) + return TRUE; + process_byte(sdi, c); } return TRUE; diff --git a/hardware/cem-dt-885x/protocol.h b/hardware/cem-dt-885x/protocol.h index 6351aa4b..7f296e83 100644 --- a/hardware/cem-dt-885x/protocol.h +++ b/hardware/cem-dt-885x/protocol.h @@ -34,19 +34,60 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) +#define BUF_SIZE 32 + +enum { + TOKEN_WEIGHT_TIME_FAST = 0x02, + TOKEN_WEIGHT_TIME_SLOW = 0x03, + TOKEN_HOLD_MAX = 0x04, + TOKEN_HOLD_MIN = 0x05, + TOKEN_TIME = 0x06, + TOKEN_MEAS_RANGE_OVER = 0x07, + TOKEN_MEAS_RANGE_UNDER = 0x08, + TOKEN_STORE_FULL = 0x09, + TOKEN_RECORDING_ON = 0x0a, + TOKEN_MEAS_WAS_READOUT = 0x0b, + TOKEN_MEAS_WAS_BARGRAPH = 0x0c, + TOKEN_MEASUREMENT = 0xd, + TOKEN_HOLD_NONE = 0x0e, + TOKEN_BATTERY_LOW = 0x0f, + TOKEN_MEAS_RANGE_OK = 0x11, + TOKEN_STORE_OK = 0x19, + TOKEN_RECORDING_OFF = 0x1a, + TOKEN_WEIGHT_FREQ_A = 0x1b, + TOKEN_WEIGHT_FREQ_C = 0x1c, + TOKEN_BATTERY_OK = 0x1f, + TOKEN_MEAS_RANGE_30_80 = 0x30, + TOKEN_MEAS_RANGE_30_130 = 0x40, + TOKEN_MEAS_RANGE_50_100 = 0x4b, + TOKEN_MEAS_RANGE_80_130 = 0x4c, +}; + /** Private, per-device-instance driver context. */ struct dev_context { - /* Model-specific information */ - /* Acquisition settings */ uint64_t limit_samples; /* Operational state */ - unsigned int num_samples; - unsigned char stream_buf[5]; + int state; + uint64_t num_samples; + uint64_t cur_mqflags; /* Temporary state across callbacks */ + void *cb_data; + unsigned char cmd; + unsigned char token; + int buf_len; + unsigned char buf[BUF_SIZE]; + +}; +/* Parser state machine. */ +enum { + ST_INIT, + ST_GET_TOKEN, + ST_GET_DATA, + ST_GET_LOG, }; SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data);