You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
371 lines
9.3 KiB
371 lines
9.3 KiB
/*- |
|
* BSD 2-Clause License |
|
* |
|
* Copyright (c) 2012-2018, Jan Breuer |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are met: |
|
* |
|
* * Redistributions of source code must retain the above copyright notice, this |
|
* list of conditions and the following disclaimer. |
|
* |
|
* * Redistributions in binary form must reproduce the above copyright notice, |
|
* this list of conditions and the following disclaimer in the documentation |
|
* and/or other materials provided with the distribution. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
/** |
|
* @file scpi_ieee488.c |
|
* @date Thu Nov 15 10:58:45 UTC 2012 |
|
* |
|
* @brief Implementation of IEEE488.2 commands and state model |
|
* |
|
* |
|
*/ |
|
|
|
#include "scpi/parser.h" |
|
#include "scpi/ieee488.h" |
|
#include "scpi/error.h" |
|
#include "scpi/constants.h" |
|
|
|
#include <stdio.h> |
|
|
|
/** |
|
* Update register value |
|
* @param context |
|
* @param name - register name |
|
*/ |
|
static void regUpdate(scpi_t * context, scpi_reg_name_t name) { |
|
SCPI_RegSet(context, name, SCPI_RegGet(context, name)); |
|
} |
|
|
|
/** |
|
* Update latching event register value based on bit transitions from 0 -> 1 |
|
* in the condition register |
|
* @param context |
|
* @param condReg - condition register name |
|
* @param eventReg - event register name |
|
*/ |
|
static void regUpdateEvent(scpi_t * context, scpi_reg_val_t oldCondVal, scpi_reg_val_t newCondVal, scpi_reg_name_t eventReg) { |
|
SCPI_RegSet(context, eventReg, ((oldCondVal ^ newCondVal) & newCondVal) | SCPI_RegGet(context, eventReg)); |
|
} |
|
|
|
/** |
|
* Update STB register according to value and its mask register |
|
* @param context |
|
* @param val value of register |
|
* @param mask name of mask register (enable register) |
|
* @param stbBits bits to clear or set in STB |
|
*/ |
|
static void regUpdateSTB(scpi_t * context, scpi_reg_val_t val, scpi_reg_name_t mask, scpi_reg_val_t stbBits) { |
|
if (val & SCPI_RegGet(context, mask)) { |
|
SCPI_RegSetBits(context, SCPI_REG_STB, stbBits); |
|
} else { |
|
SCPI_RegClearBits(context, SCPI_REG_STB, stbBits); |
|
} |
|
} |
|
|
|
/** |
|
* Get register value |
|
* @param name - register name |
|
* @return register value |
|
*/ |
|
scpi_reg_val_t SCPI_RegGet(scpi_t * context, scpi_reg_name_t name) { |
|
if ((name < SCPI_REG_COUNT) && context) { |
|
return context->registers[name]; |
|
} else { |
|
return 0; |
|
} |
|
} |
|
|
|
/** |
|
* Wrapper function to control interface from context |
|
* @param context |
|
* @param ctrl number of controll message |
|
* @param value value of related register |
|
*/ |
|
static size_t writeControl(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) { |
|
if (context && context->interface && context->interface->control) { |
|
return context->interface->control(context, ctrl, val); |
|
} else { |
|
return 0; |
|
} |
|
} |
|
|
|
/** |
|
* Set register value |
|
* @param name - register name |
|
* @param val - new value |
|
*/ |
|
void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val) { |
|
scpi_bool_t srq = FALSE; |
|
scpi_reg_val_t mask; |
|
scpi_reg_val_t old_val; |
|
|
|
if ((name >= SCPI_REG_COUNT) || (context == NULL)) { |
|
return; |
|
} |
|
|
|
/* store old register value */ |
|
old_val = context->registers[name]; |
|
|
|
/* set register value */ |
|
context->registers[name] = val; |
|
|
|
/** @TODO: remove recutsion */ |
|
switch (name) { |
|
case SCPI_REG_STB: |
|
mask = SCPI_RegGet(context, SCPI_REG_SRE); |
|
mask &= ~STB_SRQ; |
|
if (val & mask) { |
|
val |= STB_SRQ; |
|
/* avoid sending SRQ if nothing has changed */ |
|
if (old_val != val) { |
|
srq = TRUE; |
|
} |
|
} else { |
|
val &= ~STB_SRQ; |
|
} |
|
break; |
|
case SCPI_REG_SRE: |
|
regUpdate(context, SCPI_REG_STB); |
|
break; |
|
case SCPI_REG_ESR: |
|
regUpdateSTB(context, val, SCPI_REG_ESE, STB_ESR); |
|
break; |
|
case SCPI_REG_ESE: |
|
regUpdate(context, SCPI_REG_ESR); |
|
break; |
|
case SCPI_REG_QUES: |
|
regUpdateSTB(context, val, SCPI_REG_QUESE, STB_QES); |
|
break; |
|
case SCPI_REG_QUESE: |
|
regUpdate(context, SCPI_REG_QUES); |
|
break; |
|
case SCPI_REG_QUESC: |
|
regUpdateEvent(context, old_val, val, SCPI_REG_QUES); |
|
break; |
|
case SCPI_REG_OPER: |
|
regUpdateSTB(context, val, SCPI_REG_OPERE, STB_OPS); |
|
break; |
|
case SCPI_REG_OPERE: |
|
regUpdate(context, SCPI_REG_OPER); |
|
break; |
|
case SCPI_REG_OPERC: |
|
regUpdateEvent(context, old_val, val, SCPI_REG_OPER); |
|
break; |
|
|
|
|
|
case SCPI_REG_COUNT: |
|
/* nothing to do */ |
|
break; |
|
} |
|
|
|
/* set updated register value */ |
|
context->registers[name] = val; |
|
|
|
if (srq) { |
|
writeControl(context, SCPI_CTRL_SRQ, SCPI_RegGet(context, SCPI_REG_STB)); |
|
} |
|
} |
|
|
|
/** |
|
* Set register bits |
|
* @param name - register name |
|
* @param bits bit mask |
|
*/ |
|
void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits) { |
|
SCPI_RegSet(context, name, SCPI_RegGet(context, name) | bits); |
|
} |
|
|
|
/** |
|
* Clear register bits |
|
* @param name - register name |
|
* @param bits bit mask |
|
*/ |
|
void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits) { |
|
SCPI_RegSet(context, name, SCPI_RegGet(context, name) & ~bits); |
|
} |
|
|
|
/** |
|
* Clear event register |
|
* @param context |
|
*/ |
|
void SCPI_EventClear(scpi_t * context) { |
|
/* TODO */ |
|
SCPI_RegSet(context, SCPI_REG_ESR, 0); |
|
} |
|
|
|
/** |
|
* *CLS - This command clears all status data structures in a device. |
|
* For a device which minimally complies with SCPI. (SCPI std 4.1.3.2) |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreCls(scpi_t * context) { |
|
SCPI_EventClear(context); |
|
SCPI_ErrorClear(context); |
|
SCPI_RegSet(context, SCPI_REG_OPER, 0); |
|
SCPI_RegSet(context, SCPI_REG_QUES, 0); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *ESE |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreEse(scpi_t * context) { |
|
int32_t new_ESE; |
|
if (SCPI_ParamInt32(context, &new_ESE, TRUE)) { |
|
SCPI_RegSet(context, SCPI_REG_ESE, (scpi_reg_val_t) new_ESE); |
|
return SCPI_RES_OK; |
|
} |
|
return SCPI_RES_ERR; |
|
} |
|
|
|
/** |
|
* *ESE? |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreEseQ(scpi_t * context) { |
|
SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_ESE)); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *ESR? |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreEsrQ(scpi_t * context) { |
|
SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_ESR)); |
|
SCPI_RegSet(context, SCPI_REG_ESR, 0); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *IDN? |
|
* |
|
* field1: MANUFACTURE |
|
* field2: MODEL |
|
* field4: SUBSYSTEMS REVISIONS |
|
* |
|
* example: MANUFACTURE,MODEL,0,01-02-01 |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreIdnQ(scpi_t * context) { |
|
int i; |
|
for (i = 0; i < 4; i++) { |
|
if (context->idn[i]) { |
|
SCPI_ResultMnemonic(context, context->idn[i]); |
|
} else { |
|
SCPI_ResultMnemonic(context, "0"); |
|
} |
|
} |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *OPC |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreOpc(scpi_t * context) { |
|
SCPI_RegSetBits(context, SCPI_REG_ESR, ESR_OPC); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *OPC? |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreOpcQ(scpi_t * context) { |
|
/* Operation is always completed */ |
|
SCPI_ResultInt32(context, 1); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *RST |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreRst(scpi_t * context) { |
|
if (context && context->interface && context->interface->reset) { |
|
return context->interface->reset(context); |
|
} |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *SRE |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreSre(scpi_t * context) { |
|
int32_t new_SRE; |
|
if (SCPI_ParamInt32(context, &new_SRE, TRUE)) { |
|
SCPI_RegSet(context, SCPI_REG_SRE, (scpi_reg_val_t) new_SRE); |
|
return SCPI_RES_OK; |
|
} |
|
return SCPI_RES_ERR; |
|
} |
|
|
|
/** |
|
* *SRE? |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreSreQ(scpi_t * context) { |
|
SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_SRE)); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *STB? |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreStbQ(scpi_t * context) { |
|
SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_STB)); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *TST? |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreTstQ(scpi_t * context) { |
|
(void) context; |
|
SCPI_ResultInt32(context, 0); |
|
return SCPI_RES_OK; |
|
} |
|
|
|
/** |
|
* *WAI |
|
* @param context |
|
* @return |
|
*/ |
|
scpi_result_t SCPI_CoreWai(scpi_t * context) { |
|
(void) context; |
|
/* NOP */ |
|
return SCPI_RES_OK; |
|
} |
|
|
|
|