go faster, add some more prologix cmds, readme

This commit is contained in:
2025-12-02 03:47:31 +06:00
parent 7e6195f967
commit 4c6bbc58fd
3 changed files with 256 additions and 277 deletions

384
main.c
View File

@@ -44,6 +44,13 @@
#define ENV_SENSOR_READ_INTERVAL_MS 1000
#define DEFAULT_GPIB_TIMEOUT_MS 1200
// This kind of ass but.. yeah, I don't want to access systick there
// assume if the PC hasn't read after ~5ms it's stalled
#define USB_TIMEOUT_TARGET_MS 5
#define CYCLES_PER_LOOP 50
#define USB_TIMEOUT_LIMIT \
((FUNCONF_SYSTEM_CORE_CLOCK / 1000 * USB_TIMEOUT_TARGET_MS) / CYCLES_PER_LOOP)
// Menu Animation Timings
#define MENU_DOT_INTERVAL_MS 500 // Speed of "..." addition
#define MENU_COMMIT_DELAY_MS 2400 // Time to hold before entering mode
@@ -215,7 +222,7 @@ typedef enum {
MODE_FEAT_CONT, // Continuity Mode active
MODE_FEAT_DIODE, // Diode test mode
MODE_FEAT_XOHM, // Extended Ohms active
MODE_FEAT_STATS // avg/min/max
MODE_FEAT_STATS // AVG/MIN/MAX
} work_mode_t;
typedef enum {
@@ -463,14 +470,18 @@ typedef enum { SESSION_WRITE, SESSION_READ } session_mode_t;
static uint32_t gpib_write_lut[256];
// USB Ring Buffers
#define USB_RX_BUF_SIZE 512
#define USB_TX_BUF_SIZE 1024
#define USB_RX_BUF_SIZE 1024
#define USB_RX_MASK (USB_RX_BUF_SIZE - 1)
#define USB_TX_BUF_SIZE 2048
#define USB_TX_MASK (USB_TX_BUF_SIZE - 1)
volatile uint8_t usb_rx_buffer[USB_RX_BUF_SIZE];
// volatile uint8_t usb_tx_buffer[USB_TX_BUF_SIZE];
volatile int usb_rx_head = 0;
// volatile int usb_tx_head = 0;
volatile int usb_rx_tail = 0;
// volatile int usb_tx_tail = 0;
volatile uint8_t usb_tx_buffer[USB_TX_BUF_SIZE];
volatile uint32_t usb_rx_head = 0;
volatile uint32_t usb_tx_head = 0;
volatile uint32_t usb_rx_tail = 0;
volatile uint32_t usb_tx_tail = 0;
static uint8_t cdc_line_coding[7] = {0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08};
@@ -868,116 +879,20 @@ static void gpib_dump_state(const char* context) {
#define gpib_dump_state(x) ((void)0)
#endif
// low level
inline static void gpib_calc_lut(void) {
for (int i = 0; i < 256; i++) {
uint32_t bshr = 0;
// bits 0-7 mappings
if (i & 0x01)
bshr |= (1U << (16 + PIN_DIO1));
else
bshr |= (1U << PIN_DIO1);
if (i & 0x02)
bshr |= (1U << (16 + PIN_DIO2));
else
bshr |= (1U << PIN_DIO2);
if (i & 0x04)
bshr |= (1U << (16 + PIN_DIO3));
else
bshr |= (1U << PIN_DIO3);
if (i & 0x08)
bshr |= (1U << (16 + PIN_DIO4));
else
bshr |= (1U << PIN_DIO4);
if (i & 0x10)
bshr |= (1U << (16 + PIN_DIO5));
else
bshr |= (1U << PIN_DIO5);
if (i & 0x20)
bshr |= (1U << (16 + PIN_DIO6));
else
bshr |= (1U << PIN_DIO6);
if (i & 0x40)
bshr |= (1U << (16 + PIN_DIO7));
else
bshr |= (1U << PIN_DIO7);
if (i & 0x80)
bshr |= (1U << (16 + PIN_DIO8));
else
bshr |= (1U << PIN_DIO8);
void gpib_write_data(uint8_t b) { GPIOB->BSHR = gpib_write_lut[b]; }
gpib_write_lut[i] = bshr;
}
}
// void gpib_write_data(uint8_t b) { GPIOB->BSHR = gpib_write_lut[b]; }
void gpib_write_data(uint8_t b) {
uint32_t bshr = 0;
if (b & 0x01)
bshr |= (MASK_DIO1 << 16);
else
bshr |= MASK_DIO1;
if (b & 0x02)
bshr |= (MASK_DIO2 << 16);
else
bshr |= MASK_DIO2;
if (b & 0x04)
bshr |= (MASK_DIO3 << 16);
else
bshr |= MASK_DIO3;
if (b & 0x08)
bshr |= (MASK_DIO4 << 16);
else
bshr |= MASK_DIO4;
if (b & 0x10)
bshr |= (MASK_DIO5 << 16);
else
bshr |= MASK_DIO5;
if (b & 0x20)
bshr |= (MASK_DIO6 << 16);
else
bshr |= MASK_DIO6;
if (b & 0x40)
bshr |= (MASK_DIO7 << 16);
else
bshr |= MASK_DIO7;
if (b & 0x80)
bshr |= (MASK_DIO8 << 16);
else
bshr |= MASK_DIO8;
GPIOB->BSHR = bshr;
}
// uint8_t gpib_read_data(void) {
// // read all 16 pins, invert (gpib is active low)
// uint32_t r = ~(GPIOB->INDR);
// uint8_t b = 0;
// // parallel extraction
// b |= (r >> SHIFT_DIO1) & MASK_GROUP_A; // handles D1 & D6
// b |= (r >> SHIFT_DIO2) & MASK_GROUP_B; // handles D2 & D7
// b |= (r >> SHIFT_DIO3) & (1 << 2);
// b |= (r >> SHIFT_DIO4) & (1 << 3);
// b |= (r >> SHIFT_DIO5) & (1 << 4);
// b |= (r >> SHIFT_DIO8) & (1 << 7);
// return b;
// }
uint8_t gpib_read_data(void) {
uint32_t r = ~(GPIOB->INDR); // active low
// read all 16 pins, invert (gpib is active low)
uint32_t r = ~(GPIOB->INDR);
uint8_t b = 0;
if (r & MASK_DIO1) b |= 0x01;
if (r & MASK_DIO2) b |= 0x02;
if (r & MASK_DIO3) b |= 0x04;
if (r & MASK_DIO4) b |= 0x08;
if (r & MASK_DIO5) b |= 0x10;
if (r & MASK_DIO6) b |= 0x20;
if (r & MASK_DIO7) b |= 0x40;
if (r & MASK_DIO8) b |= 0x80;
// parallel extraction
b |= (r >> SHIFT_GRP_9) & MASK_GRP_9; // handles D1 & D6
b |= (r >> SHIFT_GRP_7) & MASK_GRP_7; // handles D2 & D7
b |= (r >> SHIFT_D3) & (1 << 2);
b |= (r >> SHIFT_D4) & (1 << 3);
b |= (r >> SHIFT_D5) & (1 << 4);
b |= (r >> SHIFT_D8) & (1 << 7);
return b;
}
@@ -1055,7 +970,7 @@ int gpib_read_byte(uint8_t* data, int* eoi_asserted) {
// float data lines
gpib_write_data(0x00);
Delay_Us(10);
// Delay_Us(10);
// signal ready for data
GPIB_RELEASE(PIN_NRFD);
@@ -1094,7 +1009,7 @@ int gpib_read_byte(uint8_t* data, int* eoi_asserted) {
int gpib_start_session(uint8_t target_addr, session_mode_t mode) {
printf("gpib_start_session\n");
GPIB_ASSERT(PIN_ATN);
Delay_Us(20);
Delay_Us(1);
// Unlisten everyone first to clear bus state
if (gpib_write_byte(GPIB_CMD_UNL, 0) < 0) {
@@ -1116,9 +1031,7 @@ int gpib_start_session(uint8_t target_addr, session_mode_t mode) {
GPIB_ASSERT(PIN_NRFD); // Drive LOW (Not Ready)
}
Delay_Us(10);
GPIB_RELEASE(PIN_ATN); // Switch to Data Mode
Delay_Us(10);
return 0;
err:
@@ -1131,9 +1044,8 @@ err:
// Assert Interface Clear (IFC)
void gpib_interface_clear(void) {
GPIB_ASSERT(PIN_IFC);
Delay_Ms(1); // IEEE-488 requires >100us
Delay_Us(150); // IEEE-488 requires >100us
GPIB_RELEASE(PIN_IFC);
Delay_Ms(1);
}
// Control Remote Enable (REN)
@@ -1161,7 +1073,6 @@ int gpib_universal_clear(void) {
return -1;
}
Delay_Us(10);
GPIB_RELEASE(PIN_ATN);
return 0;
}
@@ -1239,9 +1150,8 @@ err:
// Serial Poll
// Reads the Status Byte (STB) from the device
int gpib_serial_poll(uint8_t addr, uint8_t* status) {
printf("gpib_serial_poll :: entry\n");
GPIB_ASSERT(PIN_ATN);
Delay_Us(20);
Delay_Us(1);
// setupo seq: UNL -> SPE -> LAD(Me) -> TAD(Target)
if (gpib_write_byte(GPIB_CMD_UNL, 0) < 0) goto err;
@@ -1249,29 +1159,23 @@ int gpib_serial_poll(uint8_t addr, uint8_t* status) {
if (gpib_write_byte(GPIB_CMD_LAD | MY_ADDR, 0) < 0) goto err;
if (gpib_write_byte(GPIB_CMD_TAD | addr, 0) < 0) goto err;
printf("gpib_serial_poll :: gpib_write_data(0x00); \n");
gpib_write_data(0x00); // Float data lines
GPIB_ASSERT(PIN_NDAC); // Busy / Not Accepted
GPIB_ASSERT(PIN_NRFD); // Busy / Not Ready
Delay_Us(5);
// gpib_write_data(0x00); // Float data lines
// GPIB_ASSERT(PIN_NDAC); // Busy / Not Accepted
// GPIB_ASSERT(PIN_NRFD); // Busy / Not Ready
// Delay_Us(5);
// drop ATN to read data
GPIB_RELEASE(PIN_ATN);
Delay_Us(5);
int eoi;
int res = gpib_read_byte(status, &eoi);
printf("gpib_serial_poll :: after handshake (res: %d)\n", res);
// handshake complete, clean up lines
GPIB_RELEASE(PIN_NRFD);
GPIB_RELEASE(PIN_NDAC);
// end seq: ATN -> SPD -> UNT
GPIB_ASSERT(PIN_ATN);
Delay_Us(5);
gpib_write_byte(GPIB_CMD_SPD, 0); // disable spoll
gpib_write_byte(GPIB_CMD_UNT, 0); // untalk
GPIB_RELEASE(PIN_ATN);
@@ -1443,7 +1347,7 @@ void gpib_init(void) {
funPinMode(PIN_SRQ, GPIO_CNF_IN_PUPD);
funDigitalWrite(PIN_SRQ, 1);
// release all control lines to idle (HIGH)
// float all control lines
GPIB_RELEASE(PIN_EOI);
GPIB_RELEASE(PIN_REN);
GPIB_RELEASE(PIN_ATN);
@@ -1463,29 +1367,16 @@ void gpib_init(void) {
funPinMode(PIN_DIO8, GPIO_Speed_50MHz | GPIO_CNF_OUT_OD);
// calculate BSHR for the DIO lines
gpib_calc_lut();
// for (int i = 0; i < 256; i++) {
// gpib_write_lut[i] =
// CALC_PIN_BSHR(i, 0, PIN_DIO1) | CALC_PIN_BSHR(i, 1, PIN_DIO2) |
// CALC_PIN_BSHR(i, 2, PIN_DIO3) | CALC_PIN_BSHR(i, 3, PIN_DIO4) |
// CALC_PIN_BSHR(i, 4, PIN_DIO5) | CALC_PIN_BSHR(i, 5, PIN_DIO6) |
// CALC_PIN_BSHR(i, 6, PIN_DIO7) | CALC_PIN_BSHR(i, 7, PIN_DIO8);
// }
for (int i = 0; i < 256; i++) {
gpib_write_lut[i] =
CALC_PIN_BSHR(i, 0, PIN_POS_D1) | CALC_PIN_BSHR(i, 1, PIN_POS_D2) |
CALC_PIN_BSHR(i, 2, PIN_POS_D3) | CALC_PIN_BSHR(i, 3, PIN_POS_D4) |
CALC_PIN_BSHR(i, 4, PIN_POS_D5) | CALC_PIN_BSHR(i, 5, PIN_POS_D6) |
CALC_PIN_BSHR(i, 6, PIN_POS_D7) | CALC_PIN_BSHR(i, 7, PIN_POS_D8);
}
// float data lines (release to HIGH)
// float data lines
gpib_write_data(0x00);
#ifdef GPIB_DEBUG
printf("[GPIB] Asserting IFC...\n");
#endif
gpib_interface_clear();
#ifdef GPIB_DEBUG
gpib_dump_state("INIT DONE");
// if no device is connected: NRFD/NDAC/DAV should all be 1
// if device is connected: NRFD/NDAC might be 0
#endif
}
// ------------------------------------
@@ -1598,127 +1489,128 @@ void HandleDataOut(struct _USBState* ctx, int endp, uint8_t* data, int len) {
} else if (endp == 2) {
// Copy to Ring Buffer
for (int i = 0; i < len; i++) {
int next_head = (usb_rx_head + 1) % USB_RX_BUF_SIZE;
uint32_t next_head = (usb_rx_head + 1) & USB_RX_MASK;
if (next_head != usb_rx_tail) {
usb_rx_buffer[usb_rx_head] = data[i];
usb_rx_head = next_head;
} else {
// buf overflow
}
}
}
}
// void usb_process_tx(void) {
// if (!app.usb_online) return;
// // check HW Busy (endpoint 3)
// if (USBFSCTX.USBFS_Endp_Busy[3]) return;
// // check buffer empty
// if (usb_tx_head == usb_tx_tail) return;
// // calc contiguous chunk size
// int len;
// if (usb_tx_head > usb_tx_tail) {
// len = usb_tx_head - usb_tx_tail;
// } else {
// len = USB_TX_BUF_SIZE - usb_tx_tail;
// }
// // cap at USB pkt size
// if (len > 64) len = 64;
// // send to hw, with memcpy
// USBFS_SendEndpointNEW(3, (uint8_t*)&usb_tx_buffer[usb_tx_tail], len, 1);
// // advance tail
// usb_tx_tail = (usb_tx_tail + len) % USB_TX_BUF_SIZE;
// }
// void usb_send_text(const char* str) {
// if (!app.usb_online) {
// // if offline, just reset buffer
// usb_tx_head = usb_tx_tail = 0;
// return;
// }
// while (*str) {
// int next = (usb_tx_head + 1) % USB_TX_BUF_SIZE;
// while (next == usb_tx_tail) {
// return; // we just drop it
// }
// usb_tx_buffer[usb_tx_head] = *str++;
// usb_tx_head = next;
// }
// }
static void usb_send_text(const char* str) {
void usb_process_tx(void) {
if (!app.usb_online) return;
int len = strlen(str);
int pos = 0;
// check hw busy (endp 3)
if (USBFSCTX.USBFS_Endp_Busy[3]) return;
// check buffer empty
if (usb_tx_head == usb_tx_tail) return;
while (pos < len) {
int chunk = len - pos;
if (chunk > 64) chunk = 64;
// calc contiguous chunk size
uint32_t tail = usb_tx_tail;
uint32_t head = usb_tx_head;
uint32_t start_time = millis();
int sent = 0;
// calc contiguous size linear from tail to end of arr or head
int len;
if (head > tail) {
len = head - tail;
} else {
len = USB_TX_BUF_SIZE - tail;
}
while ((millis() - start_time) < USB_SEND_TIMEOUT_MS) {
int result = USBFS_SendEndpointNEW(3, (uint8_t*)(str + pos), chunk, 1);
// cap at USB pkt size
if (len > 64) len = 64;
if (result == 0) {
sent = 1;
break;
// send to hw, with memcpy
USBFS_SendEndpointNEW(3, (uint8_t*)&usb_tx_buffer[tail], len, 1);
// advance tail
usb_tx_tail = (tail + len) & USB_TX_MASK;
}
void usb_send_text(const char* str) {
if (!app.usb_online) {
// if offline, just reset buffer
usb_tx_head = usb_tx_tail = 0;
return;
}
while (*str) {
uint32_t next = (usb_tx_head + 1) & USB_TX_MASK;
// buffer full?
if (next == usb_tx_tail) {
usb_process_tx();
uint32_t timeout = USB_TIMEOUT_LIMIT; // ~5ms
while (next == usb_tx_tail) {
// this *should* be set by the ISR, so can exit immediately
if (!USB_HW_IS_ACTIVE()) return;
if (--timeout == 0) {
return; // give up and drop
}
usb_process_tx();
}
}
if (!sent) {
return;
}
pos += chunk;
usb_tx_buffer[usb_tx_head] = *str++;
usb_tx_head = next;
}
// tx rightg away
usb_process_tx();
}
// pull a line from ring buffer
int get_start_command(char* dest_buf, int max_len) {
if (usb_rx_head == usb_rx_tail) return 0;
uint32_t head = usb_rx_head;
uint32_t tail = usb_rx_tail;
if (head == tail) return 0;
int temp_tail = usb_rx_tail;
int len = 0;
int found_newline = 0;
uint32_t scan = tail;
// Peek for newline
while (temp_tail != usb_rx_head) {
char c = usb_rx_buffer[temp_tail];
while (scan != head) {
char c = usb_rx_buffer[scan];
if (c == '\n' || c == '\r') {
found_newline = 1;
break;
}
temp_tail = (temp_tail + 1) % USB_RX_BUF_SIZE;
len++;
if (len >= max_len - 1) break;
scan = (scan + 1) & USB_RX_MASK;
if (++len >= max_len - 1) break;
}
if (found_newline) {
// copy out
for (int i = 0; i < len; i++) {
dest_buf[i] = usb_rx_buffer[usb_rx_tail];
usb_rx_tail = (usb_rx_tail + 1) % USB_RX_BUF_SIZE;
dest_buf[i] = usb_rx_buffer[tail];
tail = (tail + 1) & USB_RX_MASK;
}
dest_buf[len] = 0;
// eat newline chars
while (usb_rx_tail != usb_rx_head) {
char c = usb_rx_buffer[usb_rx_tail];
// eat limiters
tail = scan;
while (tail != head) {
char c = usb_rx_buffer[tail];
if (c == '\r' || c == '\n') {
usb_rx_tail = (usb_rx_tail + 1) % USB_RX_BUF_SIZE;
tail = (tail + 1) & USB_RX_MASK;
} else {
break;
}
}
// update the global volatile tail
usb_rx_tail = tail;
return len;
}
return 0;
}
@@ -2636,21 +2528,20 @@ static void cmd_help(void) {
}
static void cmd_status(void) {
int srq_is_active = gpib_check_srq();
int srq = gpib_check_srq();
snprintf(scratch.cmd.fmt_buf, sizeof(scratch.cmd.fmt_buf),
"Config:\r\n"
" Addr: %d\r\n"
" Timeout: %lu ms\r\n"
" Auto Read: %d\r\n"
" EOS Mode: %d (0:CRLF 1:CR 2:LF 3:N)\r\n"
" EOR Mode: %d\r\n"
" EOI Assert: %d\r\n"
" EOT: %s (Char %d)\r\n"
" SRQ Line: %d %s\r\n",
"ADDR: %d\r\n"
"TMO : %lu ms\r\n"
"AUTO: %d\r\n"
"EOS : %d\r\n"
"EOR : %d\r\n"
"EOI : %d\r\n"
"EOT : %s (%d)\r\n"
"SRQ : %d\r\n",
app.target_addr, app.gpib_timeout_ms, app.auto_read, app.eos_mode,
app.eor_mode, app.eoi_assert, app.eot_enable ? "ON" : "OFF",
app.eot_char, srq_is_active, srq_is_active ? "(Active)" : "(Idle)");
app.eot_char, srq);
usb_send_text(scratch.cmd.fmt_buf);
}
@@ -2992,6 +2883,7 @@ int main() {
// Buzzer setup
buzzer_init();
play_startup_tune();
// I2C sensor
i2c_init();
@@ -3005,20 +2897,18 @@ int main() {
USBFSSetup();
// usb_debug = 1;
// play_startup_tune();
// app state
app.usb_raw_prev = USB_HW_IS_ACTIVE();
// init timers
uint32_t now = millis();
app.usb_ts = now;
app.ignore_input_start_ts = now - 2000; /* Allow input immediately */
app.ignore_input_start_ts = now - 2000;
app.last_poll_time = 0;
app.env_last_read = 0;
while (1) {
handle_usb_state();
// usb_process_tx();
usb_process_tx();
app_loop();
handle_env_sensor();