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
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
./main.elf

@ -2,13 +2,6 @@
#include <string.h>
#include <stdlib.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)
@ -61,11 +54,6 @@ void cmd_STQE_cb(const SCPI_argval_t *args)
}
const SCPI_command_t scpi_commands[] = {
{
.levels = {"*IDN?"},
.params = {},
.callback = cmd_aIDNq_cb
},
{
.levels = {"APPLy", "SINe"},
.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()
{
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 = "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 = "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++) {
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);

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

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<data>
<variable>EnvironmentId</variable>

@ -84,6 +84,8 @@ static struct {
// buffer for error messages
static char ebuf[256];
// response buffer
static char sbuf[256];
// ---------------- PRIVATE PROTOTYPES ------------------
@ -121,23 +123,188 @@ static void pars_reset_cmd_keeplevel(void);
// ---------------- 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[] = {
// ---- 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"},
.params = {},
.callback = builtin_cb_FOO
.levels = {"*SRE"},
.params = {SCPI_DT_INT},
.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
};
// ------------------- 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 ---------------------
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) {
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) {
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;
}
static void err_no_such_command()
{
char *b = ebuf;

@ -1,9 +1,10 @@
#pragma once
#include "scpi_errors.h"
#include <stdint.h>
#include <stdbool.h>
#include "scpi_errors.h"
#include "scpi_regs.h"
#define SCPI_MAX_CMD_LEN 12
#define SCPI_MAX_STRING_LEN 12
#define SCPI_MAX_LEVEL_COUNT 4
@ -55,10 +56,27 @@ typedef struct {
void (*blob_callback)(const uint8_t *bytes);
} SCPI_command_t;
// ---------------- USER CONFIG ----------------
// Zero terminated command struct array - must be defined.
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 --------------------
@ -84,3 +102,10 @@ void scpi_read_error(char *buf);
/** Discard the rest of the currently processed blob */
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