implemented default commands and SRQ callback

master
Ondřej Hruška 9 years ago
parent 94b32ec8d6
commit 1cec87973c
  1. 2
      Makefile
  2. 43
      main.c
  3. 4
      scpi.pro
  4. 2
      scpi.pro.user
  5. 192
      scpi_parser.c
  6. 29
      scpi_parser.h
  7. 42
      scpi_regs.c
  8. 104
      scpi_regs.h
  9. 8
      scpi_status.c
  10. 83
      scpi_status.h

@ -1,5 +1,5 @@
all: main.c scpi_parser.c scpi_parser.h all: main.c scpi_parser.c scpi_parser.h
gcc main.c scpi_parser.c scpi_errors.c -o main.elf gcc main.c scpi_parser.c scpi_errors.c scpi_regs.c -o main.elf
run: all run: all
./main.elf ./main.elf

@ -2,13 +2,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "scpi_parser.h" #include "scpi_parser.h"
#include "scpi_errors.h"
void cmd_aIDNq_cb(const SCPI_argval_t *args)
{
printf("cb *IDN?\n");
}
void cmd_APPL_SIN_cb(const SCPI_argval_t *args) void cmd_APPL_SIN_cb(const SCPI_argval_t *args)
@ -61,11 +54,6 @@ void cmd_STQE_cb(const SCPI_argval_t *args)
} }
const SCPI_command_t scpi_commands[] = { const SCPI_command_t scpi_commands[] = {
{
.levels = {"*IDN?"},
.params = {},
.callback = cmd_aIDNq_cb
},
{ {
.levels = {"APPLy", "SINe"}, .levels = {"APPLy", "SINe"},
.params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT}, .params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT},
@ -111,28 +99,51 @@ const SCPI_command_t scpi_commands[] = {
void scpi_send_byte_impl(uint8_t b)
{
putchar(b);
}
const char *scpi_device_identifier(void)
{
return "FEL CVUT,DDS1,0,0.1";
}
int main() int main()
{ {
char buf[256]; char buf[256];
// SCPI_REG_QUEST.CURR = 1;
// SCPI_REG_QUEST_EN.u16 = 0xFFFF;
// printf("0x%x\n", SCPI_REG_QUEST.u16);
// scpi_status_update();
// return 0;
// const char *inp = "*IDN?\n"; // const char *inp = "*IDN?\n";
// const char *inp = "FREQ 50\n"; // const char *inp = "FREQ 50\n";
const char *inp = "DISP:TEXT 'ban\\\\ana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n"; // const char *inp = "DISP:TEXT 'ban\\\\ana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n";
//const char *inp = "FOO\nDATA:BLOB 13.456, #216AbcdEfghIjklMnop\nFREQ 50\r\nAPPLY:MOO\n"; //const char *inp = "FOO\nDATA:BLOB 13.456, #216AbcdEfghIjklMnop\nFREQ 50\r\nAPPLY:MOO\n";
//const char *inp = "STAT:QUE:ENAB?;ENAB \t 1;ENAB?;:*IDN?\n"; //const char *inp = "STAT:QUE:ENAB?;ENAB \t 1;ENAB?;:*IDN?\n";
//const char *inp = "*idn?;foo;apply:sin 5,6,\n"; const char *inp = "*idn?\n";
for (int i = 0; i < strlen(inp); i++) { for (int i = 0; i < strlen(inp); i++) {
scpi_handle_byte(inp[i]); scpi_handle_byte(inp[i]);
} }
scpi_error_string(buf, E_EXE_DATA_QUESTIONABLE, "The data smells fishy"); //scpi_error_string(buf, E_EXE_DATA_QUESTIONABLE, "The data smells fishy");
scpi_read_error(buf), printf("%s\n", buf); //scpi_read_error(buf), printf("%s\n", buf);
// scpi_add_error(E_CMD_BLOCK_DATA_ERROR, NULL); // scpi_add_error(E_CMD_BLOCK_DATA_ERROR, NULL);

@ -7,7 +7,7 @@ SOURCES += \
scpi_parser.c \ scpi_parser.c \
main.c \ main.c \
scpi_errors.c \ scpi_errors.c \
scpi_status.c scpi_regs.c
DISTFILES += \ DISTFILES += \
style.astylerc \ style.astylerc \
@ -19,4 +19,4 @@ DISTFILES += \
HEADERS += \ HEADERS += \
scpi_parser.h \ scpi_parser.h \
scpi_errors.h \ scpi_errors.h \
scpi_status.h scpi_regs.h

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2015-12-04T21:00:30. --> <!-- Written by QtCreator 3.5.1, 2015-12-05T00:30:51. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

@ -84,6 +84,8 @@ static struct {
// buffer for error messages // buffer for error messages
static char ebuf[256]; static char ebuf[256];
// response buffer
static char sbuf[256];
// ---------------- PRIVATE PROTOTYPES ------------------ // ---------------- PRIVATE PROTOTYPES ------------------
@ -121,23 +123,188 @@ static void pars_reset_cmd_keeplevel(void);
// ---------------- BUILTIN SCPI COMMANDS ------------------ // ---------------- BUILTIN SCPI COMMANDS ------------------
static void builtin_cb_FOO(const SCPI_argval_t *args) static void builtin_CLS(const SCPI_argval_t *args)
{ {
printf("Builtin FOO\n"); // clear the registers
SCPI_REG_SESR.u8 = 0;
SCPI_REG_OPER.u16 = 0;
SCPI_REG_QUES.u16 = 0;
scpi_clear_errors();
if (scpi_user_CLS) {
scpi_user_CLS();
}
scpi_status_update(); // flags
}
static void builtin_RST(const SCPI_argval_t *args)
{
if (scpi_user_RST) {
scpi_user_RST();
}
}
static void builtin_TSTq(const SCPI_argval_t *args)
{
if (scpi_user_TSTq) {
scpi_user_TSTq();
}
}
static void builtin_IDNq(const SCPI_argval_t *args)
{
scpi_send_string(scpi_device_identifier());
}
static void builtin_ESE(const SCPI_argval_t *args)
{
SCPI_REG_SESR_EN.u8 = (uint8_t) args[0].INT;
}
static void builtin_ESEq(const SCPI_argval_t *args)
{
sprintf(sbuf, "%d", SCPI_REG_SESR_EN.u8);
scpi_send_string(ebuf);
}
static void builtin_ESRq(const SCPI_argval_t *args)
{
sprintf(sbuf, "%d", SCPI_REG_SESR.u8);
scpi_send_string(ebuf);
}
static void builtin_OPC(const SCPI_argval_t *args)
{
// implementation for instruments with no overlapping commands.
// Can be overridden in the user commands.
SCPI_REG_SESR.OPC = 1;
}
static void builtin_OPCq(const SCPI_argval_t *args)
{
// implementation for instruments with no overlapping commands.
// Can be overridden in the user commands.
// (would be): sprintf(sbuf, "%d", SCPI_REG_SESR.OPC);
scpi_send_string("1");
}
static void builtin_SRE(const SCPI_argval_t *args)
{
SCPI_REG_SRE.u8 = (uint8_t) args[0].INT;
}
static void builtin_SREq(const SCPI_argval_t *args)
{
sprintf(sbuf, "%d", SCPI_REG_SRE.u8);
scpi_send_string(ebuf);
}
static void builtin_STBq(const SCPI_argval_t *args)
{
sprintf(sbuf, "%d", SCPI_REG_STB.u8);
scpi_send_string(ebuf);
}
static void builtin_WAI(const SCPI_argval_t *args)
{
// no-op
} }
static const SCPI_command_t scpi_commands_builtin[] = { static const SCPI_command_t scpi_commands_builtin[] = {
// ---- COMMON COMMANDS ----
{
.levels = {"*CLS"},
.callback = builtin_CLS
},
{
.levels = {"*ESE"},
.params = {SCPI_DT_INT},
.callback = builtin_ESE
},
{
.levels = {"*ESE?"},
.callback = builtin_ESEq
},
{
.levels = {"*ESR?"},
.callback = builtin_ESRq
},
{
.levels = {"*IDN?"},
.callback = builtin_IDNq
},
{
.levels = {"*OPC"},
.callback = builtin_OPC
},
{
.levels = {"*OPCq"},
.callback = builtin_OPCq
},
{
.levels = {"*RST"},
.callback = builtin_RST
},
{ {
.levels = {"FOO"}, .levels = {"*SRE"},
.params = {}, .params = {SCPI_DT_INT},
.callback = builtin_cb_FOO .callback = builtin_SRE
}, },
{
.levels = {"*SRE?"},
.callback = builtin_SREq
},
{
.levels = {"*STB?"},
.callback = builtin_STBq
},
{
.levels = {"*WAI"},
.callback = builtin_WAI
},
{
.levels = {"*TST?"},
.callback = builtin_TSTq
},
// ---- REQUIRED SYST COMMANDS ----
{0} // end marker {0} // end marker
}; };
// ------------------- MESSAGE SEND ------------------
/** Send a message to master. Trailing newline is added. */
void scpi_send_string(const char *message)
{
char c;
while ((c = *message++) != 0) {
scpi_send_byte_impl(c);
}
scpi_send_byte_impl('\r');
scpi_send_byte_impl('\n');
}
// ------------------- ERROR QUEUE --------------------- // ------------------- ERROR QUEUE ---------------------
void scpi_add_error(SCPI_error_t errno, const char *extra) void scpi_add_error(SCPI_error_t errno, const char *extra)
@ -163,6 +330,8 @@ void scpi_add_error(SCPI_error_t errno, const char *extra)
if (pst.err_queue_w >= ERR_QUEUE_LEN) { if (pst.err_queue_w >= ERR_QUEUE_LEN) {
pst.err_queue_w = 0; pst.err_queue_w = 0;
} }
scpi_status_update();
} }
@ -179,6 +348,18 @@ void scpi_read_error(char *buf)
if (pst.err_queue_r >= ERR_QUEUE_LEN) { if (pst.err_queue_r >= ERR_QUEUE_LEN) {
pst.err_queue_r = 0; pst.err_queue_r = 0;
} }
scpi_status_update();
}
void scpi_clear_errors(void)
{
pst.err_queue_r = 0;
pst.err_queue_w = 0;
pst.err_queue_used = 0;
scpi_status_update();
} }
@ -187,6 +368,7 @@ uint8_t scpi_error_count(void)
return pst.err_queue_used; return pst.err_queue_used;
} }
static void err_no_such_command() static void err_no_such_command()
{ {
char *b = ebuf; char *b = ebuf;

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "scpi_errors.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "scpi_errors.h"
#include "scpi_regs.h"
#define SCPI_MAX_CMD_LEN 12 #define SCPI_MAX_CMD_LEN 12
#define SCPI_MAX_STRING_LEN 12 #define SCPI_MAX_STRING_LEN 12
#define SCPI_MAX_LEVEL_COUNT 4 #define SCPI_MAX_LEVEL_COUNT 4
@ -55,10 +56,27 @@ typedef struct {
void (*blob_callback)(const uint8_t *bytes); void (*blob_callback)(const uint8_t *bytes);
} SCPI_command_t; } SCPI_command_t;
// ---------------- USER CONFIG ----------------
// Zero terminated command struct array - must be defined. // Zero terminated command struct array - must be defined.
extern const SCPI_command_t scpi_commands[]; extern const SCPI_command_t scpi_commands[];
/** Send a byte to master (may be buffered) */
extern void scpi_send_byte_impl(uint8_t b);
/** *CLS command callback - clear non-SCPI device state */
extern __attribute__((weak)) void scpi_user_CLS(void);
/** *RST command callback - reset non-SCPI device state */
extern __attribute__((weak)) void scpi_user_RST(void);
/** *TST? command callback - perform self test and send response back. */
extern __attribute__((weak)) void scpi_user_TSTq(void);
/** Get device identifier. Implemented as a callback to allow dynamic serial number */
extern const char *scpi_device_identifier(void);
// --------------- functions -------------------- // --------------- functions --------------------
@ -84,3 +102,10 @@ void scpi_read_error(char *buf);
/** Discard the rest of the currently processed blob */ /** Discard the rest of the currently processed blob */
void scpi_discard_blob(void); void scpi_discard_blob(void);
/** Send a string to master. \r\n is added. */
void scpi_send_string(const char *message);
/** Clear the error queue */
void scpi_clear_errors(void);

@ -0,0 +1,42 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "scpi_regs.h"
#include "scpi_errors.h"
#include "scpi_parser.h"
SCPI_REG_QUES_t SCPI_REG_QUES;
SCPI_REG_QUES_t SCPI_REG_QUES_EN = {.u16 = 0xFFFF};
SCPI_REG_OPER_t SCPI_REG_OPER;
SCPI_REG_OPER_t SCPI_REG_OPER_EN = {.u16 = 0xFFFF};
SCPI_REG_SESR_t SCPI_REG_SESR;
SCPI_REG_SESR_t SCPI_REG_SESR_EN;
SCPI_REG_STB_t SCPI_REG_STB;
SCPI_REG_STB_t SCPI_REG_SRE;
/** Update status registers (propagate using enable registers) */
void scpi_status_update(void)
{
// propagate to STB
SCPI_REG_STB.ERRQ = scpi_error_count() > 0;
SCPI_REG_STB.QUES = SCPI_REG_QUES.u16 & SCPI_REG_QUES_EN.u16;
SCPI_REG_STB.OPER = SCPI_REG_OPER.u16 & SCPI_REG_OPER_EN.u16;
SCPI_REG_STB.SESR = SCPI_REG_SESR.u8 & SCPI_REG_SESR_EN.u8;
SCPI_REG_STB.MAV = false; // TODO!!!
// Request Service
SCPI_REG_STB.RQS = SCPI_REG_STB.u8 & SCPI_REG_SRE.u8;
// Run service request callback
if (SCPI_REG_STB.RQS) {
if (scpi_service_request_impl) {
scpi_service_request_impl();
}
}
}

@ -0,0 +1,104 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef union {
struct __attribute__((packed)) {
bool VOLT: 1;
bool CURR: 1;
bool TIME: 1;
bool POWER: 1;
bool TEMP: 1;
bool FREQ: 1;
bool PHASE: 1;
bool MODUL: 1;
bool CALIB: 1;
bool BIT_9: 1; // user defined
bool BIT_10: 1;
bool BIT_11: 1;
bool BIT_12: 1;
bool INSTR_SUM: 1; // instrument summary
bool COMMAND_WARNING: 1; // command warning
bool RESERVED: 1;
};
uint16_t u16;
} SCPI_REG_QUES_t;
typedef union {
struct __attribute__((packed)) {
bool CALIB: 1;
bool SETTING: 1;
bool RANGING: 1;
bool SWEEP: 1;
bool MEAS: 1;
bool WAIT_TRIG: 1; // waiting for trigger
bool WAIT_ARM: 1; // waiting for ARM
bool CORRECTING: 1;
bool BIT_8: 1; // user defined
bool BIT_9: 1;
bool BIT_10: 1;
bool BIT_11: 1;
bool BIT_12: 1;
bool INSTR_SUM: 1; // instrument summary
bool PROG_RUN: 1; // program running
bool RESERVED: 1;
};
uint16_t u16;
} SCPI_REG_OPER_t;
typedef union {
struct __attribute__((packed)) {
bool OPC: 1;
bool REQ_CONTROL: 1;
bool QUERY_ERROR: 1;
bool DEV_ERROR: 1;
bool EXE_ERROR: 1;
bool CMD_ERROR: 1;
bool USER_REQUEST: 1;
bool POWER_ON: 1;
};
uint8_t u8;
} SCPI_REG_SESR_t;
typedef union {
struct __attribute__((packed)) {
bool BIT_0: 1;
bool BIT_1: 1;
bool ERRQ: 1; // error queue
bool QUES: 1;
bool MAV: 1; // message available
bool SESR: 1;
bool RQS: 1; // request service
bool OPER: 1;
};
uint8_t u8;
} SCPI_REG_STB_t;
// QUESTionable register
extern SCPI_REG_QUES_t SCPI_REG_QUES;
extern SCPI_REG_QUES_t SCPI_REG_QUES_EN; // picks what to use for the STB bit
// OPERation status register
extern SCPI_REG_OPER_t SCPI_REG_OPER;
extern SCPI_REG_OPER_t SCPI_REG_OPER_EN; // picks what to use for the STB bit
// Standard Event Status register
extern SCPI_REG_SESR_t SCPI_REG_SESR;
extern SCPI_REG_SESR_t SCPI_REG_SESR_EN; // ESE
// Status byte
extern SCPI_REG_STB_t SCPI_REG_STB;
extern SCPI_REG_STB_t SCPI_REG_SRE; // SRE
void scpi_status_update(void);
extern __attribute__((weak)) void scpi_service_request_impl(void);

@ -1,8 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include "scpi_status.h"
struct SCPI_SR_QUEST_struct SCPI_SR_QUEST;
struct SCPI_SR_OPER_struct SCPI_SR_OPER;
struct SCPI_SR_SESR_struct SCPI_SR_SESR;

@ -1,83 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
struct __attribute__((packed)) SCPI_SR_QUEST_struct {
bool VOLT: 1;
bool CURR: 1;
bool TIME: 1;
bool POWER: 1;
bool TEMP: 1;
bool FREQ: 1;
bool PHASE: 1;
bool MODUL: 1;
bool CALIB: 1;
bool BIT_9: 1; // user defined
bool BIT_10: 1;
bool BIT_11: 1;
bool BIT_12: 1;
bool INSTR_SUM: 1; // instrument summary
bool COMMAND_WARNING: 1; // command warning
bool RESERVED: 1;
};
struct __attribute__((packed)) SCPI_SR_OPER_struct {
bool CALIB: 1;
bool SETTING: 1;
bool RANGING: 1;
bool SWEEP: 1;
bool MEAS: 1;
bool WAIT_TRIG: 1; // waiting for trigger
bool WAIT_ARM: 1; // waiting for ARM
bool CORRECTING: 1;
bool BIT_8: 1; // user defined
bool BIT_9: 1;
bool BIT_10: 1;
bool BIT_11: 1;
bool BIT_12: 1;
bool INSTR_SUM: 1; // instrument summary
bool PROG_RUN: 1; // program running
bool RESERVED: 1;
};
struct __attribute__((packed)) SCPI_SR_SESR_struct {
bool OP_COMPLETE: 1;
bool REQ_CONTROL: 1;
bool QUERY_ERROR: 1;
bool DEV_ERROR: 1;
bool EXE_ERROR: 1;
bool CMD_ERROR: 1;
bool USER_REQUEST: 1;
bool POWER_ON: 1;
};
struct __attribute__((packed)) SCPI_SR_STB_struct {
bool BIT_0: 1;
bool BIT_1: 1;
bool ERROR_QUEUE: 1;
bool QUEST: 1;
bool MSG_AVAIL: 1;
bool SESR: 1;
bool RQS: 1; // request service
bool OPER: 1;
};
// QUESTionable register
extern struct SCPI_SR_QUEST_struct SCPI_SR_QUEST;
extern struct SCPI_SR_QUEST_struct SCPI_SR_QUEST_EN; // picks what to use for the STB bit
// OPERation status register
extern struct SCPI_SR_OPER_struct SCPI_SR_OPER;
extern struct SCPI_SR_OPER_struct SCPI_SR_OPER_EN; // picks what to use for the STB bit
// Standard Event Status register
extern struct SCPI_SR_SESR_struct SCPI_SR_SESR;
extern struct SCPI_SR_SESR_struct SCPI_SR_SESR_EN; // ESE
// Status byte
extern struct SCPI_SR_STB_struct SCPI_SR_STB;
extern struct SCPI_SR_STB_struct SCPI_SR_STB_EN; // SRE
Loading…
Cancel
Save