scpi-parser, adopted from github

Dependents:   scpi_parser_test

Files at this revision

API Documentation at this revision

Comitter:
iesensor
Date:
Fri Nov 14 01:07:59 2014 +0000
Commit message:
tested on K64F

Changed in this revision

common/scpi-def.cpp Show annotated file Show diff for this revision Revisions of this file
common/scpi-def.h Show annotated file Show diff for this revision Revisions of this file
libscpi/debug.c Show annotated file Show diff for this revision Revisions of this file
libscpi/error.c Show annotated file Show diff for this revision Revisions of this file
libscpi/fifo.c Show annotated file Show diff for this revision Revisions of this file
libscpi/ieee488.c Show annotated file Show diff for this revision Revisions of this file
libscpi/minimal.c Show annotated file Show diff for this revision Revisions of this file
libscpi/parser.c Show annotated file Show diff for this revision Revisions of this file
libscpi/units.c Show annotated file Show diff for this revision Revisions of this file
libscpi/utils.c Show annotated file Show diff for this revision Revisions of this file
scpi/config.h Show annotated file Show diff for this revision Revisions of this file
scpi/constants.h Show annotated file Show diff for this revision Revisions of this file
scpi/debug.h Show annotated file Show diff for this revision Revisions of this file
scpi/error.h Show annotated file Show diff for this revision Revisions of this file
scpi/fifo.h Show annotated file Show diff for this revision Revisions of this file
scpi/ieee488.h Show annotated file Show diff for this revision Revisions of this file
scpi/minimal.h Show annotated file Show diff for this revision Revisions of this file
scpi/parser.h Show annotated file Show diff for this revision Revisions of this file
scpi/scpi.h Show annotated file Show diff for this revision Revisions of this file
scpi/types.h Show annotated file Show diff for this revision Revisions of this file
scpi/units.h Show annotated file Show diff for this revision Revisions of this file
scpi/utils_private.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/scpi-def.cpp	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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-def.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI parser test
+ * 
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "scpi/scpi.h"
+#include "scpi-def.h"
+
+scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) {
+    scpi_number_t param1, param2;
+    char bf[15];
+    fprintf(stderr, "meas:volt:dc\r\n"); // debug command name   
+
+    // read first parameter if present
+    if (!SCPI_ParamNumber(context, &param1, false)) {
+        // do something, if parameter not present
+    }
+
+    // read second paraeter if present
+    if (!SCPI_ParamNumber(context, &param2, false)) {
+        // do something, if parameter not present
+    }
+
+    
+    SCPI_NumberToStr(context, &param1, bf, 15);
+    fprintf(stderr, "\tP1=%s\r\n", bf);
+
+    
+    SCPI_NumberToStr(context, &param2, bf, 15);
+    fprintf(stderr, "\tP2=%s\r\n", bf);
+
+    SCPI_ResultDouble(context, 0);
+    
+    return SCPI_RES_OK;
+}
+
+
+scpi_result_t DMM_ConfigureVoltageDc(scpi_t * context) {
+    double param1, param2;
+    fprintf(stderr, "conf:volt:dc\r\n"); // debug command name   
+
+    // read first parameter if present
+    if (!SCPI_ParamDouble(context, &param1, true)) {
+        return SCPI_RES_ERR;
+    }
+
+    // read second paraeter if present
+    if (!SCPI_ParamDouble(context, &param2, false)) {
+        // do something, if parameter not present
+    }
+
+    fprintf(stderr, "\tP1=%lf\r\n", param1);
+    fprintf(stderr, "\tP2=%lf\r\n", param2);
+
+    return SCPI_RES_OK;
+}
+
+static const scpi_command_t scpi_commands[] = {
+    /* {"pattern", callback} *
+    
+    /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */
+    {"*CLS", SCPI_CoreCls,},
+    {"*ESE", SCPI_CoreEse,},
+    {"*ESE?", SCPI_CoreEseQ,},
+    {"*ESR?", SCPI_CoreEsrQ,},
+    {"*IDN?", SCPI_CoreIdnQ,},
+    {"*OPC", SCPI_CoreOpc,},
+    {"*OPC?", SCPI_CoreOpcQ,},
+    {"*RST", SCPI_CoreRst,},
+    {"*SRE", SCPI_CoreSre,},
+    {"*SRE?", SCPI_CoreSreQ,},
+    {"*STB?", SCPI_CoreStbQ,},
+    {"*TST?", SCPI_CoreTstQ,},
+    {"*WAI", SCPI_CoreWai,},
+
+    /* Required SCPI commands (SCPI std V1999.0 4.2.1) */
+    {"SYSTem:ERRor?", SCPI_SystemErrorNextQ,},
+    {"SYSTem:ERRor:NEXT?", SCPI_SystemErrorNextQ,},
+    {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ,},
+    {"SYSTem:VERSion?", SCPI_SystemVersionQ,},
+
+    //{"STATus:OPERation?", scpi_stub_callback,},
+    //{"STATus:OPERation:EVENt?", scpi_stub_callback,},
+    //{"STATus:OPERation:CONDition?", scpi_stub_callback,},
+    //{"STATus:OPERation:ENABle", scpi_stub_callback,},
+    //{"STATus:OPERation:ENABle?", scpi_stub_callback,},
+
+    {"STATus:QUEStionable?", SCPI_StatusQuestionableEventQ,},
+    {"STATus:QUEStionable:EVENt?", SCPI_StatusQuestionableEventQ,},
+    //{"STATus:QUEStionable:CONDition?", scpi_stub_callback,},
+    {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable,},
+    {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ,},
+
+    {"STATus:PRESet", SCPI_StatusPreset,},
+
+    /* DMM */
+    {"MEASure:VOLTage:DC?", DMM_MeasureVoltageDcQ,},
+    {"CONFigure:VOLTage:DC", DMM_ConfigureVoltageDc,},
+    {"MEASure:VOLTage:DC:RATio?", SCPI_StubQ,},
+    {"MEASure:VOLTage:AC?", SCPI_StubQ,},
+    {"MEASure:CURRent:DC?", SCPI_StubQ,},
+    {"MEASure:CURRent:AC?", SCPI_StubQ,},
+    {"MEASure:RESistance?", SCPI_StubQ,},
+    {"MEASure:FRESistance?", SCPI_StubQ,},
+    {"MEASure:FREQuency?", SCPI_StubQ,},
+    {"MEASure:PERiod?", SCPI_StubQ,},
+    
+    {"SYSTem:COMMunication:TCPIP:CONTROL?", SCPI_SystemCommTcpipControlQ,},
+
+    SCPI_CMD_LIST_END
+};
+
+static scpi_interface_t scpi_interface = {
+    /* error */ SCPI_Error,
+    /* write */ SCPI_Write,
+    /* control */ SCPI_Control,
+    /* flush */ SCPI_Flush,
+    /* reset */ SCPI_Reset,
+    /* test */ SCPI_Test,
+};
+
+#define SCPI_INPUT_BUFFER_LENGTH 256
+static char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH];
+
+static scpi_reg_val_t scpi_regs[SCPI_REG_COUNT];
+
+
+scpi_t scpi_context = {
+    /* cmdlist */ scpi_commands,
+    /* buffer */ { /* length */ SCPI_INPUT_BUFFER_LENGTH, /* position */ 0,  /* data */ scpi_input_buffer, },
+    /* paramlist */ { /* cmd */ NULL, /* parameters */ NULL, /* length */ 0, },
+    /* interface */ &scpi_interface,
+    /* output_count */ 0,
+    /* input_count */ 0,
+    /* cmd_error */ FALSE,
+    /* error_queue */ NULL,
+    /* registers */ scpi_regs,
+    /* units */ scpi_units_def,
+    /* special_numbers */ scpi_special_numbers_def,
+    /* user_context */ NULL,
+    /* idn */ {"MANUFACTURE", "INSTR2013", NULL, "01-02"},
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/scpi-def.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,27 @@
+#ifndef __SCPI_DEF_H_
+#define __SCPI_DEF_H_
+
+#include "scpi/scpi.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+extern scpi_t scpi_context;
+
+size_t SCPI_Write(scpi_t * context, const char * data, size_t len);
+int SCPI_Error(scpi_t * context, int_fast16_t err);
+scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val);
+scpi_result_t SCPI_Reset(scpi_t * context);
+scpi_result_t SCPI_Test(scpi_t * context);
+scpi_result_t SCPI_Flush(scpi_t * context);
+
+
+scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif // __SCPI_DEF_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/debug.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_debug.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  Debugging SCPI
+ * 
+ * 
+ */
+
+#include <stdio.h>
+#include "scpi/debug.h"
+
+/**
+ * Debug function: show current command and its parameters
+ * @param context
+ * @return 
+ */
+scpi_bool_t SCPI_DebugCommand(scpi_t * context) {
+	size_t res;
+	printf("**DEBUG: %s (\"", context->paramlist.cmd->pattern);
+	res = fwrite(context->paramlist.parameters, 1, context->paramlist.length, stdout);
+	(void)res;
+        printf("\" - %lu\r\n", (unsigned long)context->paramlist.length);
+	
+	return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/error.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_error.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  Error handling and storing routines
+ * 
+ * 
+ */
+
+#include <stdint.h>
+
+#include "scpi/parser.h"
+#include "scpi/ieee488.h"
+#include "scpi/error.h"
+#include "scpi/fifo.h"
+
+/* basic FIFO */
+static fifo_t local_error_queue;
+
+
+
+void SCPI_ErrorInit(scpi_t * context) {
+    /*
+     * // FreeRTOS
+     * context->error_queue = (scpi_error_queue_t)xQueueCreate(100, sizeof(int16_t));
+     */
+
+    /* basic FIFO */
+    context->error_queue = (scpi_error_queue_t)&local_error_queue;
+    fifo_init((fifo_t *)context->error_queue);
+}
+
+/**
+ * Clear error queue
+ * @param context - scpi context
+ */
+void SCPI_ErrorClear(scpi_t * context) {
+    /*
+     * // FreeRTOS
+     * xQueueReset((xQueueHandle)context->error_queue);
+     */
+
+    /* basic FIFO */
+    fifo_clear((fifo_t *)context->error_queue);
+}
+
+/**
+ * Pop error from queue
+ * @param context - scpi context
+ * @return error number
+ */
+int16_t SCPI_ErrorPop(scpi_t * context) {
+    int16_t result = 0;
+
+    /*
+     * // FreeRTOS
+     * if (pdFALSE == xQueueReceive((xQueueHandle)context->error_queue, &result, 0)) {
+     *   result = 0;
+     * }
+     */
+
+    /* basic FIFO */
+    fifo_remove((fifo_t *)context->error_queue, &result);
+
+    return result;
+}
+
+/**
+ * Return number of errors/events in the queue
+ * @param context
+ * @return 
+ */
+int32_t SCPI_ErrorCount(scpi_t * context) {
+    int16_t result = 0;
+
+    /*
+     * // FreeRTOS
+     * result = uxQueueMessagesWaiting((xQueueHandle)context->error_queue);
+     */
+
+    /* basic FIFO */
+    fifo_count((fifo_t *)context->error_queue, &result);
+
+    return result;
+}
+
+static void SCPI_ErrorAddInternal(scpi_t * context, int16_t err) {
+    /*
+     * // FreeRTOS
+     * xQueueSend((xQueueHandle)context->error_queue, &err, 0);
+     */
+
+    /* basic FIFO */
+    fifo_add((fifo_t *)context->error_queue, err);
+}
+
+struct error_reg {
+    int16_t from;
+    int16_t to;
+    scpi_reg_val_t bit;
+};
+
+#define ERROR_DEFS_N	8
+
+static const struct error_reg errs[ERROR_DEFS_N] = {
+    {-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9    */
+    {-200, -299, ESR_EER}, /* Execution Error (e.g. range error) ch 21.8.10  */
+    {-300, -399, ESR_DER}, /* Device specific error -300, -399 ch 21.8.11    */
+    {-400, -499, ESR_QER}, /* Query error -400, -499 ch 21.8.12              */
+    {-500, -599, ESR_PON}, /* Power on event -500, -599 ch 21.8.13           */
+    {-600, -699, ESR_URQ}, /* User Request Event -600, -699 ch 21.8.14       */
+    {-700, -799, ESR_REQ}, /* Request Control Event -700, -799 ch 21.8.15    */
+    {-800, -899, ESR_OPC}, /* Operation Complete Event -800, -899 ch 21.8.16 */
+};
+
+/**
+ * Push error to queue
+ * @param context - scpi context
+ * @param err - error number
+ */
+void SCPI_ErrorPush(scpi_t * context, int16_t err) {
+
+    int i;
+
+    SCPI_ErrorAddInternal(context, err);
+
+    for(i = 0; i < ERROR_DEFS_N; i++) {
+        if ((err <= errs[i].from) && (err >= errs[i].to)) {
+            SCPI_RegSetBits(context, SCPI_REG_ESR, errs[i].bit);
+        }
+    }
+
+    if (context) {
+        if (context->interface && context->interface->error) {
+            context->interface->error(context, err);
+        }
+
+        context->cmd_error = TRUE;
+    }
+}
+
+/**
+ * Translate error number to string
+ * @param err - error number
+ * @return Error string representation
+ */
+const char * SCPI_ErrorTranslate(int16_t err) {
+    switch (err) {
+        case 0: return "No error";
+        #define X(def, val, str) case def: return str;
+        LIST_OF_ERRORS
+        #undef X        
+        default: return "Unknown error";
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/fifo.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,48 @@
+
+#include "scpi/fifo.h"
+
+void fifo_init(fifo_t * fifo) {
+    fifo->wr = 0;
+    fifo->rd = 0;
+    fifo->size = FIFO_SIZE;
+}
+
+void fifo_clear(fifo_t * fifo) {
+    fifo->wr = 0;
+    fifo->rd = 0;
+}
+
+scpi_bool_t fifo_add(fifo_t * fifo, int16_t value) {
+    /* FIFO full? */
+    if (fifo->wr == ((fifo->rd + fifo->size) % (fifo->size + 1))) {
+        fifo_remove(fifo, NULL);
+    }
+
+    fifo->data[fifo->wr] = value;
+    fifo->wr = (fifo->wr + 1) % (fifo->size + 1);
+
+    return TRUE;
+}
+
+scpi_bool_t fifo_remove(fifo_t * fifo, int16_t * value) {
+    /* FIFO empty? */
+    if (fifo->wr == fifo->rd) {
+        return FALSE;
+    }
+
+    if(value) {
+        *value = fifo->data[fifo->rd];
+    }
+
+    fifo->rd = (fifo->rd + 1) % (fifo->size + 1);
+
+    return TRUE;
+}
+
+scpi_bool_t fifo_count(fifo_t * fifo, int16_t * value) {
+    *value = fifo->wr - fifo->rd;
+    if (*value < 0) {
+        *value += (fifo->size + 1);
+    }
+    return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/ieee488.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,350 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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 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->registers != NULL)) {
+        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->registers == 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_OPER:
+            regUpdateSTB(context, val, SCPI_REG_OPERE, STB_OPS);
+            break;
+        case SCPI_REG_OPERE:
+            regUpdate(context, 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_ParamInt(context, &new_ESE, TRUE)) {
+        SCPI_RegSet(context, SCPI_REG_ESE, new_ESE);
+    }
+    return SCPI_RES_OK;
+}
+
+/**
+ * *ESE?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_CoreEseQ(scpi_t * context) {
+    SCPI_ResultInt(context, SCPI_RegGet(context, SCPI_REG_ESE));
+    return SCPI_RES_OK;
+}
+
+/**
+ * *ESR?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_CoreEsrQ(scpi_t * context) {
+    SCPI_ResultInt(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) {
+    SCPI_ResultString(context, context->idn[0]);
+    SCPI_ResultString(context, context->idn[1]);
+    SCPI_ResultString(context, context->idn[2]);
+    SCPI_ResultString(context, context->idn[3]);
+    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_ResultInt(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_ParamInt(context, &new_SRE, TRUE)) {
+        SCPI_RegSet(context, SCPI_REG_SRE, new_SRE);
+    }
+    return SCPI_RES_OK;
+}
+
+/**
+ * *SRE?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_CoreSreQ(scpi_t * context) {
+    SCPI_ResultInt(context, SCPI_RegGet(context, SCPI_REG_SRE));
+    return SCPI_RES_OK;
+}
+
+/**
+ * *STB?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_CoreStbQ(scpi_t * context) {
+    SCPI_ResultInt(context, SCPI_RegGet(context, SCPI_REG_STB));
+    return SCPI_RES_OK;
+}
+
+/**
+ * *TST?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_CoreTstQ(scpi_t * context) {
+    int result = 0;
+    if (context && context->interface && context->interface->test) {
+        result = context->interface->test(context);
+    }
+    SCPI_ResultInt(context, result);
+    return SCPI_RES_OK;
+}
+
+/**
+ * *WAI
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_CoreWai(scpi_t * context) {
+    (void) context;
+    /* NOP */
+    return SCPI_RES_OK;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/minimal.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_minimal.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI minimal implementation
+ * 
+ * 
+ */
+
+
+#include "scpi/parser.h"
+#include "scpi/minimal.h"
+#include "scpi/constants.h"
+#include "scpi/error.h"
+#include "scpi/ieee488.h"
+
+/**
+ * Command stub function
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_Stub(scpi_t * context) {
+    (void) context;
+    return SCPI_RES_OK;
+}
+
+/**
+ * Query command stub function
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_StubQ(scpi_t * context) {
+    SCPI_ResultString(context, "");
+    return SCPI_RES_OK;
+}
+
+/**
+ * SYSTem:VERSion?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_SystemVersionQ(scpi_t * context) {
+    SCPI_ResultString(context, SCPI_STD_VERSION_REVISION);
+    return SCPI_RES_OK;
+}
+
+/**
+ * SYSTem:ERRor[:NEXT]?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context) {
+    int16_t err = SCPI_ErrorPop(context);
+
+    SCPI_ResultInt(context, err);
+    SCPI_ResultText(context, SCPI_ErrorTranslate(err));
+
+    return SCPI_RES_OK;
+}
+
+/**
+ * SYSTem:ERRor:COUNt?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context) {
+    SCPI_ResultInt(context, SCPI_ErrorCount(context));
+
+    return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable[:EVENt]?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context) {
+    /* return value */
+    SCPI_ResultInt(context, SCPI_RegGet(context, SCPI_REG_QUES));
+
+    /* clear register */
+    SCPI_RegSet(context, SCPI_REG_QUES, 0);
+
+    return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable:ENABle?
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context) {
+    /* return value */
+    SCPI_ResultInt(context, SCPI_RegGet(context, SCPI_REG_QUESE));
+
+    return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable:ENABle
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context) {
+    int32_t new_QUESE;
+    if (SCPI_ParamInt(context, &new_QUESE, TRUE)) {
+        SCPI_RegSet(context, SCPI_REG_QUESE, new_QUESE);
+    }
+    return SCPI_RES_OK;
+}
+
+/**
+ * STATus:PRESet
+ * @param context
+ * @return 
+ */
+scpi_result_t SCPI_StatusPreset(scpi_t * context) {
+    /* clear STATUS:... */
+    SCPI_RegSet(context, SCPI_REG_QUES, 0);
+    return SCPI_RES_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/parser.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,677 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_parser.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI parser implementation
+ * 
+ * 
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "scpi/config.h"
+#include "scpi/parser.h"
+#include "scpi/utils_private.h"
+#include "scpi/error.h"
+#include "scpi/constants.h"
+
+
+static size_t cmdTerminatorPos(const char * cmd, size_t len);
+static size_t cmdlineSeparatorPos(const char * cmd, size_t len);
+static const char * cmdlineSeparator(const char * cmd, size_t len);
+static const char * cmdlineTerminator(const char * cmd, size_t len);
+static size_t skipCmdLine(const char * cmd, size_t len);
+
+static void paramSkipBytes(scpi_t * context, size_t num);
+static void paramSkipWhitespace(scpi_t * context);
+static scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory);
+
+/*
+int _strnicmp(const char* s1, const char* s2, size_t len) {
+    int result = 0;
+    int i;
+
+    for (i = 0; i < len && s1[i] && s2[i]; i++) {
+        char c1 = tolower(s1[i]);
+        char c2 = tolower(s2[i]);
+        if (c1 != c2) {
+            result = (int) c1 - (int) c2;
+            break;
+        }
+    }
+
+    return result;
+}
+ */
+
+/**
+ * Find command termination character
+ * @param cmd - input command
+ * @param len - max search length
+ * @return position of terminator or len
+ */
+size_t cmdTerminatorPos(const char * cmd, size_t len) {
+    const char * terminator = strnpbrk(cmd, len, "; \r\n\t");
+    if (terminator == NULL) {
+        return len;
+    } else {
+        return terminator - cmd;
+    }
+}
+
+/**
+ * Find command line separator
+ * @param cmd - input command
+ * @param len - max search length
+ * @return pointer to line separator or NULL
+ */
+const char * cmdlineSeparator(const char * cmd, size_t len) {
+    return strnpbrk(cmd, len, ";\r\n");
+}
+
+/**
+ * Find command line terminator
+ * @param cmd - input command
+ * @param len - max search length
+ * @return pointer to command line terminator or NULL
+ */
+const char * cmdlineTerminator(const char * cmd, size_t len) {
+    return strnpbrk(cmd, len, "\r\n");
+}
+
+/**
+ * Find command line separator position
+ * @param cmd - input command
+ * @param len - max search length
+ * @return position of line separator or len
+ */
+size_t cmdlineSeparatorPos(const char * cmd, size_t len) {
+    const char * separator = cmdlineSeparator(cmd, len);
+    if (separator == NULL) {
+        return len;
+    } else {
+        return separator - cmd;
+    }
+}
+
+/**
+ * Find next part of command
+ * @param cmd - input command
+ * @param len - max search length
+ * @return number of characters to be skipped
+ */
+size_t skipCmdLine(const char * cmd, size_t len) {
+    const char * separator = cmdlineSeparator(cmd, len);
+    if (separator == NULL) {
+        return len;
+    } else {
+        return separator + 1 - cmd;
+    }
+}
+
+/**
+ * Write data to SCPI output
+ * @param context
+ * @param data
+ * @param len - lenght of data to be written
+ * @return number of bytes written
+ */
+static size_t writeData(scpi_t * context, const char * data, size_t len) {
+    return context->interface->write(context, data, len);
+}
+
+/**
+ * Flush data to SCPI output
+ * @param context
+ * @return
+ */
+static int flushData(scpi_t * context) {
+    if (context && context->interface && context->interface->flush) {
+        return context->interface->flush(context);
+    } else {
+        return SCPI_RES_OK;
+    }
+}
+
+/**
+ * Write result delimiter to output
+ * @param context
+ * @return number of bytes written
+ */
+static size_t writeDelimiter(scpi_t * context) {
+    if (context->output_count > 0) {
+        return writeData(context, ", ", 2);
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * Conditionaly write "New Line"
+ * @param context
+ * @return number of characters written
+ */
+static size_t writeNewLine(scpi_t * context) {
+    if (context->output_count > 0) {
+        size_t len;
+        len = writeData(context, "\r\n", 2);
+        flushData(context);
+        return len;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * Process command
+ * @param context
+ */
+static void processCommand(scpi_t * context) {
+    const scpi_command_t * cmd = context->paramlist.cmd;
+
+    context->cmd_error = FALSE;
+    context->output_count = 0;
+    context->input_count = 0;
+
+    SCPI_DEBUG_COMMAND(context);
+    /* if callback exists - call command callback */
+    if (cmd->callback != NULL) {
+        if ((cmd->callback(context) != SCPI_RES_OK) && !context->cmd_error) {
+            SCPI_ErrorPush(context, SCPI_ERROR_EXECUTION_ERROR);
+        }
+    }
+
+    /* conditionaly write new line */
+    writeNewLine(context);
+
+    /* skip all whitespaces */
+    paramSkipWhitespace(context);
+
+    /* set error if command callback did not read all parameters */
+    if (context->paramlist.length != 0 && !context->cmd_error) {
+        SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED);
+    }
+}
+
+/**
+ * Cycle all patterns and search matching pattern. Execute command callback.
+ * @param context
+ * @result TRUE if context->paramlist is filled with correct values
+ */
+static scpi_bool_t findCommand(scpi_t * context, const char * cmdline_ptr, size_t cmdline_len, size_t cmd_len) {
+    int32_t i;
+    const scpi_command_t * cmd;
+
+    for (i = 0; context->cmdlist[i].pattern != NULL; i++) {
+        cmd = &context->cmdlist[i];
+        if (matchCommand(cmd->pattern, cmdline_ptr, cmd_len)) {
+            context->paramlist.cmd = cmd;
+            context->paramlist.parameters = cmdline_ptr + cmd_len;
+            context->paramlist.length = cmdline_len - cmd_len;
+            context->paramlist.cmd_raw.data = cmdline_ptr;
+            context->paramlist.cmd_raw.length = cmd_len;
+            context->paramlist.cmd_raw.position = 0;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/**
+ * Parse one command line
+ * @param context
+ * @param data - complete command line
+ * @param len - command line length
+ * @return 1 if the last evaluated command was found
+ */
+int SCPI_Parse(scpi_t * context, char * data, size_t len) {
+    int result = 0;
+    const char * cmdline_end = data + len;
+    char * cmdline_ptr = data;
+    size_t cmd_len;
+    size_t cmdline_len;
+    char * cmdline_ptr_prev = NULL;
+    size_t cmd_len_prev = 0;
+
+    if (context == NULL) {
+        return -1;
+    }
+
+    while (cmdline_ptr < cmdline_end) {
+        result = 0;
+        cmd_len = cmdTerminatorPos(cmdline_ptr, cmdline_end - cmdline_ptr);
+        if (cmd_len > 0) {
+            composeCompoundCommand(cmdline_ptr_prev, cmd_len_prev,
+                                    &cmdline_ptr, &cmd_len);
+            cmdline_len = cmdlineSeparatorPos(cmdline_ptr, cmdline_end - cmdline_ptr);
+            if(findCommand(context, cmdline_ptr, cmdline_len, cmd_len)) {
+                processCommand(context);
+                result = 1;
+                cmdline_ptr_prev = cmdline_ptr;
+                cmd_len_prev = cmd_len;
+            } else {
+                SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER);
+            }
+        }
+        cmdline_ptr += skipCmdLine(cmdline_ptr, cmdline_end - cmdline_ptr);
+        cmdline_ptr += skipWhitespace(cmdline_ptr, cmdline_end - cmdline_ptr);
+    }
+    return result;
+}
+
+/**
+ * Initialize SCPI context structure
+ * @param context
+ * @param command_list
+ * @param buffer
+ * @param interface
+ */
+void SCPI_Init(scpi_t * context) {
+    if (context->idn[0] == NULL) {
+        context->idn[0] = SCPI_DEFAULT_1_MANUFACTURE;
+    }
+    if (context->idn[1] == NULL) {
+        context->idn[1] = SCPI_DEFAULT_2_MODEL;
+    }
+    if (context->idn[2] == NULL) {
+        context->idn[2] = SCPI_DEFAULT_3;
+    }
+    if (context->idn[3] == NULL) {
+        context->idn[3] = SCPI_DEFAULT_4_REVISION;
+    }
+    
+    context->buffer.position = 0;
+    SCPI_ErrorInit(context);
+}
+
+/**
+ * Interface to the application. Adds data to system buffer and try to search
+ * command line termination. If the termination is found or if len=0, command
+ * parser is called.
+ * 
+ * @param context
+ * @param data - data to process
+ * @param len - length of data
+ * @return 
+ */
+int SCPI_Input(scpi_t * context, const char * data, size_t len) {
+    int result = 0;
+    const char * cmd_term;
+    if (len == 0) {
+        context->buffer.data[context->buffer.position] = 0;
+        result = SCPI_Parse(context, context->buffer.data, context->buffer.position);
+        context->buffer.position = 0;
+    } else {
+        size_t buffer_free;
+        int ws;
+        buffer_free = context->buffer.length - context->buffer.position;
+        if (len > (buffer_free - 1)) {
+            return -1;
+        }
+        memcpy(&context->buffer.data[context->buffer.position], data, len);
+        context->buffer.position += len;
+        context->buffer.data[context->buffer.position] = 0;
+
+        ws = skipWhitespace(context->buffer.data, context->buffer.position);
+        cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws);
+        while (cmd_term != NULL) {
+            int curr_len = cmd_term - context->buffer.data;
+            result = SCPI_Parse(context, context->buffer.data + ws, curr_len - ws);
+            memmove(context->buffer.data, cmd_term, context->buffer.position - curr_len);
+            context->buffer.position -= curr_len;
+    
+            ws = skipWhitespace(context->buffer.data, context->buffer.position);
+            cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws);
+        }
+    }
+
+    return result;
+}
+
+/* writing results */
+
+/**
+ * Write raw string result to the output
+ * @param context
+ * @param data
+ * @return 
+ */
+size_t SCPI_ResultString(scpi_t * context, const char * data) {
+    size_t len = strlen(data);
+    size_t result = 0;
+    result += writeDelimiter(context);
+    result += writeData(context, data, len);
+    context->output_count++;
+    return result;
+}
+
+/**
+ * Write integer value to the result
+ * @param context
+ * @param val
+ * @return 
+ */
+size_t SCPI_ResultInt(scpi_t * context, int32_t val) {
+    char buffer[12];
+    size_t result = 0;
+    size_t len = longToStr(val, buffer, sizeof (buffer));
+    result += writeDelimiter(context);
+    result += writeData(context, buffer, len);
+    context->output_count++;
+    return result;
+}
+
+/**
+ * Write boolean value to the result
+ * @param context
+ * @param val
+ * @return 
+ */
+size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) {
+	return SCPI_ResultInt(context, val ? 1 : 0);
+}
+
+/**
+ * Write double walue to the result
+ * @param context
+ * @param val
+ * @return 
+ */
+size_t SCPI_ResultDouble(scpi_t * context, double val) {
+    char buffer[32];
+    size_t result = 0;
+    size_t len = doubleToStr(val, buffer, sizeof (buffer));
+    result += writeDelimiter(context);
+    result += writeData(context, buffer, len);
+    context->output_count++;
+    return result;
+
+}
+
+/**
+ * Write string withn " to the result
+ * @param context
+ * @param data
+ * @return 
+ */
+size_t SCPI_ResultText(scpi_t * context, const char * data) {
+    size_t result = 0;
+    result += writeDelimiter(context);
+    result += writeData(context, "\"", 1);
+    result += writeData(context, data, strlen(data));
+    result += writeData(context, "\"", 1);
+    context->output_count++;
+    return result;
+}
+
+/* parsing parameters */
+
+/**
+ * Skip num bytes from the begginig of parameters
+ * @param context
+ * @param num
+ */
+void paramSkipBytes(scpi_t * context, size_t num) {
+    if (context->paramlist.length < num) {
+        num = context->paramlist.length;
+    }
+    context->paramlist.parameters += num;
+    context->paramlist.length -= num;
+}
+
+/**
+ * Skip white spaces from the beggining of parameters
+ * @param context
+ */
+void paramSkipWhitespace(scpi_t * context) {
+    size_t ws = skipWhitespace(context->paramlist.parameters, context->paramlist.length);
+    paramSkipBytes(context, ws);
+}
+
+/**
+ * Find next parameter
+ * @param context
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory) {
+    paramSkipWhitespace(context);
+    if (context->paramlist.length == 0) {
+        if (mandatory) {
+            SCPI_ErrorPush(context, SCPI_ERROR_MISSING_PARAMETER);
+        }
+        return FALSE;
+    }
+    if (context->input_count != 0) {
+        if (context->paramlist.parameters[0] == ',') {
+            paramSkipBytes(context, 1);
+            paramSkipWhitespace(context);
+        } else {
+            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR);
+            return FALSE;
+        }
+    }
+    context->input_count++;
+    return TRUE;
+}
+
+/**
+ * Parse integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) {
+    const char * param;
+    size_t param_len;
+    size_t num_len;
+
+    if (!value) {
+        return FALSE;
+    }
+
+    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+        return FALSE;
+    }
+
+    num_len = strToLong(param, value);
+
+    if (num_len != param_len) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/**
+ * Parse double parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) {
+    const char * param;
+    size_t param_len;
+    size_t num_len;
+
+    if (!value) {
+        return FALSE;
+    }
+
+    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+        return FALSE;
+    }
+
+    num_len = strToDouble(param, value);
+
+    if (num_len != param_len) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/**
+ * Parse string parameter
+ * @param context
+ * @param value Pointer to string buffer where pointer to non-null terminated string will be returned
+ * @param len Length of returned non-null terminated string
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
+    size_t length;
+
+    if (!value || !len) {
+        return FALSE;
+    }
+
+    if (!paramNext(context, mandatory)) {
+        return FALSE;
+    }
+
+    if (locateStr(context->paramlist.parameters, context->paramlist.length, value, &length)) {
+        paramSkipBytes(context, length);
+        paramSkipWhitespace(context);
+        if (len) {
+            *len = length;
+        }
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * Parse text parameter (can be inside "")
+ * @param context
+ * @param value Pointer to string buffer where pointer to non-null terminated string will be returned
+ * @param len Length of returned non-null terminated string
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
+    size_t length;
+
+    if (!value || !len) {
+        return FALSE;
+    }
+
+    if (!paramNext(context, mandatory)) {
+        return FALSE;
+    }
+
+    if (locateText(context->paramlist.parameters, context->paramlist.length, value, &length)) {
+        paramSkipBytes(context, length);
+        if (len) {
+            *len = length;
+        }
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * Parse boolean parameter as described in the spec SCPI-99 7.3 Boolean Program Data
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) {
+    const char * param;
+    size_t param_len;
+    size_t num_len;
+    int32_t i;
+
+    if (!value) {
+        return FALSE;
+    }
+
+    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+        return FALSE;
+    }
+
+    if (matchPattern("ON", 2, param, param_len)) {
+        *value = TRUE;
+    } else if (matchPattern("OFF", 3, param, param_len)) {
+        *value = FALSE;
+    } else {
+        num_len = strToLong(param, &i);
+
+        if (num_len != param_len) {
+            SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+            return FALSE;
+        }
+
+        *value = i ? TRUE : FALSE;
+    }
+
+    return TRUE;
+}
+
+/**
+ * Parse choice parameter
+ * @param context
+ * @param options
+ * @param value
+ * @param mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory) {
+    const char * param;
+    size_t param_len;
+    size_t res;
+
+    if (!options || !value) {
+        return FALSE;
+    }
+
+    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+        return FALSE;
+    }
+
+    for (res = 0; options[res]; ++res) {
+        if (matchPattern(options[res], strlen(options[res]), param, param_len)) {
+            *value = res;
+            return TRUE;
+        }
+    }
+
+    SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
+    return FALSE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/units.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_units.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI units
+ * 
+ * 
+ */
+
+#include <string.h>
+#include "scpi/parser.h"
+#include "scpi/units.h"
+#include "scpi/utils_private.h"
+#include "scpi/error.h"
+
+
+/*
+ * multipliers IEEE 488.2-1992 tab 7-2
+ * 1E18         EX
+ * 1E15         PE
+ * 1E12         T
+ * 1E9          G
+ * 1E6          MA (use M for OHM and HZ)
+ * 1E3          K
+ * 1E-3         M (disaalowed for OHM and HZ)
+ * 1E-6         U
+ * 1E-9         N
+ * 1E-12        P
+ * 1E-15        F
+ * 1E-18        A
+ */
+
+/*
+ * units definition IEEE 488.2-1992 tab 7-1
+ */
+const scpi_unit_def_t scpi_units_def[] = {
+    /* voltage */
+    {/* name */ "UV",   /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1e-6},
+    {/* name */ "MV",   /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1e-3},
+    {/* name */ "V",    /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1},
+    {/* name */ "KV",   /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1e3},
+
+    /* current */
+    {/* name */ "UA",   /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1e-6},
+    {/* name */ "MA",   /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1e-3},
+    {/* name */ "A",    /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1},
+    {/* name */ "KA",   /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1e3},
+
+    /* resistance */
+    {/* name */ "OHM",  /* unit */ SCPI_UNIT_OHM,       /* mult */ 1},
+    {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM,       /* mult */ 1e3},
+    {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM,       /* mult */ 1e6},
+
+    /* frequency */
+    {/* name */ "HZ",   /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1},
+    {/* name */ "KHZ",  /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1e3},
+    {/* name */ "MHZ",  /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1e6},
+    {/* name */ "GHZ",  /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1e9},
+
+    /* temperature */
+    {/* name */ "CEL",  /* unit */ SCPI_UNIT_CELSIUS,   /* mult */ 1},
+
+    /* time */
+    {/* name */ "PS",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-12},
+    {/* name */ "NS",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-9},
+    {/* name */ "US",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-6},
+    {/* name */ "MS",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-3},
+    {/* name */ "S",    /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1},
+    {/* name */ "MIN",  /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 60},
+    {/* name */ "HR",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 3600},
+
+    SCPI_UNITS_LIST_END,
+};
+
+/*
+ * Special number values definition
+ */
+const scpi_special_number_def_t scpi_special_numbers_def[] = {
+    {/* name */ "MINimum",      /* type */ SCPI_NUM_MIN},
+    {/* name */ "MAXimum",      /* type */ SCPI_NUM_MAX},
+    {/* name */ "DEFault",      /* type */ SCPI_NUM_DEF},
+    {/* name */ "UP",           /* type */ SCPI_NUM_UP},
+    {/* name */ "DOWN",         /* type */ SCPI_NUM_DOWN},
+    {/* name */ "NAN",          /* type */ SCPI_NUM_NAN},
+    {/* name */ "INFinity",     /* type */ SCPI_NUM_INF},
+    {/* name */ "NINF",         /* type */ SCPI_NUM_NINF},
+    SCPI_SPECIAL_NUMBERS_LIST_END,
+};
+
+/**
+ * Match string constant to one of special number values
+ * @param specs specifications of special numbers (patterns)
+ * @param str string to be recognised
+ * @param len length of string
+ * @param value resultin value
+ * @return TRUE if str matches one of specs patterns
+ */
+static scpi_bool_t translateSpecialNumber(const scpi_special_number_def_t * specs, const char * str, size_t len, scpi_number_t * value) {
+    int i;
+
+    value->value = 0.0;
+    value->unit = SCPI_UNIT_NONE;
+    value->type = SCPI_NUM_NUMBER;
+
+    if (specs == NULL) {
+        return FALSE;
+    }
+
+    for (i = 0; specs[i].name != NULL; i++) {
+        if (matchPattern(specs[i].name, strlen(specs[i].name), str, len)) {
+            value->type = specs[i].type;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+/**
+ * Convert special number type to its string representation
+ * @param specs specifications of special numbers (patterns)
+ * @param type type of special number
+ * @return String representing special number or NULL
+ */
+static const char * translateSpecialNumberInverse(const scpi_special_number_def_t * specs, scpi_special_number_t type) {
+    int i;
+
+    if (specs == NULL) {
+        return NULL;
+    }
+    
+    for (i = 0; specs[i].name != NULL; i++) {
+        if (specs[i].type == type) {
+            return specs[i].name;
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Convert string describing unit to its representation
+ * @param units units patterns
+ * @param unit text representation of unknown unit
+ * @param len length of text representation
+ * @return pointer of related unit definition or NULL
+ */
+static const scpi_unit_def_t * translateUnit(const scpi_unit_def_t * units, const char * unit, size_t len) {
+    int i;
+    
+    if (units == NULL) {
+        return NULL;
+    }
+    
+    for (i = 0; units[i].name != NULL; i++) {
+        if (compareStr(unit, len, units[i].name, strlen(units[i].name))) {
+            return &units[i];
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Convert unit definition to string
+ * @param units units definitions (patterns)
+ * @param unit type of unit
+ * @return string representation of unit
+ */
+static const char * translateUnitInverse(const scpi_unit_def_t * units, const scpi_unit_t unit) {
+    int i;
+    
+    if (units == NULL) {
+        return NULL;
+    }
+    
+    for (i = 0; units[i].name != NULL; i++) {
+        if ((units[i].unit == unit) && (units[i].mult == 1)) {
+            return units[i].name;
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Transform number to base units
+ * @param context
+ * @param unit text representation of unit
+ * @param len length of text representation
+ * @param value preparsed numeric value
+ * @return TRUE if value parameter was converted to base units
+ */
+static scpi_bool_t transformNumber(scpi_t * context, const char * unit, size_t len, scpi_number_t * value) {
+    size_t s;
+    const scpi_unit_def_t * unitDef;
+    s = skipWhitespace(unit, len);
+
+    if (s == len) {
+        value->unit = SCPI_UNIT_NONE;
+        return TRUE;
+    }
+
+    unitDef = translateUnit(context->units, unit + s, len - s);
+
+    if (unitDef == NULL) {
+        SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SUFFIX);
+        return FALSE;
+    }
+
+    value->value *= unitDef->mult;
+    value->unit = unitDef->unit;
+
+    return TRUE;
+}
+
+/**
+ * Parse parameter as number, number with unit or special value (min, max, default, ...)
+ * @param context
+ * @param value return value
+ * @param mandatory if the parameter is mandatory
+ * @return 
+ */
+scpi_bool_t SCPI_ParamNumber(scpi_t * context, scpi_number_t * value, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    const char * param;
+    size_t len;
+    size_t numlen;
+
+    /* read parameter and shift to the next one */
+    result = SCPI_ParamString(context, &param, &len, mandatory);
+
+    /* value not initializes */
+    if (!value) {
+        return FALSE;
+    }
+
+    value->type = SCPI_NUM_DEF;
+
+    /* if parameter was not found, return TRUE or FALSE according
+     * to fact that parameter was mandatory or not */
+    if (!result) {
+        return mandatory ? FALSE : TRUE;
+    }
+
+    /* convert string to special number type */
+    if (translateSpecialNumber(context->special_numbers, param, len, value)) {
+        /* found special type */
+        return TRUE;
+    }
+
+    /* convert text from double - no special type */
+    numlen = strToDouble(param, &value->value);
+
+    /* transform units of value */
+    if (numlen <= len) {
+        return transformNumber(context, param + numlen, len - numlen, value);
+    }
+    return FALSE;
+
+}
+
+/**
+ * Convert scpi_number_t to string
+ * @param context
+ * @param value number value
+ * @param str target string
+ * @param len max length of string
+ * @return number of chars written to string
+ */
+size_t SCPI_NumberToStr(scpi_t * context, scpi_number_t * value, char * str, size_t len) {
+    const char * type;
+    const char * unit;
+    size_t result;
+
+    if (!value || !str) {
+        return 0;
+    }
+
+    type = translateSpecialNumberInverse(context->special_numbers, value->type);
+
+    if (type) {
+        strncpy(str, type, len);
+        return min(strlen(type), len);
+    }
+
+    result = doubleToStr(value->value, str, len);
+
+    unit = translateUnitInverse(context->units, value->unit);
+
+    if (unit) {
+        strncat(str, " ", len);
+        strncat(str, unit, len);
+        result += strlen(unit) + 1;
+    }
+
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libscpi/utils.c	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,730 @@
+/*-
+ * Copyright (c) 2013 Jan Breuer
+ *                    Richard.hmm
+ * Copyright (c) 2012 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_utils.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  Conversion routines and string manipulation routines
+ * 
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "scpi/utils_private.h"
+
+static size_t patternSeparatorShortPos(const char * pattern, size_t len);
+static size_t patternSeparatorPos(const char * pattern, size_t len);
+static size_t cmdSeparatorPos(const char * cmd, size_t len);
+
+/**
+ * Find the first occurrence in str of a character in set.
+ * @param str
+ * @param size
+ * @param set
+ * @return 
+ */
+const char * strnpbrk(const char *str, size_t size, const char *set) {
+    const char *scanp;
+    long c, sc;
+    const char * strend = str + size;
+
+    while ((strend != str) && ((c = *str++) != 0)) {
+        for (scanp = set; (sc = *scanp++) != '\0';)
+            if (sc == c)
+                return str - 1;
+    }
+    return (NULL);
+}
+
+/**
+ * Converts signed 32b integer value to string
+ * @param val   integer value
+ * @param str   converted textual representation
+ * @param len   string buffer length
+ * @return number of bytes written to str (without '\0')
+ */
+size_t longToStr(int32_t val, char * str, size_t len) {
+    uint32_t x = 1000000000L;
+    int_fast8_t digit;
+    size_t pos = 0;
+
+    if (val == 0) {
+        if (pos < len) str[pos++] = '0';
+    } else {
+        if (val < 0) {
+            val = -val;
+            if (pos < len) str[pos++] = '-';
+        }
+
+        while ((val / x) == 0) {
+            x /= 10;
+        }
+
+        do {
+            digit = (uint8_t) (val / x);
+            if (pos < len) str[pos++] = digit + '0';
+            val -= digit * x;
+            x /= 10;
+        } while (x && (pos < len));
+    }
+
+    if (pos < len) str[pos] = 0;
+    return pos;
+}
+
+/**
+ * Converts double value to string
+ * @param val   double value
+ * @param str   converted textual representation
+ * @param len   string buffer length
+ * @return number of bytes written to str (without '\0')
+ */
+size_t doubleToStr(double val, char * str, size_t len) {
+    return snprintf(str, len, "%lg", val);
+}
+
+/**
+ * Converts string to signed 32bit integer representation
+ * @param str   string value
+ * @param val   32bit integer result
+ * @return      number of bytes used in string
+ */
+size_t strToLong(const char * str, int32_t * val) {
+    char * endptr;
+    *val = strtol(str, &endptr, 0);
+    return endptr - str;
+}
+
+/**
+ * Converts string to double representation
+ * @param str   string value
+ * @param val   double result
+ * @return      number of bytes used in string
+ */
+size_t strToDouble(const char * str, double * val) {
+    char * endptr;
+    *val = strtod(str, &endptr);
+    return endptr - str;
+}
+
+/**
+ * Compare two strings with exact length
+ * @param str1
+ * @param len1
+ * @param str2
+ * @param len2
+ * @return TRUE if len1==len2 and "len" characters of both strings are equal
+ */
+scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) {
+    if (len1 != len2) {
+        return FALSE;
+    }
+
+    if (SCPI_strncasecmp(str1, str2, len2) == 0) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * Compare two strings, one be longer but may contains only numbers in that section
+ * @param str1
+ * @param len1
+ * @param str2
+ * @param len2
+ * @return TRUE if strings match
+ */
+scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2) {
+    scpi_bool_t result = FALSE;
+    size_t i;
+
+    if (len2 < len1) {
+        return FALSE;
+    }
+
+    if (SCPI_strncasecmp(str1, str2, len1) == 0) {
+        result = TRUE;
+    }
+
+    for (i = len1; i<len2; i++) {
+        if (!isdigit(str2[i])) {
+            result = FALSE;
+            break;
+        }
+    }
+
+    return result;
+}
+
+enum _locate_text_states {
+    STATE_FIRST_WHITESPACE,
+    STATE_TEXT_QUOTED,
+    STATE_TEXT,
+    STATE_LAST_WHITESPACE,
+    STATE_COMMA,
+    STATE_ERROR
+};
+typedef enum _locate_text_states locate_text_states;
+
+struct _locate_text_nfa {
+    locate_text_states state;
+    int32_t startIdx;
+    int32_t stopIdx;
+    size_t i;
+};
+typedef struct _locate_text_nfa locate_text_nfa;
+
+/**
+ * Test locate text state, if it is correct final state
+ */
+static scpi_bool_t isFinalState(locate_text_states state) {
+    return (
+        ((state) == STATE_COMMA)
+        || ((state) == STATE_LAST_WHITESPACE)
+        || ((state) == STATE_TEXT) ||
+        ((state) == STATE_FIRST_WHITESPACE)
+    );
+}
+
+/**
+ * Perform locateText automaton to search string pattern
+ * @param nfa stores automaton state
+ * @param c current char processed
+ */
+static scpi_bool_t locateTextAutomaton(locate_text_nfa * nfa, unsigned char c) {
+    switch(nfa->state) {
+        /* first state locating only white spaces */
+        case STATE_FIRST_WHITESPACE:
+            if(isspace(c)) {
+                nfa->startIdx = nfa->stopIdx = nfa->i + 1;
+            } else if (c == ',') {
+                nfa->state = STATE_COMMA;
+            } else if (c == '"') {
+                nfa->startIdx = nfa->i + 1;
+                nfa->state = STATE_TEXT_QUOTED;
+            } else {
+                nfa->startIdx = nfa->i;
+                nfa->stopIdx = nfa->i + 1;
+                nfa->state = STATE_TEXT;
+            }
+            break;
+        /* state locating any text inside "" */
+        case STATE_TEXT_QUOTED:
+            if(c == '"') {
+                nfa->state = STATE_LAST_WHITESPACE;
+                nfa->stopIdx = nfa->i;
+            }
+            break;
+        /* locate text ignoring quotes */
+        case STATE_TEXT:
+            if (c == ',') {
+                nfa->state = STATE_COMMA;
+            } else if (!isspace(c)) {
+                nfa->stopIdx = nfa->i + 1;
+            }
+            break;
+        /* locating text after last quote */
+        case STATE_LAST_WHITESPACE:
+            if (c == ',') {
+                nfa->state = STATE_COMMA;
+            } else if (!isspace(c)) {
+                nfa->state = STATE_ERROR;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    /* if it is terminating state, break from for loop */
+    if ((nfa->state == STATE_COMMA) || (nfa->state == STATE_ERROR)) {
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+/**
+ * Locate text in string. Text is separated by two ""
+ *   example: "text", next parameter
+ *   regexp: ^[ \t\r\n]*"([^"]*)"[ \t\r\n]*,?
+ *   regexp: ^[ \t\r\n]*([^,]*)[ \t\r\n]*,?
+ * @param str1 string to be searched
+ * @param len1 length of string
+ * @param str2 result
+ * @param len2 length of result
+ * @return string str1 contains text and str2 was set
+ */
+scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) {
+    locate_text_nfa nfa;
+    nfa.state = STATE_FIRST_WHITESPACE;
+    nfa.startIdx = 0;
+    nfa.stopIdx = 0;
+
+    for (nfa.i = 0; nfa.i < len1; nfa.i++) {
+        if(FALSE == locateTextAutomaton(&nfa, str1[nfa.i])) {
+            break;
+        }
+    }
+
+    if (isFinalState(nfa.state)) {
+
+        if (str2) {
+            *str2 = &str1[nfa.startIdx];
+        }
+
+        if (len2) {
+            *len2 = nfa.stopIdx - nfa.startIdx;
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/**
+ * Perform locateStr automaton to search string pattern
+ * @param nfa stores automaton state
+ * @param c current char processed
+ */
+static scpi_bool_t locateStrAutomaton(locate_text_nfa * nfa, unsigned char c) {
+    switch(nfa->state) {
+        /* first state locating only white spaces */
+        case STATE_FIRST_WHITESPACE:
+            if(isspace(c)) {
+                nfa->startIdx = nfa->stopIdx = nfa->i + 1;
+            } else if (c == ',') {
+                nfa->state = STATE_COMMA;
+            } else {
+                nfa->startIdx = nfa->i;
+                nfa->stopIdx = nfa->i + 1;
+                nfa->state = STATE_TEXT;
+            }
+            break;
+        /* locate text ignoring quotes */
+        case STATE_TEXT:
+            if (c == ',') {
+                nfa->state = STATE_COMMA;
+            } else if (!isspace(c)) {
+                nfa->stopIdx = nfa->i + 1;
+            }
+            break;
+
+        default:
+            break;            
+    }
+
+    /* if it is terminating state, break from for loop */
+    if ((nfa->state == STATE_COMMA) || (nfa->state == STATE_ERROR)) {
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+/**
+ * Locate string in string.
+ *   regexp: ^[ \t\r\n]*([^,]*)[ \t\r\n]*,?
+ * @param str1 string to be searched
+ * @param len1 length of string
+ * @param str2 result
+ * @param len2 length of result
+ * @return string str1 contains text and str2 was set
+ */
+scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) {
+    locate_text_nfa nfa;
+    nfa.state = STATE_FIRST_WHITESPACE;
+    nfa.startIdx = 0;
+    nfa.stopIdx = 0;
+
+
+    for (nfa.i = 0; nfa.i < len1; nfa.i++) {
+        if(FALSE == locateStrAutomaton(&nfa, str1[nfa.i])) {
+            break;
+        }
+    }
+
+    if (isFinalState(nfa.state)) {
+
+        if (str2) {
+            *str2 = &str1[nfa.startIdx];
+        }
+
+        if (len2) {
+            *len2 = nfa.stopIdx - nfa.startIdx;
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+/**
+ * Count white spaces from the beggining
+ * @param cmd - command
+ * @param len - max search length
+ * @return number of white spaces
+ */
+size_t skipWhitespace(const char * cmd, size_t len) {
+    size_t i;
+    for (i = 0; i < len; i++) {
+        if (!isspace((unsigned char) cmd[i])) {
+            return i;
+        }
+    }
+    return len;
+}
+
+/**
+ * Pattern is composed from upper case an lower case letters. This function
+ * search the first lowercase letter
+ * @param pattern
+ * @param len - max search length
+ * @return position of separator or len
+ */
+size_t patternSeparatorShortPos(const char * pattern, size_t len) {
+    size_t i;
+    for (i = 0; (i < len) && pattern[i]; i++) {
+        if (islower((unsigned char) pattern[i])) {
+            return i;
+        }
+    }
+    return i;
+}
+
+/**
+ * Find pattern separator position
+ * @param pattern
+ * @param len - max search length
+ * @return position of separator or len
+ */
+size_t patternSeparatorPos(const char * pattern, size_t len) {
+
+    const char * separator = strnpbrk(pattern, len, "?:[]");
+    if (separator == NULL) {
+        return len;
+    } else {
+        return separator - pattern;
+    }
+}
+
+/**
+ * Find command separator position
+ * @param cmd - input command
+ * @param len - max search length
+ * @return position of separator or len
+ */
+size_t cmdSeparatorPos(const char * cmd, size_t len) {
+    const char * separator = strnpbrk(cmd, len, ":?");
+    size_t result;
+    if (separator == NULL) {
+        result = len;
+    } else {
+        result = separator - cmd;
+    }
+
+    return result;
+}
+
+/**
+ * Match pattern and str. Pattern is in format UPPERCASElowercase
+ * @param pattern
+ * @param pattern_len
+ * @param str
+ * @param str_len
+ * @return 
+ */
+scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) {
+    int pattern_sep_pos_short;
+
+    if (pattern[pattern_len - 1] == '#') {
+        size_t new_pattern_len = pattern_len - 1;
+
+        pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len);
+
+        return compareStrAndNum(pattern, new_pattern_len, str, str_len) ||
+                compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len);
+    } else {
+
+        pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len);
+
+        return compareStr(pattern, pattern_len, str, str_len) ||
+                compareStr(pattern, pattern_sep_pos_short, str, str_len);
+    }
+}
+
+/**
+ * Compare pattern and command
+ * @param pattern eg. [:MEASure]:VOLTage:DC?
+ * @param cmd - command
+ * @param len - max search length
+ * @return TRUE if pattern matches, FALSE otherwise
+ */
+scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) {
+    scpi_bool_t result = FALSE;
+    int leftFlag = 0; // flag for '[' on left
+    int rightFlag = 0; // flag for ']' on right
+    int cmd_sep_pos = 0;
+
+    const char * pattern_ptr = pattern;
+    int pattern_len = strlen(pattern);
+    const char * pattern_end = pattern + pattern_len;
+
+    const char * cmd_ptr = cmd;
+    size_t cmd_len = SCPI_strnlen(cmd, len);
+    const char * cmd_end = cmd + cmd_len;
+
+    /* now support optional keywords in pattern style, e.g. [:MEASure]:VOLTage:DC? */
+    if (pattern_ptr[0] == '[') { // skip first '['
+        pattern_len--;
+        pattern_ptr++;
+        leftFlag++;
+    }
+    if (pattern_ptr[0] == ':') { // skip first ':'
+        pattern_len--;
+        pattern_ptr++;
+    }
+
+    if (cmd_ptr[0] == ':') {
+        /* handle errornouse ":*IDN?" */
+        if((cmd_len >= 2) && (cmd_ptr[1] != '*')) {
+            cmd_len--;
+            cmd_ptr++;
+        }
+    }
+
+    while (1) {
+        int pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_end - pattern_ptr);
+
+        if ((leftFlag > 0) && (rightFlag > 0)) {
+            leftFlag--;
+            rightFlag--;
+        } else {
+            cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_end - cmd_ptr);
+        }
+
+        if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos)) {
+            pattern_ptr = pattern_ptr + pattern_sep_pos;
+            cmd_ptr = cmd_ptr + cmd_sep_pos;
+            result = TRUE;
+
+            /* command is complete */
+            if ((pattern_ptr == pattern_end) && (cmd_ptr >= cmd_end)) {
+                break;
+            }
+
+            /* pattern complete, but command not */
+            if ((pattern_ptr == pattern_end) && (cmd_ptr < cmd_end)) {
+                result = FALSE;
+                break;
+            }
+
+            /* command complete, but pattern not */
+            if (cmd_ptr >= cmd_end) {
+                if (cmd_end == cmd_ptr) {
+                    if (cmd_ptr[0] == pattern_ptr[pattern_end - pattern_ptr - 1]) {
+                        break; /* exist optional keyword, command is complete */
+                    }
+                    if (']' == pattern_ptr[pattern_end - pattern_ptr - 1]) {
+                        break; /* exist optional keyword, command is complete */
+                    }
+                }
+                result = FALSE;
+                break;
+            }
+
+            /* both command and patter contains command separator at this position */
+            if ((pattern_ptr[0] == cmd_ptr[0]) && ((pattern_ptr[0] == ':') || (pattern_ptr[0] == '?'))) {
+                pattern_ptr = pattern_ptr + 1;
+                cmd_ptr = cmd_ptr + 1;
+            } else if ((pattern_ptr[1] == cmd_ptr[0])
+                    && (pattern_ptr[0] == '[')
+                    && (pattern_ptr[1] == ':')) {
+                pattern_ptr = pattern_ptr + 2; // for skip '[' in "[:"
+                cmd_ptr = cmd_ptr + 1;
+                leftFlag++;
+            } else if ((pattern_ptr[1] == cmd_ptr[0])
+                    && (pattern_ptr[0] == ']')
+                    && (pattern_ptr[1] == ':')) {
+                pattern_ptr = pattern_ptr + 2; // for skip ']' in "]:"
+                cmd_ptr = cmd_ptr + 1;
+            } else if ((pattern_ptr[2] == cmd_ptr[0])
+                    && (pattern_ptr[0] == ']')
+                    && (pattern_ptr[1] == '[')
+                    && (pattern_ptr[2] == ':')) {
+                pattern_ptr = pattern_ptr + 3; // for skip '][' in "][:"
+                cmd_ptr = cmd_ptr + 1;
+                leftFlag++;
+            } else if (((pattern_ptr[0] == ']')
+                    || (pattern_ptr[0] == '['))
+                    && (*(pattern_end - 1) == '?') // last is '?'
+                    && (cmd_ptr[0] == '?')) {
+                result = TRUE; // exist optional keyword, and they are end with '?'
+                break; // command is complete  OK
+            } else {
+                result = FALSE;
+                break;
+            }
+        } else {
+            pattern_ptr = pattern_ptr + pattern_sep_pos;
+            if ((pattern_ptr[0] == ']') && (pattern_ptr[1] == ':')) {
+                pattern_ptr = pattern_ptr + 2; // for skip ']' in "]:" , pattern_ptr continue, while cmd_ptr remain unchanged
+                rightFlag++;
+            } else if ((pattern_ptr[0] == ']')
+                    && (pattern_ptr[1] == '[')
+                    && (pattern_ptr[2] == ':')) {
+                pattern_ptr = pattern_ptr + 3; // for skip ']' in "][:" , pattern_ptr continue, while cmd_ptr remain unchanged
+                rightFlag++;
+            } else {
+                result = FALSE;
+                break;
+            }
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Compose command from previsou command anc current command
+ * 
+ * @param ptr_prev pointer to previous command
+ * @param len_prev length of previous command
+ * @param pptr pointer to pointer of current command
+ * @param plen pointer to length of current command
+ * 
+ * ptr_prev and ptr should be in the same memory buffer
+ * 
+ * Function will add part of previous command prior to ptr_prev
+ * 
+ * char * cmd = "meas:volt:dc?;ac?"
+ * char * ptr_prev = cmd;
+ * size_t len_prev = 13;
+ * char * ptr = cmd + 14;
+ * size_t len = 3;
+ * 
+ * composeCompoundCommand(ptr_prev, len_prev, &ptr, &len);
+ * 
+ * after calling this
+ * 
+ * 
+ * 
+ */
+scpi_bool_t composeCompoundCommand(char * ptr_prev, size_t len_prev,
+                              char ** pptr, size_t * plen) {
+    char * ptr;
+    size_t len;
+    size_t i;
+
+    /* Invalid input */
+    if (pptr == NULL || plen == NULL)
+        return FALSE;
+
+    /* no previous command - nothing to do*/
+    if (ptr_prev == NULL || len_prev == 0)
+        return TRUE;
+       
+    ptr = *pptr;
+    len = *plen;
+    
+    /* No current command */
+    if (len == 0 || ptr == NULL)
+        return FALSE;
+    
+    /* Common command or command root - nothing to do */
+    if (ptr[0] == '*' || ptr[0] == ':')
+        return TRUE;
+        
+    /* Previsou command was common command - nothing to do */
+    if (ptr_prev[0] == '*')
+        return TRUE;
+        
+    /* Find last occurence of ':' */
+    for (i = len_prev; i > 0; i--) {
+        if (ptr_prev[i-1] == ':') {
+            break;
+        }
+    }
+    
+    /* Previous command was simple command - nothing to do*/
+    if (i == 0)
+        return TRUE;
+    
+    ptr -= i;
+    len += i;
+    memmove(ptr, ptr_prev, i);
+    *plen = len;
+    *pptr = ptr;
+    return TRUE;
+}
+
+
+
+#if !HAVE_STRNLEN
+/* use FreeBSD strnlen */
+
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ */
+size_t
+BSD_strnlen(const char *s, size_t maxlen) {
+    size_t len;
+
+    for (len = 0; len < maxlen; len++, s++) {
+        if (!*s)
+            break;
+    }
+    return (len);
+}
+#endif
+
+#if !HAVE_STRNCASECMP && !HAVE_STRNICMP
+int OUR_strncasecmp(const char *s1, const char *s2, size_t n) {
+    unsigned char c1, c2;
+
+    for(; n != 0; n--) {
+        c1 = tolower((unsigned char)*s1++);
+        c2 = tolower((unsigned char)*s2++);
+        if (c1 != c2) {
+            return c1 - c2;
+        }
+        if (c1 = '\0') {
+            return 0;
+        }
+    }
+    return 0;
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/config.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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   config.h
+ * @date   Wed Mar 20 12:21:26 UTC 2013
+ * 
+ * @brief  SCPI Configuration
+ * 
+ * 
+ */
+
+#ifndef __SCPI_CONFIG_H_
+#define __SCPI_CONFIG_H_
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Compiler specific */
+/* 8bit PIC - PIC16, etc */
+#if defined(_MPC_)
+#define HAVE_STRNLEN            0
+#define HAVE_STRNCASECMP        0
+#define HAVE_STRNICMP           1
+#endif
+
+/* PIC24 */
+#if defined(__C30__)
+#define HAVE_STRNLEN            0
+#define HAVE_STRNCASECMP        0
+#define HAVE_STRNICMP           0
+#endif
+
+/* PIC32mx */
+#if defined(__C32__)
+#define HAVE_STRNLEN            0
+#define HAVE_STRNCASECMP        1
+#define HAVE_STRNICMP           0
+#endif
+
+/* ======== test strnlen ======== */
+#ifndef HAVE_STRNLEN
+#define HAVE_STRNLEN            0
+#endif
+/* ======== test strncasecmp ======== */
+#ifndef HAVE_STRNCASECMP
+#define HAVE_STRNCASECMP        1
+#endif
+/* ======== test strnicmp ======== */
+#ifndef HAVE_STRNICMP
+#define HAVE_STRNICMP           0
+#endif
+
+/* define local macros depending on existance of strnlen */
+#if HAVE_STRNLEN
+#define SCPI_strnlen(s, l)	strnlen((s), (l))
+#else
+#define SCPI_strnlen(s, l)	BSD_strnlen((s), (l))
+#endif
+
+/* define local macros depending on existance of strncasecmp and strnicmp */
+#if HAVE_STRNCASECMP
+#define SCPI_strncasecmp(s1, s2, l)	strncasecmp((s1), (s2), (l))
+#elif HAVE_STRNICMP
+#define SCPI_strncasecmp(s1, s2, l)     strnicmp((s1), (s2), (l))
+#else
+#define SCPI_strncasecmp(s1, s2, l)	OUR_strncasecmp((s1), (s2), (l))
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/constants.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_constants.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI Device constants
+ * 
+ * 
+ */
+
+#ifndef SCPI_CONSTANTS_H
+#define	SCPI_CONSTANTS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+
+/*  4.1.3.6 *IDN? */
+
+#define SCPI_DEFAULT_1_MANUFACTURE "CTU FEE"
+#define SCPI_DEFAULT_2_MODEL "TSI3225"
+#define SCPI_DEFAULT_3 "0"
+#define SCPI_DEFAULT_4_REVISION "01-01"
+
+/* 21.21 :VERSion? 
+ * YYYY.V
+ * YYYY = SCPI year
+ * V = SCPI revision
+ */
+#define SCPI_STD_VERSION_REVISION "1999.0"
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_CONSTANTS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/debug.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_debug.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI debug function
+ * 
+ * 
+ */
+
+#ifndef SCPI_DEBUG_H
+#define	SCPI_DEBUG_H
+
+#include "scpi/types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+
+    /* #define SCPI_DEBUG_COMMAND(a)   scpi_debug_command(a) */
+    #define SCPI_DEBUG_COMMAND(a)
+
+
+    scpi_bool_t SCPI_DebugCommand(scpi_t * context);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_DEBUG_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/error.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_error.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief  Error handling and storing routines
+ *
+ *
+ */
+
+#ifndef SCPI_ERROR_H
+#define	SCPI_ERROR_H
+
+#include "scpi/types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+    void SCPI_ErrorInit(scpi_t * context);
+    void SCPI_ErrorClear(scpi_t * context);
+    int16_t SCPI_ErrorPop(scpi_t * context);
+    void SCPI_ErrorPush(scpi_t * context, int16_t err);
+    int32_t SCPI_ErrorCount(scpi_t * context);
+    const char * SCPI_ErrorTranslate(int16_t err);
+
+/* http://en.wikipedia.org/wiki/X_Macro */
+#define LIST_OF_ERRORS \
+    X(SCPI_ERROR_SYNTAX,               -102, "Syntax error")                   \
+    X(SCPI_ERROR_INVALID_SEPARATOR,    -103, "Invalid separator")              \
+    X(SCPI_ERROR_UNDEFINED_HEADER,     -113, "Undefined header")               \
+    X(SCPI_ERROR_PARAMETER_NOT_ALLOWED,-108, "Parameter not allowed")          \
+    X(SCPI_ERROR_MISSING_PARAMETER,    -109, "Missing parameter")              \
+    X(SCPI_ERROR_INVALID_SUFFIX,       -131, "Invalid suffix")                 \
+    X(SCPI_ERROR_SUFFIX_NOT_ALLOWED,   -138, "Suffix not allowed")             \
+    X(SCPI_ERROR_EXECUTION_ERROR,      -200, "Execution error")                \
+    X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE,-224,"Illegal parameter value")       \
+
+
+enum {
+#define X(def, val, str) def = val,
+LIST_OF_ERRORS
+#undef X
+};
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_ERROR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/fifo.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_fifo.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  basic FIFO implementation
+ * 
+ * 
+ */
+
+#ifndef SCPI_FIFO_H
+#define	SCPI_FIFO_H
+
+#include "scpi/types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+
+#define FIFO_SIZE 16
+
+    struct _fifo_t {
+        int16_t wr;
+        int16_t rd;
+        int16_t size;
+        int16_t data[FIFO_SIZE];
+    };
+    typedef struct _fifo_t fifo_t;
+
+    void fifo_init(fifo_t * fifo);
+    void fifo_clear(fifo_t * fifo);
+    scpi_bool_t fifo_add(fifo_t * fifo, int16_t value);
+    scpi_bool_t fifo_remove(fifo_t * fifo, int16_t * value);
+    scpi_bool_t fifo_count(fifo_t * fifo, int16_t * value);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_FIFO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/ieee488.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  Implementation of IEEE488.2 commands and state model
+ * 
+ * 
+ */
+
+#ifndef SCPI_IEEE488_H
+#define	SCPI_IEEE488_H
+
+#include "scpi/types.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+scpi_result_t SCPI_CoreCls(scpi_t * context);
+scpi_result_t SCPI_CoreEse(scpi_t * context);
+scpi_result_t SCPI_CoreEseQ(scpi_t * context);
+scpi_result_t SCPI_CoreEsrQ(scpi_t * context);
+scpi_result_t SCPI_CoreIdnQ(scpi_t * context);
+scpi_result_t SCPI_CoreOpc(scpi_t * context);
+scpi_result_t SCPI_CoreOpcQ(scpi_t * context);
+scpi_result_t SCPI_CoreRst(scpi_t * context);
+scpi_result_t SCPI_CoreSre(scpi_t * context);
+scpi_result_t SCPI_CoreSreQ(scpi_t * context);
+scpi_result_t SCPI_CoreStbQ(scpi_t * context);
+scpi_result_t SCPI_CoreTstQ(scpi_t * context);
+scpi_result_t SCPI_CoreWai(scpi_t * context);
+
+
+#define STB_R01 0x01    /* Not used */
+#define STB_PRO 0x02    /* Protection Event Flag */
+#define STB_QMA 0x04    /* Error/Event queue message available */
+#define STB_QES 0x08    /* Questionable status */
+#define STB_MAV 0x10    /* Message Available */
+#define STB_ESR 0x20    /* Standard Event Status Register */
+#define STB_SRQ 0x40    /* Service Request */
+#define STB_OPS 0x80    /* Operation Status Flag */
+
+
+#define ESR_OPC 0x01    /* Operation complete */
+#define ESR_REQ 0x02    /* Request Control */
+#define ESR_QER 0x04    /* Query Error */
+#define ESR_DER 0x08    /* Device Dependent Error */
+#define ESR_EER 0x10    /* Execution Error (e.g. range error) */
+#define ESR_CER 0x20    /* Command error (e.g. syntax error) */
+#define ESR_URQ 0x40    /* User Request */
+#define ESR_PON 0x80    /* Power On */
+
+
+scpi_reg_val_t SCPI_RegGet(scpi_t * context, scpi_reg_name_t name);
+void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val);
+void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits);
+void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* SCPI_IEEE488_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/minimal.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_minimal.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI minimal implementation
+ * 
+ * 
+ */
+
+#ifndef SCPI_MINIMAL_H
+#define	SCPI_MINIMAL_H
+
+#include "scpi/types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+    scpi_result_t SCPI_Stub(scpi_t * context);
+    scpi_result_t SCPI_StubQ(scpi_t * context);
+
+    scpi_result_t SCPI_SystemVersionQ(scpi_t * context);
+    scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context);
+    scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context);
+    scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context);
+    scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context);
+    scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context);
+    scpi_result_t SCPI_StatusPreset(scpi_t * context);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_MINIMAL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/parser.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_parser.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI parser implementation
+ * 
+ * 
+ */
+
+#ifndef SCPI_PARSER_H
+#define	SCPI_PARSER_H
+
+#include "scpi/types.h"
+#include "scpi/debug.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+    void SCPI_Init(scpi_t * context);
+
+    int SCPI_Input(scpi_t * context, const char * data, size_t len);
+    int SCPI_Parse(scpi_t * context, char * data, size_t len);
+
+
+    size_t SCPI_ResultString(scpi_t * context, const char * data);
+    size_t SCPI_ResultInt(scpi_t * context, int32_t val);
+    size_t SCPI_ResultDouble(scpi_t * context, double val);
+    size_t SCPI_ResultText(scpi_t * context, const char * data);
+    size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val);
+
+    scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);    
+    scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_PARSER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/scpi.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI library include file
+ * 
+ * 
+ */
+
+#ifndef SCPI_H
+#define	SCPI_H
+
+#include "scpi/parser.h"
+#include "scpi/ieee488.h"
+#include "scpi/error.h"
+#include "scpi/constants.h"
+#include "scpi/minimal.h"
+#include "scpi/units.h"
+
+
+
+#endif	/* SCPI_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/types.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,220 @@
+/*-
+ * Copyright (c) 2013 Jan Breuer
+ *                    Richard.hmm
+ * Copyright (c) 2012 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_types.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI data types
+ * 
+ * 
+ */
+
+#ifndef SCPI_TYPES_H
+#define SCPI_TYPES_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifndef FALSE
+    #define FALSE 0
+#endif
+#ifndef TRUE
+    #define TRUE (!FALSE)
+#endif
+
+    /* basic data types */
+    typedef bool scpi_bool_t;
+    /* typedef enum { FALSE = 0, TRUE } scpi_bool_t; */
+
+    /* IEEE 488.2 registers */
+    enum _scpi_reg_name_t {
+        SCPI_REG_STB = 0, /* Status Byte */
+        SCPI_REG_SRE,     /* Service Request Enable Register */
+        SCPI_REG_ESR,     /* Standard Event Status Register (ESR, SESR) */
+        SCPI_REG_ESE,     /* Event Status Enable Register */
+        SCPI_REG_OPER,    /* OPERation Status Register */
+        SCPI_REG_OPERE,   /* OPERation Status Enable Register */
+        SCPI_REG_QUES,    /* QUEStionable status register */
+        SCPI_REG_QUESE,   /* QUEStionable status Enable Register */
+
+        /* last definition - number of registers */
+        SCPI_REG_COUNT
+    };
+    typedef enum _scpi_reg_name_t scpi_reg_name_t;
+
+    enum _scpi_ctrl_name_t {
+        SCPI_CTRL_SRQ = 1, /* service request */
+        SCPI_CTRL_GTL,     /* Go to local */
+        SCPI_CTRL_SDC,     /* Selected device clear */
+        SCPI_CTRL_PPC,     /* Parallel poll configure */
+        SCPI_CTRL_GET,     /* Group execute trigger */
+        SCPI_CTRL_TCT,     /* Take control */
+        SCPI_CTRL_LLO,     /* Device clear */
+        SCPI_CTRL_DCL,     /* Local lockout */
+        SCPI_CTRL_PPU,     /* Parallel poll unconfigure */
+        SCPI_CTRL_SPE,     /* Serial poll enable */
+        SCPI_CTRL_SPD,     /* Serial poll disable */
+        SCPI_CTRL_MLA,     /* My local address */
+        SCPI_CTRL_UNL,     /* Unlisten */
+        SCPI_CTRL_MTA,     /* My talk address */
+        SCPI_CTRL_UNT,     /* Untalk */
+        SCPI_CTRL_MSA      /* My secondary address */
+    };
+    typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t;
+
+    typedef uint16_t scpi_reg_val_t;
+
+    /* scpi commands */
+    enum _scpi_result_t {
+        SCPI_RES_OK = 1,
+        SCPI_RES_ERR = -1
+    };
+    typedef enum _scpi_result_t scpi_result_t;
+
+    typedef struct _scpi_command_t scpi_command_t;
+
+    struct _scpi_buffer_t {
+        size_t length;
+        size_t position;
+        char * data;
+    };
+    typedef struct _scpi_buffer_t scpi_buffer_t;
+
+    struct _scpi_param_list_t {
+        const scpi_command_t * cmd;
+        const char * parameters;
+        size_t length;
+        scpi_buffer_t cmd_raw;
+    };
+    #define SCPI_CMD_LIST_END       {NULL, NULL, }
+    typedef struct _scpi_param_list_t scpi_param_list_t;
+
+    /* scpi interface */
+    typedef struct _scpi_t scpi_t;
+    typedef struct _scpi_interface_t scpi_interface_t;
+
+    typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len);
+    typedef scpi_result_t(*scpi_write_control_t)(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val);
+    typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error);
+
+    typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *);
+
+    /* scpi error queue */
+    typedef void * scpi_error_queue_t;
+
+    /* scpi units */
+    enum _scpi_unit_t {
+        SCPI_UNIT_NONE,
+        SCPI_UNIT_VOLT,
+        SCPI_UNIT_AMPER,
+        SCPI_UNIT_OHM,
+        SCPI_UNIT_HERTZ,
+        SCPI_UNIT_CELSIUS,
+        SCPI_UNIT_SECONDS,
+        SCPI_UNIT_DISTANCE
+    };
+    typedef enum _scpi_unit_t scpi_unit_t;
+
+    struct _scpi_unit_def_t {
+        const char * name;
+        scpi_unit_t unit;
+        double mult;
+    };
+    #define SCPI_UNITS_LIST_END       {NULL, SCPI_UNIT_NONE, 0}
+    typedef struct _scpi_unit_def_t scpi_unit_def_t;
+
+    enum _scpi_special_number_t {
+        SCPI_NUM_NUMBER,
+        SCPI_NUM_MIN,
+        SCPI_NUM_MAX,
+        SCPI_NUM_DEF,
+        SCPI_NUM_UP,
+        SCPI_NUM_DOWN,
+        SCPI_NUM_NAN,
+        SCPI_NUM_INF,
+        SCPI_NUM_NINF
+    };
+    typedef enum _scpi_special_number_t scpi_special_number_t;
+
+    struct _scpi_special_number_def_t {
+        const char * name;
+        scpi_special_number_t type;
+    };
+    #define SCPI_SPECIAL_NUMBERS_LIST_END   {NULL, SCPI_NUM_NUMBER}    
+    typedef struct _scpi_special_number_def_t scpi_special_number_def_t;
+
+    struct _scpi_number_t {
+        double value;
+        scpi_unit_t unit;
+        scpi_special_number_t type;
+    };
+    typedef struct _scpi_number_t scpi_number_t;
+
+    struct _scpi_command_t {
+        const char * pattern;
+        scpi_command_callback_t callback;
+    };
+
+    struct _scpi_interface_t {
+        scpi_error_callback_t error;
+        scpi_write_t write;
+        scpi_write_control_t control;
+        scpi_command_callback_t flush;
+        scpi_command_callback_t reset;
+        scpi_command_callback_t test;
+    };
+
+    struct _scpi_t {
+        const scpi_command_t * cmdlist;
+        scpi_buffer_t buffer;
+        scpi_param_list_t paramlist;
+        scpi_interface_t * interface;
+        int_fast16_t output_count;
+        int_fast16_t input_count;
+        scpi_bool_t cmd_error;
+        scpi_error_queue_t error_queue;
+        scpi_reg_val_t * registers;
+        const scpi_unit_def_t * units;
+        const scpi_special_number_def_t * special_numbers;
+        void * user_context;
+        const char * idn[4];
+    };
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* SCPI_TYPES_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/units.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_units.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  SCPI Units
+ * 
+ * 
+ */
+
+#ifndef SCPI_UNITS_H
+#define	SCPI_UNITS_H
+
+#include "scpi/types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+    extern const scpi_unit_def_t scpi_units_def[];
+    extern const scpi_special_number_def_t scpi_special_numbers_def[];
+    
+    scpi_bool_t SCPI_ParamNumber(scpi_t * context, scpi_number_t * value, scpi_bool_t mandatory);
+    size_t SCPI_NumberToStr(scpi_t * context, scpi_number_t * value, char * str, size_t len);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_UNITS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scpi/utils_private.h	Fri Nov 14 01:07:59 2014 +0000
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2012-2013 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:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS ``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 AUTHORS 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_utils.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  Conversion routines and string manipulation routines
+ * 
+ * 
+ */
+
+#ifndef SCPI_UTILS_H
+#define	SCPI_UTILS_H
+
+#include <stdint.h>
+#include "scpi/config.h"
+#include "scpi/types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+    #define LOCAL __attribute__((visibility ("hidden")))
+#else
+    #define LOCAL
+#endif
+
+    const char * strnpbrk(const char *str, size_t size, const char *set) LOCAL;
+    scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL;
+    scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL;
+    size_t longToStr(int32_t val, char * str, size_t len) LOCAL;
+    size_t doubleToStr(double val, char * str, size_t len) LOCAL;
+    size_t strToLong(const char * str, int32_t * val) LOCAL;
+    size_t strToDouble(const char * str, double * val) LOCAL;
+    scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
+    scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
+    size_t skipWhitespace(const char * cmd, size_t len) LOCAL;
+    size_t skipColon(const char * cmd, size_t len) LOCAL;
+    scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) LOCAL;
+    scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) LOCAL;
+    scpi_bool_t composeCompoundCommand(char * ptr_prev, size_t len_prev, char ** pptr, size_t * plen);
+
+#if !HAVE_STRNLEN
+    size_t BSD_strnlen(const char *s, size_t maxlen);
+#endif
+
+#if !HAVE_STRNCASECMP && !HAVE_STRNICMP
+    int OUR_strncasecmp(const char *s1, const char *s2, size_t n);
+#endif
+
+#define min(a, b)  (((a) < (b)) ? (a) : (b))
+#define max(a, b)  (((a) > (b)) ? (a) : (b))
+
+#if 0
+#define max(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+
+#define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCPI_UTILS_H */
+