RISC-V/V203/usb/scope/firmware/samplering.cpp
2024-10-22 17:07:37 +02:00

187 lines
5.9 KiB
C++

#include "samplering.h"
static const char * const hexstr = "0123456789ABCDEF";
uint32_t SampleRing::Up (const char * data, const uint32_t len) {
for (unsigned n=0; n<len; n++) {
const char c = data [n];
switch (c) {
case '$':
rcvd_counter = 0;
rcvd_status = RCVD_DATA;
break;
case '\r':
case '\n':
CmdReceived ();
rcvd_counter = 0;
rcvd_status = RCVD_IDLE;
break;
default:
if (rcvd_status == RCVD_DATA) {
rcvd_buffer [rcvd_counter] = c;
rcvd_counter += 1u;
}
break;
}
}
return len;
}
void SampleRing::CmdReceived() {
if (rcvd_counter == 0u) return;
unsigned result = 0u;
for (unsigned n=0; n<rcvd_counter; n++) {
const char c = rcvd_buffer [n];
result *= 16;
if ((c >= '0') and (c <= '9')) {
result += (unsigned) (c - '0');
} else if ((c >= 'A') and (c <= 'F')) {
result += (unsigned) (c - 'A' + 10);
} else if ((c >= 'a') and (c <= 'f')) {
result += (unsigned) (c - 'a' + 10);
} else {
// chyba : nech byt
}
}
CommandPass (result);
}
void SampleRing::CommandPass(const unsigned int cmd) {
RcvdHeader header;
header.common = cmd & 0xFFFF;
const DESTINATION dest = static_cast<DESTINATION> (header.bits.destinat);
switch (dest) {
case DEST_CHA:
case DEST_CHB:
break;
case DEST_BASE:
ReloadTimer (header.bits.cmd_value);
break;
case DEST_TRIG: {
const TRIGGER_CMD command = static_cast<TRIGGER_CMD> (header.bits.cmd_type);
switch (command) {
case TRIGGER_CMD_OFSET: m_settings.offset = header.bits.cmd_value; break;
case TRIGGER_CMD_VALUE: m_settings.value = header.bits.cmd_value; break;
case TRIGGER_CMD_MODE: {
TriggerModeUnion new_mode_union;
new_mode_union.common = header.bits.cmd_value;
const TRIGER_MODE new_mode = static_cast<TRIGER_MODE> (new_mode_union.bits.mode);
if (m_settings.mode != new_mode) m_settings.mode = new_mode;
const ADC_CHANNELS new_channel = static_cast<ADC_CHANNELS>(new_mode_union.bits.channel);
if (m_settings.channel != new_channel) m_settings.channel = new_channel;
const bool new_rising = new_mode_union.bits.rissing ? true : false;
if (m_settings.rising != new_rising) m_settings.rising = new_rising;
} break;
}
} break;
}
}
void SampleRing::write(DATA_BLOCK const * data) {
if (m_finished) return;
/** BUG : Tady je problém - tato funkce běží pod přerušením s vyšší prioritou,
* takže m_mode se během tt. funkce změnit nemůže. Z toho vyplývá, že se
* odeslání dat musí vykonat a nelze tedy změnit m_mode dokud se data
* meodešlou do ring_buffer všechna. Tedy to funguje, pokud je TRIGER_MODE_AUTO.
* Kde zde vzít informaci, že se m_mode nějak změnilo a nějak jí použít
* zatím nevím, nejjednodušší je nechat to být a přenést do software.
* */
unsigned t_head = m_head; // dočasné proměnné kvůli zrychlení
unsigned t_lenght = m_lenght; // následujícího cyklu
if (m_mode == TIME_BASE_TRIGERED) {
for (unsigned n=0u; n<DATA_HALF_LEN; n++) {
const DATA_BLOCK & sample = data [n];
ring_buffer [t_head].common_data = sample.common_data;
t_head += 1u;
t_head &= RING_MSK;
t_lenght += 1u;
const bool compare = m_settings.rising != (sample.channels[m_settings.channel] > m_settings.value);
if (compare and m_old_triger and !m_trigered) { // TRIGERED
if (t_lenght >= m_settings.offset) {
t_lenght = m_settings.offset;
m_trigered = true;
}
}
m_old_triger = !compare;
if (t_lenght >= RING_LEN) { // je fuk o kolik je to delší
// zastavit odesílání dat, pokud není AUTO a není splněna podmínka trigeru
if ((m_settings.mode != TRIGER_MODE_AUTO) and !m_trigered) continue;
t_lenght = RING_LEN;
m_tail = t_head;
m_finished = true;
break;
}
}
} else {
const DATA_BLOCK & sample = data [0];
ring_buffer [t_head].common_data = sample.common_data;
t_head += 1u;
t_head &= RING_MSK;
t_lenght += 1u;
m_finished = true;
}
m_head = t_head; // vrať zpátky hodnoty
m_lenght = t_lenght;
}
bool SampleRing::read(DATA_BLOCK & sample) {
if (!m_finished) return false;
if (!m_lenght) {
m_head = m_tail = m_lenght = 0u;
m_trigered = false;
m_finished = false;
return false;
}
sample = ring_buffer [m_tail];
m_tail += 1u;
m_tail &= RING_MSK;
m_lenght -= 1u;
return true;
}
uint32_t SampleRing::BlockSend (const char * buf, const uint32_t len) {
uint32_t n, ofs = 0, req = len;
for (;;) {
// spodní vrstva může vrátit i nulu, pokud je FIFO plné
n = BaseLayer::Down (buf + ofs, req);
ofs += n; // Posuneme ukazatel
req -= n; // Zmenšíme další požadavek
if (!req) break;
}
return ofs;
}
void SampleRing::pass() {
if (!m_finished) return;
SendPrefix();
DATA_BLOCK data;
while (read(data)) {
SendData (data);
}
BlockSend("\r\n", 2);
}
static int to_str (char * buffer, const uint16_t data, const int len = 3) {
unsigned val = data;
for (int i=len-1; i>=0; --i) {
buffer [i] = hexstr [val & 0xF];
val >>= 4;
}
return len;
}
uint32_t SampleRing::SendPrefix() {
const int buflen = 8;
char buffer [buflen];
int n = 0;
buffer [n++] = '$';
SendHeader sh;
sh.bits.trig_flg = m_trigered ? 1 : 0;
sh.bits.pack_len = m_lenght;
n += to_str (buffer + n, sh.common, 4);
buffer [n++] = '#';
return BlockSend (buffer, n);
}
uint32_t SampleRing::SendData (const DATA_BLOCK & data) {
const int buflen = 8;
char buffer [buflen];
int n = 0;
n += to_str (buffer + n, data.channels[0]);
n += to_str (buffer + n, data.channels[1]);
return BlockSend (buffer, n);
}