From a4cffa5e99430532bb5bbad3385b910e25025296 Mon Sep 17 00:00:00 2001
From: Jan Breuer <jan.breuer@jaybee.cz>
Date: 周三, 26 12月 2012 23:32:34 +0800
Subject: [PATCH] Reimplement srq/control callback

---
 examples/common/scpi-def.h       |    5 
 examples/test-tcp-srq/Makefile   |   20 ++
 libscpi/inc/scpi/types.h         |   46 ++++-
 libscpi/src/ieee488.c            |   12 +
 examples/test-parser/main.c      |   17 +
 examples/test-tcp/main.c         |   16 +
 examples/test-interactive/main.c |   16 +
 examples/test-tcp-srq/main.c     |  337 ++++++++++++++++++++++++++++++++++++++++++
 examples/common/scpi-def.c       |    5 
 9 files changed, 448 insertions(+), 26 deletions(-)

diff --git a/examples/common/scpi-def.c b/examples/common/scpi-def.c
index 0b9bfbd..1908484 100644
--- a/examples/common/scpi-def.c
+++ b/examples/common/scpi-def.c
@@ -108,6 +108,8 @@
     {.pattern = "MEASure:FRESistance?", .callback = SCPI_StubQ,},
     {.pattern = "MEASure:FREQuency?", .callback = SCPI_StubQ,},
     {.pattern = "MEASure:PERiod?", .callback = SCPI_StubQ,},
+    
+    {.pattern = "SYSTem:COMMunication:TCPIP:CONTROL?", .callback = SCPI_SystemCommTcpipControlQ,},
 
     SCPI_CMD_LIST_END
 };
@@ -117,7 +119,8 @@
     .error = SCPI_Error,
     .reset = SCPI_Reset,
     .test = SCPI_Test,
-    .srq = SCPI_Srq,
+    .control = SCPI_Control,
+    .flush = SCPI_Flush,
 };
 
 #define SCPI_INPUT_BUFFER_LENGTH 256
diff --git a/examples/common/scpi-def.h b/examples/common/scpi-def.h
index 646a653..905aaa4 100644
--- a/examples/common/scpi-def.h
+++ b/examples/common/scpi-def.h
@@ -7,12 +7,13 @@
 
 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_Srq(scpi_t * context);
+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);
 
 #endif // __SCPI_DEF_H_
 
diff --git a/examples/test-interactive/main.c b/examples/test-interactive/main.c
index 6fd1d71..b149558 100644
--- a/examples/test-interactive/main.c
+++ b/examples/test-interactive/main.c
@@ -45,6 +45,10 @@
     return fwrite(data, 1, len, stdout);
 }
 
+scpi_result_t SCPI_Flush(scpi_t * context) {    
+    return SCPI_RES_OK;
+}
+
 int SCPI_Error(scpi_t * context, int_fast16_t err) {
     (void) context;
 
@@ -52,9 +56,12 @@
     return 0;
 }
 
-scpi_result_t SCPI_Srq(scpi_t * context) {
-    scpi_reg_val_t stb = SCPI_RegGet(context, SCPI_REG_STB);
-    fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", stb, stb);
+scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) {
+    if (SCPI_CTRL_SRQ == ctrl) {
+        fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", val, val);
+    } else {
+        fprintf(stderr, "**CTRL %02x: 0x%X (%d)\r\n", ctrl, val, val);
+    }
     return SCPI_RES_OK;
 }
 
@@ -68,6 +75,9 @@
     return SCPI_RES_OK;
 }
 
+scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context) {
+    return SCPI_RES_ERR;
+}
 /*
  * 
  */
diff --git a/examples/test-parser/main.c b/examples/test-parser/main.c
index d5e3553..0ab2b2a 100644
--- a/examples/test-parser/main.c
+++ b/examples/test-parser/main.c
@@ -45,6 +45,10 @@
     return fwrite(data, 1, len, stdout);
 }
 
+scpi_result_t SCPI_Flush(scpi_t * context) {    
+    return SCPI_RES_OK;
+}
+
 int SCPI_Error(scpi_t * context, int_fast16_t err) {
     (void) context;
 
@@ -52,9 +56,12 @@
     return 0;
 }
 
-scpi_result_t SCPI_Srq(scpi_t * context) {
-    scpi_reg_val_t stb = SCPI_RegGet(context, SCPI_REG_STB);
-    fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", stb, stb);
+scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) {
+    if (SCPI_CTRL_SRQ == ctrl) {
+        fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", val, val);
+    } else {
+        fprintf(stderr, "**CTRL %02x: 0x%X (%d)\r\n", ctrl, val, val);
+    }
     return SCPI_RES_OK;
 }
 
@@ -68,6 +75,10 @@
     return SCPI_RES_OK;
 }
 
+scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context) {
+    return SCPI_RES_ERR;
+}
+
 /*
  * 
  */
diff --git a/examples/test-tcp-srq/Makefile b/examples/test-tcp-srq/Makefile
new file mode 100644
index 0000000..1d225a9
--- /dev/null
+++ b/examples/test-tcp-srq/Makefile
@@ -0,0 +1,20 @@
+
+PROG = test
+
+SRCS = main.c ../common/scpi-def.c
+CFLAGS += -Wextra -I ../../libscpi/inc/
+LDFLAGS += ../../libscpi/dist/libscpi.a
+
+
+all: $(PROG)
+
+OBJS = $(SRCS:.c=.o)
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
+
+$(PROG): $(OBJS)
+	$(CC) -o $@ $(OBJS) $(LDFLAGS)
+
+clean:
+	$(RM) $(PROG) $(OBJS)
diff --git a/examples/test-tcp-srq/main.c b/examples/test-tcp-srq/main.c
new file mode 100644
index 0000000..0837e95
--- /dev/null
+++ b/examples/test-tcp-srq/main.c
@@ -0,0 +1,337 @@
+/*-
+ * 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   main.c
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  TCP/IP SCPI Server
+ * 
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include "scpi/scpi.h"
+#include "../common/scpi-def.h"
+
+#define CONTROL_PORT 5026
+
+
+
+typedef struct {
+    int io;
+    int io_listen;
+    int control_io;
+    int control_io_listen;
+    FILE * fio;
+    fd_set fds;
+} user_data_t;
+
+size_t SCPI_Write(scpi_t * context, const char * data, size_t len) {
+    if (context->user_context != NULL) {
+        user_data_t * u = (user_data_t *)(context->user_context);
+        if (u->fio) {
+            return fwrite(data, 1, len, u->fio);
+        }
+    }
+    return 0;
+}
+
+scpi_result_t SCPI_Flush(scpi_t * context) {    
+    if (context->user_context != NULL) {
+        user_data_t * u = (user_data_t *)(context->user_context);
+        if (u->fio) {
+            return fflush(u->fio) == 0 ? SCPI_RES_OK : SCPI_RES_ERR;
+        }
+    }
+    return SCPI_RES_OK;
+}
+
+int SCPI_Error(scpi_t * context, int_fast16_t err) {
+    (void) context;
+    // BEEP
+    fprintf(stderr, "**ERROR: %d, \"%s\"\r\n", (int32_t) err, SCPI_ErrorTranslate(err));
+    return 0;
+}
+
+
+scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) {
+    char b[16];
+
+    if (SCPI_CTRL_SRQ == ctrl) {
+        fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", val, val);
+    } else {
+        fprintf(stderr, "**CTRL %02x: 0x%X (%d)\r\n", ctrl, val, val);
+    }
+    
+    if (context->user_context != NULL) {
+        user_data_t * u = (user_data_t *)(context->user_context);
+        if (u->control_io >= 0) {
+            snprintf(b, sizeof(b), "SRQ%d\r\n", val);
+            return write(u->control_io, b, strlen(b)) > 0 ? SCPI_RES_OK : SCPI_RES_ERR;
+        }
+    }    
+    return SCPI_RES_OK;
+}
+
+scpi_result_t SCPI_Test(scpi_t * context) {
+    fprintf(stderr, "**Test\r\n");
+    return SCPI_RES_OK;
+}
+
+scpi_result_t SCPI_Reset(scpi_t * context) {
+    fprintf(stderr, "**Reset\r\n");
+    return SCPI_RES_OK;
+}
+
+scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context) {
+    SCPI_ResultInt(context, CONTROL_PORT);
+    return SCPI_RES_OK;
+}
+
+static int createServer(int port) {
+    int fd;
+    int rc;
+    int on = 1;
+    struct sockaddr_in servaddr;
+        
+    /* Configure TCP Server */
+    bzero(&servaddr, sizeof(servaddr));
+    servaddr.sin_family = AF_INET;
+    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
+    servaddr.sin_port=htons(port);
+    
+    /* Create socket */
+    fd = socket(AF_INET,SOCK_STREAM, 0);
+    if (fd < 0)
+    {
+        perror("socket() failed");
+        exit(-1);
+    }    
+    
+    /* Set address reuse enable */
+    rc = setsockopt(fd, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on));
+    if (rc < 0)
+    {
+        perror("setsockopt() failed");
+        close(fd);
+        exit(-1);
+    }
+   
+    /* Set non blocking */
+    rc = ioctl(fd, FIONBIO, (char *)&on);
+    if (rc < 0)
+    {
+        perror("ioctl() failed");
+        close(fd);
+        exit(-1);
+    }    
+    
+    /* Bind to socket */
+    rc = bind(fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
+    if (rc < 0)
+    {
+        perror("bind() failed");
+        close(fd);
+        exit(-1);
+    }
+    
+    /* Listen on socket */
+    listen(fd, 1);
+    if (rc < 0)
+    {
+        perror("listen() failed");
+        close(fd);
+        exit(-1);
+    }
+    
+    return fd;
+}
+
+static int waitServer(user_data_t * user_data) {
+    struct timeval timeout;
+    int rc;
+    
+    FD_ZERO(&user_data->fds);
+
+    if (user_data->io >= 0) {
+        FD_SET(user_data->io, &user_data->fds);
+    }
+    
+    if (user_data->io_listen >= 0) {
+        FD_SET(user_data->io_listen, &user_data->fds);
+    }
+    
+    if (user_data->control_io >= 0) {
+        FD_SET(user_data->control_io, &user_data->fds);
+    }
+    
+    if (user_data->control_io_listen >= 0) {
+        FD_SET(user_data->control_io_listen, &user_data->fds);
+    }
+    
+    timeout.tv_sec  = 5;
+    timeout.tv_usec = 0;
+    
+    rc = select(FD_SETSIZE, &user_data->fds, NULL, NULL, &timeout);
+    
+    return rc;
+}
+
+
+static int processIoListen(user_data_t * user_data) {
+    struct sockaddr_in cliaddr;
+    socklen_t clilen;
+    clilen = sizeof(cliaddr);
+    
+    user_data->io = accept(user_data->io_listen, (struct sockaddr *)&cliaddr, &clilen);
+    user_data->fio = fdopen(user_data->io, "r+");
+    
+    printf("Connection established %s\r\n", inet_ntoa(cliaddr.sin_addr));
+}
+
+static int processSrqIoListen(user_data_t * user_data) {
+    struct sockaddr_in cliaddr;
+    socklen_t clilen;
+    clilen = sizeof(cliaddr);
+
+    user_data->control_io = accept(user_data->control_io_listen, (struct sockaddr *)&cliaddr, &clilen);    
+    printf("Control Connection established %s\r\n", inet_ntoa(cliaddr.sin_addr));
+}
+
+static void closeIo(user_data_t * user_data) {
+    fclose(user_data->fio);
+    user_data->fio = NULL;
+    user_data->io = -1;
+}
+
+static void closeSrqIo(user_data_t * user_data) {
+    close(user_data->control_io);
+    user_data->control_io = -1;
+}
+
+static int processIo(user_data_t * user_data) {
+    int rc;
+    char smbuffer[10];
+    rc = recv(user_data->io, smbuffer, sizeof(smbuffer), 0);
+    if (rc < 0) {
+        if (errno != EWOULDBLOCK) {
+            closeIo(user_data);
+            perror("  recv() failed");
+        }
+    } else if (rc == 0) {
+        closeIo(user_data);
+        printf("Connection closed\r\n");
+    } else {
+        SCPI_Input(&scpi_context, smbuffer, rc);
+    }
+}
+
+static int processSrqIo(user_data_t * user_data) {
+    int rc;
+    char smbuffer[10];  
+    rc = recv(user_data->control_io, smbuffer, sizeof(smbuffer), 0);
+    if (rc < 0) {
+        if (errno != EWOULDBLOCK) {
+            closeSrqIo(user_data);
+            perror("  recv() failed");
+        }
+    } else if (rc == 0) {
+        closeSrqIo(user_data);
+        printf("Control Connection closed\r\n");
+    } else {
+        // nothing to do
+    }
+}
+
+/*
+ * 
+ */
+int main(int argc, char** argv) {
+    (void) argc;
+    (void) argv;
+    int rc;
+    
+    user_data_t user_data = {
+        .io_listen = -1,
+        .io = -1,
+        .control_io_listen = -1,
+        .control_io = -1,
+        .fio = NULL,
+    };
+
+    // user_context will be pointer to socket
+    scpi_context.user_context = &user_data;
+    
+    SCPI_Init(&scpi_context);
+
+    user_data.io_listen = createServer(5025);
+    user_data.control_io_listen = createServer(CONTROL_PORT);
+    
+    while(1) {
+        rc = waitServer(&user_data);
+        
+        if (rc < 0) { // failed
+            perror("select failed");
+            exit(-1);
+        }
+        
+        if (rc == 0) { // timeout
+            SCPI_Input(&scpi_context, NULL, 0);
+        }
+        
+        if ((user_data.io_listen >= 0) && FD_ISSET(user_data.io_listen, &user_data.fds)) {
+            processIoListen(&user_data);
+        }
+
+        if ((user_data.control_io_listen >= 0) && FD_ISSET(user_data.control_io_listen, &user_data.fds)) {
+            processSrqIoListen(&user_data);
+        }
+        
+        if ((user_data.io >= 0) && FD_ISSET(user_data.io, &user_data.fds)) {
+            processIo(&user_data);
+        }
+        
+        if ((user_data.control_io >= 0) && FD_ISSET(user_data.control_io, &user_data.fds)) {
+            processSrqIo(&user_data);
+        }
+        
+    }
+    
+    return (EXIT_SUCCESS);
+}
+
diff --git a/examples/test-tcp/main.c b/examples/test-tcp/main.c
index 55dc792..2336165 100644
--- a/examples/test-tcp/main.c
+++ b/examples/test-tcp/main.c
@@ -56,6 +56,10 @@
     return 0;
 }
 
+scpi_result_t SCPI_Flush(scpi_t * context) {    
+    return SCPI_RES_OK;
+}
+
 int SCPI_Error(scpi_t * context, int_fast16_t err) {
     (void) context;
     // BEEP
@@ -63,9 +67,12 @@
     return 0;
 }
 
-scpi_result_t SCPI_Srq(scpi_t * context) {
-    scpi_reg_val_t stb = SCPI_RegGet(context, SCPI_REG_STB);
-    fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", stb, stb);
+scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) {
+    if (SCPI_CTRL_SRQ == ctrl) {
+        fprintf(stderr, "**SRQ: 0x%X (%d)\r\n", val, val);
+    } else {
+        fprintf(stderr, "**CTRL %02x: 0x%X (%d)\r\n", ctrl, val, val);
+    }
     return SCPI_RES_OK;
 }
 
@@ -79,6 +86,9 @@
     return SCPI_RES_OK;
 }
 
+scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context) {
+    return SCPI_RES_ERR;
+}
 
 static int createServer(int port) {
     int fd;
diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h
index 2fb743f..12af335 100644
--- a/libscpi/inc/scpi/types.h
+++ b/libscpi/inc/scpi/types.h
@@ -52,19 +52,27 @@
     typedef bool bool_t;
     //typedef enum { FALSE = 0, TRUE } bool_t;
 
-    /* scpi interface */
-    typedef struct _scpi_t scpi_t;
-    typedef struct _scpi_interface_t scpi_interface_t;
-    typedef struct _scpi_buffer_t scpi_buffer_t;
-    typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len);
-    typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error);
+    /* IEEE 488.2 registers */
+    typedef enum _scpi_reg_name_t scpi_reg_name_t;
+    typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t;
+    typedef uint16_t scpi_reg_val_t;
 
     /* scpi commands */
     typedef enum _scpi_result_t scpi_result_t;
     typedef struct _scpi_param_list_t scpi_param_list_t;
     typedef struct _scpi_command_t scpi_command_t;
+
+    /* scpi interface */
+    typedef struct _scpi_t scpi_t;
+    typedef struct _scpi_interface_t scpi_interface_t;
+    typedef struct _scpi_buffer_t scpi_buffer_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;
 
@@ -74,10 +82,6 @@
     typedef enum _scpi_special_number_t scpi_special_number_t;
     typedef struct _scpi_special_number_def_t scpi_special_number_def_t;
     typedef struct _scpi_number_t scpi_number_t;
-
-    /* IEEE 488.2 registers */
-    typedef enum _scpi_reg_name_t scpi_reg_name_t;
-    typedef uint16_t scpi_reg_val_t;
     
     struct _scpi_param_list_t {
         const scpi_command_t * cmd;
@@ -102,10 +106,10 @@
     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;
-        scpi_command_callback_t srq;
     };
 
     struct _scpi_t {
@@ -186,7 +190,25 @@
         /* last definition - number of registers */
         SCPI_REG_COUNT,
     };
-
+    
+    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
+    };
 
 #ifdef	__cplusplus
 }
diff --git a/libscpi/src/ieee488.c b/libscpi/src/ieee488.c
index e493a93..513ed90 100644
--- a/libscpi/src/ieee488.c
+++ b/libscpi/src/ieee488.c
@@ -39,6 +39,8 @@
 #include "scpi/error.h"
 #include "scpi/constants.h"
 
+#include <stdio.h>
+
 /**
  * Update register value
  * @param name - register name
@@ -58,6 +60,12 @@
     } else {
         return 0;
     }
+}
+
+static size_t writeControl(scpi_t * context, int ctrl, scpi_reg_val_t val) {
+    if (context && context->interface && context->interface->control) {
+        context->interface->control(context, ctrl, val);
+    }    
 }
 
 /**
@@ -131,8 +139,8 @@
     // set updated register value
     context->registers[name] = val;
 
-    if (srq && context->interface && context->interface->srq) {
-        context->interface->srq(context);
+    if (srq) {
+        writeControl(context, SCPI_CTRL_SRQ, SCPI_RegGet(context, SCPI_REG_STB));
     }
 }
 

--
Gitblit v1.9.1