X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Fpce-322a%2Fprotocol.c;h=ee98c7c61128cd82cb0a1bdbb2d0a7ab724524d8;hp=0f822d852027145c3f41f2d96df5ac3307e3c174;hb=a4be2b327be8b6a38fe024e2a3ee614243067762;hpb=5a2c71ccd7c46b18583dd068a8508e9d93ed9190 diff --git a/src/hardware/pce-322a/protocol.c b/src/hardware/pce-322a/protocol.c index 0f822d85..ee98c7c6 100644 --- a/src/hardware/pce-322a/protocol.c +++ b/src/hardware/pce-322a/protocol.c @@ -2,6 +2,7 @@ * This file is part of the libsigrok project. * * Copyright (C) 2016 George Hopkins + * Copyright (C) 2016 Matthieu Guillaumin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,12 +19,14 @@ */ #include +#include #include "protocol.h" static int send_command(const struct sr_dev_inst *sdi, uint16_t command) { struct sr_serial_dev_inst *serial; uint8_t buffer[2]; + int ret; buffer[0] = command >> 8; buffer[1] = command; @@ -31,9 +34,35 @@ static int send_command(const struct sr_dev_inst *sdi, uint16_t command) if (!(serial = sdi->conn)) return SR_ERR; - if (serial_write_nonblocking(serial, (const void *)buffer, 2) != 2) + ret = serial_write_blocking(serial, buffer, sizeof(buffer), 0); + if (ret < 0) + return ret; + if ((size_t)ret != sizeof(buffer)) + return SR_ERR_IO; + + return SR_OK; +} + +static int send_long_command(const struct sr_dev_inst *sdi, uint32_t command) +{ + struct sr_serial_dev_inst *serial; + uint8_t buffer[4]; + int ret; + + buffer[0] = command >> 24; + buffer[1] = command >> 16; + buffer[2] = command >> 8; + buffer[3] = command; + + if (!(serial = sdi->conn)) return SR_ERR; + ret = serial_write_blocking(serial, buffer, sizeof(buffer), 0); + if (ret < 0) + return ret; + if ((size_t)ret != sizeof(buffer)) + return SR_ERR_IO; + return SR_OK; } @@ -60,8 +89,9 @@ static void send_data(const struct sr_dev_inst *sdi, float sample) sr_session_send(sdi, &packet); devc->num_samples++; - if (devc->limit_samples && devc->num_samples >= devc->limit_samples) - sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi); + /* Limiting number of samples is only supported for live data. */ + if (devc->cur_data_source == DATA_SOURCE_LIVE && devc->limit_samples && devc->num_samples >= devc->limit_samples) + sr_dev_acquisition_stop((struct sr_dev_inst *)sdi); } static void process_measurement(const struct sr_dev_inst *sdi) @@ -104,23 +134,118 @@ static void process_measurement(const struct sr_dev_inst *sdi) send_data(sdi, value / 10.0); } +static void process_memory_measurement(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + uint16_t value; + + devc = sdi->priv; + value = devc->buffer[devc->buffer_len - 1] << 8; + value |= devc->buffer[devc->buffer_len - 2]; + + send_data(sdi, value / 10.0); +} + static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c) { struct dev_context *devc; - unsigned int i; devc = sdi->priv; if (devc->buffer_len < BUFFER_SIZE) { devc->buffer[devc->buffer_len++] = c; } else { - for (i = 1; i < BUFFER_SIZE; i++) - devc->buffer[i - 1] = devc->buffer[i]; + memmove(devc->buffer, devc->buffer + 1, BUFFER_SIZE - 1); devc->buffer[BUFFER_SIZE - 1] = c; - if (devc->buffer[0] == 0x7f && devc->buffer[BUFFER_SIZE - 1] == 0x00) { - process_measurement(sdi); - devc->buffer_len = 0; + } + + if (devc->buffer_len == BUFFER_SIZE && devc->buffer[0] == 0x7f + && devc->buffer[BUFFER_SIZE - 1] == 0x00) { + process_measurement(sdi); + devc->buffer_len = 0; + } +} + +static void process_usage_byte(const struct sr_dev_inst *sdi, uint8_t c) +{ + struct dev_context *devc; + + devc = sdi->priv; + + if (devc->buffer_len < MEM_USAGE_BUFFER_SIZE) { + devc->buffer[devc->buffer_len++] = c; + } else { + memmove(devc->buffer, devc->buffer + 1, MEM_USAGE_BUFFER_SIZE - 1); + devc->buffer[MEM_USAGE_BUFFER_SIZE - 1] = c; + } + + if (devc->buffer_len == MEM_USAGE_BUFFER_SIZE && devc->buffer[0] == 0xd1 + && devc->buffer[1] == 0x05 && devc->buffer[2] == 0x00 + && devc->buffer[3] == 0x01 && devc->buffer[4] == 0xd2 + && devc->buffer[MEM_USAGE_BUFFER_SIZE - 1] == 0x20) { + devc->memory_block_usage = devc->buffer[5] << 8 | devc->buffer[6]; + devc->memory_last_block_usage = devc->buffer[7]; + sr_warn("Memory usage: %d blocks of 256 bytes, 1 block of %d bytes", + devc->memory_block_usage - 1, devc->memory_last_block_usage); + devc->buffer_len = 0; + devc->buffer_skip = 1; + devc->memory_state = MEM_STATE_REQUEST_MEMORY_BLOCK; + devc->memory_block_cursor = 0; + devc->memory_block_counter = 0; + } +} + +static void process_memory_byte(const struct sr_dev_inst *sdi, uint8_t c) +{ + struct dev_context *devc; + + devc = sdi->priv; + + if (devc->buffer_len < MEM_DATA_BUFFER_SIZE) { + devc->buffer[devc->buffer_len++] = c; + } else { + memmove(devc->buffer, devc->buffer + 1, MEM_DATA_BUFFER_SIZE - 1); + devc->buffer[MEM_DATA_BUFFER_SIZE - 1] = c; + } + + if (devc->buffer_skip == 0 \ + && (devc->buffer[devc->buffer_len-2] & 0x7f) == 0x7f + && (devc->buffer[devc->buffer_len-1] & 0xf7) == 0xf7) { + /* Recording session header bytes found, load next 7 bytes. */ + devc->buffer_skip = MEM_DATA_BUFFER_SIZE - 2; + } + + if (devc->buffer_skip == 0 && devc->buffer_len == MEM_DATA_BUFFER_SIZE + && (devc->buffer[0] & 0x7f) == 0x7f && (devc->buffer[1] & 0xf7) == 0xf7 + && devc->buffer[2] == 0x01 && devc->buffer[3] == 0x00) { + /* Print information about recording. */ + sr_err("Recording dB(%X) %02x/%02x/%02x %02x:%02x:%02x ", + devc->buffer[4], devc->buffer[5], devc->buffer[6], devc->buffer[7], + devc->buffer[8] & 0x3f, devc->buffer[9], devc->buffer[10]); + /* Set dBA/dBC flag for recording. */ + if (devc->buffer[4] == 0x0c) { + devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C; + devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_A; + } else { + devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A; + devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_C; } + send_data(sdi, -1.0); /* Signal switch of recording. */ + devc->buffer_skip = 2; + } + + if (devc->buffer_skip == 0) { + process_memory_measurement(sdi); + devc->buffer_skip = 1; + } else { + devc->buffer_skip -= 1; + } + + devc->memory_block_cursor++; /* uint8_t goes back to 0 after 255. */ + if (devc->memory_block_cursor == 0) { + /* Current block is completed. */ + devc->memory_block_counter++; + devc->memory_state = MEM_STATE_REQUEST_MEMORY_BLOCK; } } @@ -142,10 +267,62 @@ SR_PRIV int pce_322a_receive_data(int fd, int revents, void *cb_data) if (!(serial = sdi->conn)) return TRUE; - if (revents == G_IO_IN) { - if (serial_read_nonblocking(serial, &c, 1) != 1) - return TRUE; - process_byte(sdi, c); + if (devc->cur_data_source == DATA_SOURCE_MEMORY) { + switch (devc->memory_state) { + case MEM_STATE_REQUEST_MEMORY_USAGE: + /* At init, disconnect and request the memory status. */ + sr_warn("Requesting memory usage."); + pce_322a_disconnect(sdi); + devc->memory_state = MEM_STATE_GET_MEMORY_USAGE; + devc->memory_block_usage = 0; + devc->memory_last_block_usage = 0; + devc->memory_block_counter = 0; + devc->memory_block_cursor = 0; + pce_322a_memory_status(sdi); + break; + case MEM_STATE_GET_MEMORY_USAGE: + /* Listen for memory usage answer. */ + if (revents == G_IO_IN) { + if (serial_read_nonblocking(serial, &c, 1) != 1) + return TRUE; + process_usage_byte(sdi, c); + } + break; + case MEM_STATE_REQUEST_MEMORY_BLOCK: + /* When cursor is 0, request next memory block. */ + if (devc->memory_block_counter <= devc->memory_block_usage) { + sr_warn("Requesting memory block %d.", devc->memory_block_counter); + pce_322a_memory_block(sdi, devc->memory_block_counter); + devc->memory_state = MEM_STATE_GET_MEMORY_BLOCK; + } else { + sr_warn("Exhausted memory blocks."); + return FALSE; + } + break; + case MEM_STATE_GET_MEMORY_BLOCK: + /* Stop after reading last byte of last block. */ + if (devc->memory_block_counter >= devc->memory_block_usage + && devc->memory_block_cursor >= devc->memory_last_block_usage) { + sr_warn("Done reading memory (%d bytes).", + 256 * (devc->memory_block_counter - 1) + + devc->memory_block_cursor); + return FALSE; + } + /* Listen for memory data. */ + if (revents == G_IO_IN) { + if (serial_read_nonblocking(serial, &c, 1) != 1) + return TRUE; + process_memory_byte(sdi, c); + } + break; + } + } else { + /* Listen for live data. */ + if (revents == G_IO_IN) { + if (serial_read_nonblocking(serial, &c, 1) != 1) + return TRUE; + process_byte(sdi, c); + } } return TRUE; @@ -161,6 +338,24 @@ SR_PRIV int pce_322a_disconnect(const struct sr_dev_inst *sdi) return send_command(sdi, CMD_DISCONNECT); } +SR_PRIV int pce_322a_memory_status(const struct sr_dev_inst *sdi) +{ + return send_command(sdi, CMD_MEMORY_STATUS); +} + +SR_PRIV int pce_322a_memory_clear(const struct sr_dev_inst *sdi) +{ + return send_command(sdi, CMD_MEMORY_CLEAR); +} + +SR_PRIV int pce_322a_memory_block(const struct sr_dev_inst *sdi, uint16_t memblk) +{ + uint8_t buf0 = memblk; + uint8_t buf1 = memblk >> 8; + uint32_t command = CMD_MEMORY_TRANSFER << 16 | buf0 << 8 | buf1; + return send_long_command(sdi, command); +} + SR_PRIV uint64_t pce_322a_weight_freq_get(const struct sr_dev_inst *sdi) { struct dev_context *devc;