From 10d4d22edead55bdaca75bf663021a8c11a17ad6 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 8 May 2020 17:40:52 +0900 Subject: [PATCH 01/67] create a directory for HiSLIP support --- asyn/drvAsynHiSLIP/README.txt | 27 + asyn/drvAsynHiSLIP/drvAsynHiSLIP.c | 1291 ++++++++++++++++++++++++++ asyn/drvAsynHiSLIP/drvAsynHiSLIP.dbd | 1 + asyn/drvAsynHiSLIP/drvAsynHiSLIP.h | 99 ++ 4 files changed, 1418 insertions(+) create mode 100644 asyn/drvAsynHiSLIP/README.txt create mode 100644 asyn/drvAsynHiSLIP/drvAsynHiSLIP.c create mode 100644 asyn/drvAsynHiSLIP/drvAsynHiSLIP.dbd create mode 100644 asyn/drvAsynHiSLIP/drvAsynHiSLIP.h diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt new file mode 100644 index 000000000..5f6da0533 --- /dev/null +++ b/asyn/drvAsynHiSLIP/README.txt @@ -0,0 +1,27 @@ + EPICS ASYN support for USB TMC (Test and Measurement Class) devices +=============================================================================== + +Based on: + 1) "Universal Serial Bus Test and Measurement Class Specification (USBTMC)", + Revision 1.0. + 2) "Universal Serial Bus Test and Measurement Class, Subclass USB488 + Specification (USBTMC-USB488)", Revision 1.0. + +Requires libusb-1.0, available from: http://www.libusb.org/ + For best results use version 16 or higher. + +Build Issues +============ +1. Linker reports that libusb_strerror is undefined? + Check if you have multiple versions of libusb-1.0 installed. The build + system may be finding the header for a newer version (that does supply + libusb_strerror) but then links against an older library (that does not + supply libusb_strerror). + +Acknowledgements +================ +Thanks go out to Florian Sorgenfrei and Damien Lynch for +their patience and suggestions in testing this code. + + +Eric Norum diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.c b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.c new file mode 100644 index 000000000..432a211af --- /dev/null +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.c @@ -0,0 +1,1291 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drvAsynHiSLIP.h" + +#define MESSAGE_ID_DEV_DEP_MSG_OUT 1 +#define MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN 2 +#define MESSAGE_ID_DEV_DEP_MSG_IN 2 + +#define BULK_IO_HEADER_SIZE 12 +#define BULK_IO_PAYLOAD_CAPACITY 4096 +#define IDSTRING_CAPACITY 100 + +#define ASYN_REASON_SRQ 4345 +#define ASYN_REASON_STB 4346 +#define ASYN_REASON_REN 4347 + +#if (!defined(LIBUSBX_API_VERSION) || (LIBUSBX_API_VERSION < 0x01000102)) +# error "You need to get a newer version of libsb-1.0 (16 at the very least)" +#endif + +typedef struct drvPvt { + /* + * Used to find matching device + */ + const char *hostname; + const long port; + /* + * Matched device + */ + char deviceVendorID[IDSTRING_CAPACITY]; + + /* + * Asyn interfaces we provide + */ + char *portName; + asynInterface asynCommon; + asynInterface asynOctet; + asynInterface asynInt32; + void *asynInt32InterruptPvt; + asynInterface asynDrvUser; + + /* + * HiSLIP private + */ + int sync_channel; + int async_channel; + long RMT; + long message_id; + long most_recent_message_id; + + /* + * Interrupt endpoint handling + */ + char *interruptThreadName; + epicsThreadId interruptTid; + epicsMutexId interruptTidMutex; + epicsEventId pleaseTerminate; + epicsEventId didTerminate; + epicsMessageQueueId statusByteMessageQueue; + + /* + * I/O buffer + */ + unsigned char buf[BULK_IO_HEADER_SIZE+BULK_IO_PAYLOAD_CAPACITY]; + int bufCount; + const unsigned char *bufp; + unsigned char bulkInPacketFlags; + + /* + * Statistics + */ + size_t connectionCount; + size_t interruptCount; + size_t bytesSentCount; + size_t bytesReceivedCount; +} drvPvt; + +static asynStatus disconnect(void *pvt, asynUser *pasynUser); + +/* + * Interrupt endpoint support + */ +static void +interruptThread(void *arg) +{ + drvPvt *pdpvt = (drvPvt *)arg; + unsigned char cbuf[2]; + int n; + int s; + + for (;;) { + s = libusb_interrupt_transfer (pdpvt->handle, + pdpvt->interruptEndpointAddress, + cbuf, + sizeof cbuf, + &n, + 65000); + if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK) + break; + if ((s == 0) && (n == sizeof cbuf)) { + if (cbuf[0] == 0x81) { + ELLLIST *pclientList; + interruptNode *pnode; + + pdpvt->interruptCount++; + pasynManager->interruptStart(pdpvt->asynInt32InterruptPvt, &pclientList); + pnode = (interruptNode *)ellFirst(pclientList); + while (pnode) { + asynInt32Interrupt *int32Interrupt = pnode->drvPvt; + pnode = (interruptNode *)ellNext(&pnode->node); + if (int32Interrupt->pasynUser->reason == ASYN_REASON_SRQ) { + int32Interrupt->callback(int32Interrupt->userPvt, + int32Interrupt->pasynUser, + cbuf[1]); + } + } + pasynManager->interruptEnd(pdpvt->asynInt32InterruptPvt); + } + else if (cbuf[0] == 0x82) { + if (epicsMessageQueueTrySend(pdpvt->statusByteMessageQueue, + &cbuf[1], 1) != 0) { + errlogPrintf("----- WARNING ----- " + "Can't send status byte to worker thread!\n"); + } + } + } + else if (s != LIBUSB_ERROR_TIMEOUT) { + errlogPrintf("----- WARNING ----- " + "libusb_interrupt_transfer failed (%s). " + "Interrupt thread for ASYN port \"%s\" terminating.\n", + libusb_strerror(s), pdpvt->portName); + break; + } + } + epicsMutexLock(pdpvt->interruptTidMutex); + pdpvt->interruptTid = 0; + epicsEventSignal(pdpvt->didTerminate); + epicsMutexUnlock(pdpvt->interruptTidMutex); +} + +static void +startInterruptThread(drvPvt *pdpvt) +{ + epicsMutexLock(pdpvt->interruptTidMutex); + if (pdpvt->enableInterruptEndpoint + && pdpvt->interruptEndpointAddress + && (pdpvt->interruptTid == 0)) { + epicsEventTryWait(pdpvt->pleaseTerminate); + epicsEventTryWait(pdpvt->didTerminate); + pdpvt->interruptTid = epicsThreadCreate(pdpvt->interruptThreadName, + epicsThreadGetPrioritySelf(), + epicsThreadGetStackSize(epicsThreadStackSmall), + interruptThread, pdpvt); + if (pdpvt->interruptTid == 0) + errlogPrintf("----- WARNING ----- " + "Can't start interrupt handler thread %s.\n", + pdpvt->interruptThreadName); + } + epicsMutexUnlock(pdpvt->interruptTidMutex); +} + +/* + * Decode a status byte + */ +static void +showHexval(FILE *fp, const char *name, int val, int bitmask, const char *bitname, ...) +{ + const char *sep = " -- "; + va_list ap; + va_start(ap, bitname); + fprintf(fp, "%28s: ", name); + if (bitmask) + fprintf(fp, "%#x", val); + else + fprintf(fp, "%#4.4x", val); + for (;;) { + if (((bitmask > 0) && ((val & bitmask)) != 0) + || ((bitmask < 0) && ((val & -bitmask)) == 0) + || ((bitmask == 0) && (bitname != NULL) && (bitname[0] != '\0'))) { + fprintf(fp, "%s%s", sep, bitname); + sep = ", "; + } + if (bitmask == 0) + break; + bitmask = va_arg(ap, int); + if (bitmask == 0) + break; + bitname = va_arg(ap, char *); + } + fprintf(fp, "\n"); + va_end(ap); +} + +/* + * Show a byte number + */ +static void +pcomma(FILE *fp, size_t n) +{ + if (n < 1000) { + fprintf(fp, "%zu", n); + return; + } + pcomma(fp, n/1000); + fprintf(fp, ",%03zu", n%1000); +} + +static void +showCount(FILE *fp, const char *label, size_t count) +{ + fprintf(fp, "%22s Count: ", label); + pcomma(fp, count); + fprintf(fp, "\n"); +} + +/* + * asynCommon methods + */ +static void +report(void *pvt, FILE *fp, int details) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + fprintf(fp, "%20sonnected, Interrupt handler thread %sactive\n", + pdpvt->isConnected ? "C" : "Disc", + pdpvt->interruptTid ? "" : "in"); + showHexval(fp, "Vendor", pdpvt->deviceVendorId, 0, pdpvt->deviceVendorString); + showHexval(fp, "Product", pdpvt->deviceProductId, 0, pdpvt->deviceProductString); + if (pdpvt->deviceSerialString[0]) + fprintf(fp, "%28s: \"%s\"\n", "Serial Number", pdpvt->deviceSerialString); + if (details > 0) { + fprintf(fp, " Interface Protocol: %x", pdpvt->bInterfaceProtocol); + switch (pdpvt->bInterfaceProtocol) { + case 0: fprintf(fp, " -- HiSLIP\n"); break; + case 1: fprintf(fp, " -- HiSLIP USB488\n"); break; + default: fprintf(fp, "\n"); break; + } + if (pdpvt->termChar >= 0) + fprintf(fp, "%28s: %x\n", "Terminator", pdpvt->termChar); + showHexval(fp, "TMC Interface Capabilities", + pdpvt->tmcInterfaceCapabilities, + 0x4, "Accepts INDICATOR_PULSE", + 0x2, "Talk-only", + 0x1, "Listen-only", + -0x3, "Talk/Listen", + 0); + showHexval(fp, "TMC Device Capabilities", + pdpvt->tmcDeviceCapabilities, + 0x1, "Supports termChar", + 0); + if (pdpvt->bInterfaceProtocol == 1) { + showHexval(fp, "488 Interface Capabilities", + pdpvt->usb488InterfaceCapabilities, + 0x4, "488.2", + 0x2, "REN/GTL/LLO", + 0x1, "TRG", + 0); + showHexval(fp, "488 Device Capabilities", + pdpvt->usb488DeviceCapabilities, + 0x8, "SCPI", + 0x4, "SR1", + -0x4, "SR0", + 0x2, "RL1", + -0x2, "RL0", + 0x1, "DT1", + -0x1, "DT0", + 0); + } + } + if (details > 1) { + fprintf(fp, " Bulk output endpoint: %x\n", pdpvt->bulkOutEndpointAddress); + fprintf(fp, " Bulk input endpoint: %x\n", pdpvt->bulkInEndpointAddress); + fprintf(fp, " Interrupt endpoint: %x\n", pdpvt->interruptEndpointAddress); + showCount(fp, "Connection", pdpvt->connectionCount); + showCount(fp, "Interrupt", pdpvt->interruptCount); + showCount(fp, "Send", pdpvt->bytesSentCount); + showCount(fp, "Receive", pdpvt->bytesReceivedCount); + } + if (details >= 100) { + int l = details % 100; + fprintf(fp, "==== Set libusb debug level %d ====\n", l); + libusb_set_debug(pdpvt->usb, l); + } +} + +/* + * Get USB descriptor as an ASCII string. + */ +static void +getDeviceString(drvPvt *pdpvt, int i, char *dest) +{ + ssize_t n; + + n = libusb_get_string_descriptor_ascii(pdpvt->handle, i, + pdpvt->buf, sizeof pdpvt->buf); + if (n < 0) { + *dest = '\0'; + return; + } + if(n >= IDSTRING_CAPACITY) + n = IDSTRING_CAPACITY - 1; + strncpy(dest, (char *)pdpvt->buf, n); +} +static void +getDeviceStrings(drvPvt *pdpvt, struct libusb_device_descriptor *desc) +{ + getDeviceString(pdpvt, desc->iManufacturer, pdpvt->deviceVendorString); + getDeviceString(pdpvt, desc->iProduct, pdpvt->deviceProductString); + getDeviceString(pdpvt, desc->iSerialNumber, pdpvt->deviceSerialString); +} + +/* + * Get endpoints + */ +static void +getEndpoints(drvPvt *pdpvt, const struct libusb_interface_descriptor *iface_desc) +{ + int e; + + pdpvt->bulkInEndpointAddress = 0; + pdpvt->bulkOutEndpointAddress = 0; + pdpvt->interruptEndpointAddress = 0; + for (e = 0 ; e < iface_desc->bNumEndpoints ; e++) { + const struct libusb_endpoint_descriptor *ep = &iface_desc->endpoint[e]; + switch (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { + case LIBUSB_TRANSFER_TYPE_BULK: + if ((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) + pdpvt->bulkInEndpointAddress = ep->bEndpointAddress; + else + pdpvt->bulkOutEndpointAddress = ep->bEndpointAddress; + break; + + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + pdpvt->interruptEndpointAddress = ep->bEndpointAddress; + break; + } + } +} + +/* + * Search the bus for a matching device + */ +static asynStatus +findDevice(drvPvt *pdpvt, asynUser *pasynUser, libusb_device **list, int n) +{ + int i, j, k; + + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "No Vendor/Product/Serial match found"); + for (i = 0 ; i < n ; i++) { + libusb_device *dev = list[i]; + struct libusb_device_descriptor desc; + struct libusb_config_descriptor *config; + + int s = libusb_get_device_descriptor(dev, &desc); + if (s != 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_get_device_descriptor failed: %s", libusb_strerror(s)); + return asynError; + } + if (desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) + continue; + if ((libusb_get_active_config_descriptor(dev, &config) < 0) + && (libusb_get_config_descriptor(dev, 0, &config) < 0)) + continue; + if (config == NULL) + continue; + for (j = 0 ; j < config->bNumInterfaces ; j++) { + const struct libusb_interface *iface = &config->interface[j]; + for (k = 0 ; k < iface->num_altsetting ; k++) { + const struct libusb_interface_descriptor *iface_desc; + iface_desc = &iface->altsetting[k]; + if ((iface_desc->bInterfaceClass==HiSLIP_INTERFACE_CLASS) + && (iface_desc->bInterfaceSubClass==HiSLIP_INTERFACE_SUBCLASS) + && ((pdpvt->vendorId==0) || (pdpvt->vendorId==desc.idVendor)) + && ((pdpvt->productId==0) || (pdpvt->productId==desc.idProduct))) { + pdpvt->bInterfaceNumber = iface_desc->bInterfaceNumber; + pdpvt->bInterfaceProtocol = iface_desc->bInterfaceProtocol; + s = libusb_open(dev, &pdpvt->handle); + if (s == 0) { + pdpvt->deviceVendorId = desc.idVendor; + pdpvt->deviceProductId = desc.idProduct; + getDeviceStrings(pdpvt, &desc); + if ((pdpvt->serialNumber == NULL) + || (strcmp(pdpvt->serialNumber, + pdpvt->deviceSerialString) == 0)) { + getEndpoints(pdpvt, iface_desc); + libusb_free_config_descriptor(config); + pasynUser->errorMessage[0] = '\0'; + return asynSuccess; + } + libusb_close(pdpvt->handle); + } + else { + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "libusb_open failed: %s", + libusb_strerror(s)); + } + } + } + } + libusb_free_config_descriptor(config); + } + return asynError; +} + +/* + * Disconnect when it appears that device has gone away + */ +static void +disconnectIfGone(drvPvt *pdpvt, asynUser *pasynUser, int s) +{ + if (s == LIBUSB_ERROR_NO_DEVICE) + disconnect(pdpvt, pasynUser); +} + +/* + * Check results of control transfer + */ +static asynStatus +checkControlTransfer(const char *msg, drvPvt *pdpvt, asynUser *pasynUser, + int s, int want, int usbtmcStatus) +{ + if (s < 0) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "HiSLIP %s failed: %s", msg, libusb_strerror(s)); + return asynError; + } + if (s != want) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "HiSLIP %s failed -- asked for 0x%x, got %x", msg, want, s); + return asynError; + } + if (usbtmcStatus != 1) { + const char *cp; + switch (usbtmcStatus) { + case 0x02: cp = " (STATUS_PENDING)"; break; + case 0x80: cp = " (STATUS_FAILED)"; break; + case 0x81: cp = " (STATUS_TRANSFER_NOT_IN_PROGRESS)"; break; + case 0x82: cp = " (STATUS_SPLIT_NOT_IN_PROGRESS)"; break; + case 0x83: cp = " (STATUS_SPLIT_IN_PROGRESS)"; break; + default: cp = ""; break; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "HiSLIP %s failed -- HiSLIP_status: 0x%x%s", msg, usbtmcStatus, cp); + return asynError; + } + return asynSuccess; +} + +/* + * Get device capabilities + */ +static asynStatus +getCapabilities(drvPvt *pdpvt, asynUser *pasynUser) +{ + int s; + asynStatus status; + + s = libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + 0x07, // bRequest: HiSLIP GET_CAPABILITIES + 0x0000, // wValue + pdpvt->bInterfaceNumber, // wIndex + pdpvt->buf, // data + 0x0018, // wLength + 100); // timeout (ms) + status = checkControlTransfer("GET_CAPABILITIES", pdpvt, pasynUser, + s, 0x18, pdpvt->buf[0]); + if (status != asynSuccess) + return status; + pdpvt->tmcInterfaceCapabilities = pdpvt->buf[4]; + pdpvt->tmcDeviceCapabilities = pdpvt->buf[5]; + if (pdpvt->bInterfaceProtocol == 1) { + pdpvt->usb488InterfaceCapabilities = pdpvt->buf[14]; + pdpvt->usb488DeviceCapabilities = pdpvt->buf[15]; + } + return asynSuccess; +} + +/* + * Clear input/output buffers + */ +static asynStatus +clearBuffers(drvPvt *pdpvt, asynUser *pasynUser) +{ + int s; + asynStatus status; + int pass = 0; + unsigned char cbuf[2]; + + s = libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + 0x05, // bRequest: HiSLIP INITIATE_CLEAR + 0x0000, // wValue + pdpvt->bInterfaceNumber, // wIndex + cbuf, // data + 1, // wLength + 100); // timeout (ms) + status = checkControlTransfer("INITIATE_CLEAR", pdpvt, pasynUser, + s, 1, cbuf[0]); + if (status != asynSuccess) + return status; + for (;;) { + epicsThreadSleep(0.01); // I don't know why this is necessary, but without some delay here the CHECK_CLEAR_STATUS seems to be stuck at STATUS_PENDING + s = libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + 0x06, // bRequest: HiSLIP CHECK_CLEAR_STATUS + 0x0000, // wValue + pdpvt->bInterfaceNumber, // wIndex + cbuf, // data + 0x0002, // wLength + 100); // timeout (ms) + status = checkControlTransfer("CHECK_CLEAR_STATUS", pdpvt, pasynUser, + s, 2, 1); + if (status != asynSuccess) + return asynError; + if (cbuf[0] != 2) { + libusb_clear_halt(pdpvt->handle, pdpvt->bulkInEndpointAddress); + libusb_clear_halt(pdpvt->handle, pdpvt->bulkOutEndpointAddress); + if (cbuf[0] == 1) + return asynSuccess; + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "CHECK_CLEAR_STATUS failed -- status: %x", cbuf[0]); + return asynError; + } + switch (++pass) { + case 5: + asynPrint(pasynUser, ASYN_TRACE_ERROR, "Note -- RESET DEVICE.\n"); + s = libusb_reset_device(pdpvt->handle); + if (s != 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_reset_device() failed: %s", libusb_strerror(s)); + return asynError; + } + break; + + case 10: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "CHECK_CLEAR_STATUS remained 'STATUS_PENDING' for too long"); + return asynError; + } + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "Note -- retrying CHECK_CLEAR_STATUS\n"); + } + return asynSuccess; +} + +static asynStatus +connect(void *pvt, asynUser *pasynUser) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + asynStatus status; + + if (!pdpvt->isConnected) { + libusb_device **list; + ssize_t n; + int s; + + n = libusb_get_device_list(pdpvt->usb, &list); + if (n < 0) { + s = n; + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_get_device_list failed: %s", libusb_strerror(s)); + return asynError; + } + status = findDevice(pdpvt, pasynUser, list, n); + libusb_free_device_list(list, 1); + if (status != asynSuccess) + return asynError; + s = libusb_claim_interface(pdpvt->handle, pdpvt->bInterfaceNumber); + if (s == LIBUSB_ERROR_BUSY) { + libusb_detach_kernel_driver(pdpvt->handle, pdpvt->bInterfaceNumber); + s = libusb_claim_interface(pdpvt->handle, pdpvt->bInterfaceNumber); + } + if (s) { + libusb_close(pdpvt->handle); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_claim_interface failed: %s", libusb_strerror(s)); + return asynError; + } + if (getCapabilities(pdpvt, pasynUser) != asynSuccess) { + libusb_close(pdpvt->handle); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't get device capabilities: %s", pasynUser->errorMessage); + return asynError; + } + if (clearBuffers(pdpvt, pasynUser) != asynSuccess) { + libusb_close(pdpvt->handle); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't clear buffers: %s", pasynUser->errorMessage); + return asynError; + } + pdpvt->bulkInPacketFlags = 0; + pdpvt->bufCount = 0; + pdpvt->connectionCount++; + startInterruptThread(pdpvt); + } + pdpvt->isConnected = 1; + pasynManager->exceptionConnect(pasynUser); + return asynSuccess; +} + +static asynStatus +disconnect(void *pvt, asynUser *pasynUser) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (pdpvt->isConnected) { + int pass = 0; + epicsThreadId tid; + for (;;) { + unsigned char cbuf[3]; + + epicsMutexLock(pdpvt->interruptTidMutex); + tid = pdpvt->interruptTid; + epicsMutexUnlock(pdpvt->interruptTidMutex); + if (tid == 0) + break; + if (++pass == 10) { + errlogPrintf("----- WARNING ----- Thread %s won't terminate!\n", + pdpvt->interruptThreadName); + break; + } + + /* + * Send signal then force an Interrupt-In message + */ + epicsEventSignal(pdpvt->pleaseTerminate); + libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + 128, // bRequest: READ_STATUS_BYTE + 127, // wValue (bTag) + pdpvt->bInterfaceNumber, // wIndex + cbuf, // data + 3, // wLength + 100); // timeout (ms) + epicsEventWaitWithTimeout(pdpvt->didTerminate, 2.0); + } + libusb_close(pdpvt->handle); + } + pdpvt->isConnected = 0; + pasynManager->exceptionDisconnect(pasynUser); + return asynSuccess; +} +static asynCommon commonMethods = { report, connect, disconnect }; + +/* + * asynOctet methods + */ +static asynStatus +asynOctetWrite(void *pvt, asynUser *pasynUser, + const char *data, size_t numchars, size_t *nbytesTransfered) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + int timeout = pasynUser->timeout * 1000; + if (timeout == 0) timeout = 1; + + /* + * Common to all writes + */ + pdpvt->bufCount = 0; + pdpvt->bulkInPacketFlags = 0; + pdpvt->buf[0] = MESSAGE_ID_DEV_DEP_MSG_OUT; + pdpvt->buf[3] = 0; + pdpvt->buf[9] = 0; + pdpvt->buf[10] = 0; + pdpvt->buf[11] = 0; + + /* + * Send + */ + *nbytesTransfered = 0; + while (numchars) { + int nSend, pkSend, pkSent; + int s; + if (numchars > BULK_IO_PAYLOAD_CAPACITY) { + nSend = BULK_IO_PAYLOAD_CAPACITY; + pdpvt->buf[8] = 0; + } + else { + nSend = numchars; + pdpvt->buf[8] = 1; + } + pdpvt->buf[1] = pdpvt->bTag; + pdpvt->buf[2] = ~pdpvt->bTag; + pdpvt->buf[4] = nSend; + pdpvt->buf[5] = nSend >> 8; + pdpvt->buf[6] = nSend >> 16; + pdpvt->buf[7] = nSend >> 24; + memcpy(&pdpvt->buf[BULK_IO_HEADER_SIZE], data, nSend); + pdpvt->bTag = (pdpvt->bTag == 0xFF) ? 0x1 : pdpvt->bTag + 1; + pkSend = nSend + BULK_IO_HEADER_SIZE; + while (pkSend & 0x3) + pdpvt->buf[pkSend++] = 0; + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, + pkSend, "Send %d: ", pkSend); + s = libusb_bulk_transfer(pdpvt->handle, pdpvt->bulkOutEndpointAddress, + pdpvt->buf, pkSend, &pkSent, timeout); + if (s) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Bulk transfer failed: %s", libusb_strerror(s)); + return asynError; + } + if (pkSent != pkSend) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Asked to send %d, actually sent %d", pkSend, pkSent); + return asynError; + } + data += nSend; + numchars -= nSend; + *nbytesTransfered += nSend; + } + pdpvt->bytesSentCount += *nbytesTransfered; + return asynSuccess; +} + +static asynStatus +asynOctetRead(void *pvt, asynUser *pasynUser, + char *data, size_t maxchars, size_t *nbytesTransfered, + int *eomReason) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + unsigned char bTag; + int s; + int nCopy, ioCount, payloadSize; + int eom = 0; + int timeout = pasynUser->timeout * 1000; + if (timeout == 0) timeout = 1; + + *nbytesTransfered = 0; + for (;;) { + /* + * Special case for stream device which requires an asynTimeout return. + */ + if ((pasynUser->timeout == 0) && (pdpvt->bufCount == 0)) + return asynTimeout; + + /* + * Transfer buffered data + */ + if (pdpvt->bufCount) { + nCopy = maxchars; + if (nCopy > pdpvt->bufCount) + nCopy = pdpvt->bufCount; + memcpy(data, pdpvt->bufp, nCopy); + pdpvt->bufp += nCopy; + pdpvt->bufCount -= nCopy; + maxchars -= nCopy; + *nbytesTransfered += nCopy; + pdpvt->bytesReceivedCount += nCopy; + data += nCopy; + if (maxchars == 0) + eom |= ASYN_EOM_CNT; + } + if (pdpvt->bufCount == 0) { + if (pdpvt->bulkInPacketFlags & 0x2) + eom |= ASYN_EOM_EOS; + if (pdpvt->bulkInPacketFlags & 0x1) + eom |= ASYN_EOM_END; + } + if (eom) { + if (eomReason) *eomReason = eom; + return asynSuccess; + } + + /* + * Request another chunk + */ + pdpvt->bulkInPacketFlags = 0; + pdpvt->buf[0] = MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN; + pdpvt->buf[1] = pdpvt->bTag; + pdpvt->buf[2] = ~pdpvt->bTag; + pdpvt->buf[3] = 0; + pdpvt->buf[4] = BULK_IO_PAYLOAD_CAPACITY & 0xFF; + pdpvt->buf[5] = (BULK_IO_PAYLOAD_CAPACITY >> 8) & 0xFF; + pdpvt->buf[6] = (BULK_IO_PAYLOAD_CAPACITY >> 16) & 0xFF; + pdpvt->buf[7] = (BULK_IO_PAYLOAD_CAPACITY >> 24) & 0xFF; + if (pdpvt->termChar >= 0) { + pdpvt->buf[8] = 2; + pdpvt->buf[9] = pdpvt->termChar; + } + else { + pdpvt->buf[8] = 0; + pdpvt->buf[9] = 0; + } + pdpvt->buf[10] = 0; + pdpvt->buf[11] = 0; + bTag = pdpvt->bTag; + pdpvt->bTag = (pdpvt->bTag == 0xFF) ? 0x1 : pdpvt->bTag + 1; + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, + BULK_IO_HEADER_SIZE, + "Request %d, command: ", BULK_IO_PAYLOAD_CAPACITY); + s = libusb_bulk_transfer(pdpvt->handle, pdpvt->bulkOutEndpointAddress, + pdpvt->buf, BULK_IO_HEADER_SIZE, &ioCount, timeout); + if (s) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Bulk transfer request failed: %s", libusb_strerror(s)); + return asynError; + } + + /* + * Read back + */ + s = libusb_bulk_transfer(pdpvt->handle, pdpvt->bulkInEndpointAddress, pdpvt->buf, + sizeof pdpvt->buf, &ioCount, timeout); + if (s) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Bulk read failed: %s", libusb_strerror(s)); + return asynError; + } + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, + ioCount, "Read %d, flags %#x: ", ioCount, pdpvt->buf[8]); + + /* + * Sanity check on transfer + */ + if (ioCount < BULK_IO_HEADER_SIZE) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Incomplete packet header (read only %d)", ioCount); + return asynError; + } + if ((pdpvt->buf[0] != MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN) + || (pdpvt->buf[1] != bTag) + || (pdpvt->buf[2] != (unsigned char)~bTag)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Packet header corrupt %x %x %x (btag %x)", + pdpvt->buf[0], pdpvt->buf[1], pdpvt->buf[2], bTag); + return asynError; + } + payloadSize = pdpvt->buf[4] | + (pdpvt->buf[5] << 8) | + (pdpvt->buf[6] << 16) | + (pdpvt->buf[7] << 24); + if (payloadSize > (ioCount - BULK_IO_HEADER_SIZE)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Packet header claims %d sent, but packet contains only %d", + payloadSize, ioCount - BULK_IO_HEADER_SIZE); + return asynError; + } + if (payloadSize > BULK_IO_PAYLOAD_CAPACITY) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Packet header claims %d sent, but requested only %d", + payloadSize, BULK_IO_PAYLOAD_CAPACITY); + return asynError; + } + pdpvt->bufCount = payloadSize; + pdpvt->bufp = &pdpvt->buf[BULK_IO_HEADER_SIZE]; + + /* + * USB TMC uses a short packet to mark the end of a transfer + * It's not clear to me that the library exposes this short + * packet in the case following a read that just happens to + * finish on a pdpvt->buf sized boundary. For now I am assuming + * that I will, in fact, get a short packet following. + */ + pdpvt->bulkInPacketFlags = pdpvt->buf[8]; + } +} + +/* + * I see no mechanism for determining when it is necessary/possible to issue + * MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN requests and transfers from the bulk-IN + * endpoint. I welcome suggestions from libusb experts. + */ +static asynStatus +asynOctetFlush(void *pvt, asynUser *pasynUser) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + pdpvt->bufCount = 0; + pdpvt->bulkInPacketFlags = 0; + return asynSuccess; +} + +static asynStatus +asynOctetSetInputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + switch (eoslen) { + case 0: + pdpvt->termChar = -1; + break; + case 1: + if ((pdpvt->tmcDeviceCapabilities & 0x1) == 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Device does not support terminating characters"); + return asynError; + } + pdpvt->termChar = *eos & 0xFF; + break; + default: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Device does not support multiple terminating characters"); + return asynError; + } + return asynSuccess; +} + +static asynStatus +asynOctetGetInputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (pdpvt->termChar < 0) { + *eoslen = 0; + } + else { + if (eossize < 1) return asynError; + *eos = pdpvt->termChar; + *eoslen = 1; + } + return asynSuccess; +} + +static asynStatus +asynOctetSetOutputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) +{ + return asynError; +} + +static asynStatus +asynOctetGetOutputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) +{ + return asynError; +} + +static asynOctet octetMethods = { + .write = asynOctetWrite, + .read = asynOctetRead, + .flush = asynOctetFlush, + .setInputEos = asynOctetSetInputEos, + .getInputEos = asynOctetGetInputEos, + .setOutputEos = asynOctetSetOutputEos, + .getOutputEos = asynOctetGetOutputEos, +}; + +/* + * asynInt32 methods + */ +static asynStatus +asynInt32Write(void *pvt, asynUser *pasynUser, epicsInt32 value) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + int s; + asynStatus status; + unsigned char cbuf[1]; + + switch (pasynUser->reason) { + case ASYN_REASON_REN: + if ((pdpvt->usb488InterfaceCapabilities & 0x2) == 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Device does not support REN operations."); + return asynError; + } + s = libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + 160, // bRequest: HiSLIP REN_CONTROL + (value != 0), // wValue + pdpvt->bInterfaceNumber, // wIndex + cbuf, // data + 1, // wLength + 100); // timeout (ms) + status = checkControlTransfer("REN_CONTROL", pdpvt, pasynUser, + s, 1, cbuf[0]); + if (status != asynSuccess) + return status; + return asynSuccess; + + default: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "asynInt32Write -- invalid drvUser (reason) %d", pasynUser->reason); + return asynError; + } +} + +static asynStatus +asynInt32Read(void *pvt, asynUser *pasynUser, epicsInt32 *value) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + int s; + asynStatus status; + unsigned char cbuf[3]; + + switch (pasynUser->reason) { + case ASYN_REASON_STB: + if (pdpvt->interruptTid) { + /* Flush queue */ + epicsMessageQueueTryReceive(pdpvt->statusByteMessageQueue, cbuf, 1); + } + s = libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + 128, // bRequest: HiSLIP READ_STATUS_BYTE + 2, // wValue (bTag) + pdpvt->bInterfaceNumber, // wIndex + cbuf, // data + 3, // wLength + 100); // timeout (ms) + status = checkControlTransfer("READ_STATUS_BYTE", pdpvt, pasynUser, + s, 3, cbuf[0]); + if (status != asynSuccess) + return status; + + /* + * Value can be returned in three different ways + */ + if (pdpvt->interruptEndpointAddress == 0) { + /* + * 1 - Directly in the reply + */ + *value = cbuf[2]; + } + else if (pdpvt->interruptTid == 0) { + int n; + /* + * 2 - Read status here + */ + s = libusb_interrupt_transfer (pdpvt->handle, + pdpvt->interruptEndpointAddress, + cbuf, + 2, + &n, + 100); + if (s < 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_interrupt_transfer failed: %s", libusb_strerror(s)); + return asynError; + } + if (n != 2) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_interrupt_transfer got %d, expected 2", n); + return asynError; + } + if (cbuf[0] != 0x82) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "libusb_interrupt_transfer bTag 0x%x, expected 0x82", cbuf[0]); + return asynError; + } + *value = cbuf[1]; + } + else { + /* + * 3 - Read status in interrupt thread + */ + s = epicsMessageQueueReceiveWithTimeout( + pdpvt->statusByteMessageQueue, cbuf, 1, 0.2); + if (s != 1) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "No status byte from interrupt thread"); + return asynError; + } + *value = cbuf[0]; + } + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "READ_STATUS_BYTE: 0x%x\n", *value); + return asynSuccess; + + default: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "asynInt32Read -- invalid drvUser (reason) %d", pasynUser->reason); + return asynError; + } +} + +static asynInt32 int32Methods = { + .write = asynInt32Write, + .read = asynInt32Read, +}; + +/* + * drvUser methods + */ +static asynStatus +asynDrvUserCreate(void *pvt, asynUser *pasynUser, + const char *drvInfo, const char **pptypeName, size_t *psize) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (epicsStrCaseCmp(drvInfo, "SRQ") == 0) { + pasynUser->reason = ASYN_REASON_SRQ; + pdpvt->enableInterruptEndpoint = 1; + if (pdpvt->isConnected) + startInterruptThread(pdpvt); + } + else if (epicsStrCaseCmp(drvInfo, "REN") == 0) { + pasynUser->reason = ASYN_REASON_REN; + } + else if (epicsStrCaseCmp(drvInfo, "STB") == 0) { + pasynUser->reason = ASYN_REASON_STB; + } + return asynSuccess; +} + +static asynStatus +asynDrvUserGetType(void *drvPvt, asynUser *pasynUser, + const char **pptypeName, size_t *psize) +{ + return asynSuccess; +} + +static asynStatus +asynDrvUserDestroy(void *drvPvt, asynUser *pasynUser) +{ + return asynSuccess; +} + +static asynDrvUser drvUserMethods = { + .create = asynDrvUserCreate, + .getType = asynDrvUserGetType, + .destroy = asynDrvUserDestroy, +}; + +/* + * Device configuration + */ +void +usbtmcConfigure(const char *portName, + int vendorId, int productId, const char *serialNumber, + int priority, int flags) +{ + drvPvt *pdpvt; + int s; + asynStatus status; + + /* + * Set up local storage + */ + pdpvt = (drvPvt *)callocMustSucceed(1, sizeof(drvPvt), portName); + pdpvt->portName = epicsStrDup(portName); + pdpvt->interruptThreadName = callocMustSucceed(1, strlen(portName)+5, portName); + epicsSnprintf(pdpvt->interruptThreadName, sizeof pdpvt->interruptThreadName, "%sIntr", portName); + if (priority == 0) priority = epicsThreadPriorityMedium; + s = libusb_init(&pdpvt->usb); + if (s != 0) { + printf("libusb_init() failed: %s\n", libusb_strerror(s)); + return; + } + if ((serialNumber == NULL) || (*serialNumber == '\0')) { + if ((vendorId == 0) && (productId == 0)) + printf("No device information specified. Will connect to first USB TMC device found.\n"); + else if (vendorId == 0) + printf("Will connect to first USB TMC device found with product ID %#4.4x.\n", productId); + else if (productId == 0) + printf("Will connect to first USB TMC device found with vendor ID %#4.4x.\n", vendorId); + else + printf("Will connect to first USB TMC device found with vendor ID %#4.4x and product ID %#4.4x.\n", vendorId, productId); + } + pdpvt->vendorId = vendorId; + pdpvt->productId = productId; + if (serialNumber && *serialNumber) + pdpvt->serialNumber = epicsStrDup(serialNumber); + else + pdpvt->serialNumber = NULL; + pdpvt->termChar = -1; + pdpvt->bTag = 1; + pdpvt->interruptTidMutex = epicsMutexMustCreate(); + pdpvt->pleaseTerminate = epicsEventMustCreate(epicsEventEmpty); + pdpvt->didTerminate = epicsEventMustCreate(epicsEventEmpty); + pdpvt->statusByteMessageQueue = epicsMessageQueueCreate(1, 1); + if (!pdpvt->statusByteMessageQueue) { + printf("Can't create message queue!\n"); + return; + } + + /* + * Create our port + */ + status = pasynManager->registerPort(pdpvt->portName, + ASYN_CANBLOCK, + (flags & 0x1) == 0, + priority, 0); + if(status != asynSuccess) { + printf("registerPort failed\n"); + return; + } + + /* + * Register ASYN interfaces + */ + pdpvt->asynCommon.interfaceType = asynCommonType; + pdpvt->asynCommon.pinterface = &commonMethods; + pdpvt->asynCommon.drvPvt = pdpvt; + status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynCommon); + if (status != asynSuccess) { + printf("registerInterface failed\n"); + return; + } + + pdpvt->asynOctet.interfaceType = asynOctetType; + pdpvt->asynOctet.pinterface = &octetMethods; + pdpvt->asynOctet.drvPvt = pdpvt; + status = pasynOctetBase->initialize(pdpvt->portName, &pdpvt->asynOctet, 0, 0, 0); + if (status != asynSuccess) { + printf("pasynOctetBase->initialize failed\n"); + return; + } + + pdpvt->asynInt32.interfaceType = asynInt32Type; + pdpvt->asynInt32.pinterface = &int32Methods; + pdpvt->asynInt32.drvPvt = pdpvt; + status = pasynInt32Base->initialize(pdpvt->portName, &pdpvt->asynInt32); + if (status != asynSuccess) { + printf("pasynInt32Base->initialize failed\n"); + return; + } + + /* + * Always register an interrupt source, just in case we use SRQs + */ + pasynManager->registerInterruptSource(pdpvt->portName, + &pdpvt->asynInt32, + &pdpvt->asynInt32InterruptPvt); + + pdpvt->asynDrvUser.interfaceType = asynDrvUserType; + pdpvt->asynDrvUser.pinterface = &drvUserMethods; + pdpvt->asynDrvUser.drvPvt = pdpvt; + status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynDrvUser); + if (status != asynSuccess) { + printf("Can't register drvUser\n"); + return; + } +} + +/* + * IOC shell command registration + */ +static const iocshArg usbtmcConfigureArg0 = {"port name", iocshArgString}; +static const iocshArg usbtmcConfigureArg1 = {"vendor ID number", iocshArgInt}; +static const iocshArg usbtmcConfigureArg2 = {"product ID number", iocshArgInt}; +static const iocshArg usbtmcConfigureArg3 = {"serial string", iocshArgString}; +static const iocshArg usbtmcConfigureArg4 = {"priority", iocshArgInt}; +static const iocshArg usbtmcConfigureArg5 = {"flags", iocshArgInt}; +static const iocshArg *usbtmcConfigureArgs[] = {&usbtmcConfigureArg0, + &usbtmcConfigureArg1, + &usbtmcConfigureArg2, + &usbtmcConfigureArg3, + &usbtmcConfigureArg4, + &usbtmcConfigureArg5}; +static const iocshFuncDef usbtmcConfigureFuncDef = {"usbtmcConfigure",6,usbtmcConfigureArgs}; +static void usbtmcConfigureCallFunc(const iocshArgBuf *args) +{ + usbtmcConfigure (args[0].sval, + args[1].ival, args[2].ival, args[3].sval, + args[4].ival, args[5].ival); +} + +/* + * This routine is called before multitasking has started, so there's + * no race condition in the test/set of firstTime. + */ +static void usbtmcRegisterCommands (void) +{ + static int firstTime = 1; + if (firstTime) { + firstTime = 0; + iocshRegister(&usbtmcConfigureFuncDef, usbtmcConfigureCallFunc); + } +} +epicsExportRegistrar(usbtmcRegisterCommands); diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.dbd b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.dbd new file mode 100644 index 000000000..c3bd03f38 --- /dev/null +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.dbd @@ -0,0 +1 @@ +registrar(HiSLIPRegisterCommands) diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h new file mode 100644 index 000000000..e9f616f1b --- /dev/null +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h @@ -0,0 +1,99 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +//-*- coding:utf-8 -*- +/* struct HiSLIPFatalError:Exception; // Exception raised up for HiSLIP fatal errors */ + +/* struct HiSLIPError:Exception; */ + +/* struct _HiSLIP; */ + +/* struct HiSLIP:_HiSLIP; */ + +//constants + +typedef enum CC_reuqest{ + RemoteDisable=0, + RemoteEnable=1, + RemoteDisableGTL=2, // disable remote and goto local + RemoteEnableGTR=3, // Enable remote and goto remote + RemoteEnableLLO=4, // Enable remote and lock out local + RemoteEnableGTRLLO=5, // + RTL=6 +} CC_request_t; + +typedef enum CC_Lock{ + release =0, + request =1 +} CC_Lock_t; + +typedef enum CC_LockResponse{ + fail=0, //Lock was requested but not granted + success=1, //release of exclusive lock + success_shared=2, //release of shared lock + error=3 // Invalide +} CC_LockResponse_t; + +static const long HiSLIP_PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 +static const long HiSLIP_INITIAL_MESSAGE_ID = 0xffffff00 ; +static const long HiSLIP_UNKNOWN_MESSAGE_ID = 0xffffffff ; +static const long HiSLIP_MAXIMUM_MESSAGE_SIZE = 272; //# Following VISA 256 bytes + header length 16 bytes +static const long HiSLIP_SOCKET_TIMEOUT = 1; //# Socket timeout +static const long HiSLIP_LOCK_TIMEOUT = 3000;//# Lock timeout +static const long HiSLIP_Default_Port=4880; +// +typedef enum HiSLIP_Message_Types{ + Initialize = 0, + InitializeResponse = 1, + FatalError = 2, + Error = 3, + AsyncLock = 4, + AsyncLockResponse = 5, + Data = 6, + DataEnd = 7, + DeviceClearComplete = 8, + DeviceClearAcknowledge = 9, + AsyncRemoteLocalControl = 10, + AsyncRemoteLocalResponse = 11, + Trigger = 12, + Interrupted = 13, + AsyncInterrupted = 14, + AsyncMaximumMessageSize = 15, + AsyncMaximumMessageSizeResponse = 16, + AsyncInitialize = 17, + AsyncInitializeResponse = 18, + AsyncDeviceClear = 19, + AsyncServiceRequest = 20, + AsyncStatusQuery = 21, + AsyncStatusResponse = 22, + AsyncDeviceClearAcknowledge = 23, + AsyncLockInfo = 24, + AsyncLockInfoResponse = 25 +} HiSLIP_Message_Types_t; + +static const char *HiSLIP_Error_Messages[] = { + "Unidentified error", + "Unrecognized Message Type", + "Unrecognized control code", + "Unrecognized Vendor Defined Message", + "Message too large" +}; + +static const char *HiSLIP_Fatal_Error_Messages[] = { + "Unidentified error", + "Poorly formed message header", + "Attempt to use connection without both channels established", + "Invalid Initialization Sequence", + "Server refused connection due to maximum number of clients exceeded" +}; + + From c4d6c2cb3591cdfb4c0e075d87f50fc0e3ae3bb3 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 8 May 2020 17:50:31 +0900 Subject: [PATCH 02/67] update Readme in drvAsynHiSLIP --- asyn/Makefile | 10 ++++++++++ asyn/drvAsynHiSLIP/README.txt | 22 +++++----------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/asyn/Makefile b/asyn/Makefile index 7ce295c81..7f84d5d27 100644 --- a/asyn/Makefile +++ b/asyn/Makefile @@ -257,6 +257,16 @@ ifeq ($(DRV_USBTMC),YES) DBD += drvAsynUSBTMC.dbd endif + +DRV_HISLIP = YES + +ifeq ($(DRV_HISLIP),YES) + SRC_DIRS += $(ASYN)/drvAsynHiSLIP + asyn_SRCS += drvAsynHiSLIP.c + DBD += drvAsynHiSLIP.dbd + INC += drvAsynHiSLIP.h +endif + ifeq ($(DRV_FTDI),YES) SRC_DIRS += $(ASYN)/drvAsynFTDI asyn_SRCS += ftdiDriver.cpp drvAsynFTDIPort.cpp diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt index 5f6da0533..d35e2863f 100644 --- a/asyn/drvAsynHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/README.txt @@ -1,27 +1,15 @@ - EPICS ASYN support for USB TMC (Test and Measurement Class) devices + EPICS ASYN support for HiSLIP device =============================================================================== Based on: - 1) "Universal Serial Bus Test and Measurement Class Specification (USBTMC)", - Revision 1.0. - 2) "Universal Serial Bus Test and Measurement Class, Subclass USB488 - Specification (USBTMC-USB488)", Revision 1.0. + 1) IVI-6.1: IVI High-Speed LAN Instument Protocol -Requires libusb-1.0, available from: http://www.libusb.org/ - For best results use version 16 or higher. Build Issues ============ -1. Linker reports that libusb_strerror is undefined? - Check if you have multiple versions of libusb-1.0 installed. The build - system may be finding the header for a newer version (that does supply - libusb_strerror) but then links against an older library (that does not - supply libusb_strerror). Acknowledgements ================ -Thanks go out to Florian Sorgenfrei and Damien Lynch for -their patience and suggestions in testing this code. - - -Eric Norum +This is based on USB TMC support by Eric Norum . +And also PyHiSLIP modules by Levshinovskiy Mikhail(https://github.com/llemish/PyHiSLIP) is used +as a reference for the implementation. From 6c1cbb4776bc30387176c5eea00204b06f165cb1 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 15 May 2020 16:46:55 +0900 Subject: [PATCH 03/67] remove asynInt32xxx methods. --- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 844 +++++++++++++++++++++++++++ 1 file changed, 844 insertions(+) create mode 100644 asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp new file mode 100644 index 000000000..36a2cf8ab --- /dev/null +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -0,0 +1,844 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +#include "drvAsynHiSLIP.h" + +using nsHiSLIP::CC_request_t; +using nsHiSLIP::CC_Lock_t; +using nsHiSLIP::HiSLIP_t; +using nsHiSLIP::HiSLIP; +using nsHiSLIP::Message_t; + +#define BULK_IO_HEADER_SIZE 16 +#define BULK_IO_PAYLOAD_CAPACITY 4096 +#define IDSTRING_CAPACITY 100 + +#define ASYN_REASON_SRQ 4345 +#define ASYN_REASON_STB 4346 +#define ASYN_REASON_REN 4347 + +// HiSLIP methods + void HiSLIP::connect(const char *hostname, const char *dev_name, const int port, const char *vendor_id){ + osiSockAddr addr; + Message_t *msg,*resp; + int status; + + if(hostToIPAddr(hostname, &addr.ia.sin_addr) < 0) { + errlogPrintf("Unknown host \"%s\"", hostname); + } + + addr.ia.sin_port=htons(port); + addr.ia.sin_family=AF_INET; + + this->sync_channel= ::socket(AF_INET, SOCK_STREAM, 0); + this->async_channel=::socket(AF_INET, SOCK_STREAM, 0); + + status = ::connect(this->sync_channel, &addr.sa, sizeof(addr)); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + status = ::connect(this->async_channel, &addr.sa, sizeof(addr)); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + + msg= new Message(); + + msg->message_type=nsHiSLIP::Initialize; + msg->message_parameter.initParm.protocol_version=nsHiSLIP::PROTOCOL_VERSION_MAX; + memcpy(msg->message_parameter.initParm.vendor_id, vendor_id,2); + msg->send(this->sync_channel); + + resp=new Message(); + resp->recv(this->sync_channel, nsHiSLIP::InitializeResponse); + this->overlap_mode=resp->control_code; + this->session_id=resp->message_parameter.initResp.session_id; + this->server_protocol_version=resp->message_parameter.initResp.protocol_version; + + msg= new Message(nsHiSLIP::AsyncInitialize); + msg->message_parameter.word=this->session_id; + msg->send(this->sync_channel); + + resp=new Message(); + resp->recv(this->sync_channel, nsHiSLIP::AsyncInitializeResponse); + this->overlap_mode=resp->control_code; + this->session_id=resp->message_parameter.initResp.session_id; + this->server_vendorID=resp->message_parameter.word; + + this->sync_poll.fd=this->sync_channel; + this->sync_poll.events=POLLIN; + this->sync_poll.revents=0; + + this->async_poll.fd=this->async_channel; + this->async_poll.events=POLLIN; + this->async_poll.revents=0; + + + }; + +long HiSLIP::set_max_size(long message_size){ + Message *resp; + epicsUInt64 msg_size=htobe64(message_size); + + Message *msg=new Message(nsHiSLIP::AsyncMaximumMessageSize, + 0, + new message_parameter(0), + sizeof(msg_size),&msg_size); + + msg->send(this->async_channel); + + resp->recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + + this->maximum_message_size=*((epicsUInt64 *)(resp->payload)); + return this->maximum_message_size; + +}; + +asynStatus HiSLIP::device_clear(){ + Message resp; + epicsUInt8 feature_preference; + + Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, + 0, + 0, + 0,NULL); + + msg->send(this->async_channel); + + resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + feature_preference=resp.control_code; + + msg=new Message(nsHiSLIP::DeviceClearComplete, + feature_preference, + 0, + 0, NULL); + + msg->send(this->sync_channel); + + resp.recv(this->async_channel,nsHiSLIP::DeviceClearAcknowledge); + + this->overlap_mode=resp.control_code; + this->reset_message_id(); + this->rmt_delivered = false; + + return asynSuccess; + +}; + +epicsUInt8 HiSLIP::status_query(){ + epicsUInt8 status; + Message resp; + + Message *msg=new Message((epicsUInt8) nsHiSLIP::AsyncStatusQuery, + (epicsUInt8) this->rmt_delivered, + new nsHiSLIP::message_parameter((epicsUInt32) this->most_recent_message_id), + 0, NULL); + msg->send(this->async_channel); + + resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); + status= resp.control_code &0xff; + return status; +} + + // EPICS Async Support +typedef struct drvPvt { + /* + * Matched device + * HiSLIP private + */ + + HiSLIP_t *device; + const char *hostname; + const long port; + bool isConnected; + int termChar; + + char deviceVendorID[IDSTRING_CAPACITY]; + + /* + * Asyn interfaces we provide + */ + char *portName; + asynInterface asynCommon; + asynInterface asynOctet; + void *asynOctetInterruptPvt; + // asynInterface asynInt32; + // void *asynInt32InterruptPvt; + asynInterface asynDrvUser; + + /* + * Interrupt endpoint handling + */ + char *interruptThreadName; + epicsThreadId interruptTid; + epicsMutexId interruptTidMutex; + epicsEventId pleaseTerminate; + epicsEventId didTerminate; + epicsMessageQueueId statusByteMessageQueue; + + /* + * I/O buffer + */ + unsigned char buf[BULK_IO_HEADER_SIZE+BULK_IO_PAYLOAD_CAPACITY]; + int bufCount; + const unsigned char *bufp; + unsigned char bulkInPacketFlags; + + /* + * Statistics + */ + size_t connectionCount; + size_t interruptCount; + size_t bytesSentCount; + size_t bytesReceivedCount; +} drvPvt; + +static asynStatus disconnect(void *pvt, asynUser *pasynUser); + + +/* + * Interrupt endpoint support + */ +static void +interruptThread(void *arg) +{ + drvPvt *pdpvt = (drvPvt *)arg; + int s; + + for (;;) { + s = pdpvt->device->wait_for_SRQ(65000); + + if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK) + break; + + Message_t srqmsg=pdpvt->device->get_Service_Request(); + epicsUInt8 st =srqmsg.control_code; + + if ((s == 0)&& (st != 0)){ + if (st == 0x81) { + ELLLIST *pclientList; + interruptNode *pnode; + + pdpvt->interruptCount++; + pasynManager->interruptStart(pdpvt->asynOctetInterruptPvt, &pclientList); + pnode = (interruptNode *)ellFirst(pclientList); + while (pnode) { + asynOctetInterrupt *int32Interrupt = (asynOctetInterrupt *) pnode->drvPvt; + pnode = (interruptNode *)ellNext(&pnode->node); + if (int32Interrupt->pasynUser->reason == ASYN_REASON_SRQ) { + int32Interrupt->callback(int32Interrupt->userPvt, + int32Interrupt->pasynUser, + st); + } + } + pasynManager->interruptEnd(pdpvt->asynOctetInterruptPvt); + } + else if (st== 0x82) { + if (epicsMessageQueueTrySend(pdpvt->statusByteMessageQueue, + &st, 1) != 0) { + errlogPrintf("----- WARNING ----- " + "Can't send status byte to worker thread!\n"); + } + } + } + else if (NULL){ + errlogPrintf("----- WARNING ----- " + "libusb_interrupt_transfer failed (%s). " + "Interrupt thread for ASYN port \"%s\" terminating.\n", + nsHiSLIP::Error_Messages[s], pdpvt->portName); + break; + } + } + epicsMutexLock(pdpvt->interruptTidMutex); + pdpvt->interruptTid = 0; + epicsEventSignal(pdpvt->didTerminate); + epicsMutexUnlock(pdpvt->interruptTidMutex); +} + +static void +startInterruptThread(drvPvt *pdpvt) +{ + epicsMutexLock(pdpvt->interruptTidMutex); + if ((pdpvt->interruptTid == 0)) { + epicsEventTryWait(pdpvt->pleaseTerminate); + epicsEventTryWait(pdpvt->didTerminate); + pdpvt->interruptTid = epicsThreadCreate(pdpvt->interruptThreadName, + epicsThreadGetPrioritySelf(), + epicsThreadGetStackSize(epicsThreadStackSmall), + interruptThread, pdpvt); + if (pdpvt->interruptTid == 0) + errlogPrintf("----- WARNING ----- " + "Can't start interrupt handler thread %s.\n", + pdpvt->interruptThreadName); + } + epicsMutexUnlock(pdpvt->interruptTidMutex); +} + +/* + * Decode a status byte + */ +static void +showHexval(FILE *fp, const char *name, int val, int bitmask, const char *bitname, ...) +{ + const char *sep = " -- "; + va_list ap; + va_start(ap, bitname); + fprintf(fp, "%28s: ", name); + if (bitmask) + fprintf(fp, "%#x", val); + else + fprintf(fp, "%#4.4x", val); + for (;;) { + if (((bitmask > 0) && ((val & bitmask)) != 0) + || ((bitmask < 0) && ((val & -bitmask)) == 0) + || ((bitmask == 0) && (bitname != NULL) && (bitname[0] != '\0'))) { + fprintf(fp, "%s%s", sep, bitname); + sep = ", "; + } + if (bitmask == 0) + break; + bitmask = va_arg(ap, int); + if (bitmask == 0) + break; + bitname = va_arg(ap, char *); + } + fprintf(fp, "\n"); + va_end(ap); +} + +/* + * Show a byte number + */ +static void +pcomma(FILE *fp, size_t n) +{ + if (n < 1000) { + fprintf(fp, "%zu", n); + return; + } + pcomma(fp, n/1000); + fprintf(fp, ",%03zu", n%1000); +} + +static void +showCount(FILE *fp, const char *label, size_t count) +{ + fprintf(fp, "%22s Count: ", label); + pcomma(fp, count); + fprintf(fp, "\n"); +} + +/* + * asynCommon methods + */ +static void +report(void *pvt, FILE *fp, int details) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + fprintf(fp, "%20sonnected, Interrupt handler thread %sactive\n", + pdpvt->isConnected ? "C" : "Disc", + pdpvt->interruptTid ? "" : "in"); + if (details > 0) { + if (pdpvt->termChar >= 0) + fprintf(fp, "%28s: %x\n", "Terminator", pdpvt->termChar); + } + if (details > 1) { + showCount(fp, "Connection", pdpvt->connectionCount); + showCount(fp, "Interrupt", pdpvt->interruptCount); + showCount(fp, "Send", pdpvt->bytesSentCount); + showCount(fp, "Receive", pdpvt->bytesReceivedCount); + } + if (details >= 100) { + int l = details % 100; + fprintf(fp, "==== Set libusb debug level %d ====\n", l); + } +}; + +/* + * Disconnect when it appears that device has gone away + */ +static void +disconnectIfGone(drvPvt *pdpvt, asynUser *pasynUser, int s) +{ + if(s == nsHiSLIP::ServerRefusedConnection){ + disconnect(pdpvt, pasynUser); + } +} + +/* + * Check results of control transfer + */ +/* + * Clear input/output buffers + */ +static asynStatus +clearBuffers(drvPvt *pdpvt, asynUser *pasynUser) +{ + int s; + asynStatus status; + int pass = 0; + + status = pdpvt->device->device_clear(); + if (status != asynSuccess) + return status; + for (;;) { + epicsThreadSleep(0.01); + // I don't know why this is necessary, but without some delay here the CHECK_CLEAR_STATUS seems to be stuck at STATUS_PENDING + status = pdpvt->device->device_clear(); + if (status != asynSuccess) + return asynError; + switch (++pass) { + case 5: + asynPrint(pasynUser, ASYN_TRACE_ERROR, "Note -- RESET DEVICE.\n"); + //s = libusb_reset_device(pdpvt->handle); + status = pdpvt->device->device_clear(); + if (s != 0) { + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "hislip_reset_device() failed: %s", + nsHiSLIP::Error_Messages[s]); + return asynError; + } + break; + + case 10: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "CHECK_CLEAR_STATUS remained 'STATUS_PENDING' for too long"); + return asynError; + } + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "Note -- retrying CHECK_CLEAR_STATUS\n"); + } + return asynSuccess; +} + +static asynStatus +connect(void *pvt, asynUser *pasynUser) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (!pdpvt->isConnected) { + pdpvt->device->connect(pdpvt->hostname); + } + pdpvt->isConnected = 1; + pasynManager->exceptionConnect(pasynUser); + return asynSuccess; +} + +static asynStatus +disconnect(void *pvt, asynUser *pasynUser) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (pdpvt->isConnected) { + int pass = 0; + epicsThreadId tid; + for (;;) { + + epicsMutexLock(pdpvt->interruptTidMutex); + tid = pdpvt->interruptTid; + epicsMutexUnlock(pdpvt->interruptTidMutex); + if (tid == 0) + break; + if (++pass == 10) { + errlogPrintf("----- WARNING ----- Thread %s won't terminate!\n", + pdpvt->interruptThreadName); + break; + } + + /* + * Send signal then force an Interrupt-In message + */ + epicsEventSignal(pdpvt->pleaseTerminate); + pdpvt->device->status_query(); + // libusb_control_transfer(pdpvt->handle, + // 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + // 128, // bRequest: READ_STATUS_BYTE + // 127, // wValue (bTag) + // pdpvt->bInterfaceNumber, // wIndex + // cbuf, // data + // 3, // wLength + // 100); // timeout (ms) + epicsEventWaitWithTimeout(pdpvt->didTerminate, 2.0); + } + pdpvt->device->disconnect(); + } + pdpvt->isConnected = 0; + pasynManager->exceptionDisconnect(pasynUser); + return asynSuccess; +} +static asynCommon commonMethods = { report, connect, disconnect }; + +/* + * asynOctet methods + */ +static asynStatus +asynOctetWrite(void *pvt, asynUser *pasynUser, + const char *data, size_t numchars, size_t *nbytesTransfered) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + int timeout = pasynUser->timeout * 1000; + if (timeout == 0) timeout = 1; + + /* + * Common to all writes + */ + + /* + * Send + */ + *nbytesTransfered = 0; + while (numchars) { + int nSend, pkSend, pkSent; + int s; + s = pdpvt->device->write( pdpvt->buf, timeout); + + if (s) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Bulk transfer failed: %s", + nsHiSLIP::Error_Messages[s]); + return asynError; + } + if (s!= nSend) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Asked to send %d, actually sent %d", pkSend, pkSent); + return asynError; + } + data += nSend; + numchars -= nSend; + *nbytesTransfered += nSend; + } + pdpvt->bytesSentCount += *nbytesTransfered; + return asynSuccess; +} + +static asynStatus +asynOctetRead(void *pvt, asynUser *pasynUser, + char *data, size_t maxchars, size_t *nbytesTransfered, + int *eomReason) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + unsigned char bTag; + int s; + int nCopy, ioCount, payloadSize; + int eom = 0; + int timeout = pasynUser->timeout * 1000; + if (timeout == 0) timeout = 1; + + *nbytesTransfered = 0; + for (;;) { + /* + * Special case for stream device which requires an asynTimeout return. + */ + ioCount = pdpvt->device->read( + data, BULK_IO_HEADER_SIZE, + timeout); + if (s) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "Bulk transfer request failed: %s", + nsHiSLIP::Error_Message[s]); + return asynError; + } + + /* + * Read back + */ + s = pdpvt->device.read(sizeof pdpvt->buf, &ioCount, timeout); + + if (s) { + disconnectIfGone(pdpvt, pasynUser, s); + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "Bulk read failed: %s", + nsHiSLIP::Error_Messages[2]); + return asynError; + } + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, + ioCount, "Read %d, flags %#x: ", ioCount, pdpvt->buf[8]); + + /* + * Sanity check on transfer + */ + if (ioCount < BULK_IO_HEADER_SIZE) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Incomplete packet header (read only %d)", ioCount); + return asynError; + } + if (payloadSize > (ioCount - BULK_IO_HEADER_SIZE)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Packet header claims %d sent, but packet contains only %d", + payloadSize, ioCount - BULK_IO_HEADER_SIZE); + return asynError; + } + if (payloadSize > BULK_IO_PAYLOAD_CAPACITY) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Packet header claims %d sent, but requested only %d", + payloadSize, BULK_IO_PAYLOAD_CAPACITY); + return asynError; + } + pdpvt->bufCount = payloadSize; + } +} + +/* + * I see no mechanism for determining when it is necessary/possible to issue + * MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN requests and transfers from the bulk-IN + * endpoint. I welcome suggestions from libusb experts. + */ +static asynStatus +asynOctetFlush(void *pvt, asynUser *pasynUser) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + pdpvt->bufCount = 0; + pdpvt->bulkInPacketFlags = 0; + return asynSuccess; +} + +static asynStatus +asynOctetSetInputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + switch (eoslen) { + case 0: + pdpvt->termChar = -1; + break; + case 1: + if ((pdpvt->tmcDeviceCapabilities & 0x1) == 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Device does not support terminating characters"); + return asynError; + } + pdpvt->termChar = *eos & 0xFF; + break; + default: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Device does not support multiple terminating characters"); + return asynError; + } + return asynSuccess; +} + +static asynStatus +asynOctetGetInputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (pdpvt->termChar < 0) { + *eoslen = 0; + } + else { + if (eossize < 1) return asynError; + *eos = pdpvt->termChar; + *eoslen = 1; + } + return asynSuccess; +} + +static asynStatus +asynOctetSetOutputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) +{ + return asynError; +} + +static asynStatus +asynOctetGetOutputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) +{ + return asynError; +} + +static asynOctet octetMethods = { + .write = asynOctetWrite, + .read = asynOctetRead, + .flush = asynOctetFlush, + .setInputEos = asynOctetSetInputEos, + .getInputEos = asynOctetGetInputEos, + .setOutputEos = asynOctetSetOutputEos, + .getOutputEos = asynOctetGetOutputEos, +}; + +/* + * drvUser methods + */ +static asynStatus +asynDrvUserCreate(void *pvt, asynUser *pasynUser, + const char *drvInfo, const char **pptypeName, size_t *psize) +{ + drvPvt *pdpvt = (drvPvt *)pvt; + + if (epicsStrCaseCmp(drvInfo, "SRQ") == 0) { + pasynUser->reason = ASYN_REASON_SRQ; + pdpvt->enableInterruptEndpoint = 1; + if (pdpvt->isConnected) + startInterruptThread(pdpvt); + } + else if (epicsStrCaseCmp(drvInfo, "REN") == 0) { + pasynUser->reason = ASYN_REASON_REN; + } + else if (epicsStrCaseCmp(drvInfo, "STB") == 0) { + pasynUser->reason = ASYN_REASON_STB; + } + return asynSuccess; +} + +static asynStatus +asynDrvUserGetType(void *drvPvt, asynUser *pasynUser, + const char **pptypeName, size_t *psize) +{ + return asynSuccess; +} + +static asynStatus +asynDrvUserDestroy(void *drvPvt, asynUser *pasynUser) +{ + return asynSuccess; +} + +static asynDrvUser drvUserMethods = { + .create = asynDrvUserCreate, + .getType = asynDrvUserGetType, + .destroy = asynDrvUserDestroy, +}; + +/* + * Device configuration + */ +void +HiSLIPConfigure(const char *portName, + const char *hostInfo, + int priority) +{ + drvPvt *pdpvt; + int s; + asynStatus status; + int flags=0; + + /* + * Set up local storage + */ + pdpvt = (drvPvt *)callocMustSucceed(1, sizeof(drvPvt), portName); + pdpvt->portName = epicsStrDup(portName); + pdpvt->interruptThreadName = callocMustSucceed(1, strlen(portName)+5, portName); + epicsSnprintf(pdpvt->interruptThreadName, sizeof pdpvt->interruptThreadName, + "%sIntr", portName); + if (priority == 0) priority = epicsThreadPriorityMedium; + pdpvt->device=new HiSLIP_t(hostInfo); + if (s != 0) { + printf("libusb_init() failed: %s\n", nsHiSLIP::Error_Messages[2]); + return; + } + + pdpvt->termChar = -1; + pdpvt->interruptTidMutex = epicsMutexMustCreate(); + pdpvt->pleaseTerminate = epicsEventMustCreate(epicsEventEmpty); + pdpvt->didTerminate = epicsEventMustCreate(epicsEventEmpty); + pdpvt->statusByteMessageQueue = epicsMessageQueueCreate(1, 1); + if (!pdpvt->statusByteMessageQueue) { + printf("Can't create message queue!\n"); + return; + } + + /* + * Create our port + */ + status = pasynManager->registerPort(pdpvt->portName, + ASYN_CANBLOCK, + (flags & 0x1) == 0, + priority, 0); + if(status != asynSuccess) { + printf("registerPort failed\n"); + return; + } + + /* + * Register ASYN interfaces + */ + pdpvt->asynCommon.interfaceType = asynCommonType; + pdpvt->asynCommon.pinterface = &commonMethods; + pdpvt->asynCommon.drvPvt = pdpvt; + status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynCommon); + if (status != asynSuccess) { + printf("registerInterface failed\n"); + return; + } + + pdpvt->asynOctet.interfaceType = asynOctetType; + pdpvt->asynOctet.pinterface = &octetMethods; + pdpvt->asynOctet.drvPvt = pdpvt; + status = pasynOctetBase->initialize(pdpvt->portName, &pdpvt->asynOctet, 0, 0, 0); + if (status != asynSuccess) { + printf("pasynOctetBase->initialize failed\n"); + return; + } + + /* + * Always register an interrupt source, just in case we use SRQs + */ + pasynManager->registerInterruptSource(pdpvt->portName, + &pdpvt->asynOctet, + &pdpvt->asynOctetInterruptPvt); + + pdpvt->asynDrvUser.interfaceType = asynDrvUserType; + pdpvt->asynDrvUser.pinterface = &drvUserMethods; + pdpvt->asynDrvUser.drvPvt = pdpvt; + status = pasynManager->registerInterface(pdpvt->portName, + &pdpvt->asynDrvUser); + if (status != asynSuccess) { + printf("Can't register drvUser\n"); + return; + } +} + +/* + * IOC shell command registration + */ +static const iocshArg HiSLIPConfigureArg0 = {"port name", + iocshArgString}; +static const iocshArg HiSLIPConfigureArg1 = {"HiSLIP host addressr", + iocshArgString}; +static const iocshArg HiSLIPConfigureArg2 = {"priority", + iocshArgInt}; +static const iocshArg *HiSLIPConfigureArgs[] = { + &HiSLIPConfigureArg0 + , &HiSLIPConfigureArg1 + , &HiSLIPConfigureArg2 +} + + static const iocshFuncDef HiSLIPConfigureFuncDef = + {"HiSLIPConfigure", 3, HiSLIPConfigureArgs}; + +static void HiSLIPConfigureCallFunc(const iocshArgBuf *args) +{ + HiSLIPConfigure (args[0].sval, + args[1].sval, args[2].ival) +} + +/* + * This routine is called before multitasking has started, so there's + * no race condition in the test/set of firstTime. + */ +static void HiSLIPRegisterCommands (void) +{ + static int firstTime = 1; + if (firstTime) { + firstTime = 0; + iocshRegister(&HiSLIPConfigureFuncDef, HiSLIPConfigureCallFunc); + } +} +epicsExportRegistrar(HiSLIPRegisterCommands); From 655acdbc30ebc6b984fa68b5f7a7aec61a4193ff Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 23 May 2020 14:20:27 +0900 Subject: [PATCH 04/67] read/write message from a HiSLIP device. --- asyn/Makefile | 5 +- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 985 +++++++++++++++++---------- asyn/drvAsynHiSLIP/drvAsynHiSLIP.h | 535 ++++++++++++--- 3 files changed, 1093 insertions(+), 432 deletions(-) diff --git a/asyn/Makefile b/asyn/Makefile index 7f84d5d27..4d75891d2 100644 --- a/asyn/Makefile +++ b/asyn/Makefile @@ -258,11 +258,10 @@ ifeq ($(DRV_USBTMC),YES) endif -DRV_HISLIP = YES - ifeq ($(DRV_HISLIP),YES) + USR_CXXFLAGS += -fpermissive SRC_DIRS += $(ASYN)/drvAsynHiSLIP - asyn_SRCS += drvAsynHiSLIP.c + asyn_SRCS += drvAsynHiSLIP.cpp DBD += drvAsynHiSLIP.dbd INC += drvAsynHiSLIP.h endif diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index 36a2cf8ab..e1dd43428 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -18,8 +18,7 @@ using nsHiSLIP::HiSLIP_t; using nsHiSLIP::HiSLIP; using nsHiSLIP::Message_t; -#define BULK_IO_HEADER_SIZE 16 -#define BULK_IO_PAYLOAD_CAPACITY 4096 +#define MAX_PAYLOAD_CAPACITY 4096 #define IDSTRING_CAPACITY 100 #define ASYN_REASON_SRQ 4345 @@ -27,131 +26,414 @@ using nsHiSLIP::Message_t; #define ASYN_REASON_REN 4347 // HiSLIP methods - void HiSLIP::connect(const char *hostname, const char *dev_name, const int port, const char *vendor_id){ - osiSockAddr addr; - Message_t *msg,*resp; - int status; +namespace nsHiSLIP{ + void HiSLIP::connect(const char *hostname, + const char *dev_name, + const int port //, + //const char vendor_id[2] + ){ + osiSockAddr addr; + //Message_t *msg; + int status; + //const char vendor_id[]=Default_vendor_id; - if(hostToIPAddr(hostname, &addr.ia.sin_addr) < 0) { - errlogPrintf("Unknown host \"%s\"", hostname); - } + errlogPrintf("connecting to host \"%s\"\n", hostname); + + if(hostToIPAddr(hostname, &addr.ia.sin_addr) < 0) { + errlogPrintf("Unknown host \"%s\"", hostname); + } - addr.ia.sin_port=htons(port); - addr.ia.sin_family=AF_INET; + addr.ia.sin_port=htons(port); + addr.ia.sin_family=AF_INET; - this->sync_channel= ::socket(AF_INET, SOCK_STREAM, 0); - this->async_channel=::socket(AF_INET, SOCK_STREAM, 0); + errlogPrintf("address : %x %x %x\n",addr.ia.sin_addr.s_addr,addr.ia.sin_port, + addr.ia.sin_family); - status = ::connect(this->sync_channel, &addr.sa, sizeof(addr)); - if (status!=0){ - // Error handling - perror(__FUNCTION__); - } - status = ::connect(this->async_channel, &addr.sa, sizeof(addr)); - if (status!=0){ - // Error handling - perror(__FUNCTION__); - } + //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); + this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); + + errlogPrintf("socceks created %d %d\n",this->sync_channel, this->async_channel); + + errlogPrintf("address : %x %x %x\n",addr.ia.sin_addr.s_addr,addr.ia.sin_port, + addr.ia.sin_family); - msg= new Message(); + status = ::connect(this->sync_channel, &(addr.sa), sizeof(addr)); + + errlogPrintf("connected to sync channel %d\n",this->sync_channel); + + if (status!=0){ + // Error handling + perror(__FUNCTION__); + errlogPrintf("Error !! %d\n",status); + } + + { + Message msg(nsHiSLIP::Initialize, + 0, + message_parameter((epicsUInt16) nsHiSLIP::PROTOCOL_VERSION_MAX, + (char *) Default_vendor_id), + (epicsUInt64) 0, (epicsUInt8 *) NULL); + errlogPrintf("sending message %d \n", msg.message_type); + msg.send(this->sync_channel); + } + + errlogPrintf("Sent a initialize message\n"); - msg->message_type=nsHiSLIP::Initialize; - msg->message_parameter.initParm.protocol_version=nsHiSLIP::PROTOCOL_VERSION_MAX; - memcpy(msg->message_parameter.initParm.vendor_id, vendor_id,2); - msg->send(this->sync_channel); + { Message resp(AnyMessages); - resp=new Message(); - resp->recv(this->sync_channel, nsHiSLIP::InitializeResponse); - this->overlap_mode=resp->control_code; - this->session_id=resp->message_parameter.initResp.session_id; - this->server_protocol_version=resp->message_parameter.initResp.protocol_version; + errlogPrintf("Receive message created\n"); + + resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); - msg= new Message(nsHiSLIP::AsyncInitialize); - msg->message_parameter.word=this->session_id; - msg->send(this->sync_channel); + this->overlap_mode=resp.control_code; + this->session_id=resp.message_parameter.getSessionId(); + this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); + } + errlogPrintf("Receive a initialized message %d 0x%x %d \n", + this->overlap_mode,this->session_id, this->server_protocol_version + ); + + errlogPrintf("Sending Async initialize message %x\n",this->session_id); + + status = ::connect(this->async_channel, &addr.sa, sizeof(addr)); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + errlogPrintf("Error !!:%d\n",status); + } + errlogPrintf("connected to async channel %d\n",this->async_channel); + + { + Message msg(nsHiSLIP::AsyncInitialize); + msg.message_parameter.word=this->session_id; + msg.send(this->async_channel); + } + errlogPrintf("reading Async initialize response\n"); + + { + Message resp(AnyMessages); + resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + this->overlap_mode=resp.control_code; + this->server_vendorID=resp.message_parameter.word; + } + errlogPrintf("reading Async initialize done\n"); + + //now setup poll object + this->reset_message_id(); + + this->sync_poll.fd=this->sync_channel; + this->sync_poll.events=POLLIN; + this->sync_poll.revents=0; - resp=new Message(); - resp->recv(this->sync_channel, nsHiSLIP::AsyncInitializeResponse); - this->overlap_mode=resp->control_code; - this->session_id=resp->message_parameter.initResp.session_id; - this->server_vendorID=resp->message_parameter.word; + this->async_poll.fd=this->async_channel; + this->async_poll.events=POLLIN; + this->async_poll.revents=0; - this->sync_poll.fd=this->sync_channel; - this->sync_poll.events=POLLIN; - this->sync_poll.revents=0; + errlogPrintf("Receive a Async initialized message\n"); + }; - this->async_poll.fd=this->async_channel; - this->async_poll.events=POLLIN; - this->async_poll.revents=0; + long HiSLIP::set_max_size(long message_size){ + Message resp(AnyMessages); + epicsUInt64 msg_size=htobe64(message_size); - + Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, + 0, + message_parameter(0), + sizeof(msg_size), (epicsUInt8 *) &msg_size); + msg.send(this->async_channel); + + int ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + + this->maximum_message_size=*((epicsUInt64 *)(resp.payload)); + this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; + return this->maximum_message_size; }; -long HiSLIP::set_max_size(long message_size){ - Message *resp; - epicsUInt64 msg_size=htobe64(message_size); + int HiSLIP::device_clear(){ + Message resp(AnyMessages); + epicsUInt8 feature_preference; + int ready; + + Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, + 0, + 0, + 0,NULL); - Message *msg=new Message(nsHiSLIP::AsyncMaximumMessageSize, - 0, - new message_parameter(0), - sizeof(msg_size),&msg_size); + msg->send(this->async_channel); - msg->send(this->async_channel); + ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + feature_preference=resp.control_code; + + msg=new Message(nsHiSLIP::DeviceClearComplete, + feature_preference, + 0, + 0, NULL); - resp->recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + msg->send(this->sync_channel); + + ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return asynTimeout; + } + resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); - this->maximum_message_size=*((epicsUInt64 *)(resp->payload)); - return this->maximum_message_size; + this->overlap_mode=resp.control_code; + this->reset_message_id(); + this->rmt_delivered = false; -}; - -asynStatus HiSLIP::device_clear(){ - Message resp; - epicsUInt8 feature_preference; + return 0; - Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, - 0, - 0, - 0,NULL); + }; - msg->send(this->async_channel); + epicsUInt8 HiSLIP::status_query(){ + epicsUInt8 status; + int ready; + + Message resp(AnyMessages); + + Message msg((epicsUInt8) nsHiSLIP::AsyncStatusQuery, + (epicsUInt8) this->rmt_delivered, + message_parameter((epicsUInt32) this->most_recent_message_id), + 0, NULL); + msg.send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); + + status= resp.control_code &0xff; + + return status; + } - resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); - feature_preference=resp.control_code; - msg=new Message(nsHiSLIP::DeviceClearComplete, - feature_preference, - 0, - 0, NULL); + // long HiSLIP::write(epicsUInt8 *data_str, long timeout){ + // return this->write(data_str, this->maximum_message_size,timeout); + // }; - msg->send(this->sync_channel); - - resp.recv(this->async_channel,nsHiSLIP::DeviceClearAcknowledge); + long HiSLIP::write(epicsUInt8 const* data_str, size_t const dsize, long timeout){ - this->overlap_mode=resp.control_code; - this->reset_message_id(); - this->rmt_delivered = false; + size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; + size_t bytestosend=dsize; + const epicsUInt8 *buffer=data_str; + size_t delivered=0; + size_t count; + + errlogPrintf("HiSLIP::write sending data %s\n", data_str); - return asynSuccess; + while(bytestosend){ + if (bytestosend < max_payload_size){ + Message msg(nsHiSLIP::DataEnd, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + bytestosend, (epicsUInt8 *) buffer); + buffer += bytestosend; + errlogPrintf("sending message %s\n",(char *) msg.payload); + count=msg.send(this->sync_channel); + count -=HEADER_SIZE; + bytestosend = 0; + delivered += count ; + } + else{ + Message msg(nsHiSLIP::Data, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + max_payload_size, (epicsUInt8 *) buffer); + count=msg.send(this->sync_channel); + count -= HEADER_SIZE; + bytestosend -=count; + delivered += count; + buffer += max_payload_size; + } + errlogPrintf("data sent= %lu\n",count); + this->increment_message_id(); + } + return delivered; + }; -}; + int HiSLIP::read(size_t *received, epicsUInt8 **buffer, long timeout){ + bool eom=false; + size_t rsize=0; + + errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", + buffer, timeout); + + *received=0; + this->rmt_delivered = false; -epicsUInt8 HiSLIP::status_query(){ - epicsUInt8 status; - Message resp; + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + rsize=resp.recv(this->sync_channel); + errlogPrintf("HiSLIP read rsize %ld\n",rsize); + if (rsize < resp.payload_length){ + //Error!! + return -1; + }; + + // may not be a good idea. + { epicsUInt8 *newbuf; + + newbuf=(epicsUInt8 *) reallocarray(*buffer, 1, + *received+resp.payload_length); + if (newbuf == NULL){ + errlogPrintf("Cannot extend memory area\n"); + return -1; + } + else{ + *buffer=newbuf; + } + } + ::memcpy((*buffer + *received), resp.payload, resp.payload_length); + *received +=resp.payload_length; + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if ( resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + return 0; + } else{ + // error unexpected message type. + return -1; + } + } + return -1; + }; - Message *msg=new Message((epicsUInt8) nsHiSLIP::AsyncStatusQuery, - (epicsUInt8) this->rmt_delivered, - new nsHiSLIP::message_parameter((epicsUInt32) this->most_recent_message_id), - 0, NULL); - msg->send(this->async_channel); + int HiSLIP::read(size_t *received, + epicsUInt8 *buffer, size_t bsize, long timeout){ + bool eom=false; + size_t rsize=0; + + errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", + buffer, bsize, timeout); + *received=0; + this->rmt_delivered = false; + + if (buffer==NULL || bsize <= 0){ + errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", + buffer, bsize, timeout); + return -1; + } + if (bsize < this->maximum_payload_size){ + errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", + bsize, this->maximum_payload_size); + } + while(!eom) { + int ready; + Message resp(AnyMessages); - resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); - status= resp.control_code &0xff; - return status; -} + ready=::poll(&this->sync_poll, 1, timeout); + + if (ready == 0){ + errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); + return -1; + } + + rsize=resp.recv(this->sync_channel); + + if (rsize < resp.payload_length){ + errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); + return -1; + }; + if (( (*received) + resp.payload_length) > bsize){ + errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", + *received, resp.payload_length, bsize); + + ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); + *received = bsize; + return 0; + } + else{ + errlogPrintf("received message size %ld %ld data:%s mt:%d\n", + rsize, *received, (char *) resp.payload, resp.message_type); + ::memcpy( (buffer + *received), resp.payload, resp.payload_length); + + *received +=resp.payload_length; + } + + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if (resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", + buffer, (char *) resp.payload, eom,this->rmt_delivered); + return 0; + } else{ + errlogPrintf("Unexpected message type:%d\n", + resp.message_type); + resp.printf(); + // error unexpected message type. + return -1; + } + } + return -1; + }; - // EPICS Async Support + size_t HiSLIP::ask(epicsUInt8 *const data_str, size_t const dsize, + epicsUInt8 **rbuffer, + long wait_time){ + size_t rsize=-1; + epicsUInt8 *buffer=NULL; + int status; + + errlogPrintf("sending a command %s %lu",data_str, dsize); + + this->write(data_str, dsize); + if(this->wait_for_answer(wait_time) == 0){ + // error + return -1; + }; + status=this->read(&rsize, &buffer); + if (status !=0){ + rsize=-1; + } + *rbuffer=buffer; + return rsize; + }; + + long HiSLIP::trigger_message(void){ + return 0; + }; + long HiSLIP::remote_local(bool request){ + return 0; + }; + long HiSLIP::request_lock(const char* lock_string){ + return 0; + }; + long HiSLIP::release_lock(void){ + return 0; + }; + long HiSLIP::request_srq_lock(void){ + return 0; + }; + long HiSLIP::release_srq_lock(void){ + return 0; + }; + +} // end of namespace HiSLIP +// +// EPICS Async Support typedef struct drvPvt { /* * Matched device @@ -159,8 +441,8 @@ typedef struct drvPvt { */ HiSLIP_t *device; - const char *hostname; - const long port; + char *hostname; + long port; bool isConnected; int termChar; @@ -173,39 +455,42 @@ typedef struct drvPvt { asynInterface asynCommon; asynInterface asynOctet; void *asynOctetInterruptPvt; - // asynInterface asynInt32; - // void *asynInt32InterruptPvt; asynInterface asynDrvUser; /* - * Interrupt endpoint handling - */ - char *interruptThreadName; - epicsThreadId interruptTid; - epicsMutexId interruptTidMutex; - epicsEventId pleaseTerminate; - epicsEventId didTerminate; - epicsMessageQueueId statusByteMessageQueue; + * Interrupt through async_channel handling + */ + char *interruptThreadName; + epicsThreadId interruptTid; + epicsMutexId interruptTidMutex; + epicsEventId pleaseTerminate; + epicsEventId didTerminate; + epicsMessageQueueId statusByteMessageQueue; + + /* + * I/O buffer: Asyn clients may request data size smaller than + max_payload size. + */ + unsigned char *buf;// + size_t bufSize; + size_t bufCount; + const unsigned char *bufp; //top of unread data buffer. - /* - * I/O buffer - */ - unsigned char buf[BULK_IO_HEADER_SIZE+BULK_IO_PAYLOAD_CAPACITY]; - int bufCount; - const unsigned char *bufp; - unsigned char bulkInPacketFlags; + /* + * Statistics + */ - /* - * Statistics - */ - size_t connectionCount; - size_t interruptCount; - size_t bytesSentCount; - size_t bytesReceivedCount; + size_t connectionCount; + size_t interruptCount; + size_t bytesSentCount; + size_t bytesReceivedCount; } drvPvt; static asynStatus disconnect(void *pvt, asynUser *pasynUser); +// forward declarations. +static asynStatus +asynOctetFlush(void *pvt, asynUser *pasynUser); /* * Interrupt endpoint support @@ -222,29 +507,40 @@ interruptThread(void *arg) if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK) break; - Message_t srqmsg=pdpvt->device->get_Service_Request(); - epicsUInt8 st =srqmsg.control_code; + Message_t *srqmsg=pdpvt->device->get_Service_Request(); + + epicsUInt8 st =srqmsg->control_code; - if ((s == 0)&& (st != 0)){ - if (st == 0x81) { + if (s != 0 ){ + if (st != 0){ ELLLIST *pclientList; interruptNode *pnode; pdpvt->interruptCount++; - pasynManager->interruptStart(pdpvt->asynOctetInterruptPvt, &pclientList); - pnode = (interruptNode *)ellFirst(pclientList); - while (pnode) { - asynOctetInterrupt *int32Interrupt = (asynOctetInterrupt *) pnode->drvPvt; - pnode = (interruptNode *)ellNext(&pnode->node); - if (int32Interrupt->pasynUser->reason == ASYN_REASON_SRQ) { - int32Interrupt->callback(int32Interrupt->userPvt, - int32Interrupt->pasynUser, - st); + pasynManager->interruptStart(pdpvt->asynOctetInterruptPvt, + &pclientList); + { + pnode = (interruptNode *)ellFirst(pclientList); + // see asynDriver/asynDriver.h + while (pnode) { + int eomReason=0; // 0:None, ASYN_EOM_CNT:0x0001,ASYN_EOM_EOS:0x0002 End of StrIng detected ASYN_EOM_END: 0x0004 End indicator detected + + size_t numchars=1; + asynOctetInterrupt *octetInterrupt = + (asynOctetInterrupt *) pnode->drvPvt; + pnode = (interruptNode *)ellNext(&pnode->node); + if (octetInterrupt->pasynUser->reason == ASYN_REASON_SRQ) { + octetInterrupt->callback(octetInterrupt->userPvt, + octetInterrupt->pasynUser, + (char *) &st, + numchars, + eomReason); + } } + pasynManager->interruptEnd(pdpvt->asynOctetInterruptPvt); } - pasynManager->interruptEnd(pdpvt->asynOctetInterruptPvt); } - else if (st== 0x82) { + else{ if (epicsMessageQueueTrySend(pdpvt->statusByteMessageQueue, &st, 1) != 0) { errlogPrintf("----- WARNING ----- " @@ -285,37 +581,6 @@ startInterruptThread(drvPvt *pdpvt) epicsMutexUnlock(pdpvt->interruptTidMutex); } -/* - * Decode a status byte - */ -static void -showHexval(FILE *fp, const char *name, int val, int bitmask, const char *bitname, ...) -{ - const char *sep = " -- "; - va_list ap; - va_start(ap, bitname); - fprintf(fp, "%28s: ", name); - if (bitmask) - fprintf(fp, "%#x", val); - else - fprintf(fp, "%#4.4x", val); - for (;;) { - if (((bitmask > 0) && ((val & bitmask)) != 0) - || ((bitmask < 0) && ((val & -bitmask)) == 0) - || ((bitmask == 0) && (bitname != NULL) && (bitname[0] != '\0'))) { - fprintf(fp, "%s%s", sep, bitname); - sep = ", "; - } - if (bitmask == 0) - break; - bitmask = va_arg(ap, int); - if (bitmask == 0) - break; - bitname = va_arg(ap, char *); - } - fprintf(fp, "\n"); - va_end(ap); -} /* * Show a byte number @@ -348,8 +613,8 @@ report(void *pvt, FILE *fp, int details) drvPvt *pdpvt = (drvPvt *)pvt; fprintf(fp, "%20sonnected, Interrupt handler thread %sactive\n", - pdpvt->isConnected ? "C" : "Disc", - pdpvt->interruptTid ? "" : "in"); + pdpvt->isConnected ? "C" : "Disc", + pdpvt->interruptTid ? "" : "in"); if (details > 0) { if (pdpvt->termChar >= 0) fprintf(fp, "%28s: %x\n", "Terminator", pdpvt->termChar); @@ -359,10 +624,26 @@ report(void *pvt, FILE *fp, int details) showCount(fp, "Interrupt", pdpvt->interruptCount); showCount(fp, "Send", pdpvt->bytesSentCount); showCount(fp, "Receive", pdpvt->bytesReceivedCount); - } - if (details >= 100) { - int l = details % 100; - fprintf(fp, "==== Set libusb debug level %d ====\n", l); + // + fprintf(fp, "HiSLIP device Info:\n"); + fprintf(fp, "%s: %x\n", "Terminator", pdpvt->termChar); + fprintf(fp, "HiSLIP device address:%s\n", + pdpvt->hostname); + fprintf(fp, "overlap/sync. mode:%s\n", + pdpvt->device->overlap_mode?"ovelap":"synchronized"); + fprintf(fp, "Session ID:%d\n", + pdpvt->device->session_id); + fprintf(fp, "server_protocol_version/server_vendorID : %#x %#x\n", + pdpvt->device->server_protocol_version, + pdpvt->device->server_vendorID); + fprintf(fp, "sync/async socket number %d/%d\n", + pdpvt->device->sync_channel, + pdpvt->device->async_channel); + fprintf(fp, "socket/locktime %ld/%ld\n", + pdpvt->device->socket_timeout, + pdpvt->device->lock_timeout); + fprintf(fp, "current message id/most recent message id %x/%x\n", + pdpvt->device->message_id,pdpvt->device->most_recent_message_id); } }; @@ -377,68 +658,47 @@ disconnectIfGone(drvPvt *pdpvt, asynUser *pasynUser, int s) } } -/* - * Check results of control transfer - */ -/* - * Clear input/output buffers - */ -static asynStatus -clearBuffers(drvPvt *pdpvt, asynUser *pasynUser) -{ - int s; - asynStatus status; - int pass = 0; - - status = pdpvt->device->device_clear(); - if (status != asynSuccess) - return status; - for (;;) { - epicsThreadSleep(0.01); - // I don't know why this is necessary, but without some delay here the CHECK_CLEAR_STATUS seems to be stuck at STATUS_PENDING - status = pdpvt->device->device_clear(); - if (status != asynSuccess) - return asynError; - switch (++pass) { - case 5: - asynPrint(pasynUser, ASYN_TRACE_ERROR, "Note -- RESET DEVICE.\n"); - //s = libusb_reset_device(pdpvt->handle); - status = pdpvt->device->device_clear(); - if (s != 0) { - epicsSnprintf(pasynUser->errorMessage, - pasynUser->errorMessageSize, - "hislip_reset_device() failed: %s", - nsHiSLIP::Error_Messages[s]); - return asynError; - } - break; - - case 10: - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "CHECK_CLEAR_STATUS remained 'STATUS_PENDING' for too long"); - return asynError; - } - asynPrint(pasynUser, ASYN_TRACE_ERROR, - "Note -- retrying CHECK_CLEAR_STATUS\n"); - } - return asynSuccess; -} static asynStatus connect(void *pvt, asynUser *pasynUser) { drvPvt *pdpvt = (drvPvt *)pvt; - if (!pdpvt->isConnected) { + if (!pdpvt->isConnected || (pdpvt->device == NULL)) { + if (pdpvt->device == NULL){ + pdpvt->device=new HiSLIP(); + } pdpvt->device->connect(pdpvt->hostname); } - pdpvt->isConnected = 1; + pdpvt->isConnected = true; + pdpvt->connectionCount +=1; + + // setup private buffer for read. + pdpvt->bufSize=pdpvt->device->maximum_payload_size; + + if (pdpvt->bufSize <=0){ + errlogPrintf("HiSLIP::connect invalid buffersize\n"); + return asynError; + } + + pdpvt->buf=(unsigned char *)callocMustSucceed(1, + pdpvt->bufSize+1, + pdpvt->portName); + //ensure buffer ends with a null character. + *(pdpvt->buf + pdpvt->bufSize)=0x00; + + if(pdpvt->buf ==0){ + errlogPrintf("HiSLIP::failed to allocate input buffer\n"); + return asynError; + } + asynOctetFlush(pvt, pasynUser); + // pdpvt->bufCount=0; + // pdpvt->bufp=0; // NO data in buf. pasynManager->exceptionConnect(pasynUser); return asynSuccess; } -static asynStatus -disconnect(void *pvt, asynUser *pasynUser) +static asynStatus disconnect(void *pvt, asynUser *pasynUser) { drvPvt *pdpvt = (drvPvt *)pvt; @@ -453,8 +713,9 @@ disconnect(void *pvt, asynUser *pasynUser) if (tid == 0) break; if (++pass == 10) { - errlogPrintf("----- WARNING ----- Thread %s won't terminate!\n", - pdpvt->interruptThreadName); + errlogPrintf + ("----- WARNING ----- Thread %s won't terminate!\n", + pdpvt->interruptThreadName); break; } @@ -462,7 +723,7 @@ disconnect(void *pvt, asynUser *pasynUser) * Send signal then force an Interrupt-In message */ epicsEventSignal(pdpvt->pleaseTerminate); - pdpvt->device->status_query(); + pdpvt->device->status_query(); // libusb_control_transfer(pdpvt->handle, // 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE // 128, // bRequest: READ_STATUS_BYTE @@ -475,7 +736,7 @@ disconnect(void *pvt, asynUser *pasynUser) } pdpvt->device->disconnect(); } - pdpvt->isConnected = 0; + pdpvt->isConnected = false; pasynManager->exceptionDisconnect(pasynUser); return asynSuccess; } @@ -495,31 +756,31 @@ asynOctetWrite(void *pvt, asynUser *pasynUser, /* * Common to all writes */ - + errlogPrintf("OctetWrite %s %ld %ld\n",data,numchars,*nbytesTransfered); /* * Send */ *nbytesTransfered = 0; while (numchars) { - int nSend, pkSend, pkSent; - int s; - s = pdpvt->device->write( pdpvt->buf, timeout); + size_t nSent; + + nSent = pdpvt->device->write((epicsUInt8 *) data, numchars, timeout); - if (s) { - disconnectIfGone(pdpvt, pasynUser, s); + if (nSent < 0) { + disconnectIfGone(pdpvt, pasynUser, 0); epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Bulk transfer failed: %s", - nsHiSLIP::Error_Messages[s]); + "data transfer failed: %s", + "Error in write operation"); return asynError; } - if (s!= nSend) { + if (nSent != numchars) { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Asked to send %d, actually sent %d", pkSend, pkSent); + "Asked to send %lu, actually sent %lu", numchars,nSent); return asynError; } - data += nSend; - numchars -= nSend; - *nbytesTransfered += nSend; + data += nSent; + numchars -= nSent; + *nbytesTransfered += nSent; } pdpvt->bytesSentCount += *nbytesTransfered; return asynSuccess; @@ -531,68 +792,84 @@ asynOctetRead(void *pvt, asynUser *pasynUser, int *eomReason) { drvPvt *pdpvt = (drvPvt *)pvt; - unsigned char bTag; - int s; - int nCopy, ioCount, payloadSize; - int eom = 0; + size_t ioCount, nCopy; + int status; + int eom=0; int timeout = pasynUser->timeout * 1000; if (timeout == 0) timeout = 1; - + + assert(pdpvt->device); + assert(nbytesTransfered); + *nbytesTransfered = 0; - for (;;) { - /* - * Special case for stream device which requires an asynTimeout return. - */ - ioCount = pdpvt->device->read( - data, BULK_IO_HEADER_SIZE, - timeout); - if (s) { - disconnectIfGone(pdpvt, pasynUser, s); - epicsSnprintf(pasynUser->errorMessage, - pasynUser->errorMessageSize, - "Bulk transfer request failed: %s", - nsHiSLIP::Error_Message[s]); - return asynError; - } - - /* - * Read back - */ - s = pdpvt->device.read(sizeof pdpvt->buf, &ioCount, timeout); - - if (s) { - disconnectIfGone(pdpvt, pasynUser, s); - epicsSnprintf(pasynUser->errorMessage, - pasynUser->errorMessageSize, - "Bulk read failed: %s", - nsHiSLIP::Error_Messages[2]); - return asynError; - } - asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, - ioCount, "Read %d, flags %#x: ", ioCount, pdpvt->buf[8]); - - /* - * Sanity check on transfer - */ - if (ioCount < BULK_IO_HEADER_SIZE) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Incomplete packet header (read only %d)", ioCount); - return asynError; - } - if (payloadSize > (ioCount - BULK_IO_HEADER_SIZE)) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Packet header claims %d sent, but packet contains only %d", - payloadSize, ioCount - BULK_IO_HEADER_SIZE); - return asynError; - } - if (payloadSize > BULK_IO_PAYLOAD_CAPACITY) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Packet header claims %d sent, but requested only %d", - payloadSize, BULK_IO_PAYLOAD_CAPACITY); - return asynError; - } - pdpvt->bufCount = payloadSize; + if(eomReason) *eomReason=0; + + errlogPrintf("asynOctetRead timeout:%g host:%s maxchars:%ld bufCount:%ld\n", + pasynUser->timeout, + pdpvt->hostname, + maxchars, pdpvt->bufCount); + /* + * Special case for stream device which requires an asynTimeout return. + */ + while(eom==0){ + if ((pasynUser->timeout == 0) && (pdpvt->bufCount == 0)) + return asynTimeout; + if (pdpvt->bufCount ==0) { + // read adittional data from device + status = pdpvt->device->read( &ioCount, + (epicsUInt8 *) pdpvt->buf, + pdpvt->bufSize, + timeout); + if (status != 0){ + disconnectIfGone(pdpvt, pasynUser, 0); + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "Data transfer request failed: %s %d", + "Error in read operation",status); + return asynError; + } + assert(ioCount); + pdpvt->bufp=pdpvt->buf; + pdpvt->bufCount = ioCount; + pdpvt->bytesReceivedCount += ioCount; + errlogPrintf("asynOctetRead data:%s, maxchars:%ld,nbytesTransfered:%ld, eomReason:%d\n", + data, maxchars, *nbytesTransfered, eom); + } + if (pdpvt->bufCount) { + if (maxchars > pdpvt->bufCount){ + nCopy = pdpvt->bufCount; + } + else{ + nCopy = maxchars; + } + memcpy(data, pdpvt->bufp, nCopy); + pdpvt->bufCount -= nCopy; + if(pdpvt->bufCount<0){ + errlogPrintf("woo. something wrong"); + exit(-1); + } + if (pdpvt->bufCount == 0){ + pdpvt->bufp = 0; + } + else{ + pdpvt->bufp += nCopy; + } + maxchars -= nCopy; + *nbytesTransfered += nCopy; + pdpvt->bytesReceivedCount += nCopy; + data += nCopy; + if (maxchars == 0){ + eom |= ASYN_EOM_CNT; + } + if(pdpvt->bufCount == 0 ){ + if (pdpvt->device->rmt_delivered){ + eom |=ASYN_EOM_END; + } + } + } } + if(eomReason) *eomReason = eom; + return asynSuccess; } /* @@ -605,8 +882,9 @@ asynOctetFlush(void *pvt, asynUser *pasynUser) { drvPvt *pdpvt = (drvPvt *)pvt; + errlogPrintf("OctetFlush:\n"); pdpvt->bufCount = 0; - pdpvt->bulkInPacketFlags = 0; + pdpvt->bufp = 0; return asynSuccess; } @@ -615,39 +893,22 @@ asynOctetSetInputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen { drvPvt *pdpvt = (drvPvt *)pvt; - switch (eoslen) { - case 0: - pdpvt->termChar = -1; - break; - case 1: - if ((pdpvt->tmcDeviceCapabilities & 0x1) == 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support terminating characters"); - return asynError; - } - pdpvt->termChar = *eos & 0xFF; - break; - default: - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + if (eoslen ==0) { + pdpvt->termChar = -1; + return asynSuccess; + } + else{ + pdpvt->termChar = -1; + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Device does not support multiple terminating characters"); - return asynError; + return asynError; } - return asynSuccess; } static asynStatus asynOctetGetInputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) { - drvPvt *pdpvt = (drvPvt *)pvt; - - if (pdpvt->termChar < 0) { - *eoslen = 0; - } - else { - if (eossize < 1) return asynError; - *eos = pdpvt->termChar; - *eoslen = 1; - } + *eoslen = 0; return asynSuccess; } @@ -665,7 +926,7 @@ asynOctetGetOutputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, in static asynOctet octetMethods = { .write = asynOctetWrite, - .read = asynOctetRead, + .read = asynOctetRead, .flush = asynOctetFlush, .setInputEos = asynOctetSetInputEos, .getInputEos = asynOctetGetInputEos, @@ -682,9 +943,12 @@ asynDrvUserCreate(void *pvt, asynUser *pasynUser, { drvPvt *pdpvt = (drvPvt *)pvt; + errlogPrintf("DrvUserCreate drvinfo:%s typeName:%s size:%ld\n", + drvInfo, *pptypeName, *psize + ); + if (epicsStrCaseCmp(drvInfo, "SRQ") == 0) { pasynUser->reason = ASYN_REASON_SRQ; - pdpvt->enableInterruptEndpoint = 1; if (pdpvt->isConnected) startInterruptThread(pdpvt); } @@ -725,7 +989,6 @@ HiSLIPConfigure(const char *portName, int priority) { drvPvt *pdpvt; - int s; asynStatus status; int flags=0; @@ -734,62 +997,90 @@ HiSLIPConfigure(const char *portName, */ pdpvt = (drvPvt *)callocMustSucceed(1, sizeof(drvPvt), portName); pdpvt->portName = epicsStrDup(portName); - pdpvt->interruptThreadName = callocMustSucceed(1, strlen(portName)+5, portName); - epicsSnprintf(pdpvt->interruptThreadName, sizeof pdpvt->interruptThreadName, + pdpvt->interruptThreadName = (char *) callocMustSucceed(1, + strlen(portName)+5, + portName); + epicsSnprintf(pdpvt->interruptThreadName, + sizeof pdpvt->interruptThreadName, "%sIntr", portName); if (priority == 0) priority = epicsThreadPriorityMedium; - pdpvt->device=new HiSLIP_t(hostInfo); - if (s != 0) { - printf("libusb_init() failed: %s\n", nsHiSLIP::Error_Messages[2]); - return; - } + + pdpvt->hostname=(char *)callocMustSucceed(1, + strlen(hostInfo)+1, + "HiSLIPConfigure"); + strcpy(pdpvt->hostname, hostInfo); + + // errlogPrintf("creating HiSLIP object %s", hostInfo); + // pdpvt->device=new HiSLIP_t(); + // errlogPrintf("connecting HiSLIP object to host:%s\n", hostInfo); + // pdpvt->device->connect(hostInfo); + // pdpvt->isConnected = true; + // errlogPrintf("HiSLIP object connected to host:%s\n", hostInfo); + // if (pdpvt->device == 0) { + // errlogPrintf("Failed to create HiSLIP device for %s(%s)\n", + // hostInfo, nsHiSLIP::Error_Messages[2]); + // return; + // } pdpvt->termChar = -1; pdpvt->interruptTidMutex = epicsMutexMustCreate(); pdpvt->pleaseTerminate = epicsEventMustCreate(epicsEventEmpty); pdpvt->didTerminate = epicsEventMustCreate(epicsEventEmpty); pdpvt->statusByteMessageQueue = epicsMessageQueueCreate(1, 1); + if (!pdpvt->statusByteMessageQueue) { - printf("Can't create message queue!\n"); + errlogPrintf("Can't create message queue!\n"); return; } /* * Create our port */ + errlogPrintf("* registerPort to asynManager \n"); status = pasynManager->registerPort(pdpvt->portName, ASYN_CANBLOCK, (flags & 0x1) == 0, priority, 0); if(status != asynSuccess) { - printf("registerPort failed\n"); - return; + errlogPrintf("registerPort failed portname %s\n", + pdpvt->portName); + return; } /* * Register ASYN interfaces */ + errlogPrintf("* Register ASYN interfaces \n"); + pdpvt->asynCommon.interfaceType = asynCommonType; pdpvt->asynCommon.pinterface = &commonMethods; pdpvt->asynCommon.drvPvt = pdpvt; + status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynCommon); + if (status != asynSuccess) { - printf("registerInterface failed\n"); + errlogPrintf("registerInterface failed\n"); return; } + errlogPrintf("* Register ASYN Octet interfaces \n"); pdpvt->asynOctet.interfaceType = asynOctetType; pdpvt->asynOctet.pinterface = &octetMethods; pdpvt->asynOctet.drvPvt = pdpvt; - status = pasynOctetBase->initialize(pdpvt->portName, &pdpvt->asynOctet, 0, 0, 0); + status = pasynOctetBase->initialize(pdpvt->portName, + &pdpvt->asynOctet, + 0, + 0, + 0); if (status != asynSuccess) { - printf("pasynOctetBase->initialize failed\n"); + errlogPrintf("pasynOctetBase->initialize failed\n"); return; } /* * Always register an interrupt source, just in case we use SRQs */ + errlogPrintf("* Register Interrupt source \n"); pasynManager->registerInterruptSource(pdpvt->portName, &pdpvt->asynOctet, &pdpvt->asynOctetInterruptPvt); @@ -800,7 +1091,7 @@ HiSLIPConfigure(const char *portName, status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynDrvUser); if (status != asynSuccess) { - printf("Can't register drvUser\n"); + errlogPrintf("Can't register drvUser\n"); return; } } @@ -818,15 +1109,15 @@ static const iocshArg *HiSLIPConfigureArgs[] = { &HiSLIPConfigureArg0 , &HiSLIPConfigureArg1 , &HiSLIPConfigureArg2 -} - - static const iocshFuncDef HiSLIPConfigureFuncDef = +}; + +static const iocshFuncDef HiSLIPConfigureFuncDef = {"HiSLIPConfigure", 3, HiSLIPConfigureArgs}; static void HiSLIPConfigureCallFunc(const iocshArgBuf *args) { HiSLIPConfigure (args[0].sval, - args[1].sval, args[2].ival) + args[1].sval, args[2].ival); } /* diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h index e9f616f1b..bf3977d8b 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h @@ -11,89 +11,460 @@ *************************************************************************** */ //-*- coding:utf-8 -*- -/* struct HiSLIPFatalError:Exception; // Exception raised up for HiSLIP fatal errors */ - -/* struct HiSLIPError:Exception; */ - -/* struct _HiSLIP; */ - -/* struct HiSLIP:_HiSLIP; */ - -//constants - -typedef enum CC_reuqest{ - RemoteDisable=0, - RemoteEnable=1, - RemoteDisableGTL=2, // disable remote and goto local - RemoteEnableGTR=3, // Enable remote and goto remote - RemoteEnableLLO=4, // Enable remote and lock out local - RemoteEnableGTRLLO=5, // - RTL=6 -} CC_request_t; - -typedef enum CC_Lock{ - release =0, - request =1 -} CC_Lock_t; - -typedef enum CC_LockResponse{ - fail=0, //Lock was requested but not granted - success=1, //release of exclusive lock - success_shared=2, //release of shared lock - error=3 // Invalide -} CC_LockResponse_t; - -static const long HiSLIP_PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 -static const long HiSLIP_INITIAL_MESSAGE_ID = 0xffffff00 ; -static const long HiSLIP_UNKNOWN_MESSAGE_ID = 0xffffffff ; -static const long HiSLIP_MAXIMUM_MESSAGE_SIZE = 272; //# Following VISA 256 bytes + header length 16 bytes -static const long HiSLIP_SOCKET_TIMEOUT = 1; //# Socket timeout -static const long HiSLIP_LOCK_TIMEOUT = 3000;//# Lock timeout -static const long HiSLIP_Default_Port=4880; -// -typedef enum HiSLIP_Message_Types{ - Initialize = 0, - InitializeResponse = 1, - FatalError = 2, - Error = 3, - AsyncLock = 4, - AsyncLockResponse = 5, - Data = 6, - DataEnd = 7, - DeviceClearComplete = 8, - DeviceClearAcknowledge = 9, - AsyncRemoteLocalControl = 10, - AsyncRemoteLocalResponse = 11, - Trigger = 12, - Interrupted = 13, - AsyncInterrupted = 14, - AsyncMaximumMessageSize = 15, - AsyncMaximumMessageSizeResponse = 16, - AsyncInitialize = 17, - AsyncInitializeResponse = 18, - AsyncDeviceClear = 19, - AsyncServiceRequest = 20, - AsyncStatusQuery = 21, - AsyncStatusResponse = 22, - AsyncDeviceClearAcknowledge = 23, - AsyncLockInfo = 24, - AsyncLockInfoResponse = 25 -} HiSLIP_Message_Types_t; - -static const char *HiSLIP_Error_Messages[] = { - "Unidentified error", - "Unrecognized Message Type", - "Unrecognized control code", - "Unrecognized Vendor Defined Message", - "Message too large" -}; +#define NDEBUG 1 +#include + +#include +#include +#include +#include // network endian is "be". + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include -static const char *HiSLIP_Fatal_Error_Messages[] = { - "Unidentified error", - "Poorly formed message header", - "Attempt to use connection without both channels established", - "Invalid Initialization Sequence", - "Server refused connection due to maximum number of clients exceeded" +template struct Property { + T& r; + operator T() {return r;} + void operator =(const T v){ r=v;} }; + +namespace nsHiSLIP{ + + //constants + typedef enum CC_reuqest{ + RemoteDisable=0, + RemoteEnable=1, + RemoteDisableGTL=2, // disable remote and goto local + RemoteEnableGTR=3, // Enable remote and goto remote + RemoteEnableLLO=4, // Enable remote and lock out local + RemoteEnableGTRLLO=5, // + RTL=6 + } CC_request_t; + + typedef enum CC_Lock{ + release =0, + request =1 + } CC_Lock_t; + + typedef enum CC_LockResponse{ + fail=0, //Lock was requested but not granted + success=1, //release of exclusive lock + success_shared=2, //release of shared lock + error=3 // Invalide + } CC_LockResponse_t; + + static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 + static const long INITIAL_MESSAGE_ID = 0xffffff00 ; + static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; + static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes + static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept + static const long HEADER_SIZE=16; + static const long SOCKET_TIMEOUT = 1; //# Socket timeout + static const long LOCK_TIMEOUT = 3000;//# Lock timeout + static const long Default_Port = 4880; + static const char Default_device_name[]="hslip0"; + static const char Default_vendor_id[]={'E','P'}; + static const char Prologue[]={'H','S'}; + // + typedef enum Message_Types{ + Initialize = 0, + InitializeResponse = 1, + FatalError = 2, + Error = 3, + AsyncLock = 4, + AsyncLockResponse = 5, + Data = 6, + DataEnd = 7, + DeviceClearComplete = 8, + DeviceClearAcknowledge = 9, + AsyncRemoteLocalControl = 10, + AsyncRemoteLocalResponse = 11, + Trigger = 12, + Interrupted = 13, + AsyncInterrupted = 14, + AsyncMaximumMessageSize = 15, + AsyncMaximumMessageSizeResponse = 16, + AsyncInitialize = 17, + AsyncInitializeResponse = 18, + AsyncDeviceClear = 19, + AsyncServiceRequest = 20, + AsyncStatusQuery = 21, + AsyncStatusResponse = 22, + AsyncDeviceClearAcknowledge = 23, + AsyncLockInfo = 24, + AsyncLockInfoResponse = 25, + // 26-127 are reserved for future use. + // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. + AnyMessages=127 // 128-255 are reserved for vendor use. + } Message_Types_t; + + typedef enum Error_code{ + UnidentifiedError, + UnrecognizedMessageType, + UnrecognizedControlCode, + UnrecognizedVendorDefinedMessage, + MessageTooLarge + } Error_code_t; + static const char *Error_Messages[] = + { + "Unidentified error", + "Unrecognized Message Type", + "Unrecognized control code", + "Unrecognized Vendor Defined Message", + "Message too large" + }; + typedef enum Fatal_Error_code { + UnidentifiedFatalError, + PoorlyFormedMmessageHeader, + AttemptToUseConnectionWithoutBothChannels, + InvalidInitializationSequence, + ServerRefusedConnection + } Fatal_Erro_code_t; + static const char *Fatal_Error_Messages[] = + { + "Unidentified error", + "Poorly formed message header", + "Attempt to use connection without both channels established", + "Invalid Initialization Sequence", + "Server refused connection due to maximum number of clients exceeded" + }; + + typedef class message_parameter{ + public: + epicsUInt32 word; + // struct InitializeParameter{ + // epicsUInt16 protocol_version; + // char vendor_id[2]={0x00 ,0x00}; + // } initParm; + // struct InitializeResponseParameter{ + // epicsUInt16 session_id; + // epicsUInt16 protocol_version; + // } initResp; + message_parameter(epicsUInt32 word){this->word=word;}; + message_parameter(epicsUInt16 proto, char vers[2]){ + this->word= ((epicsInt32)proto << 16) + + (vers[1] << 8) + (vers[0]<<0); + errlogPrintf("messagParameter:%#010x, protocol:%#06x, version:[%c%c]\n", + this->word, + proto, vers[0], vers[1]); + }; + message_parameter(epicsUInt16 proto, epicsUInt16 sid){ + this->word = (proto << 16) + sid; + errlogPrintf("messagParameter:%#010x, protocol:%#06x, session id:%#06x\n", + this->word, + proto, sid); + }; + epicsUInt16 getServerProtocolVersion(){ + errlogPrintf("getServerProtocolVersion messagParameter:%#010x, ServerProtocolVersion %d\n", + this->word, + (epicsUInt16) (((this->word) & 0xffff0000)>>16)); + return (epicsUInt16) (((this->word) & 0xffff0000)>>16); + } + epicsUInt16 getSessionId(){ + errlogPrintf("getSessionId messagParameter %#010x, sessionID:%d\n", + this->word, + (epicsUInt16) ((this->word) & 0xffff)); + return ((epicsUInt16) ((this->word) & 0xffff)); + } + } message_parameter_t; + + class Header{ + public: + const char prologue[2]={'H','S'}; + epicsUInt8 message_type; + epicsUInt8 control_code; + message_parameter_t message_parameter; + epicsUInt64 payload_length; + + Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ + this->message_type=message_type; + } + Header(const void *buffer):message_parameter(0){ + assert(memcmp(this->prologue, buffer,2) == 0); + this->message_type=*((epicsUInt8 *) ((char *) buffer+2)); + this->control_code=*((epicsUInt8 *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(epicsUInt32 *) ((char *) buffer+4)); + this->payload_length = be64toh(*(epicsUInt64 *) ((char *) buffer+8)); + } + Header(const epicsUInt8 type, + const epicsUInt8 cce, + const message_parameter_t param, + const epicsUInt64 length):message_parameter(param.word){ + this->message_type=type; + this->control_code=cce; + this->payload_length=length; + } + void printf(void){ + errlogPrintf("message type:%d\n",this->message_type); + errlogPrintf("control_code:%d\n",this->control_code); + errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); + errlogPrintf("payload length: %qd\n",this->payload_length); + } + + size_t send(int socket){ + char hbuf[HEADER_SIZE]; + ssize_t ssize; + + this->toRawData(hbuf); + errlogPrintf("sending header dump: %#016qx,%#016qx\n", + *((epicsUInt64*)hbuf),*(((epicsUInt64*)hbuf) +1)); + ssize=::send(socket, hbuf, sizeof(hbuf), 0); + + return ssize; + } + + size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ + + + char buffer[HEADER_SIZE]; + ssize_t rsize; + + + errlogPrintf("recv header\n"); + + rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + + errlogPrintf("read header dump: %#016qx, %#016qx\n", + *((epicsUInt64*)buffer), + *(((epicsUInt64*)buffer) +1) ); + + if (rsize < HEADER_SIZE){ + //raise exception? + errlogPrintf("too short header %ld\n",rsize); + return -1; + } + else if (memcmp(this->prologue, buffer,2) != 0){ + //error + errlogPrintf("incorrect prologue %2s %2s\n",buffer,this->prologue); + return -1; + } + + //errlogPrintf("Recieved message %2s %2s\n",buffer,this->prologue); + + this->message_type=*((epicsUInt8 *) ((char *) buffer+2)); + this->control_code=*((epicsUInt8 *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(epicsUInt32 *) ((char *) buffer+4)); + this->payload_length = be64toh(*(epicsUInt64 *) ((char *) buffer+8)); + + this->printf(); + + if((expected_message_type != AnyMessages) && + (expected_message_type != this->message_type)){ + //error! + // in overlapped mode, should we keep it? + errlogPrintf("Error message types does not match %d vs %d\n",expected_message_type, + this->message_type); + return -1; + } + + errlogPrintf("successfull recieved message header %ld \n",rsize); + + return rsize; + } + + int fromRawData(void *buffer){ //DeSerialize + if (memcmp(this->prologue, buffer,2) != 0){ + //error + return -1; + } + this->message_type=*((epicsUInt8 *) ((char *) buffer+2)); + this->control_code=*((epicsUInt8 *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(epicsUInt32 *) ((char *) buffer+4)); + this->payload_length = be64toh(*(epicsUInt64 *) ((char *) buffer+8)); + return 0; + } + int toRawData(void *buffer){ //Serialize this as bytes data in buffer. + memcpy( buffer, this->prologue, 2); + *((char *) buffer + 2) = this->message_type; + *((char *) buffer + 3) = this->control_code; + *((epicsUInt32 *)((char *) buffer+4))=htobe32(this->message_parameter.word); + *((epicsUInt64 *)((char *) buffer+8))=htobe64(this->payload_length); + return 0; + } + }; + + typedef class Message:public Header{ + public: + void *payload=NULL; + + Message(Message_Types_t message_type):Header(message_type){ + }; + Message(void *raw_header):Header(raw_header){ + //this->fromRawData(raw_header); + }; + Message(void *raw_header, void *payload):Message(raw_header){ + this->payload= (void *) callocMustSucceed(1, + this->payload_length, + "HiSLIP payload buffer"); + memcpy(this->payload, payload, this->payload_length); + } + Message(epicsUInt8 type, + epicsUInt8 cce, + message_parameter_t param, + epicsUInt64 length, + epicsUInt8 *payload):Header(type,cce,param,length),payload(payload) { + //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); + //memcpy(this->payload, payload, length); + //this->payload = payload; + } + size_t send(int socket){ + size_t ssize; + ssize=this->Header::send(socket); + if (ssize < HEADER_SIZE){ + return -1; + } + return (ssize + ::send(socket, this->payload, this->payload_length,0)); + } + + ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ + size_t rsize; + size_t status; + + /* setsockopt(sock, SOL_SOCKET, */ + /* SO_RCVTIMEO, &(msg->socket_timeout), sizeof(int)); */ + + // read header part and update header. + + rsize=this->Header::recv(socket, expected_message_type); + + if (rsize < 0){ + // Error! + errlogPrintf("failed to read header.%ld \n",rsize); + return rsize; + } + + // now prepare for a pyload. + if (this->payload==NULL && this->payload_length > 0){ + this->payload= (void *) callocMustSucceed(1, + this->payload_length, + "HiSLIP pyload buffer"); + } + + rsize=0; //returns size of recieved payload. + if (this->payload_length > 0){ + size_t bytestoread=this->payload_length; + + while (bytestoread){ + status = ::recv(socket, ((epicsUInt8 *)this->payload+rsize), bytestoread, 0); + + if (status <= 0){ + perror("payload read error:"); + errlogPrintf("recive error\n"); + return -1; + } + rsize +=status; + if (status >= bytestoread){ + break; + } + bytestoread -=status; + } + } + errlogPrintf("successfull recieved message %ld \n",rsize); + return (rsize); + } + } Message_t; + + typedef class HiSLIP { + public: + unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; + unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + long socket_timeout=SOCKET_TIMEOUT; + long lock_timeout=LOCK_TIMEOUT; + int sync_channel; + int async_channel; + struct pollfd sync_poll; + struct pollfd async_poll; + int overlap_mode; + int session_id; + int server_protocol_version; + unsigned int server_vendorID; + + bool rmt_delivered; + epicsUInt32 message_id; + epicsUInt32 most_recent_message_id; + void set_timeout( long timeout){ + this->socket_timeout=timeout; + }; + long get_timeout(void){ + return this->socket_timeout; + }; + void set_lock_timeout( long timeout){ + this->lock_timeout=timeout; + } + ; + long get_lock_timeout(void){ + return this->lock_timeout; + }; + HiSLIP(){ + }; + void connect(char const* hostname){ + this->connect(hostname, + Default_device_name, + Default_Port); + }; + void connect(char const* hostname, + char const* dev_name, + int port); + long set_max_size(long message_size); + int device_clear(void); + epicsUInt8 status_query(); + //long write(epicsUInt8 *data_str, long timeout=LOCK_TIMEOUT); + long write(const epicsUInt8 *data_str, const size_t size, long timeout=LOCK_TIMEOUT); + size_t ask(epicsUInt8 *data_str, size_t size, + epicsUInt8 **rbuffer, long wait_time=LOCK_TIMEOUT); + int read(size_t *received, long timeout=LOCK_TIMEOUT ); + int read(size_t *received, epicsUInt8 **buffer, long timeout=LOCK_TIMEOUT); + int read(size_t *received, epicsUInt8 *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); + long trigger_message(void); + long remote_local(bool request); + long request_lock(const char* lock_string=NULL); + long release_lock(void); + long request_srq_lock(void); + long release_srq_lock(void); + Message *get_Service_Request(void){ + Message *msg=new Message(0); + long status; + status= msg->recv(this->async_channel, AsyncServiceRequest); + if (status != 0){ + perror(__FUNCTION__); + } + return msg; + }; + int wait_for_SRQ(int wait_time){ + return ::poll(&this->async_poll, 1, wait_time); + } + void disconnect(){}; + + private: + int wait_for_answer(int wait_time){ + return ::poll(&this->sync_poll, 1, wait_time); + } + void reset_message_id(void){ + this->most_recent_message_id=0; + this->message_id = 0xffffff00; + } + epicsUInt32 increment_message_id(void){ + this->most_recent_message_id=this->message_id; + this->message_id = (this->message_id +2) & 0xffffffff; + return this->message_id; + }; + } HiSLIP_t; +}; // namespace From 647eb47427ecf1071fd06296d7b0f4cc994399ae Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 23 May 2020 14:35:27 +0900 Subject: [PATCH 05/67] delete drvAsynHiSLIP.c. replaced by drvHiSLIP.cpp --- asyn/drvAsynHiSLIP/drvAsynHiSLIP.c | 1291 ---------------------------- 1 file changed, 1291 deletions(-) delete mode 100644 asyn/drvAsynHiSLIP/drvAsynHiSLIP.c diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.c b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.c deleted file mode 100644 index 432a211af..000000000 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.c +++ /dev/null @@ -1,1291 +0,0 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "drvAsynHiSLIP.h" - -#define MESSAGE_ID_DEV_DEP_MSG_OUT 1 -#define MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN 2 -#define MESSAGE_ID_DEV_DEP_MSG_IN 2 - -#define BULK_IO_HEADER_SIZE 12 -#define BULK_IO_PAYLOAD_CAPACITY 4096 -#define IDSTRING_CAPACITY 100 - -#define ASYN_REASON_SRQ 4345 -#define ASYN_REASON_STB 4346 -#define ASYN_REASON_REN 4347 - -#if (!defined(LIBUSBX_API_VERSION) || (LIBUSBX_API_VERSION < 0x01000102)) -# error "You need to get a newer version of libsb-1.0 (16 at the very least)" -#endif - -typedef struct drvPvt { - /* - * Used to find matching device - */ - const char *hostname; - const long port; - /* - * Matched device - */ - char deviceVendorID[IDSTRING_CAPACITY]; - - /* - * Asyn interfaces we provide - */ - char *portName; - asynInterface asynCommon; - asynInterface asynOctet; - asynInterface asynInt32; - void *asynInt32InterruptPvt; - asynInterface asynDrvUser; - - /* - * HiSLIP private - */ - int sync_channel; - int async_channel; - long RMT; - long message_id; - long most_recent_message_id; - - /* - * Interrupt endpoint handling - */ - char *interruptThreadName; - epicsThreadId interruptTid; - epicsMutexId interruptTidMutex; - epicsEventId pleaseTerminate; - epicsEventId didTerminate; - epicsMessageQueueId statusByteMessageQueue; - - /* - * I/O buffer - */ - unsigned char buf[BULK_IO_HEADER_SIZE+BULK_IO_PAYLOAD_CAPACITY]; - int bufCount; - const unsigned char *bufp; - unsigned char bulkInPacketFlags; - - /* - * Statistics - */ - size_t connectionCount; - size_t interruptCount; - size_t bytesSentCount; - size_t bytesReceivedCount; -} drvPvt; - -static asynStatus disconnect(void *pvt, asynUser *pasynUser); - -/* - * Interrupt endpoint support - */ -static void -interruptThread(void *arg) -{ - drvPvt *pdpvt = (drvPvt *)arg; - unsigned char cbuf[2]; - int n; - int s; - - for (;;) { - s = libusb_interrupt_transfer (pdpvt->handle, - pdpvt->interruptEndpointAddress, - cbuf, - sizeof cbuf, - &n, - 65000); - if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK) - break; - if ((s == 0) && (n == sizeof cbuf)) { - if (cbuf[0] == 0x81) { - ELLLIST *pclientList; - interruptNode *pnode; - - pdpvt->interruptCount++; - pasynManager->interruptStart(pdpvt->asynInt32InterruptPvt, &pclientList); - pnode = (interruptNode *)ellFirst(pclientList); - while (pnode) { - asynInt32Interrupt *int32Interrupt = pnode->drvPvt; - pnode = (interruptNode *)ellNext(&pnode->node); - if (int32Interrupt->pasynUser->reason == ASYN_REASON_SRQ) { - int32Interrupt->callback(int32Interrupt->userPvt, - int32Interrupt->pasynUser, - cbuf[1]); - } - } - pasynManager->interruptEnd(pdpvt->asynInt32InterruptPvt); - } - else if (cbuf[0] == 0x82) { - if (epicsMessageQueueTrySend(pdpvt->statusByteMessageQueue, - &cbuf[1], 1) != 0) { - errlogPrintf("----- WARNING ----- " - "Can't send status byte to worker thread!\n"); - } - } - } - else if (s != LIBUSB_ERROR_TIMEOUT) { - errlogPrintf("----- WARNING ----- " - "libusb_interrupt_transfer failed (%s). " - "Interrupt thread for ASYN port \"%s\" terminating.\n", - libusb_strerror(s), pdpvt->portName); - break; - } - } - epicsMutexLock(pdpvt->interruptTidMutex); - pdpvt->interruptTid = 0; - epicsEventSignal(pdpvt->didTerminate); - epicsMutexUnlock(pdpvt->interruptTidMutex); -} - -static void -startInterruptThread(drvPvt *pdpvt) -{ - epicsMutexLock(pdpvt->interruptTidMutex); - if (pdpvt->enableInterruptEndpoint - && pdpvt->interruptEndpointAddress - && (pdpvt->interruptTid == 0)) { - epicsEventTryWait(pdpvt->pleaseTerminate); - epicsEventTryWait(pdpvt->didTerminate); - pdpvt->interruptTid = epicsThreadCreate(pdpvt->interruptThreadName, - epicsThreadGetPrioritySelf(), - epicsThreadGetStackSize(epicsThreadStackSmall), - interruptThread, pdpvt); - if (pdpvt->interruptTid == 0) - errlogPrintf("----- WARNING ----- " - "Can't start interrupt handler thread %s.\n", - pdpvt->interruptThreadName); - } - epicsMutexUnlock(pdpvt->interruptTidMutex); -} - -/* - * Decode a status byte - */ -static void -showHexval(FILE *fp, const char *name, int val, int bitmask, const char *bitname, ...) -{ - const char *sep = " -- "; - va_list ap; - va_start(ap, bitname); - fprintf(fp, "%28s: ", name); - if (bitmask) - fprintf(fp, "%#x", val); - else - fprintf(fp, "%#4.4x", val); - for (;;) { - if (((bitmask > 0) && ((val & bitmask)) != 0) - || ((bitmask < 0) && ((val & -bitmask)) == 0) - || ((bitmask == 0) && (bitname != NULL) && (bitname[0] != '\0'))) { - fprintf(fp, "%s%s", sep, bitname); - sep = ", "; - } - if (bitmask == 0) - break; - bitmask = va_arg(ap, int); - if (bitmask == 0) - break; - bitname = va_arg(ap, char *); - } - fprintf(fp, "\n"); - va_end(ap); -} - -/* - * Show a byte number - */ -static void -pcomma(FILE *fp, size_t n) -{ - if (n < 1000) { - fprintf(fp, "%zu", n); - return; - } - pcomma(fp, n/1000); - fprintf(fp, ",%03zu", n%1000); -} - -static void -showCount(FILE *fp, const char *label, size_t count) -{ - fprintf(fp, "%22s Count: ", label); - pcomma(fp, count); - fprintf(fp, "\n"); -} - -/* - * asynCommon methods - */ -static void -report(void *pvt, FILE *fp, int details) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - - fprintf(fp, "%20sonnected, Interrupt handler thread %sactive\n", - pdpvt->isConnected ? "C" : "Disc", - pdpvt->interruptTid ? "" : "in"); - showHexval(fp, "Vendor", pdpvt->deviceVendorId, 0, pdpvt->deviceVendorString); - showHexval(fp, "Product", pdpvt->deviceProductId, 0, pdpvt->deviceProductString); - if (pdpvt->deviceSerialString[0]) - fprintf(fp, "%28s: \"%s\"\n", "Serial Number", pdpvt->deviceSerialString); - if (details > 0) { - fprintf(fp, " Interface Protocol: %x", pdpvt->bInterfaceProtocol); - switch (pdpvt->bInterfaceProtocol) { - case 0: fprintf(fp, " -- HiSLIP\n"); break; - case 1: fprintf(fp, " -- HiSLIP USB488\n"); break; - default: fprintf(fp, "\n"); break; - } - if (pdpvt->termChar >= 0) - fprintf(fp, "%28s: %x\n", "Terminator", pdpvt->termChar); - showHexval(fp, "TMC Interface Capabilities", - pdpvt->tmcInterfaceCapabilities, - 0x4, "Accepts INDICATOR_PULSE", - 0x2, "Talk-only", - 0x1, "Listen-only", - -0x3, "Talk/Listen", - 0); - showHexval(fp, "TMC Device Capabilities", - pdpvt->tmcDeviceCapabilities, - 0x1, "Supports termChar", - 0); - if (pdpvt->bInterfaceProtocol == 1) { - showHexval(fp, "488 Interface Capabilities", - pdpvt->usb488InterfaceCapabilities, - 0x4, "488.2", - 0x2, "REN/GTL/LLO", - 0x1, "TRG", - 0); - showHexval(fp, "488 Device Capabilities", - pdpvt->usb488DeviceCapabilities, - 0x8, "SCPI", - 0x4, "SR1", - -0x4, "SR0", - 0x2, "RL1", - -0x2, "RL0", - 0x1, "DT1", - -0x1, "DT0", - 0); - } - } - if (details > 1) { - fprintf(fp, " Bulk output endpoint: %x\n", pdpvt->bulkOutEndpointAddress); - fprintf(fp, " Bulk input endpoint: %x\n", pdpvt->bulkInEndpointAddress); - fprintf(fp, " Interrupt endpoint: %x\n", pdpvt->interruptEndpointAddress); - showCount(fp, "Connection", pdpvt->connectionCount); - showCount(fp, "Interrupt", pdpvt->interruptCount); - showCount(fp, "Send", pdpvt->bytesSentCount); - showCount(fp, "Receive", pdpvt->bytesReceivedCount); - } - if (details >= 100) { - int l = details % 100; - fprintf(fp, "==== Set libusb debug level %d ====\n", l); - libusb_set_debug(pdpvt->usb, l); - } -} - -/* - * Get USB descriptor as an ASCII string. - */ -static void -getDeviceString(drvPvt *pdpvt, int i, char *dest) -{ - ssize_t n; - - n = libusb_get_string_descriptor_ascii(pdpvt->handle, i, - pdpvt->buf, sizeof pdpvt->buf); - if (n < 0) { - *dest = '\0'; - return; - } - if(n >= IDSTRING_CAPACITY) - n = IDSTRING_CAPACITY - 1; - strncpy(dest, (char *)pdpvt->buf, n); -} -static void -getDeviceStrings(drvPvt *pdpvt, struct libusb_device_descriptor *desc) -{ - getDeviceString(pdpvt, desc->iManufacturer, pdpvt->deviceVendorString); - getDeviceString(pdpvt, desc->iProduct, pdpvt->deviceProductString); - getDeviceString(pdpvt, desc->iSerialNumber, pdpvt->deviceSerialString); -} - -/* - * Get endpoints - */ -static void -getEndpoints(drvPvt *pdpvt, const struct libusb_interface_descriptor *iface_desc) -{ - int e; - - pdpvt->bulkInEndpointAddress = 0; - pdpvt->bulkOutEndpointAddress = 0; - pdpvt->interruptEndpointAddress = 0; - for (e = 0 ; e < iface_desc->bNumEndpoints ; e++) { - const struct libusb_endpoint_descriptor *ep = &iface_desc->endpoint[e]; - switch (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { - case LIBUSB_TRANSFER_TYPE_BULK: - if ((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) - pdpvt->bulkInEndpointAddress = ep->bEndpointAddress; - else - pdpvt->bulkOutEndpointAddress = ep->bEndpointAddress; - break; - - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - pdpvt->interruptEndpointAddress = ep->bEndpointAddress; - break; - } - } -} - -/* - * Search the bus for a matching device - */ -static asynStatus -findDevice(drvPvt *pdpvt, asynUser *pasynUser, libusb_device **list, int n) -{ - int i, j, k; - - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "No Vendor/Product/Serial match found"); - for (i = 0 ; i < n ; i++) { - libusb_device *dev = list[i]; - struct libusb_device_descriptor desc; - struct libusb_config_descriptor *config; - - int s = libusb_get_device_descriptor(dev, &desc); - if (s != 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_get_device_descriptor failed: %s", libusb_strerror(s)); - return asynError; - } - if (desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) - continue; - if ((libusb_get_active_config_descriptor(dev, &config) < 0) - && (libusb_get_config_descriptor(dev, 0, &config) < 0)) - continue; - if (config == NULL) - continue; - for (j = 0 ; j < config->bNumInterfaces ; j++) { - const struct libusb_interface *iface = &config->interface[j]; - for (k = 0 ; k < iface->num_altsetting ; k++) { - const struct libusb_interface_descriptor *iface_desc; - iface_desc = &iface->altsetting[k]; - if ((iface_desc->bInterfaceClass==HiSLIP_INTERFACE_CLASS) - && (iface_desc->bInterfaceSubClass==HiSLIP_INTERFACE_SUBCLASS) - && ((pdpvt->vendorId==0) || (pdpvt->vendorId==desc.idVendor)) - && ((pdpvt->productId==0) || (pdpvt->productId==desc.idProduct))) { - pdpvt->bInterfaceNumber = iface_desc->bInterfaceNumber; - pdpvt->bInterfaceProtocol = iface_desc->bInterfaceProtocol; - s = libusb_open(dev, &pdpvt->handle); - if (s == 0) { - pdpvt->deviceVendorId = desc.idVendor; - pdpvt->deviceProductId = desc.idProduct; - getDeviceStrings(pdpvt, &desc); - if ((pdpvt->serialNumber == NULL) - || (strcmp(pdpvt->serialNumber, - pdpvt->deviceSerialString) == 0)) { - getEndpoints(pdpvt, iface_desc); - libusb_free_config_descriptor(config); - pasynUser->errorMessage[0] = '\0'; - return asynSuccess; - } - libusb_close(pdpvt->handle); - } - else { - epicsSnprintf(pasynUser->errorMessage, - pasynUser->errorMessageSize, - "libusb_open failed: %s", - libusb_strerror(s)); - } - } - } - } - libusb_free_config_descriptor(config); - } - return asynError; -} - -/* - * Disconnect when it appears that device has gone away - */ -static void -disconnectIfGone(drvPvt *pdpvt, asynUser *pasynUser, int s) -{ - if (s == LIBUSB_ERROR_NO_DEVICE) - disconnect(pdpvt, pasynUser); -} - -/* - * Check results of control transfer - */ -static asynStatus -checkControlTransfer(const char *msg, drvPvt *pdpvt, asynUser *pasynUser, - int s, int want, int usbtmcStatus) -{ - if (s < 0) { - disconnectIfGone(pdpvt, pasynUser, s); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "HiSLIP %s failed: %s", msg, libusb_strerror(s)); - return asynError; - } - if (s != want) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "HiSLIP %s failed -- asked for 0x%x, got %x", msg, want, s); - return asynError; - } - if (usbtmcStatus != 1) { - const char *cp; - switch (usbtmcStatus) { - case 0x02: cp = " (STATUS_PENDING)"; break; - case 0x80: cp = " (STATUS_FAILED)"; break; - case 0x81: cp = " (STATUS_TRANSFER_NOT_IN_PROGRESS)"; break; - case 0x82: cp = " (STATUS_SPLIT_NOT_IN_PROGRESS)"; break; - case 0x83: cp = " (STATUS_SPLIT_IN_PROGRESS)"; break; - default: cp = ""; break; - } - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "HiSLIP %s failed -- HiSLIP_status: 0x%x%s", msg, usbtmcStatus, cp); - return asynError; - } - return asynSuccess; -} - -/* - * Get device capabilities - */ -static asynStatus -getCapabilities(drvPvt *pdpvt, asynUser *pasynUser) -{ - int s; - asynStatus status; - - s = libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 0x07, // bRequest: HiSLIP GET_CAPABILITIES - 0x0000, // wValue - pdpvt->bInterfaceNumber, // wIndex - pdpvt->buf, // data - 0x0018, // wLength - 100); // timeout (ms) - status = checkControlTransfer("GET_CAPABILITIES", pdpvt, pasynUser, - s, 0x18, pdpvt->buf[0]); - if (status != asynSuccess) - return status; - pdpvt->tmcInterfaceCapabilities = pdpvt->buf[4]; - pdpvt->tmcDeviceCapabilities = pdpvt->buf[5]; - if (pdpvt->bInterfaceProtocol == 1) { - pdpvt->usb488InterfaceCapabilities = pdpvt->buf[14]; - pdpvt->usb488DeviceCapabilities = pdpvt->buf[15]; - } - return asynSuccess; -} - -/* - * Clear input/output buffers - */ -static asynStatus -clearBuffers(drvPvt *pdpvt, asynUser *pasynUser) -{ - int s; - asynStatus status; - int pass = 0; - unsigned char cbuf[2]; - - s = libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 0x05, // bRequest: HiSLIP INITIATE_CLEAR - 0x0000, // wValue - pdpvt->bInterfaceNumber, // wIndex - cbuf, // data - 1, // wLength - 100); // timeout (ms) - status = checkControlTransfer("INITIATE_CLEAR", pdpvt, pasynUser, - s, 1, cbuf[0]); - if (status != asynSuccess) - return status; - for (;;) { - epicsThreadSleep(0.01); // I don't know why this is necessary, but without some delay here the CHECK_CLEAR_STATUS seems to be stuck at STATUS_PENDING - s = libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 0x06, // bRequest: HiSLIP CHECK_CLEAR_STATUS - 0x0000, // wValue - pdpvt->bInterfaceNumber, // wIndex - cbuf, // data - 0x0002, // wLength - 100); // timeout (ms) - status = checkControlTransfer("CHECK_CLEAR_STATUS", pdpvt, pasynUser, - s, 2, 1); - if (status != asynSuccess) - return asynError; - if (cbuf[0] != 2) { - libusb_clear_halt(pdpvt->handle, pdpvt->bulkInEndpointAddress); - libusb_clear_halt(pdpvt->handle, pdpvt->bulkOutEndpointAddress); - if (cbuf[0] == 1) - return asynSuccess; - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "CHECK_CLEAR_STATUS failed -- status: %x", cbuf[0]); - return asynError; - } - switch (++pass) { - case 5: - asynPrint(pasynUser, ASYN_TRACE_ERROR, "Note -- RESET DEVICE.\n"); - s = libusb_reset_device(pdpvt->handle); - if (s != 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_reset_device() failed: %s", libusb_strerror(s)); - return asynError; - } - break; - - case 10: - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "CHECK_CLEAR_STATUS remained 'STATUS_PENDING' for too long"); - return asynError; - } - asynPrint(pasynUser, ASYN_TRACE_ERROR, - "Note -- retrying CHECK_CLEAR_STATUS\n"); - } - return asynSuccess; -} - -static asynStatus -connect(void *pvt, asynUser *pasynUser) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - asynStatus status; - - if (!pdpvt->isConnected) { - libusb_device **list; - ssize_t n; - int s; - - n = libusb_get_device_list(pdpvt->usb, &list); - if (n < 0) { - s = n; - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_get_device_list failed: %s", libusb_strerror(s)); - return asynError; - } - status = findDevice(pdpvt, pasynUser, list, n); - libusb_free_device_list(list, 1); - if (status != asynSuccess) - return asynError; - s = libusb_claim_interface(pdpvt->handle, pdpvt->bInterfaceNumber); - if (s == LIBUSB_ERROR_BUSY) { - libusb_detach_kernel_driver(pdpvt->handle, pdpvt->bInterfaceNumber); - s = libusb_claim_interface(pdpvt->handle, pdpvt->bInterfaceNumber); - } - if (s) { - libusb_close(pdpvt->handle); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_claim_interface failed: %s", libusb_strerror(s)); - return asynError; - } - if (getCapabilities(pdpvt, pasynUser) != asynSuccess) { - libusb_close(pdpvt->handle); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Can't get device capabilities: %s", pasynUser->errorMessage); - return asynError; - } - if (clearBuffers(pdpvt, pasynUser) != asynSuccess) { - libusb_close(pdpvt->handle); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Can't clear buffers: %s", pasynUser->errorMessage); - return asynError; - } - pdpvt->bulkInPacketFlags = 0; - pdpvt->bufCount = 0; - pdpvt->connectionCount++; - startInterruptThread(pdpvt); - } - pdpvt->isConnected = 1; - pasynManager->exceptionConnect(pasynUser); - return asynSuccess; -} - -static asynStatus -disconnect(void *pvt, asynUser *pasynUser) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - - if (pdpvt->isConnected) { - int pass = 0; - epicsThreadId tid; - for (;;) { - unsigned char cbuf[3]; - - epicsMutexLock(pdpvt->interruptTidMutex); - tid = pdpvt->interruptTid; - epicsMutexUnlock(pdpvt->interruptTidMutex); - if (tid == 0) - break; - if (++pass == 10) { - errlogPrintf("----- WARNING ----- Thread %s won't terminate!\n", - pdpvt->interruptThreadName); - break; - } - - /* - * Send signal then force an Interrupt-In message - */ - epicsEventSignal(pdpvt->pleaseTerminate); - libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 128, // bRequest: READ_STATUS_BYTE - 127, // wValue (bTag) - pdpvt->bInterfaceNumber, // wIndex - cbuf, // data - 3, // wLength - 100); // timeout (ms) - epicsEventWaitWithTimeout(pdpvt->didTerminate, 2.0); - } - libusb_close(pdpvt->handle); - } - pdpvt->isConnected = 0; - pasynManager->exceptionDisconnect(pasynUser); - return asynSuccess; -} -static asynCommon commonMethods = { report, connect, disconnect }; - -/* - * asynOctet methods - */ -static asynStatus -asynOctetWrite(void *pvt, asynUser *pasynUser, - const char *data, size_t numchars, size_t *nbytesTransfered) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - int timeout = pasynUser->timeout * 1000; - if (timeout == 0) timeout = 1; - - /* - * Common to all writes - */ - pdpvt->bufCount = 0; - pdpvt->bulkInPacketFlags = 0; - pdpvt->buf[0] = MESSAGE_ID_DEV_DEP_MSG_OUT; - pdpvt->buf[3] = 0; - pdpvt->buf[9] = 0; - pdpvt->buf[10] = 0; - pdpvt->buf[11] = 0; - - /* - * Send - */ - *nbytesTransfered = 0; - while (numchars) { - int nSend, pkSend, pkSent; - int s; - if (numchars > BULK_IO_PAYLOAD_CAPACITY) { - nSend = BULK_IO_PAYLOAD_CAPACITY; - pdpvt->buf[8] = 0; - } - else { - nSend = numchars; - pdpvt->buf[8] = 1; - } - pdpvt->buf[1] = pdpvt->bTag; - pdpvt->buf[2] = ~pdpvt->bTag; - pdpvt->buf[4] = nSend; - pdpvt->buf[5] = nSend >> 8; - pdpvt->buf[6] = nSend >> 16; - pdpvt->buf[7] = nSend >> 24; - memcpy(&pdpvt->buf[BULK_IO_HEADER_SIZE], data, nSend); - pdpvt->bTag = (pdpvt->bTag == 0xFF) ? 0x1 : pdpvt->bTag + 1; - pkSend = nSend + BULK_IO_HEADER_SIZE; - while (pkSend & 0x3) - pdpvt->buf[pkSend++] = 0; - asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, - pkSend, "Send %d: ", pkSend); - s = libusb_bulk_transfer(pdpvt->handle, pdpvt->bulkOutEndpointAddress, - pdpvt->buf, pkSend, &pkSent, timeout); - if (s) { - disconnectIfGone(pdpvt, pasynUser, s); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Bulk transfer failed: %s", libusb_strerror(s)); - return asynError; - } - if (pkSent != pkSend) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Asked to send %d, actually sent %d", pkSend, pkSent); - return asynError; - } - data += nSend; - numchars -= nSend; - *nbytesTransfered += nSend; - } - pdpvt->bytesSentCount += *nbytesTransfered; - return asynSuccess; -} - -static asynStatus -asynOctetRead(void *pvt, asynUser *pasynUser, - char *data, size_t maxchars, size_t *nbytesTransfered, - int *eomReason) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - unsigned char bTag; - int s; - int nCopy, ioCount, payloadSize; - int eom = 0; - int timeout = pasynUser->timeout * 1000; - if (timeout == 0) timeout = 1; - - *nbytesTransfered = 0; - for (;;) { - /* - * Special case for stream device which requires an asynTimeout return. - */ - if ((pasynUser->timeout == 0) && (pdpvt->bufCount == 0)) - return asynTimeout; - - /* - * Transfer buffered data - */ - if (pdpvt->bufCount) { - nCopy = maxchars; - if (nCopy > pdpvt->bufCount) - nCopy = pdpvt->bufCount; - memcpy(data, pdpvt->bufp, nCopy); - pdpvt->bufp += nCopy; - pdpvt->bufCount -= nCopy; - maxchars -= nCopy; - *nbytesTransfered += nCopy; - pdpvt->bytesReceivedCount += nCopy; - data += nCopy; - if (maxchars == 0) - eom |= ASYN_EOM_CNT; - } - if (pdpvt->bufCount == 0) { - if (pdpvt->bulkInPacketFlags & 0x2) - eom |= ASYN_EOM_EOS; - if (pdpvt->bulkInPacketFlags & 0x1) - eom |= ASYN_EOM_END; - } - if (eom) { - if (eomReason) *eomReason = eom; - return asynSuccess; - } - - /* - * Request another chunk - */ - pdpvt->bulkInPacketFlags = 0; - pdpvt->buf[0] = MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN; - pdpvt->buf[1] = pdpvt->bTag; - pdpvt->buf[2] = ~pdpvt->bTag; - pdpvt->buf[3] = 0; - pdpvt->buf[4] = BULK_IO_PAYLOAD_CAPACITY & 0xFF; - pdpvt->buf[5] = (BULK_IO_PAYLOAD_CAPACITY >> 8) & 0xFF; - pdpvt->buf[6] = (BULK_IO_PAYLOAD_CAPACITY >> 16) & 0xFF; - pdpvt->buf[7] = (BULK_IO_PAYLOAD_CAPACITY >> 24) & 0xFF; - if (pdpvt->termChar >= 0) { - pdpvt->buf[8] = 2; - pdpvt->buf[9] = pdpvt->termChar; - } - else { - pdpvt->buf[8] = 0; - pdpvt->buf[9] = 0; - } - pdpvt->buf[10] = 0; - pdpvt->buf[11] = 0; - bTag = pdpvt->bTag; - pdpvt->bTag = (pdpvt->bTag == 0xFF) ? 0x1 : pdpvt->bTag + 1; - asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, - BULK_IO_HEADER_SIZE, - "Request %d, command: ", BULK_IO_PAYLOAD_CAPACITY); - s = libusb_bulk_transfer(pdpvt->handle, pdpvt->bulkOutEndpointAddress, - pdpvt->buf, BULK_IO_HEADER_SIZE, &ioCount, timeout); - if (s) { - disconnectIfGone(pdpvt, pasynUser, s); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Bulk transfer request failed: %s", libusb_strerror(s)); - return asynError; - } - - /* - * Read back - */ - s = libusb_bulk_transfer(pdpvt->handle, pdpvt->bulkInEndpointAddress, pdpvt->buf, - sizeof pdpvt->buf, &ioCount, timeout); - if (s) { - disconnectIfGone(pdpvt, pasynUser, s); - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Bulk read failed: %s", libusb_strerror(s)); - return asynError; - } - asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, (const char *)pdpvt->buf, - ioCount, "Read %d, flags %#x: ", ioCount, pdpvt->buf[8]); - - /* - * Sanity check on transfer - */ - if (ioCount < BULK_IO_HEADER_SIZE) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Incomplete packet header (read only %d)", ioCount); - return asynError; - } - if ((pdpvt->buf[0] != MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN) - || (pdpvt->buf[1] != bTag) - || (pdpvt->buf[2] != (unsigned char)~bTag)) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Packet header corrupt %x %x %x (btag %x)", - pdpvt->buf[0], pdpvt->buf[1], pdpvt->buf[2], bTag); - return asynError; - } - payloadSize = pdpvt->buf[4] | - (pdpvt->buf[5] << 8) | - (pdpvt->buf[6] << 16) | - (pdpvt->buf[7] << 24); - if (payloadSize > (ioCount - BULK_IO_HEADER_SIZE)) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Packet header claims %d sent, but packet contains only %d", - payloadSize, ioCount - BULK_IO_HEADER_SIZE); - return asynError; - } - if (payloadSize > BULK_IO_PAYLOAD_CAPACITY) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Packet header claims %d sent, but requested only %d", - payloadSize, BULK_IO_PAYLOAD_CAPACITY); - return asynError; - } - pdpvt->bufCount = payloadSize; - pdpvt->bufp = &pdpvt->buf[BULK_IO_HEADER_SIZE]; - - /* - * USB TMC uses a short packet to mark the end of a transfer - * It's not clear to me that the library exposes this short - * packet in the case following a read that just happens to - * finish on a pdpvt->buf sized boundary. For now I am assuming - * that I will, in fact, get a short packet following. - */ - pdpvt->bulkInPacketFlags = pdpvt->buf[8]; - } -} - -/* - * I see no mechanism for determining when it is necessary/possible to issue - * MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN requests and transfers from the bulk-IN - * endpoint. I welcome suggestions from libusb experts. - */ -static asynStatus -asynOctetFlush(void *pvt, asynUser *pasynUser) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - - pdpvt->bufCount = 0; - pdpvt->bulkInPacketFlags = 0; - return asynSuccess; -} - -static asynStatus -asynOctetSetInputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - - switch (eoslen) { - case 0: - pdpvt->termChar = -1; - break; - case 1: - if ((pdpvt->tmcDeviceCapabilities & 0x1) == 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support terminating characters"); - return asynError; - } - pdpvt->termChar = *eos & 0xFF; - break; - default: - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support multiple terminating characters"); - return asynError; - } - return asynSuccess; -} - -static asynStatus -asynOctetGetInputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - - if (pdpvt->termChar < 0) { - *eoslen = 0; - } - else { - if (eossize < 1) return asynError; - *eos = pdpvt->termChar; - *eoslen = 1; - } - return asynSuccess; -} - -static asynStatus -asynOctetSetOutputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) -{ - return asynError; -} - -static asynStatus -asynOctetGetOutputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) -{ - return asynError; -} - -static asynOctet octetMethods = { - .write = asynOctetWrite, - .read = asynOctetRead, - .flush = asynOctetFlush, - .setInputEos = asynOctetSetInputEos, - .getInputEos = asynOctetGetInputEos, - .setOutputEos = asynOctetSetOutputEos, - .getOutputEos = asynOctetGetOutputEos, -}; - -/* - * asynInt32 methods - */ -static asynStatus -asynInt32Write(void *pvt, asynUser *pasynUser, epicsInt32 value) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - int s; - asynStatus status; - unsigned char cbuf[1]; - - switch (pasynUser->reason) { - case ASYN_REASON_REN: - if ((pdpvt->usb488InterfaceCapabilities & 0x2) == 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support REN operations."); - return asynError; - } - s = libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 160, // bRequest: HiSLIP REN_CONTROL - (value != 0), // wValue - pdpvt->bInterfaceNumber, // wIndex - cbuf, // data - 1, // wLength - 100); // timeout (ms) - status = checkControlTransfer("REN_CONTROL", pdpvt, pasynUser, - s, 1, cbuf[0]); - if (status != asynSuccess) - return status; - return asynSuccess; - - default: - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "asynInt32Write -- invalid drvUser (reason) %d", pasynUser->reason); - return asynError; - } -} - -static asynStatus -asynInt32Read(void *pvt, asynUser *pasynUser, epicsInt32 *value) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - int s; - asynStatus status; - unsigned char cbuf[3]; - - switch (pasynUser->reason) { - case ASYN_REASON_STB: - if (pdpvt->interruptTid) { - /* Flush queue */ - epicsMessageQueueTryReceive(pdpvt->statusByteMessageQueue, cbuf, 1); - } - s = libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 128, // bRequest: HiSLIP READ_STATUS_BYTE - 2, // wValue (bTag) - pdpvt->bInterfaceNumber, // wIndex - cbuf, // data - 3, // wLength - 100); // timeout (ms) - status = checkControlTransfer("READ_STATUS_BYTE", pdpvt, pasynUser, - s, 3, cbuf[0]); - if (status != asynSuccess) - return status; - - /* - * Value can be returned in three different ways - */ - if (pdpvt->interruptEndpointAddress == 0) { - /* - * 1 - Directly in the reply - */ - *value = cbuf[2]; - } - else if (pdpvt->interruptTid == 0) { - int n; - /* - * 2 - Read status here - */ - s = libusb_interrupt_transfer (pdpvt->handle, - pdpvt->interruptEndpointAddress, - cbuf, - 2, - &n, - 100); - if (s < 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_interrupt_transfer failed: %s", libusb_strerror(s)); - return asynError; - } - if (n != 2) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_interrupt_transfer got %d, expected 2", n); - return asynError; - } - if (cbuf[0] != 0x82) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "libusb_interrupt_transfer bTag 0x%x, expected 0x82", cbuf[0]); - return asynError; - } - *value = cbuf[1]; - } - else { - /* - * 3 - Read status in interrupt thread - */ - s = epicsMessageQueueReceiveWithTimeout( - pdpvt->statusByteMessageQueue, cbuf, 1, 0.2); - if (s != 1) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "No status byte from interrupt thread"); - return asynError; - } - *value = cbuf[0]; - } - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "READ_STATUS_BYTE: 0x%x\n", *value); - return asynSuccess; - - default: - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "asynInt32Read -- invalid drvUser (reason) %d", pasynUser->reason); - return asynError; - } -} - -static asynInt32 int32Methods = { - .write = asynInt32Write, - .read = asynInt32Read, -}; - -/* - * drvUser methods - */ -static asynStatus -asynDrvUserCreate(void *pvt, asynUser *pasynUser, - const char *drvInfo, const char **pptypeName, size_t *psize) -{ - drvPvt *pdpvt = (drvPvt *)pvt; - - if (epicsStrCaseCmp(drvInfo, "SRQ") == 0) { - pasynUser->reason = ASYN_REASON_SRQ; - pdpvt->enableInterruptEndpoint = 1; - if (pdpvt->isConnected) - startInterruptThread(pdpvt); - } - else if (epicsStrCaseCmp(drvInfo, "REN") == 0) { - pasynUser->reason = ASYN_REASON_REN; - } - else if (epicsStrCaseCmp(drvInfo, "STB") == 0) { - pasynUser->reason = ASYN_REASON_STB; - } - return asynSuccess; -} - -static asynStatus -asynDrvUserGetType(void *drvPvt, asynUser *pasynUser, - const char **pptypeName, size_t *psize) -{ - return asynSuccess; -} - -static asynStatus -asynDrvUserDestroy(void *drvPvt, asynUser *pasynUser) -{ - return asynSuccess; -} - -static asynDrvUser drvUserMethods = { - .create = asynDrvUserCreate, - .getType = asynDrvUserGetType, - .destroy = asynDrvUserDestroy, -}; - -/* - * Device configuration - */ -void -usbtmcConfigure(const char *portName, - int vendorId, int productId, const char *serialNumber, - int priority, int flags) -{ - drvPvt *pdpvt; - int s; - asynStatus status; - - /* - * Set up local storage - */ - pdpvt = (drvPvt *)callocMustSucceed(1, sizeof(drvPvt), portName); - pdpvt->portName = epicsStrDup(portName); - pdpvt->interruptThreadName = callocMustSucceed(1, strlen(portName)+5, portName); - epicsSnprintf(pdpvt->interruptThreadName, sizeof pdpvt->interruptThreadName, "%sIntr", portName); - if (priority == 0) priority = epicsThreadPriorityMedium; - s = libusb_init(&pdpvt->usb); - if (s != 0) { - printf("libusb_init() failed: %s\n", libusb_strerror(s)); - return; - } - if ((serialNumber == NULL) || (*serialNumber == '\0')) { - if ((vendorId == 0) && (productId == 0)) - printf("No device information specified. Will connect to first USB TMC device found.\n"); - else if (vendorId == 0) - printf("Will connect to first USB TMC device found with product ID %#4.4x.\n", productId); - else if (productId == 0) - printf("Will connect to first USB TMC device found with vendor ID %#4.4x.\n", vendorId); - else - printf("Will connect to first USB TMC device found with vendor ID %#4.4x and product ID %#4.4x.\n", vendorId, productId); - } - pdpvt->vendorId = vendorId; - pdpvt->productId = productId; - if (serialNumber && *serialNumber) - pdpvt->serialNumber = epicsStrDup(serialNumber); - else - pdpvt->serialNumber = NULL; - pdpvt->termChar = -1; - pdpvt->bTag = 1; - pdpvt->interruptTidMutex = epicsMutexMustCreate(); - pdpvt->pleaseTerminate = epicsEventMustCreate(epicsEventEmpty); - pdpvt->didTerminate = epicsEventMustCreate(epicsEventEmpty); - pdpvt->statusByteMessageQueue = epicsMessageQueueCreate(1, 1); - if (!pdpvt->statusByteMessageQueue) { - printf("Can't create message queue!\n"); - return; - } - - /* - * Create our port - */ - status = pasynManager->registerPort(pdpvt->portName, - ASYN_CANBLOCK, - (flags & 0x1) == 0, - priority, 0); - if(status != asynSuccess) { - printf("registerPort failed\n"); - return; - } - - /* - * Register ASYN interfaces - */ - pdpvt->asynCommon.interfaceType = asynCommonType; - pdpvt->asynCommon.pinterface = &commonMethods; - pdpvt->asynCommon.drvPvt = pdpvt; - status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynCommon); - if (status != asynSuccess) { - printf("registerInterface failed\n"); - return; - } - - pdpvt->asynOctet.interfaceType = asynOctetType; - pdpvt->asynOctet.pinterface = &octetMethods; - pdpvt->asynOctet.drvPvt = pdpvt; - status = pasynOctetBase->initialize(pdpvt->portName, &pdpvt->asynOctet, 0, 0, 0); - if (status != asynSuccess) { - printf("pasynOctetBase->initialize failed\n"); - return; - } - - pdpvt->asynInt32.interfaceType = asynInt32Type; - pdpvt->asynInt32.pinterface = &int32Methods; - pdpvt->asynInt32.drvPvt = pdpvt; - status = pasynInt32Base->initialize(pdpvt->portName, &pdpvt->asynInt32); - if (status != asynSuccess) { - printf("pasynInt32Base->initialize failed\n"); - return; - } - - /* - * Always register an interrupt source, just in case we use SRQs - */ - pasynManager->registerInterruptSource(pdpvt->portName, - &pdpvt->asynInt32, - &pdpvt->asynInt32InterruptPvt); - - pdpvt->asynDrvUser.interfaceType = asynDrvUserType; - pdpvt->asynDrvUser.pinterface = &drvUserMethods; - pdpvt->asynDrvUser.drvPvt = pdpvt; - status = pasynManager->registerInterface(pdpvt->portName, &pdpvt->asynDrvUser); - if (status != asynSuccess) { - printf("Can't register drvUser\n"); - return; - } -} - -/* - * IOC shell command registration - */ -static const iocshArg usbtmcConfigureArg0 = {"port name", iocshArgString}; -static const iocshArg usbtmcConfigureArg1 = {"vendor ID number", iocshArgInt}; -static const iocshArg usbtmcConfigureArg2 = {"product ID number", iocshArgInt}; -static const iocshArg usbtmcConfigureArg3 = {"serial string", iocshArgString}; -static const iocshArg usbtmcConfigureArg4 = {"priority", iocshArgInt}; -static const iocshArg usbtmcConfigureArg5 = {"flags", iocshArgInt}; -static const iocshArg *usbtmcConfigureArgs[] = {&usbtmcConfigureArg0, - &usbtmcConfigureArg1, - &usbtmcConfigureArg2, - &usbtmcConfigureArg3, - &usbtmcConfigureArg4, - &usbtmcConfigureArg5}; -static const iocshFuncDef usbtmcConfigureFuncDef = {"usbtmcConfigure",6,usbtmcConfigureArgs}; -static void usbtmcConfigureCallFunc(const iocshArgBuf *args) -{ - usbtmcConfigure (args[0].sval, - args[1].ival, args[2].ival, args[3].sval, - args[4].ival, args[5].ival); -} - -/* - * This routine is called before multitasking has started, so there's - * no race condition in the test/set of firstTime. - */ -static void usbtmcRegisterCommands (void) -{ - static int firstTime = 1; - if (firstTime) { - firstTime = 0; - iocshRegister(&usbtmcConfigureFuncDef, usbtmcConfigureCallFunc); - } -} -epicsExportRegistrar(usbtmcRegisterCommands); From 687a07b62d0466ab01112f7c0b05147766608490 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 08:56:12 +0900 Subject: [PATCH 06/67] separate drvAsynHiSLIP into two files. separate drvAsynHiSLIP.{cpp, h} into drvAsynHiSLIP.{cpp, h} and cPyHiSLIP/HiSPLIPMessage.{cpp,h}. /HiSPLIPMessage.{cpp,h} should be able to compile without EPICS headers. --- asyn/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/asyn/Makefile b/asyn/Makefile index 4d75891d2..4347b1160 100644 --- a/asyn/Makefile +++ b/asyn/Makefile @@ -261,9 +261,12 @@ endif ifeq ($(DRV_HISLIP),YES) USR_CXXFLAGS += -fpermissive SRC_DIRS += $(ASYN)/drvAsynHiSLIP + SRC_DIRS += $(ASYN)/drvAsynHiSLIP/cPyHiSLIP asyn_SRCS += drvAsynHiSLIP.cpp + asyn_SRCS += HiSLIPMessage.cpp DBD += drvAsynHiSLIP.dbd INC += drvAsynHiSLIP.h + INC += HiSLIPMessage.h endif ifeq ($(DRV_FTDI),YES) From c70dae282b7ee207f3cc50f5121a68943411eab2 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 08:58:53 +0900 Subject: [PATCH 07/67] separate drvAsynHiSLIP into two files. separate drvAsynHiSLIP.{cpp, h} into drvAsynHiSLIP.{cpp, h} and cPyHiSLIP/HiSPLIPMessage.{cpp,h}. /HiSPLIPMessage.{cpp,h} should be able to compile without EPICS headers. --- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 526 ++++----------------------- asyn/drvAsynHiSLIP/drvAsynHiSLIP.h | 436 +--------------------- 2 files changed, 69 insertions(+), 893 deletions(-) diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index e1dd43428..ac62e110d 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -25,414 +25,6 @@ using nsHiSLIP::Message_t; #define ASYN_REASON_STB 4346 #define ASYN_REASON_REN 4347 -// HiSLIP methods -namespace nsHiSLIP{ - void HiSLIP::connect(const char *hostname, - const char *dev_name, - const int port //, - //const char vendor_id[2] - ){ - osiSockAddr addr; - //Message_t *msg; - int status; - //const char vendor_id[]=Default_vendor_id; - - errlogPrintf("connecting to host \"%s\"\n", hostname); - - if(hostToIPAddr(hostname, &addr.ia.sin_addr) < 0) { - errlogPrintf("Unknown host \"%s\"", hostname); - } - - addr.ia.sin_port=htons(port); - addr.ia.sin_family=AF_INET; - - errlogPrintf("address : %x %x %x\n",addr.ia.sin_addr.s_addr,addr.ia.sin_port, - addr.ia.sin_family); - - //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); - this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); - - errlogPrintf("socceks created %d %d\n",this->sync_channel, this->async_channel); - - errlogPrintf("address : %x %x %x\n",addr.ia.sin_addr.s_addr,addr.ia.sin_port, - addr.ia.sin_family); - - status = ::connect(this->sync_channel, &(addr.sa), sizeof(addr)); - - errlogPrintf("connected to sync channel %d\n",this->sync_channel); - - if (status!=0){ - // Error handling - perror(__FUNCTION__); - errlogPrintf("Error !! %d\n",status); - } - - { - Message msg(nsHiSLIP::Initialize, - 0, - message_parameter((epicsUInt16) nsHiSLIP::PROTOCOL_VERSION_MAX, - (char *) Default_vendor_id), - (epicsUInt64) 0, (epicsUInt8 *) NULL); - errlogPrintf("sending message %d \n", msg.message_type); - msg.send(this->sync_channel); - } - - errlogPrintf("Sent a initialize message\n"); - - { Message resp(AnyMessages); - - errlogPrintf("Receive message created\n"); - - resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); - - this->overlap_mode=resp.control_code; - this->session_id=resp.message_parameter.getSessionId(); - this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); - } - errlogPrintf("Receive a initialized message %d 0x%x %d \n", - this->overlap_mode,this->session_id, this->server_protocol_version - ); - - errlogPrintf("Sending Async initialize message %x\n",this->session_id); - - status = ::connect(this->async_channel, &addr.sa, sizeof(addr)); - if (status!=0){ - // Error handling - perror(__FUNCTION__); - errlogPrintf("Error !!:%d\n",status); - } - errlogPrintf("connected to async channel %d\n",this->async_channel); - - { - Message msg(nsHiSLIP::AsyncInitialize); - msg.message_parameter.word=this->session_id; - msg.send(this->async_channel); - } - errlogPrintf("reading Async initialize response\n"); - - { - Message resp(AnyMessages); - resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); - this->overlap_mode=resp.control_code; - this->server_vendorID=resp.message_parameter.word; - } - errlogPrintf("reading Async initialize done\n"); - - //now setup poll object - this->reset_message_id(); - - this->sync_poll.fd=this->sync_channel; - this->sync_poll.events=POLLIN; - this->sync_poll.revents=0; - - this->async_poll.fd=this->async_channel; - this->async_poll.events=POLLIN; - this->async_poll.revents=0; - - errlogPrintf("Receive a Async initialized message\n"); - }; - - long HiSLIP::set_max_size(long message_size){ - Message resp(AnyMessages); - epicsUInt64 msg_size=htobe64(message_size); - - Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, - 0, - message_parameter(0), - sizeof(msg_size), (epicsUInt8 *) &msg_size); - msg.send(this->async_channel); - - int ready=poll(&this->async_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - - resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); - - this->maximum_message_size=*((epicsUInt64 *)(resp.payload)); - this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; - return this->maximum_message_size; - }; - - int HiSLIP::device_clear(){ - Message resp(AnyMessages); - epicsUInt8 feature_preference; - int ready; - - Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, - 0, - 0, - 0,NULL); - - msg->send(this->async_channel); - - ready=poll(&this->async_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - - resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); - feature_preference=resp.control_code; - - msg=new Message(nsHiSLIP::DeviceClearComplete, - feature_preference, - 0, - 0, NULL); - - msg->send(this->sync_channel); - - ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return asynTimeout; - } - resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); - - this->overlap_mode=resp.control_code; - this->reset_message_id(); - this->rmt_delivered = false; - - return 0; - - }; - - epicsUInt8 HiSLIP::status_query(){ - epicsUInt8 status; - int ready; - - Message resp(AnyMessages); - - Message msg((epicsUInt8) nsHiSLIP::AsyncStatusQuery, - (epicsUInt8) this->rmt_delivered, - message_parameter((epicsUInt32) this->most_recent_message_id), - 0, NULL); - msg.send(this->async_channel); - - ready=poll(&this->async_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); - - status= resp.control_code &0xff; - - return status; - } - - - // long HiSLIP::write(epicsUInt8 *data_str, long timeout){ - // return this->write(data_str, this->maximum_message_size,timeout); - // }; - - long HiSLIP::write(epicsUInt8 const* data_str, size_t const dsize, long timeout){ - - size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; - size_t bytestosend=dsize; - const epicsUInt8 *buffer=data_str; - size_t delivered=0; - size_t count; - - errlogPrintf("HiSLIP::write sending data %s\n", data_str); - - while(bytestosend){ - if (bytestosend < max_payload_size){ - Message msg(nsHiSLIP::DataEnd, - this->rmt_delivered, - nsHiSLIP::message_parameter(this->message_id), - bytestosend, (epicsUInt8 *) buffer); - buffer += bytestosend; - errlogPrintf("sending message %s\n",(char *) msg.payload); - count=msg.send(this->sync_channel); - count -=HEADER_SIZE; - bytestosend = 0; - delivered += count ; - } - else{ - Message msg(nsHiSLIP::Data, - this->rmt_delivered, - nsHiSLIP::message_parameter(this->message_id), - max_payload_size, (epicsUInt8 *) buffer); - count=msg.send(this->sync_channel); - count -= HEADER_SIZE; - bytestosend -=count; - delivered += count; - buffer += max_payload_size; - } - errlogPrintf("data sent= %lu\n",count); - this->increment_message_id(); - } - return delivered; - }; - - int HiSLIP::read(size_t *received, epicsUInt8 **buffer, long timeout){ - bool eom=false; - size_t rsize=0; - - errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", - buffer, timeout); - - *received=0; - this->rmt_delivered = false; - - while(!eom) { - int ready; - Message resp(AnyMessages); - - ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - rsize=resp.recv(this->sync_channel); - errlogPrintf("HiSLIP read rsize %ld\n",rsize); - if (rsize < resp.payload_length){ - //Error!! - return -1; - }; - - // may not be a good idea. - { epicsUInt8 *newbuf; - - newbuf=(epicsUInt8 *) reallocarray(*buffer, 1, - *received+resp.payload_length); - if (newbuf == NULL){ - errlogPrintf("Cannot extend memory area\n"); - return -1; - } - else{ - *buffer=newbuf; - } - } - ::memcpy((*buffer + *received), resp.payload, resp.payload_length); - *received +=resp.payload_length; - if ( resp.message_type == nsHiSLIP::Data){ - continue; - } else if ( resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - return 0; - } else{ - // error unexpected message type. - return -1; - } - } - return -1; - }; - - int HiSLIP::read(size_t *received, - epicsUInt8 *buffer, size_t bsize, long timeout){ - bool eom=false; - size_t rsize=0; - - errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", - buffer, bsize, timeout); - *received=0; - this->rmt_delivered = false; - - if (buffer==NULL || bsize <= 0){ - errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", - buffer, bsize, timeout); - return -1; - } - if (bsize < this->maximum_payload_size){ - errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", - bsize, this->maximum_payload_size); - } - while(!eom) { - int ready; - Message resp(AnyMessages); - - ready=::poll(&this->sync_poll, 1, timeout); - - if (ready == 0){ - errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); - return -1; - } - - rsize=resp.recv(this->sync_channel); - - if (rsize < resp.payload_length){ - errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); - return -1; - }; - if (( (*received) + resp.payload_length) > bsize){ - errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", - *received, resp.payload_length, bsize); - - ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); - *received = bsize; - return 0; - } - else{ - errlogPrintf("received message size %ld %ld data:%s mt:%d\n", - rsize, *received, (char *) resp.payload, resp.message_type); - ::memcpy( (buffer + *received), resp.payload, resp.payload_length); - - *received +=resp.payload_length; - } - - if ( resp.message_type == nsHiSLIP::Data){ - continue; - } else if (resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", - buffer, (char *) resp.payload, eom,this->rmt_delivered); - return 0; - } else{ - errlogPrintf("Unexpected message type:%d\n", - resp.message_type); - resp.printf(); - // error unexpected message type. - return -1; - } - } - return -1; - }; - - size_t HiSLIP::ask(epicsUInt8 *const data_str, size_t const dsize, - epicsUInt8 **rbuffer, - long wait_time){ - size_t rsize=-1; - epicsUInt8 *buffer=NULL; - int status; - - errlogPrintf("sending a command %s %lu",data_str, dsize); - - this->write(data_str, dsize); - if(this->wait_for_answer(wait_time) == 0){ - // error - return -1; - }; - status=this->read(&rsize, &buffer); - if (status !=0){ - rsize=-1; - } - *rbuffer=buffer; - return rsize; - }; - - long HiSLIP::trigger_message(void){ - return 0; - }; - long HiSLIP::remote_local(bool request){ - return 0; - }; - long HiSLIP::request_lock(const char* lock_string){ - return 0; - }; - long HiSLIP::release_lock(void){ - return 0; - }; - long HiSLIP::request_srq_lock(void){ - return 0; - }; - long HiSLIP::release_srq_lock(void){ - return 0; - }; - -} // end of namespace HiSLIP -// // EPICS Async Support typedef struct drvPvt { /* @@ -460,6 +52,7 @@ typedef struct drvPvt { /* * Interrupt through async_channel handling */ + bool enableInterruptSRQ; char *interruptThreadName; epicsThreadId interruptTid; epicsMutexId interruptTidMutex; @@ -501,60 +94,72 @@ interruptThread(void *arg) drvPvt *pdpvt = (drvPvt *)arg; int s; - for (;;) { + while(true) { s = pdpvt->device->wait_for_SRQ(65000); - + + if (s == 0){ + errlogPrintf("timeout poll for async channel.\n"); + continue; + } if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK) break; - - Message_t *srqmsg=pdpvt->device->get_Service_Request(); - - epicsUInt8 st =srqmsg->control_code; if (s != 0 ){ - if (st != 0){ + assert(pdpvt); + if (pdpvt == NULL){ + errlogPrintf(" NULL drvPvt as an argument.\n"); + } + Message_t *srqmsg=pdpvt->device->get_Service_Request(); + assert(srqmsg); + u_int8_t stb =srqmsg->control_code;// Ststus Byte + srqmsg->printf(); + + errlogPrintf("Get SRQ with STB: 0x%2x\n", stb); + if ((srqmsg->message_type == nsHiSLIP::AsyncServiceRequest) + && (stb != 0)){ // may need mask here. ELLLIST *pclientList; interruptNode *pnode; - pdpvt->interruptCount++; + pdpvt->interruptCount +=1; pasynManager->interruptStart(pdpvt->asynOctetInterruptPvt, &pclientList); { pnode = (interruptNode *)ellFirst(pclientList); // see asynDriver/asynDriver.h while (pnode) { - int eomReason=0; // 0:None, ASYN_EOM_CNT:0x0001,ASYN_EOM_EOS:0x0002 End of StrIng detected ASYN_EOM_END: 0x0004 End indicator detected - - size_t numchars=1; + //int eomReason=0; + // 0:None, ASYN_EOM_CNT:0x0001, + //ASYN_EOM_EOS:0x0002 End of StrIng detected + //ASYN_EOM_END: 0x0004 End indicator detected + //size_t numchars=1; asynOctetInterrupt *octetInterrupt = (asynOctetInterrupt *) pnode->drvPvt; - pnode = (interruptNode *)ellNext(&pnode->node); + errlogPrintf("scan pnode in InterruptThread " + "pnode:%p reason:0x%x\n", + pnode, octetInterrupt->pasynUser->reason + ); if (octetInterrupt->pasynUser->reason == ASYN_REASON_SRQ) { octetInterrupt->callback(octetInterrupt->userPvt, octetInterrupt->pasynUser, - (char *) &st, - numchars, - eomReason); + (char *) &stb, + sizeof(stb), + ASYN_REASON_SRQ); } + pnode = (interruptNode *)ellNext(&pnode->node); + } pasynManager->interruptEnd(pdpvt->asynOctetInterruptPvt); + errlogPrintf("Finish SRQ process 0x%2x\n", stb); } } - else{ + else if (srqmsg->message_type == nsHiSLIP::AsyncStatusResponse){ if (epicsMessageQueueTrySend(pdpvt->statusByteMessageQueue, - &st, 1) != 0) { + &stb, 1) != 0) { errlogPrintf("----- WARNING ----- " "Can't send status byte to worker thread!\n"); } } } - else if (NULL){ - errlogPrintf("----- WARNING ----- " - "libusb_interrupt_transfer failed (%s). " - "Interrupt thread for ASYN port \"%s\" terminating.\n", - nsHiSLIP::Error_Messages[s], pdpvt->portName); - break; - } } epicsMutexLock(pdpvt->interruptTidMutex); pdpvt->interruptTid = 0; @@ -572,7 +177,8 @@ startInterruptThread(drvPvt *pdpvt) pdpvt->interruptTid = epicsThreadCreate(pdpvt->interruptThreadName, epicsThreadGetPrioritySelf(), epicsThreadGetStackSize(epicsThreadStackSmall), - interruptThread, pdpvt); + interruptThread, + pdpvt); if (pdpvt->interruptTid == 0) errlogPrintf("----- WARNING ----- " "Can't start interrupt handler thread %s.\n", @@ -764,7 +370,7 @@ asynOctetWrite(void *pvt, asynUser *pasynUser, while (numchars) { size_t nSent; - nSent = pdpvt->device->write((epicsUInt8 *) data, numchars, timeout); + nSent = pdpvt->device->write((u_int8_t *) data, numchars, timeout); if (nSent < 0) { disconnectIfGone(pdpvt, pasynUser, 0); @@ -795,29 +401,31 @@ asynOctetRead(void *pvt, asynUser *pasynUser, size_t ioCount, nCopy; int status; int eom=0; + size_t nout=0; int timeout = pasynUser->timeout * 1000; if (timeout == 0) timeout = 1; assert(pdpvt->device); assert(nbytesTransfered); - *nbytesTransfered = 0; - if(eomReason) *eomReason=0; - - errlogPrintf("asynOctetRead timeout:%g host:%s maxchars:%ld bufCount:%ld\n", - pasynUser->timeout, - pdpvt->hostname, - maxchars, pdpvt->bufCount); - /* - * Special case for stream device which requires an asynTimeout return. - */ + if(eomReason) {*eomReason=eom=0;} + if(nbytesTransfered) {*nbytesTransfered = nout = 0;} + + // errlogPrintf("asynOctetRead timeout:%g host:%s maxchars:%ld bufCount:%ld reason:%x\n", + // pasynUser->timeout, + // pdpvt->hostname, + // maxchars, pdpvt->bufCount, + // pasynUser->reason); + // /* + // * Special case for stream device which requires an asynTimeout return. + // */ while(eom==0){ if ((pasynUser->timeout == 0) && (pdpvt->bufCount == 0)) return asynTimeout; if (pdpvt->bufCount ==0) { // read adittional data from device status = pdpvt->device->read( &ioCount, - (epicsUInt8 *) pdpvt->buf, + (u_int8_t *) pdpvt->buf, pdpvt->bufSize, timeout); if (status != 0){ @@ -832,8 +440,9 @@ asynOctetRead(void *pvt, asynUser *pasynUser, pdpvt->bufp=pdpvt->buf; pdpvt->bufCount = ioCount; pdpvt->bytesReceivedCount += ioCount; - errlogPrintf("asynOctetRead data:%s, maxchars:%ld,nbytesTransfered:%ld, eomReason:%d\n", - data, maxchars, *nbytesTransfered, eom); + errlogPrintf("asynOctetRead data:%s, " + "maxchars:%ld,nbytesTransfered:%ld, eomReason:%d\n", + data, maxchars, nout, eom); } if (pdpvt->bufCount) { if (maxchars > pdpvt->bufCount){ @@ -855,7 +464,7 @@ asynOctetRead(void *pvt, asynUser *pasynUser, pdpvt->bufp += nCopy; } maxchars -= nCopy; - *nbytesTransfered += nCopy; + nout += nCopy; pdpvt->bytesReceivedCount += nCopy; data += nCopy; if (maxchars == 0){ @@ -869,6 +478,8 @@ asynOctetRead(void *pvt, asynUser *pasynUser, } } if(eomReason) *eomReason = eom; + if(nbytesTransfered) {*nbytesTransfered = nout;} + return asynSuccess; } @@ -943,12 +554,12 @@ asynDrvUserCreate(void *pvt, asynUser *pasynUser, { drvPvt *pdpvt = (drvPvt *)pvt; - errlogPrintf("DrvUserCreate drvinfo:%s typeName:%s size:%ld\n", - drvInfo, *pptypeName, *psize - ); + errlogPrintf("DrvUserCreate drvinfo:%s\n", + drvInfo); if (epicsStrCaseCmp(drvInfo, "SRQ") == 0) { pasynUser->reason = ASYN_REASON_SRQ; + pdpvt->enableInterruptSRQ = true; if (pdpvt->isConnected) startInterruptThread(pdpvt); } @@ -1010,19 +621,8 @@ HiSLIPConfigure(const char *portName, "HiSLIPConfigure"); strcpy(pdpvt->hostname, hostInfo); - // errlogPrintf("creating HiSLIP object %s", hostInfo); - // pdpvt->device=new HiSLIP_t(); - // errlogPrintf("connecting HiSLIP object to host:%s\n", hostInfo); - // pdpvt->device->connect(hostInfo); - // pdpvt->isConnected = true; - // errlogPrintf("HiSLIP object connected to host:%s\n", hostInfo); - // if (pdpvt->device == 0) { - // errlogPrintf("Failed to create HiSLIP device for %s(%s)\n", - // hostInfo, nsHiSLIP::Error_Messages[2]); - // return; - // } - pdpvt->termChar = -1; + pdpvt->termChar = 0; pdpvt->interruptTidMutex = epicsMutexMustCreate(); pdpvt->pleaseTerminate = epicsEventMustCreate(epicsEventEmpty); pdpvt->didTerminate = epicsEventMustCreate(epicsEventEmpty); diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h index bf3977d8b..5c6dfd5c7 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.h @@ -12,12 +12,17 @@ */ //-*- coding:utf-8 -*- #define NDEBUG 1 +#define DEBUG 1 + #include #include #include #include #include // network endian is "be". +#include +//#include + #include #include @@ -38,433 +43,4 @@ #include #include -template struct Property { - T& r; - operator T() {return r;} - void operator =(const T v){ r=v;} -}; - -namespace nsHiSLIP{ - - //constants - typedef enum CC_reuqest{ - RemoteDisable=0, - RemoteEnable=1, - RemoteDisableGTL=2, // disable remote and goto local - RemoteEnableGTR=3, // Enable remote and goto remote - RemoteEnableLLO=4, // Enable remote and lock out local - RemoteEnableGTRLLO=5, // - RTL=6 - } CC_request_t; - - typedef enum CC_Lock{ - release =0, - request =1 - } CC_Lock_t; - - typedef enum CC_LockResponse{ - fail=0, //Lock was requested but not granted - success=1, //release of exclusive lock - success_shared=2, //release of shared lock - error=3 // Invalide - } CC_LockResponse_t; - - static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 - static const long INITIAL_MESSAGE_ID = 0xffffff00 ; - static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; - static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes - static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept - static const long HEADER_SIZE=16; - static const long SOCKET_TIMEOUT = 1; //# Socket timeout - static const long LOCK_TIMEOUT = 3000;//# Lock timeout - static const long Default_Port = 4880; - static const char Default_device_name[]="hslip0"; - static const char Default_vendor_id[]={'E','P'}; - static const char Prologue[]={'H','S'}; - // - typedef enum Message_Types{ - Initialize = 0, - InitializeResponse = 1, - FatalError = 2, - Error = 3, - AsyncLock = 4, - AsyncLockResponse = 5, - Data = 6, - DataEnd = 7, - DeviceClearComplete = 8, - DeviceClearAcknowledge = 9, - AsyncRemoteLocalControl = 10, - AsyncRemoteLocalResponse = 11, - Trigger = 12, - Interrupted = 13, - AsyncInterrupted = 14, - AsyncMaximumMessageSize = 15, - AsyncMaximumMessageSizeResponse = 16, - AsyncInitialize = 17, - AsyncInitializeResponse = 18, - AsyncDeviceClear = 19, - AsyncServiceRequest = 20, - AsyncStatusQuery = 21, - AsyncStatusResponse = 22, - AsyncDeviceClearAcknowledge = 23, - AsyncLockInfo = 24, - AsyncLockInfoResponse = 25, - // 26-127 are reserved for future use. - // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. - AnyMessages=127 // 128-255 are reserved for vendor use. - } Message_Types_t; - - typedef enum Error_code{ - UnidentifiedError, - UnrecognizedMessageType, - UnrecognizedControlCode, - UnrecognizedVendorDefinedMessage, - MessageTooLarge - } Error_code_t; - static const char *Error_Messages[] = - { - "Unidentified error", - "Unrecognized Message Type", - "Unrecognized control code", - "Unrecognized Vendor Defined Message", - "Message too large" - }; - typedef enum Fatal_Error_code { - UnidentifiedFatalError, - PoorlyFormedMmessageHeader, - AttemptToUseConnectionWithoutBothChannels, - InvalidInitializationSequence, - ServerRefusedConnection - } Fatal_Erro_code_t; - static const char *Fatal_Error_Messages[] = - { - "Unidentified error", - "Poorly formed message header", - "Attempt to use connection without both channels established", - "Invalid Initialization Sequence", - "Server refused connection due to maximum number of clients exceeded" - }; - - typedef class message_parameter{ - public: - epicsUInt32 word; - // struct InitializeParameter{ - // epicsUInt16 protocol_version; - // char vendor_id[2]={0x00 ,0x00}; - // } initParm; - // struct InitializeResponseParameter{ - // epicsUInt16 session_id; - // epicsUInt16 protocol_version; - // } initResp; - message_parameter(epicsUInt32 word){this->word=word;}; - message_parameter(epicsUInt16 proto, char vers[2]){ - this->word= ((epicsInt32)proto << 16) + - (vers[1] << 8) + (vers[0]<<0); - errlogPrintf("messagParameter:%#010x, protocol:%#06x, version:[%c%c]\n", - this->word, - proto, vers[0], vers[1]); - }; - message_parameter(epicsUInt16 proto, epicsUInt16 sid){ - this->word = (proto << 16) + sid; - errlogPrintf("messagParameter:%#010x, protocol:%#06x, session id:%#06x\n", - this->word, - proto, sid); - }; - epicsUInt16 getServerProtocolVersion(){ - errlogPrintf("getServerProtocolVersion messagParameter:%#010x, ServerProtocolVersion %d\n", - this->word, - (epicsUInt16) (((this->word) & 0xffff0000)>>16)); - return (epicsUInt16) (((this->word) & 0xffff0000)>>16); - } - epicsUInt16 getSessionId(){ - errlogPrintf("getSessionId messagParameter %#010x, sessionID:%d\n", - this->word, - (epicsUInt16) ((this->word) & 0xffff)); - return ((epicsUInt16) ((this->word) & 0xffff)); - } - } message_parameter_t; - - class Header{ - public: - const char prologue[2]={'H','S'}; - epicsUInt8 message_type; - epicsUInt8 control_code; - message_parameter_t message_parameter; - epicsUInt64 payload_length; - - Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ - this->message_type=message_type; - } - Header(const void *buffer):message_parameter(0){ - assert(memcmp(this->prologue, buffer,2) == 0); - this->message_type=*((epicsUInt8 *) ((char *) buffer+2)); - this->control_code=*((epicsUInt8 *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(epicsUInt32 *) ((char *) buffer+4)); - this->payload_length = be64toh(*(epicsUInt64 *) ((char *) buffer+8)); - } - Header(const epicsUInt8 type, - const epicsUInt8 cce, - const message_parameter_t param, - const epicsUInt64 length):message_parameter(param.word){ - this->message_type=type; - this->control_code=cce; - this->payload_length=length; - } - void printf(void){ - errlogPrintf("message type:%d\n",this->message_type); - errlogPrintf("control_code:%d\n",this->control_code); - errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); - errlogPrintf("payload length: %qd\n",this->payload_length); - } - - size_t send(int socket){ - char hbuf[HEADER_SIZE]; - ssize_t ssize; - - this->toRawData(hbuf); - errlogPrintf("sending header dump: %#016qx,%#016qx\n", - *((epicsUInt64*)hbuf),*(((epicsUInt64*)hbuf) +1)); - ssize=::send(socket, hbuf, sizeof(hbuf), 0); - - return ssize; - } - - size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ - - - char buffer[HEADER_SIZE]; - ssize_t rsize; - - - errlogPrintf("recv header\n"); - - rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - - errlogPrintf("read header dump: %#016qx, %#016qx\n", - *((epicsUInt64*)buffer), - *(((epicsUInt64*)buffer) +1) ); - - if (rsize < HEADER_SIZE){ - //raise exception? - errlogPrintf("too short header %ld\n",rsize); - return -1; - } - else if (memcmp(this->prologue, buffer,2) != 0){ - //error - errlogPrintf("incorrect prologue %2s %2s\n",buffer,this->prologue); - return -1; - } - - //errlogPrintf("Recieved message %2s %2s\n",buffer,this->prologue); - - this->message_type=*((epicsUInt8 *) ((char *) buffer+2)); - this->control_code=*((epicsUInt8 *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(epicsUInt32 *) ((char *) buffer+4)); - this->payload_length = be64toh(*(epicsUInt64 *) ((char *) buffer+8)); - - this->printf(); - - if((expected_message_type != AnyMessages) && - (expected_message_type != this->message_type)){ - //error! - // in overlapped mode, should we keep it? - errlogPrintf("Error message types does not match %d vs %d\n",expected_message_type, - this->message_type); - return -1; - } - - errlogPrintf("successfull recieved message header %ld \n",rsize); - - return rsize; - } - - int fromRawData(void *buffer){ //DeSerialize - if (memcmp(this->prologue, buffer,2) != 0){ - //error - return -1; - } - this->message_type=*((epicsUInt8 *) ((char *) buffer+2)); - this->control_code=*((epicsUInt8 *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(epicsUInt32 *) ((char *) buffer+4)); - this->payload_length = be64toh(*(epicsUInt64 *) ((char *) buffer+8)); - return 0; - } - int toRawData(void *buffer){ //Serialize this as bytes data in buffer. - memcpy( buffer, this->prologue, 2); - *((char *) buffer + 2) = this->message_type; - *((char *) buffer + 3) = this->control_code; - *((epicsUInt32 *)((char *) buffer+4))=htobe32(this->message_parameter.word); - *((epicsUInt64 *)((char *) buffer+8))=htobe64(this->payload_length); - return 0; - } - }; - - typedef class Message:public Header{ - public: - void *payload=NULL; - - Message(Message_Types_t message_type):Header(message_type){ - }; - Message(void *raw_header):Header(raw_header){ - //this->fromRawData(raw_header); - }; - Message(void *raw_header, void *payload):Message(raw_header){ - this->payload= (void *) callocMustSucceed(1, - this->payload_length, - "HiSLIP payload buffer"); - memcpy(this->payload, payload, this->payload_length); - } - Message(epicsUInt8 type, - epicsUInt8 cce, - message_parameter_t param, - epicsUInt64 length, - epicsUInt8 *payload):Header(type,cce,param,length),payload(payload) { - //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); - //memcpy(this->payload, payload, length); - //this->payload = payload; - } - size_t send(int socket){ - size_t ssize; - ssize=this->Header::send(socket); - if (ssize < HEADER_SIZE){ - return -1; - } - return (ssize + ::send(socket, this->payload, this->payload_length,0)); - } - - ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ - size_t rsize; - size_t status; - - /* setsockopt(sock, SOL_SOCKET, */ - /* SO_RCVTIMEO, &(msg->socket_timeout), sizeof(int)); */ - - // read header part and update header. - - rsize=this->Header::recv(socket, expected_message_type); - - if (rsize < 0){ - // Error! - errlogPrintf("failed to read header.%ld \n",rsize); - return rsize; - } - - // now prepare for a pyload. - if (this->payload==NULL && this->payload_length > 0){ - this->payload= (void *) callocMustSucceed(1, - this->payload_length, - "HiSLIP pyload buffer"); - } - - rsize=0; //returns size of recieved payload. - if (this->payload_length > 0){ - size_t bytestoread=this->payload_length; - - while (bytestoread){ - status = ::recv(socket, ((epicsUInt8 *)this->payload+rsize), bytestoread, 0); - - if (status <= 0){ - perror("payload read error:"); - errlogPrintf("recive error\n"); - return -1; - } - rsize +=status; - if (status >= bytestoread){ - break; - } - bytestoread -=status; - } - } - errlogPrintf("successfull recieved message %ld \n",rsize); - return (rsize); - } - } Message_t; - - typedef class HiSLIP { - public: - unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; - unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; - long socket_timeout=SOCKET_TIMEOUT; - long lock_timeout=LOCK_TIMEOUT; - int sync_channel; - int async_channel; - struct pollfd sync_poll; - struct pollfd async_poll; - int overlap_mode; - int session_id; - int server_protocol_version; - unsigned int server_vendorID; - - bool rmt_delivered; - epicsUInt32 message_id; - epicsUInt32 most_recent_message_id; - - void set_timeout( long timeout){ - this->socket_timeout=timeout; - }; - long get_timeout(void){ - return this->socket_timeout; - }; - void set_lock_timeout( long timeout){ - this->lock_timeout=timeout; - } - ; - long get_lock_timeout(void){ - return this->lock_timeout; - }; - - HiSLIP(){ - }; - void connect(char const* hostname){ - this->connect(hostname, - Default_device_name, - Default_Port); - }; - void connect(char const* hostname, - char const* dev_name, - int port); - long set_max_size(long message_size); - int device_clear(void); - epicsUInt8 status_query(); - //long write(epicsUInt8 *data_str, long timeout=LOCK_TIMEOUT); - long write(const epicsUInt8 *data_str, const size_t size, long timeout=LOCK_TIMEOUT); - size_t ask(epicsUInt8 *data_str, size_t size, - epicsUInt8 **rbuffer, long wait_time=LOCK_TIMEOUT); - int read(size_t *received, long timeout=LOCK_TIMEOUT ); - int read(size_t *received, epicsUInt8 **buffer, long timeout=LOCK_TIMEOUT); - int read(size_t *received, epicsUInt8 *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); - long trigger_message(void); - long remote_local(bool request); - long request_lock(const char* lock_string=NULL); - long release_lock(void); - long request_srq_lock(void); - long release_srq_lock(void); - Message *get_Service_Request(void){ - Message *msg=new Message(0); - long status; - status= msg->recv(this->async_channel, AsyncServiceRequest); - if (status != 0){ - perror(__FUNCTION__); - } - return msg; - }; - int wait_for_SRQ(int wait_time){ - return ::poll(&this->async_poll, 1, wait_time); - } - void disconnect(){}; - - private: - int wait_for_answer(int wait_time){ - return ::poll(&this->sync_poll, 1, wait_time); - } - void reset_message_id(void){ - this->most_recent_message_id=0; - this->message_id = 0xffffff00; - } - epicsUInt32 increment_message_id(void){ - this->most_recent_message_id=this->message_id; - this->message_id = (this->message_id +2) & 0xffffffff; - return this->message_id; - }; - } HiSLIP_t; -}; // namespace +#include "HiSLIPMessage.h" From 7c2db3792ee82806d4f01e8da90a26406421ede1 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 09:00:13 +0900 Subject: [PATCH 08/67] separate drvAsynHiSLIP into two files. separate drvAsynHiSLIP into two files. --- asyn/drvAsynHiSLIP/HiSLIPMessage.cpp | 463 +++++++++++++++++++++++++ asyn/drvAsynHiSLIP/HiSLIPMessage.h | 483 +++++++++++++++++++++++++++ 2 files changed, 946 insertions(+) create mode 100644 asyn/drvAsynHiSLIP/HiSLIPMessage.cpp create mode 100644 asyn/drvAsynHiSLIP/HiSLIPMessage.h diff --git a/asyn/drvAsynHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/HiSLIPMessage.cpp new file mode 100644 index 000000000..296adfd95 --- /dev/null +++ b/asyn/drvAsynHiSLIP/HiSLIPMessage.cpp @@ -0,0 +1,463 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +#include "HiSLIPMessage.h" + +using nsHiSLIP::CC_request_t; +using nsHiSLIP::CC_Lock_t; +using nsHiSLIP::HiSLIP_t; +using nsHiSLIP::HiSLIP; +using nsHiSLIP::Message_t; + +#define MAX_PAYLOAD_CAPACITY 4096 +#define IDSTRING_CAPACITY 100 + +// HiSLIP methods +namespace nsHiSLIP{ + void HiSLIP::connect(const char *hostname, + const char *dev_name, + const int port //, + //const char vendor_id[2] + ){ + //osiSockAddr addr; + //Message_t *msg; + int status; + //const char vendor_id[]=Default_vendor_id; + + struct addrinfo hints, *res=NULL; + memset(&hints,0, sizeof(struct addrinfo)); + hints.ai_flags=AI_NUMERICSERV | AI_CANONNAME; + hints.ai_flags=AI_NUMERICSERV; + hints.ai_family=AF_INET; // IPv4 + hints.ai_socktype=SOCK_STREAM; + hints.ai_protocol=0; // any protocol + hints.ai_addrlen=0; + hints.ai_addr=NULL; + hints.ai_canonname=NULL; + hints.ai_next=NULL; + + { + char *service=NULL; + asprintf(&service, "%d",port);// "4880" for example. + status=getaddrinfo(hostname, service, &hints, &res); + free(service); + } + + if ((status !=0) || res == NULL){ + char *msg; + asprintf(&msg, "getaddrinfo error status:%d res %p",status,res); + perror(msg); + free(msg); + exit (9999); + } + + //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + + this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); + this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); + + if (res-> ai_addr == NULL || res->ai_addrlen == 0){ + perror("empty addinfo"); + freeaddrinfo(res); + exit (999); + }; + status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); + + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + + status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + // errlogPrintf("connected to async channel %d\n",this->async_channel); + + freeaddrinfo(res); + + { + Message msg(nsHiSLIP::Initialize, + 0, + message_parameter((u_int16_t) nsHiSLIP::PROTOCOL_VERSION_MAX, + (char *) Default_vendor_id), + (u_int64_t) 0, (u_int8_t *) NULL); + // errlogPrintf("sending message %d \n", msg.message_type); + msg.send(this->sync_channel); + } + + // errlogPrintf("Sent a initialize message\n"); + + { Message resp(AnyMessages); + + // errlogPrintf("Receive message created\n"); + + resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); + + this->overlap_mode=resp.control_code; + this->session_id=resp.message_parameter.getSessionId(); + this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); + } + // errlogPrintf("Receive a initialized message %d 0x%x %d \n", + // this->overlap_mode,this->session_id, this->server_protocol_version + // ); + + // errlogPrintf("Sending Async initialize message %x\n",this->session_id); + + + + { + Message msg(nsHiSLIP::AsyncInitialize); + msg.message_parameter.word=this->session_id; + msg.send(this->async_channel); + } + // errlogPrintf("reading Async initialize response\n"); + + { + Message resp(AnyMessages); + resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + this->overlap_mode=resp.control_code; + this->server_vendorID=resp.message_parameter.word; + } + // errlogPrintf("reading Async initialize done\n"); + + //now setup poll object + this->reset_message_id(); + + this->sync_poll.fd=this->sync_channel; + this->sync_poll.events=POLLIN; + this->sync_poll.revents=0; + + this->async_poll.fd=this->async_channel; + this->async_poll.events=POLLIN; + this->async_poll.revents=0; + + // errlogPrintf("Receive a Async initialized message\n"); + }; + + long HiSLIP::set_max_size(long message_size){ + Message resp(AnyMessages); + u_int64_t msg_size=htobe64(message_size); + + Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, + 0, + message_parameter(0), + sizeof(msg_size), (u_int8_t *) &msg_size); + msg.send(this->async_channel); + + int ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + + this->maximum_message_size=*((u_int64_t *)(resp.payload)); + this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; + return this->maximum_message_size; + }; + + int HiSLIP::device_clear(){ + Message resp(AnyMessages); + u_int8_t feature_preference; + int ready; + + Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, + 0, + 0, + 0,NULL); + + msg->send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + feature_preference=resp.control_code; + + msg=new Message(nsHiSLIP::DeviceClearComplete, + feature_preference, + 0, + 0, NULL); + + msg->send(this->sync_channel); + + ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); + + this->overlap_mode=resp.control_code; + this->reset_message_id(); + this->rmt_delivered = false; + + return 0; + + }; + + u_int8_t HiSLIP::status_query(){ + u_int8_t status; + int ready; + + Message resp(AnyMessages); + + Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, + (u_int8_t) this->rmt_delivered, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL); + msg.send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); + + status= resp.control_code &0xff; + + return status; + } + + + // long HiSLIP::write(u_int8_t *data_str, long timeout){ + // return this->write(data_str, this->maximum_message_size,timeout); + // }; + + long HiSLIP::write(u_int8_t const* data_str, size_t const dsize, long timeout){ + + size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; + size_t bytestosend=dsize; + const u_int8_t *buffer=data_str; + size_t delivered=0; + size_t count; + + // errlogPrintf("HiSLIP::write sending data %s\n", data_str); + + while(bytestosend){ + if (bytestosend < max_payload_size){ + Message msg(nsHiSLIP::DataEnd, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + bytestosend, (u_int8_t *) buffer); + buffer += bytestosend; + // errlogPrintf("sending message %s\n",(char *) msg.payload); + count=msg.send(this->sync_channel); + count -=HEADER_SIZE; + bytestosend = 0; + delivered += count ; + } + else{ + Message msg(nsHiSLIP::Data, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + max_payload_size, (u_int8_t *) buffer); + count=msg.send(this->sync_channel); + count -= HEADER_SIZE; + bytestosend -=count; + delivered += count; + buffer += max_payload_size; + } + // errlogPrintf("data sent= %lu\n",count); + this->increment_message_id(); + } + return delivered; + }; + + int HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ + bool eom=false; + size_t rsize=0; + + // errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", + // buffer, timeout); + + *received=0; + this->rmt_delivered = false; + + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + rsize=resp.recv(this->sync_channel); + // errlogPrintf("HiSLIP read rsize %ld\n",rsize); + if (rsize < resp.payload_length){ + //Error!! + return -1; + }; + + // may not be a good idea. + { u_int8_t *newbuf; + + newbuf=(u_int8_t *) reallocarray(*buffer, 1, + *received+resp.payload_length); + if (newbuf == NULL){ + // errlogPrintf("Cannot extend memory area\n"); + return -1; + } + else{ + *buffer=newbuf; + } + } + ::memcpy((*buffer + *received), resp.payload, resp.payload_length); + *received +=resp.payload_length; + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if ( resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + return 0; + } else{ + // error unexpected message type. + return -1; + } + } + return -1; + }; + + int HiSLIP::read(size_t *received, + u_int8_t *buffer, size_t bsize, long timeout){ + bool eom=false; + size_t rsize=0; + + // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", + // buffer, bsize, timeout); + *received=0; + this->rmt_delivered = false; + + if (buffer==NULL || bsize <= 0){ + // errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", + // buffer, bsize, timeout); + return -1; + } + if (bsize < this->maximum_payload_size){ + // errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", + // bsize, this->maximum_payload_size); + } + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=::poll(&this->sync_poll, 1, timeout); + + if (ready == 0){ + // errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); + return -1; + } + + rsize=resp.recv(this->sync_channel); + + if (rsize < resp.payload_length){ + // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); + return -1; + }; + if (( (*received) + resp.payload_length) > bsize){ + // errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", + // *received, resp.payload_length, bsize); + + ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); + *received = bsize; + return 0; + } + else{ + // errlogPrintf("received message size %ld %ld data:%s mt:%d\n", + // rsize, *received, (char *) resp.payload, resp.message_type); + ::memcpy( (buffer + *received), resp.payload, resp.payload_length); + + *received +=resp.payload_length; + } + + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if (resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + // errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", + // buffer, (char *) resp.payload, eom,this->rmt_delivered); + return 0; + } else{ + // errlogPrintf("Unexpected message type:%d\n", + // resp.message_type); + resp.printf(); + // error unexpected message type. + return -1; + } + } + return -1; + }; + + size_t HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, + u_int8_t **rbuffer, + long wait_time){ + size_t rsize=-1; + u_int8_t *buffer=NULL; + int status; + + // errlogPrintf("sending a command %s %lu",data_str, dsize); + + this->write(data_str, dsize); + if(this->wait_for_answer(wait_time) == 0){ + // error + return -1; + }; + status=this->read(&rsize, &buffer); + if (status !=0){ + rsize=-1; + } + *rbuffer=buffer; + return rsize; + }; + + long HiSLIP::trigger_message(void){ + return 0; + }; + long HiSLIP::remote_local(bool request){ + return 0; + }; + long HiSLIP::request_lock(const char* lock_string){ + { + // errlogPrintf("request_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + long HiSLIP::release_lock(void){ + { + // errlogPrintf("release_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + long HiSLIP::request_srq_lock(void){ + { + // errlogPrintf("request_srq_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + long HiSLIP::release_srq_lock(void){ + { + // errlogPrintf("release_srq_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + +} // end of namespace HiSLIP + diff --git a/asyn/drvAsynHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/HiSLIPMessage.h new file mode 100644 index 000000000..4d032ddfc --- /dev/null +++ b/asyn/drvAsynHiSLIP/HiSLIPMessage.h @@ -0,0 +1,483 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +//-*- coding:utf-8 -*- +#define NDEBUG 1 +#define DEBUG 1 + +#include +#include + +//#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include + +#include +#include +#include +#include +#include // network endian is "be". +#include +#include +#include +#include /* for MAXHOSTNAMELEN */ +#include /* close() and others */ + +//#include +//#include +//#include +//#include +//#include +//#include + + + +template struct Property { + T& r; + operator T() {return r;} + void operator =(const T v){ r=v;} +}; + +namespace nsHiSLIP{ + + //constants + typedef enum CC_reuqest{ + RemoteDisable=0, + RemoteEnable=1, + RemoteDisableGTL=2, // disable remote and goto local + RemoteEnableGTR=3, // Enable remote and goto remote + RemoteEnableLLO=4, // Enable remote and lock out local + RemoteEnableGTRLLO=5, // + RTL=6 + } CC_request_t; + + typedef enum CC_Lock{ + release =0, + request =1 + } CC_Lock_t; + + typedef enum CC_LockResponse{ + fail=0, //Lock was requested but not granted + success=1, //release of exclusive lock + success_shared=2, //release of shared lock + error=3 // Invalide + } CC_LockResponse_t; + + static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 + static const long INITIAL_MESSAGE_ID = 0xffffff00 ; + static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; + static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes + static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept + static const long HEADER_SIZE=16; + static const long SOCKET_TIMEOUT = 1; //# Socket timeout + static const long LOCK_TIMEOUT = 3000;//# Lock timeout + static const long Default_Port = 4880; + static const char Default_device_name[]="hslip0"; + static const char Default_vendor_id[]={'E','P'}; + static const char Prologue[]={'H','S'}; + // + typedef enum Message_Types{ + Initialize = 0, + InitializeResponse = 1, + FatalError = 2, + Error = 3, + AsyncLock = 4, + AsyncLockResponse = 5, + Data = 6, + DataEnd = 7, + DeviceClearComplete = 8, + DeviceClearAcknowledge = 9, + AsyncRemoteLocalControl = 10, + AsyncRemoteLocalResponse = 11, + Trigger = 12, + Interrupted = 13, + AsyncInterrupted = 14, + AsyncMaximumMessageSize = 15, + AsyncMaximumMessageSizeResponse = 16, + AsyncInitialize = 17, + AsyncInitializeResponse = 18, + AsyncDeviceClear = 19, + AsyncServiceRequest = 20, + AsyncStatusQuery = 21, + AsyncStatusResponse = 22, + AsyncDeviceClearAcknowledge = 23, + AsyncLockInfo = 24, + AsyncLockInfoResponse = 25, + // 26-127 are reserved for future use. + // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. + AnyMessages=127 // 128-255 are reserved for vendor use. + } Message_Types_t; + + typedef enum Error_code{ + UnidentifiedError, + UnrecognizedMessageType, + UnrecognizedControlCode, + UnrecognizedVendorDefinedMessage, + MessageTooLarge + } Error_code_t; + static const char *Error_Messages[] = + { + "Unidentified error", + "Unrecognized Message Type", + "Unrecognized control code", + "Unrecognized Vendor Defined Message", + "Message too large" + }; + typedef enum Fatal_Error_code { + UnidentifiedFatalError, + PoorlyFormedMmessageHeader, + AttemptToUseConnectionWithoutBothChannels, + InvalidInitializationSequence, + ServerRefusedConnection + } Fatal_Erro_code_t; + static const char *Fatal_Error_Messages[] = + { + "Unidentified error", + "Poorly formed message header", + "Attempt to use connection without both channels established", + "Invalid Initialization Sequence", + "Server refused connection due to maximum number of clients exceeded" + }; + + typedef class message_parameter{ + public: + u_int32_t word; + // struct InitializeParameter{ + // u_int16_t protocol_version; + // char vendor_id[2]={0x00 ,0x00}; + // } initParm; + // struct InitializeResponseParameter{ + // u_int16_t session_id; + // u_int16_t protocol_version; + // } initResp; + message_parameter(u_int32_t word){this->word=word;}; + message_parameter(u_int16_t proto, char vers[2]){ + this->word= ((int32_t)proto << 16) + + (vers[1] << 8) + (vers[0]<<0); + // errlogPrintf("messagParameter:%#010x, protocol:%#06x, version:[%c%c]\n", + // this->word, + // proto, vers[0], vers[1]); + }; + message_parameter(u_int16_t proto, u_int16_t sid){ + this->word = (proto << 16) + sid; + // errlogPrintf("messagParameter:%#010x, protocol:%#06x, session id:%#06x\n", + // this->word, + // proto, sid); + }; + u_int16_t getServerProtocolVersion(){ + // errlogPrintf("getServerProtocolVersion messagParameter:%#010x, ServerProtocolVersion %d\n", + // this->word, + // (u_int16_t) (((this->word) & 0xffff0000)>>16)); + return (u_int16_t) (((this->word) & 0xffff0000)>>16); + } + u_int16_t getSessionId(){ + // errlogPrintf("getSessionId messagParameter %#010x, sessionID:%d\n", + // this->word, + // (u_int16_t) ((this->word) & 0xffff)); + return ((u_int16_t) ((this->word) & 0xffff)); + } + } message_parameter_t; + + class Header{ + public: + const char prologue[2]={'H','S'}; + u_int8_t message_type; + u_int8_t control_code; + message_parameter_t message_parameter; + u_int64_t payload_length; + + Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ + this->message_type=message_type; + } + Header(const void *buffer):message_parameter(0){ + assert(memcmp(this->prologue, buffer,2) == 0); + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + } + Header(const u_int8_t type, + const u_int8_t cce, + const message_parameter_t param, + const u_int64_t length):message_parameter(param.word){ + this->message_type=type; + this->control_code=cce; + this->payload_length=length; + } + void printf(void){ + // errlogPrintf("message type:%d\n",this->message_type); + // errlogPrintf("control_code:%d\n",this->control_code); + // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); + // errlogPrintf("payload length: %qd\n",this->payload_length); + } + + size_t send(int socket){ + char hbuf[HEADER_SIZE]; + ssize_t ssize; + + this->toRawData(hbuf); + // errlogPrintf("sending header dump: %#016qx,%#016qx\n", + // *((u_int64_t*)hbuf),*(((u_int64_t*)hbuf) +1)); + ssize=::send(socket, hbuf, sizeof(hbuf), 0); + + return ssize; + } + + size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ + + + char buffer[HEADER_SIZE]; + ssize_t rsize; + + + // errlogPrintf("recv header\n"); + + rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + + // errlogPrintf("read header dump: %#016qx, %#016qx\n", + // *((u_int64_t*)buffer), + // *(((u_int64_t*)buffer) +1) ); + + if (rsize < HEADER_SIZE){ + //raise exception? + // errlogPrintf("too short header %ld\n",rsize); + return -1; + } + else if (memcmp(this->prologue, buffer,2) != 0){ + //error + // errlogPrintf("incorrect prologue %2s %2s\n",buffer,this->prologue); + return -1; + } + + //errlogPrintf("Recieved message %2s %2s\n",buffer,this->prologue); + + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + + this->printf(); + + if((expected_message_type != AnyMessages) && + (expected_message_type != this->message_type)){ + //error! + // in overlapped mode, should we keep it? + // errlogPrintf("Error message types does not match %d vs %d\n",expected_message_type, + // this->message_type); + return -1; + } + + // errlogPrintf("successfull recieved message header %ld \n",rsize); + + return rsize; + } + + int fromRawData(void *buffer){ //DeSerialize + if (memcmp(this->prologue, buffer,2) != 0){ + //error + return -1; + } + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + return 0; + } + int toRawData(void *buffer){ //Serialize this as bytes data in buffer. + memcpy( buffer, this->prologue, 2); + *((char *) buffer + 2) = this->message_type; + *((char *) buffer + 3) = this->control_code; + *((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); + *((u_int64_t *)((char *) buffer+8))=htobe64(this->payload_length); + return 0; + } + }; + + typedef class Message:public Header{ + public: + void *payload=NULL; + + Message(Message_Types_t message_type):Header(message_type){ + }; + Message(void *raw_header):Header(raw_header){ + //this->fromRawData(raw_header); + }; + Message(void *raw_header, void *payload):Message(raw_header){ + this->payload = calloc(this->payload_length, 1); + if (this->payload != NULL){ + memcpy(this->payload, payload, this->payload_length); + }; + } + Message(u_int8_t type, + u_int8_t cce, + message_parameter_t param, + u_int64_t length, + u_int8_t *payload):Header(type,cce,param,length),payload(payload) { + //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); + //memcpy(this->payload, payload, length); + //this->payload = payload; + } + size_t send(int socket){ + size_t ssize; + ssize=this->Header::send(socket); + if (ssize < HEADER_SIZE){ + return -1; + } + return (ssize + ::send(socket, this->payload, this->payload_length,0)); + } + + ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ + size_t rsize; + size_t status; + + /* setsockopt(sock, SOL_SOCKET, */ + /* SO_RCVTIMEO, &(msg->socket_timeout), sizeof(int)); */ + + // read header part and update header. + + rsize=this->Header::recv(socket, expected_message_type); + + if (rsize < 0){ + // Error! + // errlogPrintf("failed to read header.%ld \n",rsize); + return rsize; + } + + // now prepare for a pyload. + if (this->payload==NULL && this->payload_length > 0){ + this->payload = (void *) calloc(this->payload_length,1); + if (this->payload == NULL){ + perror("faile to allocate memory for payload."); + return -1; + } + } + + rsize=0; //returns size of recieved payload. + if (this->payload_length > 0){ + size_t bytestoread=this->payload_length; + + while (bytestoread){ + status = ::recv(socket, ((u_int8_t *)this->payload+rsize), bytestoread, 0); + + if (status <= 0){ + perror("payload read error:"); + // errlogPrintf("recive error\n"); + return -1; + } + rsize +=status; + if (status >= bytestoread){ + break; + } + bytestoread -=status; + } + } + // errlogPrintf("successfull recieved message %ld \n",rsize); + return (rsize); + } + } Message_t; + + typedef class HiSLIP { + public: + unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; + unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + long socket_timeout=SOCKET_TIMEOUT; + long lock_timeout=LOCK_TIMEOUT; + int sync_channel; + int async_channel; + struct pollfd sync_poll; + struct pollfd async_poll; + int overlap_mode; + int session_id; + int server_protocol_version; + unsigned int server_vendorID; + + bool rmt_delivered; + u_int32_t message_id; + u_int32_t most_recent_message_id; + + void set_timeout( long timeout){ + this->socket_timeout=timeout; + }; + long get_timeout(void){ + return this->socket_timeout; + }; + void set_lock_timeout( long timeout){ + this->lock_timeout=timeout; + } + ; + long get_lock_timeout(void){ + return this->lock_timeout; + }; + + HiSLIP(){ + }; + void connect(char const* hostname){ + this->connect(hostname, + Default_device_name, + Default_Port); + }; + void connect(char const* hostname, + char const* dev_name, + int port); + long set_max_size(long message_size); + int device_clear(void); + u_int8_t status_query(); + //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); + long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); + size_t ask(u_int8_t *data_str, size_t size, + u_int8_t **rbuffer, long wait_time=LOCK_TIMEOUT); + int read(size_t *received, long timeout=LOCK_TIMEOUT ); + int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); + int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); + long trigger_message(void); + long remote_local(bool request); + long request_lock(const char* lock_string=NULL); + long release_lock(void); + long request_srq_lock(void); + long release_srq_lock(void); + Message *get_Service_Request(void){ + Message *msg=new Message(AnyMessages); + long status; + // errlogPrintf("In get_service_Request\n"); + this->request_srq_lock(); + + //status= msg->recv(this->async_channel, AsyncServiceRequest); + status= msg->recv(this->async_channel); + + if (status != 0){ + // errlogPrintf("get_service_Request: failed to read error.\n"); + // should handle Error/Fatal Error/Async Interrupted messages. + perror(__FUNCTION__); + } + this->release_srq_lock(); + // errlogPrintf("Exit from get_service_Request\n"); + return msg; + }; + int wait_for_SRQ(int wait_time){ + return ::poll(&this->async_poll, 1, wait_time); + } + void disconnect(){}; + + private: + int wait_for_answer(int wait_time){ + return ::poll(&this->sync_poll, 1, wait_time); + } + void reset_message_id(void){ + this->most_recent_message_id=0; + this->message_id = 0xffffff00; + } + u_int32_t increment_message_id(void){ + this->most_recent_message_id=this->message_id; + this->message_id = (this->message_id +2) & 0xffffffff; + return this->message_id; + }; + } HiSLIP_t; +}; // namespace From 004ae0e65dc75b069a4c17b659640c5e9e4049e7 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 09:06:59 +0900 Subject: [PATCH 09/67] Create HiSLIPMessage.cpp --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 1 + 1 file changed, 1 insertion(+) create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -0,0 +1 @@ + From c47db334ed32055f7d9bb6ed46475ff7e1626430 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 09:07:43 +0900 Subject: [PATCH 10/67] separate drvAsynHiSLIP into two files. separate drvAsynHiSLIP.{cpp, h} into drvAsynHiSLIP.{cpp, h} and cPyHiSLIP/HiSPLIPMessage.{cpp,h}. /HiSPLIPMessage.{cpp,h} should be able to compile without EPICS headers. --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 462 +++++++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 483 ++++++++++++++++++ 2 files changed, 945 insertions(+) create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 8b1378917..296adfd95 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -1 +1,463 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +#include "HiSLIPMessage.h" + +using nsHiSLIP::CC_request_t; +using nsHiSLIP::CC_Lock_t; +using nsHiSLIP::HiSLIP_t; +using nsHiSLIP::HiSLIP; +using nsHiSLIP::Message_t; + +#define MAX_PAYLOAD_CAPACITY 4096 +#define IDSTRING_CAPACITY 100 + +// HiSLIP methods +namespace nsHiSLIP{ + void HiSLIP::connect(const char *hostname, + const char *dev_name, + const int port //, + //const char vendor_id[2] + ){ + //osiSockAddr addr; + //Message_t *msg; + int status; + //const char vendor_id[]=Default_vendor_id; + + struct addrinfo hints, *res=NULL; + memset(&hints,0, sizeof(struct addrinfo)); + hints.ai_flags=AI_NUMERICSERV | AI_CANONNAME; + hints.ai_flags=AI_NUMERICSERV; + hints.ai_family=AF_INET; // IPv4 + hints.ai_socktype=SOCK_STREAM; + hints.ai_protocol=0; // any protocol + hints.ai_addrlen=0; + hints.ai_addr=NULL; + hints.ai_canonname=NULL; + hints.ai_next=NULL; + + { + char *service=NULL; + asprintf(&service, "%d",port);// "4880" for example. + status=getaddrinfo(hostname, service, &hints, &res); + free(service); + } + + if ((status !=0) || res == NULL){ + char *msg; + asprintf(&msg, "getaddrinfo error status:%d res %p",status,res); + perror(msg); + free(msg); + exit (9999); + } + + //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + + this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); + this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); + + if (res-> ai_addr == NULL || res->ai_addrlen == 0){ + perror("empty addinfo"); + freeaddrinfo(res); + exit (999); + }; + status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); + + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + + status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + // errlogPrintf("connected to async channel %d\n",this->async_channel); + + freeaddrinfo(res); + + { + Message msg(nsHiSLIP::Initialize, + 0, + message_parameter((u_int16_t) nsHiSLIP::PROTOCOL_VERSION_MAX, + (char *) Default_vendor_id), + (u_int64_t) 0, (u_int8_t *) NULL); + // errlogPrintf("sending message %d \n", msg.message_type); + msg.send(this->sync_channel); + } + + // errlogPrintf("Sent a initialize message\n"); + + { Message resp(AnyMessages); + + // errlogPrintf("Receive message created\n"); + + resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); + + this->overlap_mode=resp.control_code; + this->session_id=resp.message_parameter.getSessionId(); + this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); + } + // errlogPrintf("Receive a initialized message %d 0x%x %d \n", + // this->overlap_mode,this->session_id, this->server_protocol_version + // ); + + // errlogPrintf("Sending Async initialize message %x\n",this->session_id); + + + + { + Message msg(nsHiSLIP::AsyncInitialize); + msg.message_parameter.word=this->session_id; + msg.send(this->async_channel); + } + // errlogPrintf("reading Async initialize response\n"); + + { + Message resp(AnyMessages); + resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + this->overlap_mode=resp.control_code; + this->server_vendorID=resp.message_parameter.word; + } + // errlogPrintf("reading Async initialize done\n"); + + //now setup poll object + this->reset_message_id(); + + this->sync_poll.fd=this->sync_channel; + this->sync_poll.events=POLLIN; + this->sync_poll.revents=0; + + this->async_poll.fd=this->async_channel; + this->async_poll.events=POLLIN; + this->async_poll.revents=0; + + // errlogPrintf("Receive a Async initialized message\n"); + }; + + long HiSLIP::set_max_size(long message_size){ + Message resp(AnyMessages); + u_int64_t msg_size=htobe64(message_size); + + Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, + 0, + message_parameter(0), + sizeof(msg_size), (u_int8_t *) &msg_size); + msg.send(this->async_channel); + + int ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + + this->maximum_message_size=*((u_int64_t *)(resp.payload)); + this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; + return this->maximum_message_size; + }; + + int HiSLIP::device_clear(){ + Message resp(AnyMessages); + u_int8_t feature_preference; + int ready; + + Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, + 0, + 0, + 0,NULL); + + msg->send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + feature_preference=resp.control_code; + + msg=new Message(nsHiSLIP::DeviceClearComplete, + feature_preference, + 0, + 0, NULL); + + msg->send(this->sync_channel); + + ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); + + this->overlap_mode=resp.control_code; + this->reset_message_id(); + this->rmt_delivered = false; + + return 0; + + }; + + u_int8_t HiSLIP::status_query(){ + u_int8_t status; + int ready; + + Message resp(AnyMessages); + + Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, + (u_int8_t) this->rmt_delivered, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL); + msg.send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); + + status= resp.control_code &0xff; + + return status; + } + + + // long HiSLIP::write(u_int8_t *data_str, long timeout){ + // return this->write(data_str, this->maximum_message_size,timeout); + // }; + + long HiSLIP::write(u_int8_t const* data_str, size_t const dsize, long timeout){ + + size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; + size_t bytestosend=dsize; + const u_int8_t *buffer=data_str; + size_t delivered=0; + size_t count; + + // errlogPrintf("HiSLIP::write sending data %s\n", data_str); + + while(bytestosend){ + if (bytestosend < max_payload_size){ + Message msg(nsHiSLIP::DataEnd, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + bytestosend, (u_int8_t *) buffer); + buffer += bytestosend; + // errlogPrintf("sending message %s\n",(char *) msg.payload); + count=msg.send(this->sync_channel); + count -=HEADER_SIZE; + bytestosend = 0; + delivered += count ; + } + else{ + Message msg(nsHiSLIP::Data, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + max_payload_size, (u_int8_t *) buffer); + count=msg.send(this->sync_channel); + count -= HEADER_SIZE; + bytestosend -=count; + delivered += count; + buffer += max_payload_size; + } + // errlogPrintf("data sent= %lu\n",count); + this->increment_message_id(); + } + return delivered; + }; + + int HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ + bool eom=false; + size_t rsize=0; + + // errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", + // buffer, timeout); + + *received=0; + this->rmt_delivered = false; + + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + if ( ready == 0){ + return -1; + } + rsize=resp.recv(this->sync_channel); + // errlogPrintf("HiSLIP read rsize %ld\n",rsize); + if (rsize < resp.payload_length){ + //Error!! + return -1; + }; + + // may not be a good idea. + { u_int8_t *newbuf; + + newbuf=(u_int8_t *) reallocarray(*buffer, 1, + *received+resp.payload_length); + if (newbuf == NULL){ + // errlogPrintf("Cannot extend memory area\n"); + return -1; + } + else{ + *buffer=newbuf; + } + } + ::memcpy((*buffer + *received), resp.payload, resp.payload_length); + *received +=resp.payload_length; + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if ( resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + return 0; + } else{ + // error unexpected message type. + return -1; + } + } + return -1; + }; + + int HiSLIP::read(size_t *received, + u_int8_t *buffer, size_t bsize, long timeout){ + bool eom=false; + size_t rsize=0; + + // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", + // buffer, bsize, timeout); + *received=0; + this->rmt_delivered = false; + + if (buffer==NULL || bsize <= 0){ + // errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", + // buffer, bsize, timeout); + return -1; + } + if (bsize < this->maximum_payload_size){ + // errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", + // bsize, this->maximum_payload_size); + } + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=::poll(&this->sync_poll, 1, timeout); + + if (ready == 0){ + // errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); + return -1; + } + + rsize=resp.recv(this->sync_channel); + + if (rsize < resp.payload_length){ + // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); + return -1; + }; + if (( (*received) + resp.payload_length) > bsize){ + // errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", + // *received, resp.payload_length, bsize); + + ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); + *received = bsize; + return 0; + } + else{ + // errlogPrintf("received message size %ld %ld data:%s mt:%d\n", + // rsize, *received, (char *) resp.payload, resp.message_type); + ::memcpy( (buffer + *received), resp.payload, resp.payload_length); + + *received +=resp.payload_length; + } + + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if (resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + // errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", + // buffer, (char *) resp.payload, eom,this->rmt_delivered); + return 0; + } else{ + // errlogPrintf("Unexpected message type:%d\n", + // resp.message_type); + resp.printf(); + // error unexpected message type. + return -1; + } + } + return -1; + }; + + size_t HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, + u_int8_t **rbuffer, + long wait_time){ + size_t rsize=-1; + u_int8_t *buffer=NULL; + int status; + + // errlogPrintf("sending a command %s %lu",data_str, dsize); + + this->write(data_str, dsize); + if(this->wait_for_answer(wait_time) == 0){ + // error + return -1; + }; + status=this->read(&rsize, &buffer); + if (status !=0){ + rsize=-1; + } + *rbuffer=buffer; + return rsize; + }; + + long HiSLIP::trigger_message(void){ + return 0; + }; + long HiSLIP::remote_local(bool request){ + return 0; + }; + long HiSLIP::request_lock(const char* lock_string){ + { + // errlogPrintf("request_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + long HiSLIP::release_lock(void){ + { + // errlogPrintf("release_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + long HiSLIP::request_srq_lock(void){ + { + // errlogPrintf("request_srq_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + long HiSLIP::release_srq_lock(void){ + { + // errlogPrintf("release_srq_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + +} // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h new file mode 100644 index 000000000..4d032ddfc --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -0,0 +1,483 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +//-*- coding:utf-8 -*- +#define NDEBUG 1 +#define DEBUG 1 + +#include +#include + +//#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include + +#include +#include +#include +#include +#include // network endian is "be". +#include +#include +#include +#include /* for MAXHOSTNAMELEN */ +#include /* close() and others */ + +//#include +//#include +//#include +//#include +//#include +//#include + + + +template struct Property { + T& r; + operator T() {return r;} + void operator =(const T v){ r=v;} +}; + +namespace nsHiSLIP{ + + //constants + typedef enum CC_reuqest{ + RemoteDisable=0, + RemoteEnable=1, + RemoteDisableGTL=2, // disable remote and goto local + RemoteEnableGTR=3, // Enable remote and goto remote + RemoteEnableLLO=4, // Enable remote and lock out local + RemoteEnableGTRLLO=5, // + RTL=6 + } CC_request_t; + + typedef enum CC_Lock{ + release =0, + request =1 + } CC_Lock_t; + + typedef enum CC_LockResponse{ + fail=0, //Lock was requested but not granted + success=1, //release of exclusive lock + success_shared=2, //release of shared lock + error=3 // Invalide + } CC_LockResponse_t; + + static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 + static const long INITIAL_MESSAGE_ID = 0xffffff00 ; + static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; + static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes + static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept + static const long HEADER_SIZE=16; + static const long SOCKET_TIMEOUT = 1; //# Socket timeout + static const long LOCK_TIMEOUT = 3000;//# Lock timeout + static const long Default_Port = 4880; + static const char Default_device_name[]="hslip0"; + static const char Default_vendor_id[]={'E','P'}; + static const char Prologue[]={'H','S'}; + // + typedef enum Message_Types{ + Initialize = 0, + InitializeResponse = 1, + FatalError = 2, + Error = 3, + AsyncLock = 4, + AsyncLockResponse = 5, + Data = 6, + DataEnd = 7, + DeviceClearComplete = 8, + DeviceClearAcknowledge = 9, + AsyncRemoteLocalControl = 10, + AsyncRemoteLocalResponse = 11, + Trigger = 12, + Interrupted = 13, + AsyncInterrupted = 14, + AsyncMaximumMessageSize = 15, + AsyncMaximumMessageSizeResponse = 16, + AsyncInitialize = 17, + AsyncInitializeResponse = 18, + AsyncDeviceClear = 19, + AsyncServiceRequest = 20, + AsyncStatusQuery = 21, + AsyncStatusResponse = 22, + AsyncDeviceClearAcknowledge = 23, + AsyncLockInfo = 24, + AsyncLockInfoResponse = 25, + // 26-127 are reserved for future use. + // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. + AnyMessages=127 // 128-255 are reserved for vendor use. + } Message_Types_t; + + typedef enum Error_code{ + UnidentifiedError, + UnrecognizedMessageType, + UnrecognizedControlCode, + UnrecognizedVendorDefinedMessage, + MessageTooLarge + } Error_code_t; + static const char *Error_Messages[] = + { + "Unidentified error", + "Unrecognized Message Type", + "Unrecognized control code", + "Unrecognized Vendor Defined Message", + "Message too large" + }; + typedef enum Fatal_Error_code { + UnidentifiedFatalError, + PoorlyFormedMmessageHeader, + AttemptToUseConnectionWithoutBothChannels, + InvalidInitializationSequence, + ServerRefusedConnection + } Fatal_Erro_code_t; + static const char *Fatal_Error_Messages[] = + { + "Unidentified error", + "Poorly formed message header", + "Attempt to use connection without both channels established", + "Invalid Initialization Sequence", + "Server refused connection due to maximum number of clients exceeded" + }; + + typedef class message_parameter{ + public: + u_int32_t word; + // struct InitializeParameter{ + // u_int16_t protocol_version; + // char vendor_id[2]={0x00 ,0x00}; + // } initParm; + // struct InitializeResponseParameter{ + // u_int16_t session_id; + // u_int16_t protocol_version; + // } initResp; + message_parameter(u_int32_t word){this->word=word;}; + message_parameter(u_int16_t proto, char vers[2]){ + this->word= ((int32_t)proto << 16) + + (vers[1] << 8) + (vers[0]<<0); + // errlogPrintf("messagParameter:%#010x, protocol:%#06x, version:[%c%c]\n", + // this->word, + // proto, vers[0], vers[1]); + }; + message_parameter(u_int16_t proto, u_int16_t sid){ + this->word = (proto << 16) + sid; + // errlogPrintf("messagParameter:%#010x, protocol:%#06x, session id:%#06x\n", + // this->word, + // proto, sid); + }; + u_int16_t getServerProtocolVersion(){ + // errlogPrintf("getServerProtocolVersion messagParameter:%#010x, ServerProtocolVersion %d\n", + // this->word, + // (u_int16_t) (((this->word) & 0xffff0000)>>16)); + return (u_int16_t) (((this->word) & 0xffff0000)>>16); + } + u_int16_t getSessionId(){ + // errlogPrintf("getSessionId messagParameter %#010x, sessionID:%d\n", + // this->word, + // (u_int16_t) ((this->word) & 0xffff)); + return ((u_int16_t) ((this->word) & 0xffff)); + } + } message_parameter_t; + + class Header{ + public: + const char prologue[2]={'H','S'}; + u_int8_t message_type; + u_int8_t control_code; + message_parameter_t message_parameter; + u_int64_t payload_length; + + Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ + this->message_type=message_type; + } + Header(const void *buffer):message_parameter(0){ + assert(memcmp(this->prologue, buffer,2) == 0); + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + } + Header(const u_int8_t type, + const u_int8_t cce, + const message_parameter_t param, + const u_int64_t length):message_parameter(param.word){ + this->message_type=type; + this->control_code=cce; + this->payload_length=length; + } + void printf(void){ + // errlogPrintf("message type:%d\n",this->message_type); + // errlogPrintf("control_code:%d\n",this->control_code); + // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); + // errlogPrintf("payload length: %qd\n",this->payload_length); + } + + size_t send(int socket){ + char hbuf[HEADER_SIZE]; + ssize_t ssize; + + this->toRawData(hbuf); + // errlogPrintf("sending header dump: %#016qx,%#016qx\n", + // *((u_int64_t*)hbuf),*(((u_int64_t*)hbuf) +1)); + ssize=::send(socket, hbuf, sizeof(hbuf), 0); + + return ssize; + } + + size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ + + + char buffer[HEADER_SIZE]; + ssize_t rsize; + + + // errlogPrintf("recv header\n"); + + rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + + // errlogPrintf("read header dump: %#016qx, %#016qx\n", + // *((u_int64_t*)buffer), + // *(((u_int64_t*)buffer) +1) ); + + if (rsize < HEADER_SIZE){ + //raise exception? + // errlogPrintf("too short header %ld\n",rsize); + return -1; + } + else if (memcmp(this->prologue, buffer,2) != 0){ + //error + // errlogPrintf("incorrect prologue %2s %2s\n",buffer,this->prologue); + return -1; + } + + //errlogPrintf("Recieved message %2s %2s\n",buffer,this->prologue); + + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + + this->printf(); + + if((expected_message_type != AnyMessages) && + (expected_message_type != this->message_type)){ + //error! + // in overlapped mode, should we keep it? + // errlogPrintf("Error message types does not match %d vs %d\n",expected_message_type, + // this->message_type); + return -1; + } + + // errlogPrintf("successfull recieved message header %ld \n",rsize); + + return rsize; + } + + int fromRawData(void *buffer){ //DeSerialize + if (memcmp(this->prologue, buffer,2) != 0){ + //error + return -1; + } + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + return 0; + } + int toRawData(void *buffer){ //Serialize this as bytes data in buffer. + memcpy( buffer, this->prologue, 2); + *((char *) buffer + 2) = this->message_type; + *((char *) buffer + 3) = this->control_code; + *((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); + *((u_int64_t *)((char *) buffer+8))=htobe64(this->payload_length); + return 0; + } + }; + + typedef class Message:public Header{ + public: + void *payload=NULL; + + Message(Message_Types_t message_type):Header(message_type){ + }; + Message(void *raw_header):Header(raw_header){ + //this->fromRawData(raw_header); + }; + Message(void *raw_header, void *payload):Message(raw_header){ + this->payload = calloc(this->payload_length, 1); + if (this->payload != NULL){ + memcpy(this->payload, payload, this->payload_length); + }; + } + Message(u_int8_t type, + u_int8_t cce, + message_parameter_t param, + u_int64_t length, + u_int8_t *payload):Header(type,cce,param,length),payload(payload) { + //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); + //memcpy(this->payload, payload, length); + //this->payload = payload; + } + size_t send(int socket){ + size_t ssize; + ssize=this->Header::send(socket); + if (ssize < HEADER_SIZE){ + return -1; + } + return (ssize + ::send(socket, this->payload, this->payload_length,0)); + } + + ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ + size_t rsize; + size_t status; + + /* setsockopt(sock, SOL_SOCKET, */ + /* SO_RCVTIMEO, &(msg->socket_timeout), sizeof(int)); */ + + // read header part and update header. + + rsize=this->Header::recv(socket, expected_message_type); + + if (rsize < 0){ + // Error! + // errlogPrintf("failed to read header.%ld \n",rsize); + return rsize; + } + + // now prepare for a pyload. + if (this->payload==NULL && this->payload_length > 0){ + this->payload = (void *) calloc(this->payload_length,1); + if (this->payload == NULL){ + perror("faile to allocate memory for payload."); + return -1; + } + } + + rsize=0; //returns size of recieved payload. + if (this->payload_length > 0){ + size_t bytestoread=this->payload_length; + + while (bytestoread){ + status = ::recv(socket, ((u_int8_t *)this->payload+rsize), bytestoread, 0); + + if (status <= 0){ + perror("payload read error:"); + // errlogPrintf("recive error\n"); + return -1; + } + rsize +=status; + if (status >= bytestoread){ + break; + } + bytestoread -=status; + } + } + // errlogPrintf("successfull recieved message %ld \n",rsize); + return (rsize); + } + } Message_t; + + typedef class HiSLIP { + public: + unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; + unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + long socket_timeout=SOCKET_TIMEOUT; + long lock_timeout=LOCK_TIMEOUT; + int sync_channel; + int async_channel; + struct pollfd sync_poll; + struct pollfd async_poll; + int overlap_mode; + int session_id; + int server_protocol_version; + unsigned int server_vendorID; + + bool rmt_delivered; + u_int32_t message_id; + u_int32_t most_recent_message_id; + + void set_timeout( long timeout){ + this->socket_timeout=timeout; + }; + long get_timeout(void){ + return this->socket_timeout; + }; + void set_lock_timeout( long timeout){ + this->lock_timeout=timeout; + } + ; + long get_lock_timeout(void){ + return this->lock_timeout; + }; + + HiSLIP(){ + }; + void connect(char const* hostname){ + this->connect(hostname, + Default_device_name, + Default_Port); + }; + void connect(char const* hostname, + char const* dev_name, + int port); + long set_max_size(long message_size); + int device_clear(void); + u_int8_t status_query(); + //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); + long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); + size_t ask(u_int8_t *data_str, size_t size, + u_int8_t **rbuffer, long wait_time=LOCK_TIMEOUT); + int read(size_t *received, long timeout=LOCK_TIMEOUT ); + int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); + int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); + long trigger_message(void); + long remote_local(bool request); + long request_lock(const char* lock_string=NULL); + long release_lock(void); + long request_srq_lock(void); + long release_srq_lock(void); + Message *get_Service_Request(void){ + Message *msg=new Message(AnyMessages); + long status; + // errlogPrintf("In get_service_Request\n"); + this->request_srq_lock(); + + //status= msg->recv(this->async_channel, AsyncServiceRequest); + status= msg->recv(this->async_channel); + + if (status != 0){ + // errlogPrintf("get_service_Request: failed to read error.\n"); + // should handle Error/Fatal Error/Async Interrupted messages. + perror(__FUNCTION__); + } + this->release_srq_lock(); + // errlogPrintf("Exit from get_service_Request\n"); + return msg; + }; + int wait_for_SRQ(int wait_time){ + return ::poll(&this->async_poll, 1, wait_time); + } + void disconnect(){}; + + private: + int wait_for_answer(int wait_time){ + return ::poll(&this->sync_poll, 1, wait_time); + } + void reset_message_id(void){ + this->most_recent_message_id=0; + this->message_id = 0xffffff00; + } + u_int32_t increment_message_id(void){ + this->most_recent_message_id=this->message_id; + this->message_id = (this->message_id +2) & 0xffffffff; + return this->message_id; + }; + } HiSLIP_t; +}; // namespace From 632175410ca1da6ce8ccc96a40be6659596d2083 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 09:08:33 +0900 Subject: [PATCH 11/67] moved to cPyHiSLIP --- asyn/drvAsynHiSLIP/HiSLIPMessage.h | 483 ----------------------------- 1 file changed, 483 deletions(-) delete mode 100644 asyn/drvAsynHiSLIP/HiSLIPMessage.h diff --git a/asyn/drvAsynHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/HiSLIPMessage.h deleted file mode 100644 index 4d032ddfc..000000000 --- a/asyn/drvAsynHiSLIP/HiSLIPMessage.h +++ /dev/null @@ -1,483 +0,0 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ -//-*- coding:utf-8 -*- -#define NDEBUG 1 -#define DEBUG 1 - -#include -#include - -//#define _GNU_SOURCE /* See feature_test_macros(7) */ -#include - -#include -#include -#include -#include -#include // network endian is "be". -#include -#include -#include -#include /* for MAXHOSTNAMELEN */ -#include /* close() and others */ - -//#include -//#include -//#include -//#include -//#include -//#include - - - -template struct Property { - T& r; - operator T() {return r;} - void operator =(const T v){ r=v;} -}; - -namespace nsHiSLIP{ - - //constants - typedef enum CC_reuqest{ - RemoteDisable=0, - RemoteEnable=1, - RemoteDisableGTL=2, // disable remote and goto local - RemoteEnableGTR=3, // Enable remote and goto remote - RemoteEnableLLO=4, // Enable remote and lock out local - RemoteEnableGTRLLO=5, // - RTL=6 - } CC_request_t; - - typedef enum CC_Lock{ - release =0, - request =1 - } CC_Lock_t; - - typedef enum CC_LockResponse{ - fail=0, //Lock was requested but not granted - success=1, //release of exclusive lock - success_shared=2, //release of shared lock - error=3 // Invalide - } CC_LockResponse_t; - - static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 - static const long INITIAL_MESSAGE_ID = 0xffffff00 ; - static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; - static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes - static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept - static const long HEADER_SIZE=16; - static const long SOCKET_TIMEOUT = 1; //# Socket timeout - static const long LOCK_TIMEOUT = 3000;//# Lock timeout - static const long Default_Port = 4880; - static const char Default_device_name[]="hslip0"; - static const char Default_vendor_id[]={'E','P'}; - static const char Prologue[]={'H','S'}; - // - typedef enum Message_Types{ - Initialize = 0, - InitializeResponse = 1, - FatalError = 2, - Error = 3, - AsyncLock = 4, - AsyncLockResponse = 5, - Data = 6, - DataEnd = 7, - DeviceClearComplete = 8, - DeviceClearAcknowledge = 9, - AsyncRemoteLocalControl = 10, - AsyncRemoteLocalResponse = 11, - Trigger = 12, - Interrupted = 13, - AsyncInterrupted = 14, - AsyncMaximumMessageSize = 15, - AsyncMaximumMessageSizeResponse = 16, - AsyncInitialize = 17, - AsyncInitializeResponse = 18, - AsyncDeviceClear = 19, - AsyncServiceRequest = 20, - AsyncStatusQuery = 21, - AsyncStatusResponse = 22, - AsyncDeviceClearAcknowledge = 23, - AsyncLockInfo = 24, - AsyncLockInfoResponse = 25, - // 26-127 are reserved for future use. - // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. - AnyMessages=127 // 128-255 are reserved for vendor use. - } Message_Types_t; - - typedef enum Error_code{ - UnidentifiedError, - UnrecognizedMessageType, - UnrecognizedControlCode, - UnrecognizedVendorDefinedMessage, - MessageTooLarge - } Error_code_t; - static const char *Error_Messages[] = - { - "Unidentified error", - "Unrecognized Message Type", - "Unrecognized control code", - "Unrecognized Vendor Defined Message", - "Message too large" - }; - typedef enum Fatal_Error_code { - UnidentifiedFatalError, - PoorlyFormedMmessageHeader, - AttemptToUseConnectionWithoutBothChannels, - InvalidInitializationSequence, - ServerRefusedConnection - } Fatal_Erro_code_t; - static const char *Fatal_Error_Messages[] = - { - "Unidentified error", - "Poorly formed message header", - "Attempt to use connection without both channels established", - "Invalid Initialization Sequence", - "Server refused connection due to maximum number of clients exceeded" - }; - - typedef class message_parameter{ - public: - u_int32_t word; - // struct InitializeParameter{ - // u_int16_t protocol_version; - // char vendor_id[2]={0x00 ,0x00}; - // } initParm; - // struct InitializeResponseParameter{ - // u_int16_t session_id; - // u_int16_t protocol_version; - // } initResp; - message_parameter(u_int32_t word){this->word=word;}; - message_parameter(u_int16_t proto, char vers[2]){ - this->word= ((int32_t)proto << 16) + - (vers[1] << 8) + (vers[0]<<0); - // errlogPrintf("messagParameter:%#010x, protocol:%#06x, version:[%c%c]\n", - // this->word, - // proto, vers[0], vers[1]); - }; - message_parameter(u_int16_t proto, u_int16_t sid){ - this->word = (proto << 16) + sid; - // errlogPrintf("messagParameter:%#010x, protocol:%#06x, session id:%#06x\n", - // this->word, - // proto, sid); - }; - u_int16_t getServerProtocolVersion(){ - // errlogPrintf("getServerProtocolVersion messagParameter:%#010x, ServerProtocolVersion %d\n", - // this->word, - // (u_int16_t) (((this->word) & 0xffff0000)>>16)); - return (u_int16_t) (((this->word) & 0xffff0000)>>16); - } - u_int16_t getSessionId(){ - // errlogPrintf("getSessionId messagParameter %#010x, sessionID:%d\n", - // this->word, - // (u_int16_t) ((this->word) & 0xffff)); - return ((u_int16_t) ((this->word) & 0xffff)); - } - } message_parameter_t; - - class Header{ - public: - const char prologue[2]={'H','S'}; - u_int8_t message_type; - u_int8_t control_code; - message_parameter_t message_parameter; - u_int64_t payload_length; - - Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ - this->message_type=message_type; - } - Header(const void *buffer):message_parameter(0){ - assert(memcmp(this->prologue, buffer,2) == 0); - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - } - Header(const u_int8_t type, - const u_int8_t cce, - const message_parameter_t param, - const u_int64_t length):message_parameter(param.word){ - this->message_type=type; - this->control_code=cce; - this->payload_length=length; - } - void printf(void){ - // errlogPrintf("message type:%d\n",this->message_type); - // errlogPrintf("control_code:%d\n",this->control_code); - // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); - // errlogPrintf("payload length: %qd\n",this->payload_length); - } - - size_t send(int socket){ - char hbuf[HEADER_SIZE]; - ssize_t ssize; - - this->toRawData(hbuf); - // errlogPrintf("sending header dump: %#016qx,%#016qx\n", - // *((u_int64_t*)hbuf),*(((u_int64_t*)hbuf) +1)); - ssize=::send(socket, hbuf, sizeof(hbuf), 0); - - return ssize; - } - - size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ - - - char buffer[HEADER_SIZE]; - ssize_t rsize; - - - // errlogPrintf("recv header\n"); - - rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - - // errlogPrintf("read header dump: %#016qx, %#016qx\n", - // *((u_int64_t*)buffer), - // *(((u_int64_t*)buffer) +1) ); - - if (rsize < HEADER_SIZE){ - //raise exception? - // errlogPrintf("too short header %ld\n",rsize); - return -1; - } - else if (memcmp(this->prologue, buffer,2) != 0){ - //error - // errlogPrintf("incorrect prologue %2s %2s\n",buffer,this->prologue); - return -1; - } - - //errlogPrintf("Recieved message %2s %2s\n",buffer,this->prologue); - - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - - this->printf(); - - if((expected_message_type != AnyMessages) && - (expected_message_type != this->message_type)){ - //error! - // in overlapped mode, should we keep it? - // errlogPrintf("Error message types does not match %d vs %d\n",expected_message_type, - // this->message_type); - return -1; - } - - // errlogPrintf("successfull recieved message header %ld \n",rsize); - - return rsize; - } - - int fromRawData(void *buffer){ //DeSerialize - if (memcmp(this->prologue, buffer,2) != 0){ - //error - return -1; - } - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - return 0; - } - int toRawData(void *buffer){ //Serialize this as bytes data in buffer. - memcpy( buffer, this->prologue, 2); - *((char *) buffer + 2) = this->message_type; - *((char *) buffer + 3) = this->control_code; - *((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); - *((u_int64_t *)((char *) buffer+8))=htobe64(this->payload_length); - return 0; - } - }; - - typedef class Message:public Header{ - public: - void *payload=NULL; - - Message(Message_Types_t message_type):Header(message_type){ - }; - Message(void *raw_header):Header(raw_header){ - //this->fromRawData(raw_header); - }; - Message(void *raw_header, void *payload):Message(raw_header){ - this->payload = calloc(this->payload_length, 1); - if (this->payload != NULL){ - memcpy(this->payload, payload, this->payload_length); - }; - } - Message(u_int8_t type, - u_int8_t cce, - message_parameter_t param, - u_int64_t length, - u_int8_t *payload):Header(type,cce,param,length),payload(payload) { - //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); - //memcpy(this->payload, payload, length); - //this->payload = payload; - } - size_t send(int socket){ - size_t ssize; - ssize=this->Header::send(socket); - if (ssize < HEADER_SIZE){ - return -1; - } - return (ssize + ::send(socket, this->payload, this->payload_length,0)); - } - - ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ - size_t rsize; - size_t status; - - /* setsockopt(sock, SOL_SOCKET, */ - /* SO_RCVTIMEO, &(msg->socket_timeout), sizeof(int)); */ - - // read header part and update header. - - rsize=this->Header::recv(socket, expected_message_type); - - if (rsize < 0){ - // Error! - // errlogPrintf("failed to read header.%ld \n",rsize); - return rsize; - } - - // now prepare for a pyload. - if (this->payload==NULL && this->payload_length > 0){ - this->payload = (void *) calloc(this->payload_length,1); - if (this->payload == NULL){ - perror("faile to allocate memory for payload."); - return -1; - } - } - - rsize=0; //returns size of recieved payload. - if (this->payload_length > 0){ - size_t bytestoread=this->payload_length; - - while (bytestoread){ - status = ::recv(socket, ((u_int8_t *)this->payload+rsize), bytestoread, 0); - - if (status <= 0){ - perror("payload read error:"); - // errlogPrintf("recive error\n"); - return -1; - } - rsize +=status; - if (status >= bytestoread){ - break; - } - bytestoread -=status; - } - } - // errlogPrintf("successfull recieved message %ld \n",rsize); - return (rsize); - } - } Message_t; - - typedef class HiSLIP { - public: - unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; - unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; - long socket_timeout=SOCKET_TIMEOUT; - long lock_timeout=LOCK_TIMEOUT; - int sync_channel; - int async_channel; - struct pollfd sync_poll; - struct pollfd async_poll; - int overlap_mode; - int session_id; - int server_protocol_version; - unsigned int server_vendorID; - - bool rmt_delivered; - u_int32_t message_id; - u_int32_t most_recent_message_id; - - void set_timeout( long timeout){ - this->socket_timeout=timeout; - }; - long get_timeout(void){ - return this->socket_timeout; - }; - void set_lock_timeout( long timeout){ - this->lock_timeout=timeout; - } - ; - long get_lock_timeout(void){ - return this->lock_timeout; - }; - - HiSLIP(){ - }; - void connect(char const* hostname){ - this->connect(hostname, - Default_device_name, - Default_Port); - }; - void connect(char const* hostname, - char const* dev_name, - int port); - long set_max_size(long message_size); - int device_clear(void); - u_int8_t status_query(); - //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); - long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); - size_t ask(u_int8_t *data_str, size_t size, - u_int8_t **rbuffer, long wait_time=LOCK_TIMEOUT); - int read(size_t *received, long timeout=LOCK_TIMEOUT ); - int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); - int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); - long trigger_message(void); - long remote_local(bool request); - long request_lock(const char* lock_string=NULL); - long release_lock(void); - long request_srq_lock(void); - long release_srq_lock(void); - Message *get_Service_Request(void){ - Message *msg=new Message(AnyMessages); - long status; - // errlogPrintf("In get_service_Request\n"); - this->request_srq_lock(); - - //status= msg->recv(this->async_channel, AsyncServiceRequest); - status= msg->recv(this->async_channel); - - if (status != 0){ - // errlogPrintf("get_service_Request: failed to read error.\n"); - // should handle Error/Fatal Error/Async Interrupted messages. - perror(__FUNCTION__); - } - this->release_srq_lock(); - // errlogPrintf("Exit from get_service_Request\n"); - return msg; - }; - int wait_for_SRQ(int wait_time){ - return ::poll(&this->async_poll, 1, wait_time); - } - void disconnect(){}; - - private: - int wait_for_answer(int wait_time){ - return ::poll(&this->sync_poll, 1, wait_time); - } - void reset_message_id(void){ - this->most_recent_message_id=0; - this->message_id = 0xffffff00; - } - u_int32_t increment_message_id(void){ - this->most_recent_message_id=this->message_id; - this->message_id = (this->message_id +2) & 0xffffffff; - return this->message_id; - }; - } HiSLIP_t; -}; // namespace From 9d5e45e221480779c3dee7c2b995dcc7a713d6ed Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 25 Jun 2020 09:08:58 +0900 Subject: [PATCH 12/67] moved to cPyHiSLIP --- asyn/drvAsynHiSLIP/HiSLIPMessage.cpp | 463 --------------------------- 1 file changed, 463 deletions(-) delete mode 100644 asyn/drvAsynHiSLIP/HiSLIPMessage.cpp diff --git a/asyn/drvAsynHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/HiSLIPMessage.cpp deleted file mode 100644 index 296adfd95..000000000 --- a/asyn/drvAsynHiSLIP/HiSLIPMessage.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ -#include "HiSLIPMessage.h" - -using nsHiSLIP::CC_request_t; -using nsHiSLIP::CC_Lock_t; -using nsHiSLIP::HiSLIP_t; -using nsHiSLIP::HiSLIP; -using nsHiSLIP::Message_t; - -#define MAX_PAYLOAD_CAPACITY 4096 -#define IDSTRING_CAPACITY 100 - -// HiSLIP methods -namespace nsHiSLIP{ - void HiSLIP::connect(const char *hostname, - const char *dev_name, - const int port //, - //const char vendor_id[2] - ){ - //osiSockAddr addr; - //Message_t *msg; - int status; - //const char vendor_id[]=Default_vendor_id; - - struct addrinfo hints, *res=NULL; - memset(&hints,0, sizeof(struct addrinfo)); - hints.ai_flags=AI_NUMERICSERV | AI_CANONNAME; - hints.ai_flags=AI_NUMERICSERV; - hints.ai_family=AF_INET; // IPv4 - hints.ai_socktype=SOCK_STREAM; - hints.ai_protocol=0; // any protocol - hints.ai_addrlen=0; - hints.ai_addr=NULL; - hints.ai_canonname=NULL; - hints.ai_next=NULL; - - { - char *service=NULL; - asprintf(&service, "%d",port);// "4880" for example. - status=getaddrinfo(hostname, service, &hints, &res); - free(service); - } - - if ((status !=0) || res == NULL){ - char *msg; - asprintf(&msg, "getaddrinfo error status:%d res %p",status,res); - perror(msg); - free(msg); - exit (9999); - } - - //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - - this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); - this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); - - if (res-> ai_addr == NULL || res->ai_addrlen == 0){ - perror("empty addinfo"); - freeaddrinfo(res); - exit (999); - }; - status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); - - if (status!=0){ - // Error handling - perror(__FUNCTION__); - } - - status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); - if (status!=0){ - // Error handling - perror(__FUNCTION__); - } - // errlogPrintf("connected to async channel %d\n",this->async_channel); - - freeaddrinfo(res); - - { - Message msg(nsHiSLIP::Initialize, - 0, - message_parameter((u_int16_t) nsHiSLIP::PROTOCOL_VERSION_MAX, - (char *) Default_vendor_id), - (u_int64_t) 0, (u_int8_t *) NULL); - // errlogPrintf("sending message %d \n", msg.message_type); - msg.send(this->sync_channel); - } - - // errlogPrintf("Sent a initialize message\n"); - - { Message resp(AnyMessages); - - // errlogPrintf("Receive message created\n"); - - resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); - - this->overlap_mode=resp.control_code; - this->session_id=resp.message_parameter.getSessionId(); - this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); - } - // errlogPrintf("Receive a initialized message %d 0x%x %d \n", - // this->overlap_mode,this->session_id, this->server_protocol_version - // ); - - // errlogPrintf("Sending Async initialize message %x\n",this->session_id); - - - - { - Message msg(nsHiSLIP::AsyncInitialize); - msg.message_parameter.word=this->session_id; - msg.send(this->async_channel); - } - // errlogPrintf("reading Async initialize response\n"); - - { - Message resp(AnyMessages); - resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); - this->overlap_mode=resp.control_code; - this->server_vendorID=resp.message_parameter.word; - } - // errlogPrintf("reading Async initialize done\n"); - - //now setup poll object - this->reset_message_id(); - - this->sync_poll.fd=this->sync_channel; - this->sync_poll.events=POLLIN; - this->sync_poll.revents=0; - - this->async_poll.fd=this->async_channel; - this->async_poll.events=POLLIN; - this->async_poll.revents=0; - - // errlogPrintf("Receive a Async initialized message\n"); - }; - - long HiSLIP::set_max_size(long message_size){ - Message resp(AnyMessages); - u_int64_t msg_size=htobe64(message_size); - - Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, - 0, - message_parameter(0), - sizeof(msg_size), (u_int8_t *) &msg_size); - msg.send(this->async_channel); - - int ready=poll(&this->async_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - - resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); - - this->maximum_message_size=*((u_int64_t *)(resp.payload)); - this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; - return this->maximum_message_size; - }; - - int HiSLIP::device_clear(){ - Message resp(AnyMessages); - u_int8_t feature_preference; - int ready; - - Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, - 0, - 0, - 0,NULL); - - msg->send(this->async_channel); - - ready=poll(&this->async_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - - resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); - feature_preference=resp.control_code; - - msg=new Message(nsHiSLIP::DeviceClearComplete, - feature_preference, - 0, - 0, NULL); - - msg->send(this->sync_channel); - - ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); - - this->overlap_mode=resp.control_code; - this->reset_message_id(); - this->rmt_delivered = false; - - return 0; - - }; - - u_int8_t HiSLIP::status_query(){ - u_int8_t status; - int ready; - - Message resp(AnyMessages); - - Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, - (u_int8_t) this->rmt_delivered, - message_parameter((u_int32_t) this->most_recent_message_id), - 0, NULL); - msg.send(this->async_channel); - - ready=poll(&this->async_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); - - status= resp.control_code &0xff; - - return status; - } - - - // long HiSLIP::write(u_int8_t *data_str, long timeout){ - // return this->write(data_str, this->maximum_message_size,timeout); - // }; - - long HiSLIP::write(u_int8_t const* data_str, size_t const dsize, long timeout){ - - size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; - size_t bytestosend=dsize; - const u_int8_t *buffer=data_str; - size_t delivered=0; - size_t count; - - // errlogPrintf("HiSLIP::write sending data %s\n", data_str); - - while(bytestosend){ - if (bytestosend < max_payload_size){ - Message msg(nsHiSLIP::DataEnd, - this->rmt_delivered, - nsHiSLIP::message_parameter(this->message_id), - bytestosend, (u_int8_t *) buffer); - buffer += bytestosend; - // errlogPrintf("sending message %s\n",(char *) msg.payload); - count=msg.send(this->sync_channel); - count -=HEADER_SIZE; - bytestosend = 0; - delivered += count ; - } - else{ - Message msg(nsHiSLIP::Data, - this->rmt_delivered, - nsHiSLIP::message_parameter(this->message_id), - max_payload_size, (u_int8_t *) buffer); - count=msg.send(this->sync_channel); - count -= HEADER_SIZE; - bytestosend -=count; - delivered += count; - buffer += max_payload_size; - } - // errlogPrintf("data sent= %lu\n",count); - this->increment_message_id(); - } - return delivered; - }; - - int HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ - bool eom=false; - size_t rsize=0; - - // errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", - // buffer, timeout); - - *received=0; - this->rmt_delivered = false; - - while(!eom) { - int ready; - Message resp(AnyMessages); - - ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); - if ( ready == 0){ - return -1; - } - rsize=resp.recv(this->sync_channel); - // errlogPrintf("HiSLIP read rsize %ld\n",rsize); - if (rsize < resp.payload_length){ - //Error!! - return -1; - }; - - // may not be a good idea. - { u_int8_t *newbuf; - - newbuf=(u_int8_t *) reallocarray(*buffer, 1, - *received+resp.payload_length); - if (newbuf == NULL){ - // errlogPrintf("Cannot extend memory area\n"); - return -1; - } - else{ - *buffer=newbuf; - } - } - ::memcpy((*buffer + *received), resp.payload, resp.payload_length); - *received +=resp.payload_length; - if ( resp.message_type == nsHiSLIP::Data){ - continue; - } else if ( resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - return 0; - } else{ - // error unexpected message type. - return -1; - } - } - return -1; - }; - - int HiSLIP::read(size_t *received, - u_int8_t *buffer, size_t bsize, long timeout){ - bool eom=false; - size_t rsize=0; - - // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", - // buffer, bsize, timeout); - *received=0; - this->rmt_delivered = false; - - if (buffer==NULL || bsize <= 0){ - // errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", - // buffer, bsize, timeout); - return -1; - } - if (bsize < this->maximum_payload_size){ - // errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", - // bsize, this->maximum_payload_size); - } - while(!eom) { - int ready; - Message resp(AnyMessages); - - ready=::poll(&this->sync_poll, 1, timeout); - - if (ready == 0){ - // errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); - return -1; - } - - rsize=resp.recv(this->sync_channel); - - if (rsize < resp.payload_length){ - // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); - return -1; - }; - if (( (*received) + resp.payload_length) > bsize){ - // errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", - // *received, resp.payload_length, bsize); - - ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); - *received = bsize; - return 0; - } - else{ - // errlogPrintf("received message size %ld %ld data:%s mt:%d\n", - // rsize, *received, (char *) resp.payload, resp.message_type); - ::memcpy( (buffer + *received), resp.payload, resp.payload_length); - - *received +=resp.payload_length; - } - - if ( resp.message_type == nsHiSLIP::Data){ - continue; - } else if (resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - // errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", - // buffer, (char *) resp.payload, eom,this->rmt_delivered); - return 0; - } else{ - // errlogPrintf("Unexpected message type:%d\n", - // resp.message_type); - resp.printf(); - // error unexpected message type. - return -1; - } - } - return -1; - }; - - size_t HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, - u_int8_t **rbuffer, - long wait_time){ - size_t rsize=-1; - u_int8_t *buffer=NULL; - int status; - - // errlogPrintf("sending a command %s %lu",data_str, dsize); - - this->write(data_str, dsize); - if(this->wait_for_answer(wait_time) == 0){ - // error - return -1; - }; - status=this->read(&rsize, &buffer); - if (status !=0){ - rsize=-1; - } - *rbuffer=buffer; - return rsize; - }; - - long HiSLIP::trigger_message(void){ - return 0; - }; - long HiSLIP::remote_local(bool request){ - return 0; - }; - long HiSLIP::request_lock(const char* lock_string){ - { - // errlogPrintf("request_lock not implemented yet\n"); - return -1; - }; - return 0; - }; - long HiSLIP::release_lock(void){ - { - // errlogPrintf("release_lock not implemented yet\n"); - return -1; - }; - return 0; - }; - long HiSLIP::request_srq_lock(void){ - { - // errlogPrintf("request_srq_lock not implemented yet\n"); - return -1; - }; - return 0; - }; - long HiSLIP::release_srq_lock(void){ - { - // errlogPrintf("release_srq_lock not implemented yet\n"); - return -1; - }; - return 0; - }; - -} // end of namespace HiSLIP - From 5255e0019de0153c65db469cef12b7f057627998 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Fri, 26 Jun 2020 20:22:13 +0900 Subject: [PATCH 13/67] Cython setup Now ready, well almost, ready for python. --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 76 +++++++++++++------ asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 30 ++++---- 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 296adfd95..87cf0cb8e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -47,16 +47,26 @@ namespace nsHiSLIP{ { char *service=NULL; - asprintf(&service, "%d",port);// "4880" for example. - status=getaddrinfo(hostname, service, &hints, &res); - free(service); + if (asprintf(&service, "%d",port)// "4880" for example. + > 0){ + status=getaddrinfo(hostname, service, &hints, &res); + free(service); + } + else{ + status=getaddrinfo(hostname, "hislip", &hints, &res); + perror("asprintf failes"); + } } if ((status !=0) || res == NULL){ char *msg; - asprintf(&msg, "getaddrinfo error status:%d res %p",status,res); - perror(msg); - free(msg); + if (asprintf(&msg, "getaddrinfo error status:%d res %p",status,res) >0){ + perror(msg); + free(msg); + } + else{ + perror("getaddrinfo"); + } exit (9999); } @@ -156,14 +166,14 @@ namespace nsHiSLIP{ sizeof(msg_size), (u_int8_t *) &msg_size); msg.send(this->async_channel); - int ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + int ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); - - this->maximum_message_size=*((u_int64_t *)(resp.payload)); + //The 8-byte buffer size is sent in network order as a 64-bit integer. + this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; return this->maximum_message_size; }; @@ -180,7 +190,7 @@ namespace nsHiSLIP{ msg->send(this->async_channel); - ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } @@ -195,7 +205,7 @@ namespace nsHiSLIP{ msg->send(this->sync_channel); - ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + ready=poll(&this->sync_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } @@ -221,7 +231,7 @@ namespace nsHiSLIP{ 0, NULL); msg.send(this->async_channel); - ready=poll(&this->async_poll, 1, this->socket_timeout*1000); + ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } @@ -291,7 +301,7 @@ namespace nsHiSLIP{ int ready; Message resp(AnyMessages); - ready=poll(&this->sync_poll, 1, this->socket_timeout*1000); + ready=poll(&this->sync_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } @@ -299,7 +309,7 @@ namespace nsHiSLIP{ // errlogPrintf("HiSLIP read rsize %ld\n",rsize); if (rsize < resp.payload_length){ //Error!! - return -1; + return -2; }; // may not be a good idea. @@ -309,7 +319,7 @@ namespace nsHiSLIP{ *received+resp.payload_length); if (newbuf == NULL){ // errlogPrintf("Cannot extend memory area\n"); - return -1; + return -3; } else{ *buffer=newbuf; @@ -325,10 +335,10 @@ namespace nsHiSLIP{ return 0; } else{ // error unexpected message type. - return -1; + return -999; } } - return -1; + return -999; }; int HiSLIP::read(size_t *received, @@ -425,18 +435,38 @@ namespace nsHiSLIP{ }; long HiSLIP::trigger_message(void){ + Message msg(nsHiSLIP::Trigger, + (u_int8_t) this->rmt_delivered, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL); + msg.send(this->sync_channel); + this->increment_message_id(); return 0; }; - long HiSLIP::remote_local(bool request){ + + long HiSLIP::remote_local(u_int8_t request){ + Message msg(nsHiSLIP::AsyncRemoteLocalControl, + request, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL), resp(AnyMessages); + msg.send(this->async_channel); + resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); return 0; }; + long HiSLIP::request_lock(const char* lock_string){ - { - // errlogPrintf("request_lock not implemented yet\n"); - return -1; - }; - return 0; + Message msg(nsHiSLIP::AsyncLock, + 1, // request + this->lock_timeout, + strnlen(lock_string,256), (u_int8_t *) lock_string), resp(AnyMessages);; + + msg.send(this->async_channel); + + resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + + return resp.control_code; }; + long HiSLIP::release_lock(void){ { // errlogPrintf("release_lock not implemented yet\n"); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 4d032ddfc..77e547914 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -16,20 +16,18 @@ #include #include - //#define _GNU_SOURCE /* See feature_test_macros(7) */ #include - #include -#include -#include +#include +#include //memcpy, etc +#include /* for MAXHOSTNAMELEN */ +#include /* close() and others */ + #include #include // network endian is "be". -#include #include #include -#include /* for MAXHOSTNAMELEN */ -#include /* close() and others */ //#include //#include @@ -77,7 +75,7 @@ namespace nsHiSLIP{ static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept static const long HEADER_SIZE=16; - static const long SOCKET_TIMEOUT = 1; //# Socket timeout + static const long SOCKET_TIMEOUT = 1000; //# Socket timeout in msec static const long LOCK_TIMEOUT = 3000;//# Lock timeout static const long Default_Port = 4880; static const char Default_device_name[]="hslip0"; @@ -417,8 +415,7 @@ namespace nsHiSLIP{ return this->lock_timeout; }; - HiSLIP(){ - }; + HiSLIP(){}; void connect(char const* hostname){ this->connect(hostname, Default_device_name, @@ -429,7 +426,7 @@ namespace nsHiSLIP{ int port); long set_max_size(long message_size); int device_clear(void); - u_int8_t status_query(); + u_int8_t status_query(void); //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); size_t ask(u_int8_t *data_str, size_t size, @@ -438,7 +435,7 @@ namespace nsHiSLIP{ int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); long trigger_message(void); - long remote_local(bool request); + long remote_local(u_int8_t request); long request_lock(const char* lock_string=NULL); long release_lock(void); long request_srq_lock(void); @@ -464,7 +461,14 @@ namespace nsHiSLIP{ int wait_for_SRQ(int wait_time){ return ::poll(&this->async_poll, 1, wait_time); } - void disconnect(){}; + void disconnect(){ + if (this->sync_channel){ + close(this->sync_channel); + }; + if (this->async_channel){ + close(this->async_channel); + }; + }; private: int wait_for_answer(int wait_time){ From af110a5424e0cb8dd81169960828ab388ce715d8 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Fri, 26 Jun 2020 20:24:16 +0900 Subject: [PATCH 14/67] for python/cython files for building python extension using cython --- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 64 +++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 198 +++++++++++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 111 ++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd new file mode 100644 index 000000000..a39cf558a --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -0,0 +1,64 @@ +#!cython +# -*- coding:utf-8 -*- +# distutils: language=c++ + +cdef int SCPIRawSocketPort=5025 # both udp/tcp +cdef int SCPITelnetPort=5024 # both udp/tcp + + +cdef extern from "HiSLIPMessage.h": + # you don’t need to match the type exactly, + # just use something of the right general kind (int, float, etc). + + ctypedef unsigned long u_long + ctypedef unsigned int u_int + ctypedef unsigned short u_short + ctypedef unsigned char u_char + ctypedef int bool_t + + ctypedef signed char int8_t + ctypedef signed short int int16_t + ctypedef signed int int32_t + ctypedef signed long int int64_t + + ctypedef unsigned char u_int8_t + ctypedef unsigned short int u_int16_t + ctypedef unsigned int u_int32_t + ctypedef unsigned long int u_int64_t + + +cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": + cdef char * Default_device_name "nsHiSLIP::Default_device_name" + cdef int HiSLIPPort "nsHiSLIP::Default_Port" # not in /etc/services + + cdef cppclass message_parameter "nsHiSLIP::message_parameter" + cdef cppclass Header "nsHiSLIP::Header" + cdef cppclass Message "nsHiSLIP::Message" + + cdef cppclass cHiSLIP "nsHiSLIP::HiSLIP": + unsigned long maximum_message_size + unsigned long maximum_payload_size + cHiSLIP() except+ + void connect(char * hostname, + char * dev_name, + int port) + void set_timeout(long) + long get_timeout() + void set_lock_timeout(long) + long get_lock_timeout() + + long set_max_size(long) + int device_clear() + u_int8_t status_query() + long write(u_int8_t *, size_t, long) + int read(size_t *, u_int8_t **, long) + size_t ask(u_int8_t *, size_t, u_int8_t **,long) + long trigger_message() + long remote_local(bool) + long request_lock(char *) + long release_lock() + long request_srq_lock() + long release_srq_loc() + int wait_for_SRQ(int) + void disconnect() + diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx new file mode 100644 index 000000000..be66ce002 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -0,0 +1,198 @@ +#!cython +#-*- coding:utf-8 -*- + +# distutils: sources = HiSLIPMessage.cpp + +from cython.operator cimport dereference as deref, preincrement as inc, address as addressof + +from cPyHiSLIP cimport cHiSLIP +#from cPyHiSLIP cimport HiSLIPPort +#from cPyHiSLIP cimport Default_device_name +import logging +from logging import info,debug,warn,log,fatal +#logging.root.setLevel(logging.DEBUG) + +cdef class HiSLIP: + cdef cHiSLIP *thisobj + + def __cinit__(self,host): + self.thisobj=new cHiSLIP() + self.thisobj.connect(host, Default_device_name, HiSLIPPort) + + def __dealloc__(self): + del self.thisobj + pass + + def connect(self, host, device=Default_device_name, port=HiSLIPPort): + debug("connect to {} {} {}".format(host,device, port)) + self.thisobj.connect(host,device,port) + + def write(self, msg, timeout=3000): + self.thisobj.write(msg, len(msg), timeout) + + cdef _cread(self,timeout=3000): + cdef unsigned char *buffer=NULL + cdef size_t recieved=0 + cdef int rt + debug("calling read in c++") + rt=self.thisobj.read(addressof(recieved), addressof(buffer), timeout) + if rt == -1: + raise RuntimeError("Timeout") + elif rt < 0: + raise RuntimeError + elif (buffer == NULL): + raise RuntimeError("NULL pointer") + if recieved == 0: + return (recieved, None) + else: + return (recieved, buffer) + + def read(self,timeout=3000): + recieved, buffer=self._cread(timeout) + debug("cread result {} {}".format(recieved,len(buffer))) + return (recieved, buffer[:recieved]) + + def ask(self, msg, wait_time=3000): + rsize, result=self._ask(msg, wait_time) + return result[:rsize] + + cdef _ask(self, u_int8_t *msg, wait_time): + cdef unsigned char *buffer=NULL + cdef size_t recieved=0 + cdef int rt + recieved=self.thisobj.ask(msg, len(msg), + addressof(buffer), + wait_time) + return (recieved, buffer) + + def set_timeout(self,timeout): + self.thisobj.set_timeout(timeout) + return + + def get_timeout(self): + cdef long to + to=self.thisobj.get_timeout() + return to + + def set_lock_timeout(self, to): + to=self.thisobj.set_lock_timeout(to) + + def get_lock_timeout(self): + cdef long to + to=self.thisobj.get_lock_timeout() + return to + + def set_max_message_size(self, message_size): + cdef long ms + ms=self.thisobj.set_max_size(message_size) + return ms + + def get_max_message_size(self): + cdef long ms + ms=self.thisobj.maximum_message_size + return ms + + def get_max_payload_size(self): + cdef long ms + ms=self.thisobj.maximum_payload_size + return ms + + def device_clear(self): + cdef long rc + rc=self.thisobj.device_clear() + return rc + + def status_query(self): + cdef u_int8_t rc + rc=self.thisobj.status_query() + return rc + + def wait_for_SRQ(self, wait_time): + cdef int rc + rc=self.thisobj.wait_for_SRQ(wait_time) + return rc + + + +cdef class enumType: + @classmethod + def getKey(cls, v): + for k,kv in cls.__dict__.iteritems(): + if kv == v: + return k + return None + + @classmethod + def getValue(cls, k): + return cls.__dict__.get(k,None) + +cdef class HiSLIPMessageType(enumType): + Initialize=0 + InitializeResPonce=1 + FatalError=2 + Error=3 + AsynLock=4 + AsynLockResponse=5, + Data=6 + DataEnd=7 + DeviceClearComplete=8 + DeviceCLearAcknowledge=9 + AsyncRemoteLocalContro=10 + AsyncRemoteLocalResponcse=11 + Trigger=12 + Interrupted=13 + AsyncInterrupted=14 + AsyncMaximumMessageSize=15 + AsyncMaximumMessageSizeResponse=16 + AsyncInitilalize=17 + AsyncIntializeResponse=18 + AsyncDeviceClear=19 + AsyncServiceRequest=20 + AsynStatusQuery=21 + AsyncStatusResponse=22 + AsyncDeviceClearAcknowledge=23 + AsynLockInfo=24 + AsynLockInfoResponse=25 + # VendorSpecific 128-255 inclusive + +cdef class FatalErrorCodes(enumType): # Defined Fatal Error codes. Table-7 + UndefinedFatalError=0 + PoorlyFormedMessage=1 + UnEstablishedConnection=2 + InvalidInitializationSequence=3 + ServerRefued=4 + # 5-127 : reserved + FirstDeviceDefinedError=128 + # 128-255 : Device Defined Error + +cdef class ErrorCode(enumType): # defined Error codes(non-fatal). Table-9 + UndefinedError=0 + UnrecognizedMessageType=1 + UnrecognizedControlCode=2 + UnrecognizedVendorDefinedMessage=3 + MessageTooLarge=4 + # 5-127 : Reserved + FirstDviceDefinedError=128 + #128-255:Device Defined Error + +cdef class LockControlCode(enumType): + release=0 + request=1 + +cdef class LockResponseControlCode(enumType): + fail=0 + success=1 + successSharedLock=2 + error=3 + +cdef class RemoteLocalControlCode(enumType): + disableRemote=0 + enableRemote=1 + disableAndGTL=2 + enableAndGotoRemote=3 + enableAndLockoutLocal=4 + enableAndGTRLLO=5 + justGTL=6 + + + diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py new file mode 100644 index 000000000..bf1d76e2d --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +""" +Author:Noboru Yamamoto, KEK, Japan (c) 2020 + +contact info: http://gofer.kek.jp/ +or https://plus.google.com/i/xW1BWwWsj3s:2rbmfOGOM4c + + +Revision Info: +$Author: $ +$Date: $ (isodatesec ) +$HGdate: $ +$Header: $ +$Id: setup.py $ +$RCSfile: $ +$Revision: $ +$Source: $ + +change log: +2020/06/25 : created +""" +import os,platform,re,sys,os.path + +from Cython.Distutils.extension import Extension +from Cython.Distutils import build_ext +from Cython.Build import cythonize + +# python2/python3 +extra=dict() + +# if sys.version_info >= (3,): +# extra['use_2to3'] = True + +try: + from distutils.command.build_py import build_py_2to3 as build_py #for Python3 +except ImportError: + from distutils.command.build_py import build_py # for Python2 + +from distutils.core import setup +#from distutils.extension import Extension + +# macros managedd by mercurial keyword extension +# +HGTag="$HGTag: $" +HGdate="$HGdate: $" #(rfc822date) +HGlastlog="$lastlog: $" +HGchangelog="$changelog$" + +HGcheckedin="$checked in by:$" +release=HGTag +#rev=HGTag[HGTag.index(":")+1:HGTag.index("-")].strip() +#rev=HGTagShort.strip() +rev="0.1.1" +# + +sysname=platform.system() + +ext_modules=[] + +# cPyHiSLIP-2.pyx and cPyHiSLIP-3.pyx are hard links to cPyHiSLIP.pyx +cPyHiSLIP_source_PY2="cPyHiSLIP_2.pyx" +cPyHiSLIP_source_PY3="cPyHiSLIP_3.pyx" + +if sys.version_info >= (3,): + PY3=True + cPyHiSLIP_source=cPyHiSLIP_source_PY3 +else: + PY3=False + cPyHiSLIP_source=cPyHiSLIP_source_PY2 + +if not os.path.exists(cPyHiSLIP_source): + os.link("cPyHiSLIP.pyx", cPyHiSLIP_source) +elif not os.path.samefile("cPyHiSLIP.pyx", cPyHiSLIP_source): + os.remove(cPyHiSLIP_source) + os.link("cPyHiSLIP.pyx", cPyHiSLIP_source) + +ext_modules.append(Extension("cPyHiSLIP", + [ cPyHiSLIP_source, # Cython source. i.e. .pyx + ] + ,libraries=[] + ,depends=["cPyHiSLIP.pxd"] # Cython interface file + ,language="c++" + ,cython_cplus=True + ,undef_macros=["CFLAGS"] + ,extra_compile_args=[], +)) + + + +ext_modules=cythonize( # generate .c files. + ext_modules, + compiler_directives={"language_level":"3" if PY3 else "2"}, # "2","3","3str" +) + +setup(name="cPyHiSLIP", + version=rev, + author="Noboru Yamamoto, KEK, JAPAN", + author_email = "Noboru.YAMAMOTO@kek.jp", + description='A Cython based Python module to control devices over HiSKIP protocol.', + url="http://www-cont.j-parc.jp/", + classifiers=['Programming Language :: Python', + 'Programming Language :: Cython', + 'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator', + ], + ext_modules=ext_modules, + cmdclass = {'build_ext': build_ext, + # 'build_py':build_py # for 2to3 + }, + py_modules=[ ], + **extra +) From 178bacf5b05fa52c46b866cf0784d1e353872bc6 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 27 Jun 2020 13:56:06 +0900 Subject: [PATCH 15/67] remote_local/request-release lock --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 50 +++++-------- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 75 ++++++------------- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 4 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 69 ++++++++++++++++- 4 files changed, 108 insertions(+), 90 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 87cf0cb8e..28e08ec72 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -28,8 +28,6 @@ namespace nsHiSLIP{ const int port //, //const char vendor_id[2] ){ - //osiSockAddr addr; - //Message_t *msg; int status; //const char vendor_id[]=Default_vendor_id; @@ -82,19 +80,15 @@ namespace nsHiSLIP{ exit (999); }; status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); - if (status!=0){ // Error handling perror(__FUNCTION__); } - status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); if (status!=0){ // Error handling perror(__FUNCTION__); } - // errlogPrintf("connected to async channel %d\n",this->async_channel); - freeaddrinfo(res); { @@ -107,40 +101,25 @@ namespace nsHiSLIP{ msg.send(this->sync_channel); } - // errlogPrintf("Sent a initialize message\n"); - { Message resp(AnyMessages); - // errlogPrintf("Receive message created\n"); - resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); this->overlap_mode=resp.control_code; this->session_id=resp.message_parameter.getSessionId(); this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); } - // errlogPrintf("Receive a initialized message %d 0x%x %d \n", - // this->overlap_mode,this->session_id, this->server_protocol_version - // ); - - // errlogPrintf("Sending Async initialize message %x\n",this->session_id); - - - { Message msg(nsHiSLIP::AsyncInitialize); msg.message_parameter.word=this->session_id; msg.send(this->async_channel); } - // errlogPrintf("reading Async initialize response\n"); - { Message resp(AnyMessages); resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); this->overlap_mode=resp.control_code; this->server_vendorID=resp.message_parameter.word; } - // errlogPrintf("reading Async initialize done\n"); //now setup poll object this->reset_message_id(); @@ -152,8 +131,6 @@ namespace nsHiSLIP{ this->async_poll.fd=this->async_channel; this->async_poll.events=POLLIN; this->async_poll.revents=0; - - // errlogPrintf("Receive a Async initialized message\n"); }; long HiSLIP::set_max_size(long message_size){ @@ -238,7 +215,6 @@ namespace nsHiSLIP{ resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); status= resp.control_code &0xff; - return status; } @@ -441,6 +417,7 @@ namespace nsHiSLIP{ 0, NULL); msg.send(this->sync_channel); this->increment_message_id(); + this->rmt_delivered=false; return 0; }; @@ -458,7 +435,8 @@ namespace nsHiSLIP{ Message msg(nsHiSLIP::AsyncLock, 1, // request this->lock_timeout, - strnlen(lock_string,256), (u_int8_t *) lock_string), resp(AnyMessages);; + strnlen(lock_string,256), (u_int8_t *) lock_string), + resp(AnyMessages); msg.send(this->async_channel); @@ -468,12 +446,23 @@ namespace nsHiSLIP{ }; long HiSLIP::release_lock(void){ - { - // errlogPrintf("release_lock not implemented yet\n"); - return -1; - }; - return 0; + long message_id =this->most_recent_message_id; + if ( message_id == nsHiSLIP::INITIAL_MESSAGE_ID){ + message_id=0; + } + Message msg(nsHiSLIP::AsyncLock, + 0, // release + message_id, + 0, NULL), + resp(AnyMessages); + + msg.send(this->async_channel); + + resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + + return resp.control_code; }; + long HiSLIP::request_srq_lock(void){ { // errlogPrintf("request_srq_lock not implemented yet\n"); @@ -481,6 +470,7 @@ namespace nsHiSLIP{ }; return 0; }; + long HiSLIP::release_srq_lock(void){ { // errlogPrintf("release_srq_lock not implemented yet\n"); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 77e547914..d2f5f24cc 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -160,26 +160,15 @@ namespace nsHiSLIP{ message_parameter(u_int16_t proto, char vers[2]){ this->word= ((int32_t)proto << 16) + (vers[1] << 8) + (vers[0]<<0); - // errlogPrintf("messagParameter:%#010x, protocol:%#06x, version:[%c%c]\n", - // this->word, - // proto, vers[0], vers[1]); }; message_parameter(u_int16_t proto, u_int16_t sid){ this->word = (proto << 16) + sid; - // errlogPrintf("messagParameter:%#010x, protocol:%#06x, session id:%#06x\n", - // this->word, - // proto, sid); + }; u_int16_t getServerProtocolVersion(){ - // errlogPrintf("getServerProtocolVersion messagParameter:%#010x, ServerProtocolVersion %d\n", - // this->word, - // (u_int16_t) (((this->word) & 0xffff0000)>>16)); return (u_int16_t) (((this->word) & 0xffff0000)>>16); } u_int16_t getSessionId(){ - // errlogPrintf("getSessionId messagParameter %#010x, sessionID:%d\n", - // this->word, - // (u_int16_t) ((this->word) & 0xffff)); return ((u_int16_t) ((this->word) & 0xffff)); } } message_parameter_t; @@ -211,6 +200,10 @@ namespace nsHiSLIP{ this->payload_length=length; } void printf(void){ + ::printf("message type:%d\n",this->message_type); + ::printf("control_code:%d\n",this->control_code); + ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); + ::printf("payload length: %ld\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -222,60 +215,44 @@ namespace nsHiSLIP{ ssize_t ssize; this->toRawData(hbuf); - // errlogPrintf("sending header dump: %#016qx,%#016qx\n", - // *((u_int64_t*)hbuf),*(((u_int64_t*)hbuf) +1)); ssize=::send(socket, hbuf, sizeof(hbuf), 0); return ssize; } size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ - - char buffer[HEADER_SIZE]; ssize_t rsize; - - - // errlogPrintf("recv header\n"); - rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - // errlogPrintf("read header dump: %#016qx, %#016qx\n", - // *((u_int64_t*)buffer), - // *(((u_int64_t*)buffer) +1) ); - if (rsize < HEADER_SIZE){ //raise exception? - // errlogPrintf("too short header %ld\n",rsize); return -1; } else if (memcmp(this->prologue, buffer,2) != 0){ - //error - // errlogPrintf("incorrect prologue %2s %2s\n",buffer,this->prologue); return -1; } - //errlogPrintf("Recieved message %2s %2s\n",buffer,this->prologue); - this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - this->printf(); + //this->printf(); - if((expected_message_type != AnyMessages) && - (expected_message_type != this->message_type)){ - //error! - // in overlapped mode, should we keep it? - // errlogPrintf("Error message types does not match %d vs %d\n",expected_message_type, - // this->message_type); - return -1; + if((expected_message_type == AnyMessages) || + (expected_message_type == this->message_type)){ + return rsize; } - - // errlogPrintf("successfull recieved message header %ld \n",rsize); - - return rsize; + //error! + // in overlapped mode, should we keep it? + else if(this->message_type == nsHiSLIP::Error){ + return -(this->control_code+1); + } + else if(this->message_type == nsHiSLIP::FatalError){ + return -(this->control_code+1); + } + return -1; } int fromRawData(void *buffer){ //DeSerialize @@ -336,16 +313,10 @@ namespace nsHiSLIP{ size_t rsize; size_t status; - /* setsockopt(sock, SOL_SOCKET, */ - /* SO_RCVTIMEO, &(msg->socket_timeout), sizeof(int)); */ - - // read header part and update header. - rsize=this->Header::recv(socket, expected_message_type); if (rsize < 0){ // Error! - // errlogPrintf("failed to read header.%ld \n",rsize); return rsize; } @@ -363,11 +334,11 @@ namespace nsHiSLIP{ size_t bytestoread=this->payload_length; while (bytestoread){ - status = ::recv(socket, ((u_int8_t *)this->payload+rsize), bytestoread, 0); + status = ::recv(socket, ((u_int8_t *)this->payload+rsize), + bytestoread, 0); if (status <= 0){ perror("payload read error:"); - // errlogPrintf("recive error\n"); return -1; } rsize +=status; @@ -377,7 +348,6 @@ namespace nsHiSLIP{ bytestoread -=status; } } - // errlogPrintf("successfull recieved message %ld \n",rsize); return (rsize); } } Message_t; @@ -443,19 +413,16 @@ namespace nsHiSLIP{ Message *get_Service_Request(void){ Message *msg=new Message(AnyMessages); long status; - // errlogPrintf("In get_service_Request\n"); this->request_srq_lock(); //status= msg->recv(this->async_channel, AsyncServiceRequest); status= msg->recv(this->async_channel); if (status != 0){ - // errlogPrintf("get_service_Request: failed to read error.\n"); // should handle Error/Fatal Error/Async Interrupted messages. perror(__FUNCTION__); } this->release_srq_lock(); - // errlogPrintf("Exit from get_service_Request\n"); return msg; }; int wait_for_SRQ(int wait_time){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index a39cf558a..83cd270ea 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -54,11 +54,11 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int read(size_t *, u_int8_t **, long) size_t ask(u_int8_t *, size_t, u_int8_t **,long) long trigger_message() - long remote_local(bool) + long remote_local(u_int8_t) long request_lock(char *) long release_lock() long request_srq_lock() long release_srq_loc() - int wait_for_SRQ(int) + int wait_for_SRQ(int) void disconnect() diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index be66ce002..3b5c53782 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -15,9 +15,10 @@ from logging import info,debug,warn,log,fatal cdef class HiSLIP: cdef cHiSLIP *thisobj - def __cinit__(self,host): + def __cinit__(self,host=None): self.thisobj=new cHiSLIP() - self.thisobj.connect(host, Default_device_name, HiSLIPPort) + if host: + self.thisobj.connect(host, Default_device_name, HiSLIPPort) def __dealloc__(self): del self.thisobj @@ -107,12 +108,72 @@ cdef class HiSLIP: rc=self.thisobj.status_query() return rc + def trigger_message(self): + cdef long rc + rc=self.thisobj.trigger_message() + return rc + + def remote_local(self, request): + """ + Table 18: Remote Local Control Transactions + 0 - Disable remote + 1 - Enable remote + 2 - Disable remote and go to LOCAL + 3 - Enable remote and go to REMOTE + 4 - Enable remote and Lock Out LOCAL + 5 - Enable remote, go to REMOTE, and set local LOCKOUT + 6 - go to local without changing state of remote enable. + """ + cdef long rc + cdef u_int8_t _request=request + + rc=self.thisobj.remote_local(_request) + + return rc + + def request_lock(self, lock_string): + """ + response to request: + 0 - Failure + 1 - Success + 3 - Error + """ + cdef long rc + cdef char *_lock_string=lock_string + + rc=self.thisobj.request_lock(_lock_string) + + return rc + + def release_lock(self): + """ + response to release: + 1 - Success exclusive + 2 - Success shared + 3 - Error + """ + cdef long rc + rc=self.thisobj.release_lock() + return rc + + def request_srq_lock(self): + """ + Not implemented in .cpp yet. + """ + cdef long rc=0 + return rc + + def release_srq_loc(self): + """ + Not implemented in .cpp yet. + """ + cdef long rc=0 + return rc + def wait_for_SRQ(self, wait_time): cdef int rc rc=self.thisobj.wait_for_SRQ(wait_time) return rc - - cdef class enumType: @classmethod From e9be40058dface6192220ffb06a5acbed4fcfa9b Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 27 Jun 2020 14:53:47 +0900 Subject: [PATCH 16/67] rest rmt_delivered flag at initilaise --- HiSLIPMessage.cpp | 484 ++++++++++++++++++++++++++++++++++++++++++++++ HiSLIPMessage.h | 456 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 940 insertions(+) create mode 100644 HiSLIPMessage.cpp create mode 100644 HiSLIPMessage.h diff --git a/HiSLIPMessage.cpp b/HiSLIPMessage.cpp new file mode 100644 index 000000000..e46a230c5 --- /dev/null +++ b/HiSLIPMessage.cpp @@ -0,0 +1,484 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +#include "HiSLIPMessage.h" + +using nsHiSLIP::CC_request_t; +using nsHiSLIP::CC_Lock_t; +using nsHiSLIP::HiSLIP_t; +using nsHiSLIP::HiSLIP; +using nsHiSLIP::Message_t; + +#define MAX_PAYLOAD_CAPACITY 4096 +#define IDSTRING_CAPACITY 100 + +// HiSLIP methods +namespace nsHiSLIP{ + void HiSLIP::connect(const char *hostname, + const char *dev_name, + const int port //, + //const char vendor_id[2] + ){ + int status; + //const char vendor_id[]=Default_vendor_id; + + struct addrinfo hints, *res=NULL; + memset(&hints,0, sizeof(struct addrinfo)); + hints.ai_flags=AI_NUMERICSERV | AI_CANONNAME; + hints.ai_flags=AI_NUMERICSERV; + hints.ai_family=AF_INET; // IPv4 + hints.ai_socktype=SOCK_STREAM; + hints.ai_protocol=0; // any protocol + hints.ai_addrlen=0; + hints.ai_addr=NULL; + hints.ai_canonname=NULL; + hints.ai_next=NULL; + + { + char *service=NULL; + if (asprintf(&service, "%d",port)// "4880" for example. + > 0){ + status=getaddrinfo(hostname, service, &hints, &res); + free(service); + } + else{ + status=getaddrinfo(hostname, "hislip", &hints, &res); + perror("asprintf failes"); + } + } + + if ((status !=0) || res == NULL){ + char *msg; + if (asprintf(&msg, "getaddrinfo error status:%d res %p",status,res) >0){ + perror(msg); + free(msg); + } + else{ + perror("getaddrinfo"); + } + exit (9999); + } + + //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + + this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); + this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); + + if (res-> ai_addr == NULL || res->ai_addrlen == 0){ + perror("empty addinfo"); + freeaddrinfo(res); + exit (999); + }; + status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); + if (status!=0){ + // Error handling + perror(__FUNCTION__); + } + freeaddrinfo(res); + + { + Message msg(nsHiSLIP::Initialize, + 0, + message_parameter((u_int16_t) nsHiSLIP::PROTOCOL_VERSION_MAX, + (char *) Default_vendor_id), + (u_int64_t) 0, (u_int8_t *) NULL); + // errlogPrintf("sending message %d \n", msg.message_type); + msg.send(this->sync_channel); + } + + { Message resp(AnyMessages); + + resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); + + this->overlap_mode=resp.control_code; + this->session_id=resp.message_parameter.getSessionId(); + this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); + } + { + Message msg(nsHiSLIP::AsyncInitialize); + msg.message_parameter.word=this->session_id; + msg.send(this->async_channel); + } + { + Message resp(AnyMessages); + resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + this->overlap_mode=resp.control_code; + this->server_vendorID=resp.message_parameter.word; + } + + //now setup poll object + this->reset_message_id(); + this->rmt_delivered = false; + + this->sync_poll.fd=this->sync_channel; + this->sync_poll.events=POLLIN; + this->sync_poll.revents=0; + + this->async_poll.fd=this->async_channel; + this->async_poll.events=POLLIN; + this->async_poll.revents=0; + }; + + long HiSLIP::set_max_size(long message_size){ + Message resp(AnyMessages); + u_int64_t msg_size=htobe64(message_size); + + Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, + 0, + message_parameter(0), + sizeof(msg_size), (u_int8_t *) &msg_size); + msg.send(this->async_channel); + + int ready=poll(&this->async_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + //The 8-byte buffer size is sent in network order as a 64-bit integer. + this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); + this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; + return this->maximum_message_size; + }; + + int HiSLIP::device_clear(){ + Message resp(AnyMessages); + u_int8_t feature_preference; + int ready; + + Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, + 0, + 0, + 0,NULL); + + msg->send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + + resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + feature_preference=resp.control_code; + + msg=new Message(nsHiSLIP::DeviceClearComplete, + feature_preference, + 0, + 0, NULL); + + msg->send(this->sync_channel); + + ready=poll(&this->sync_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); + + this->overlap_mode=resp.control_code; + this->reset_message_id(); + this->rmt_delivered = false; + + return 0; + + }; + + u_int8_t HiSLIP::status_query(){ + u_int8_t status; + int ready; + + Message resp(AnyMessages); + + Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, + (u_int8_t) this->rmt_delivered, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL); + msg.send(this->async_channel); + + ready=poll(&this->async_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); + + status= resp.control_code &0xff; + return status; + } + + + // long HiSLIP::write(u_int8_t *data_str, long timeout){ + // return this->write(data_str, this->maximum_message_size,timeout); + // }; + + long HiSLIP::write(u_int8_t const* data_str, size_t const dsize, long timeout){ + + size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; + size_t bytestosend=dsize; + const u_int8_t *buffer=data_str; + size_t delivered=0; + size_t count; + + // errlogPrintf("HiSLIP::write sending data %s\n", data_str); + + while(bytestosend){ + if (bytestosend < max_payload_size){ + Message msg(nsHiSLIP::DataEnd, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + bytestosend, (u_int8_t *) buffer); + buffer += bytestosend; + // errlogPrintf("sending message %s\n",(char *) msg.payload); + count=msg.send(this->sync_channel); + count -=HEADER_SIZE; + bytestosend = 0; + delivered += count ; + } + else{ + Message msg(nsHiSLIP::Data, + this->rmt_delivered, + nsHiSLIP::message_parameter(this->message_id), + max_payload_size, (u_int8_t *) buffer); + count=msg.send(this->sync_channel); + count -= HEADER_SIZE; + bytestosend -=count; + delivered += count; + buffer += max_payload_size; + } + // errlogPrintf("data sent= %lu\n",count); + this->increment_message_id(); + } + return delivered; + }; + + int HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ + bool eom=false; + size_t rsize=0; + + // errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", + // buffer, timeout); + + *received=0; + this->rmt_delivered = false; + + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=poll(&this->sync_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + rsize=resp.recv(this->sync_channel); + // errlogPrintf("HiSLIP read rsize %ld\n",rsize); + if (rsize < resp.payload_length){ + //Error!! + return -2; + }; + + // may not be a good idea. + { u_int8_t *newbuf; + + newbuf=(u_int8_t *) reallocarray(*buffer, 1, + *received+resp.payload_length); + if (newbuf == NULL){ + // errlogPrintf("Cannot extend memory area\n"); + return -3; + } + else{ + *buffer=newbuf; + } + } + ::memcpy((*buffer + *received), resp.payload, resp.payload_length); + *received +=resp.payload_length; + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if ( resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + return 0; + } else{ + // error unexpected message type. + return -999; + } + } + return -999; + }; + + int HiSLIP::read(size_t *received, + u_int8_t *buffer, size_t bsize, long timeout){ + bool eom=false; + size_t rsize=0; + + // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", + // buffer, bsize, timeout); + *received=0; + this->rmt_delivered = false; + + if (buffer==NULL || bsize <= 0){ + // errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", + // buffer, bsize, timeout); + return -1; + } + if (bsize < this->maximum_payload_size){ + // errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", + // bsize, this->maximum_payload_size); + } + while(!eom) { + int ready; + Message resp(AnyMessages); + + ready=::poll(&this->sync_poll, 1, timeout); + + if (ready == 0){ + // errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); + return -1; + } + + rsize=resp.recv(this->sync_channel); + + if (rsize < resp.payload_length){ + // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); + return -1; + }; + if (( (*received) + resp.payload_length) > bsize){ + // errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", + // *received, resp.payload_length, bsize); + + ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); + *received = bsize; + return 0; + } + else{ + // errlogPrintf("received message size %ld %ld data:%s mt:%d\n", + // rsize, *received, (char *) resp.payload, resp.message_type); + ::memcpy( (buffer + *received), resp.payload, resp.payload_length); + + *received +=resp.payload_length; + } + + if ( resp.message_type == nsHiSLIP::Data){ + continue; + } else if (resp.message_type == nsHiSLIP::DataEnd){ + eom=true; + this->rmt_delivered=true; + // errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", + // buffer, (char *) resp.payload, eom,this->rmt_delivered); + return 0; + } else{ + // errlogPrintf("Unexpected message type:%d\n", + // resp.message_type); + resp.printf(); + // error unexpected message type. + return -1; + } + } + return -1; + }; + + size_t HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, + u_int8_t **rbuffer, + long wait_time){ + size_t rsize=-1; + u_int8_t *buffer=NULL; + int status; + + // errlogPrintf("sending a command %s %lu",data_str, dsize); + + this->write(data_str, dsize); + if(this->wait_for_answer(wait_time) == 0){ + // error + return -1; + }; + status=this->read(&rsize, &buffer); + if (status !=0){ + rsize=-1; + } + *rbuffer=buffer; + return rsize; + }; + + long HiSLIP::trigger_message(void){ + Message msg(nsHiSLIP::Trigger, + (u_int8_t) this->rmt_delivered, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL); + msg.send(this->sync_channel); + this->increment_message_id(); + this->rmt_delivered=false; + return 0; + }; + + long HiSLIP::remote_local(u_int8_t request){ + Message msg(nsHiSLIP::AsyncRemoteLocalControl, + request, + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL), resp(AnyMessages); + msg.send(this->async_channel); + resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + return 0; + }; + + long HiSLIP::request_lock(const char* lock_string){ + Message msg(nsHiSLIP::AsyncLock, + 1, // request + this->lock_timeout, + strnlen(lock_string,256), (u_int8_t *) lock_string), + resp(AnyMessages); + + msg.send(this->async_channel); + + resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + + return resp.control_code; + }; + + long HiSLIP::release_lock(void){ + long message_id =this->most_recent_message_id; + if ( message_id == nsHiSLIP::INITIAL_MESSAGE_ID){ + message_id=0; + } + Message msg(nsHiSLIP::AsyncLock, + 0, // release + message_id, + 0, NULL), + resp(AnyMessages); + + msg.send(this->async_channel); + + resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + + return resp.control_code; + }; + + long HiSLIP::request_srq_lock(void){ + { + // errlogPrintf("request_srq_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + + long HiSLIP::release_srq_lock(void){ + { + // errlogPrintf("release_srq_lock not implemented yet\n"); + return -1; + }; + return 0; + }; + +} // end of namespace HiSLIP + diff --git a/HiSLIPMessage.h b/HiSLIPMessage.h new file mode 100644 index 000000000..d28039339 --- /dev/null +++ b/HiSLIPMessage.h @@ -0,0 +1,456 @@ +/* + * ASYN support for HiSLIP + * + + *************************************************************************** + * Copyright (c) 2020 N. Yamamoto + * based on AsynUSBTMC supoort by + * Copyright (c) 2013 W. Eric Norum * + * This file is distributed subject to a Software License Agreement found * + * in the file LICENSE that is included with this distribution. * + *************************************************************************** + */ +//-*- coding:utf-8 -*- +#define NDEBUG 1 +#define DEBUG 1 + +#include +#include +//#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include +#include +#include +#include //memcpy, etc +#include /* for MAXHOSTNAMELEN */ +#include /* close() and others */ + +#include +#include // network endian is "be". +#include +#include + +//#include +//#include +//#include +//#include +//#include +//#include + + + +template struct Property { + T& r; + operator T() {return r;} + void operator =(const T v){ r=v;} +}; + +namespace nsHiSLIP{ + + //constants + typedef enum CC_reuqest{ + RemoteDisable=0, + RemoteEnable=1, + RemoteDisableGTL=2, // disable remote and goto local + RemoteEnableGTR=3, // Enable remote and goto remote + RemoteEnableLLO=4, // Enable remote and lock out local + RemoteEnableGTRLLO=5, // + RTL=6 + } CC_request_t; + + typedef enum CC_Lock{ + release =0, + request =1 + } CC_Lock_t; + + typedef enum CC_LockResponse{ + fail=0, //Lock was requested but not granted + success=1, //release of exclusive lock + success_shared=2, //release of shared lock + error=3 // Invalide + } CC_LockResponse_t; + + static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 + static const long INITIAL_MESSAGE_ID = 0xffffff00 ; + static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; + static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes + static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept + static const long HEADER_SIZE=16; + static const long SOCKET_TIMEOUT = 1000; //# Socket timeout in msec + static const long LOCK_TIMEOUT = 3000;//# Lock timeout + static const long Default_Port = 4880; + static const char Default_device_name[]="hslip0"; + static const char Default_vendor_id[]={'E','P'}; + static const char Prologue[]={'H','S'}; + // + typedef enum Message_Types{ + Initialize = 0, + InitializeResponse = 1, + FatalError = 2, + Error = 3, + AsyncLock = 4, + AsyncLockResponse = 5, + Data = 6, + DataEnd = 7, + DeviceClearComplete = 8, + DeviceClearAcknowledge = 9, + AsyncRemoteLocalControl = 10, + AsyncRemoteLocalResponse = 11, + Trigger = 12, + Interrupted = 13, + AsyncInterrupted = 14, + AsyncMaximumMessageSize = 15, + AsyncMaximumMessageSizeResponse = 16, + AsyncInitialize = 17, + AsyncInitializeResponse = 18, + AsyncDeviceClear = 19, + AsyncServiceRequest = 20, + AsyncStatusQuery = 21, + AsyncStatusResponse = 22, + AsyncDeviceClearAcknowledge = 23, + AsyncLockInfo = 24, + AsyncLockInfoResponse = 25, + // 26-127 are reserved for future use. + // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. + AnyMessages=127 // 128-255 are reserved for vendor use. + } Message_Types_t; + + typedef enum Error_code{ + UnidentifiedError, + UnrecognizedMessageType, + UnrecognizedControlCode, + UnrecognizedVendorDefinedMessage, + MessageTooLarge + } Error_code_t; + static const char *Error_Messages[] = + { + "Unidentified error", + "Unrecognized Message Type", + "Unrecognized control code", + "Unrecognized Vendor Defined Message", + "Message too large" + }; + typedef enum Fatal_Error_code { + UnidentifiedFatalError, + PoorlyFormedMmessageHeader, + AttemptToUseConnectionWithoutBothChannels, + InvalidInitializationSequence, + ServerRefusedConnection + } Fatal_Erro_code_t; + static const char *Fatal_Error_Messages[] = + { + "Unidentified error", + "Poorly formed message header", + "Attempt to use connection without both channels established", + "Invalid Initialization Sequence", + "Server refused connection due to maximum number of clients exceeded" + }; + + typedef class message_parameter{ + public: + u_int32_t word; + // struct InitializeParameter{ + // u_int16_t protocol_version; + // char vendor_id[2]={0x00 ,0x00}; + // } initParm; + // struct InitializeResponseParameter{ + // u_int16_t session_id; + // u_int16_t protocol_version; + // } initResp; + message_parameter(u_int32_t word){this->word=word;}; + message_parameter(u_int16_t proto, char vers[2]){ + this->word= ((int32_t)proto << 16) + + (vers[1] << 8) + (vers[0]<<0); + }; + message_parameter(u_int16_t proto, u_int16_t sid){ + this->word = (proto << 16) + sid; + + }; + u_int16_t getServerProtocolVersion(){ + return (u_int16_t) (((this->word) & 0xffff0000)>>16); + } + u_int16_t getSessionId(){ + return ((u_int16_t) ((this->word) & 0xffff)); + } + } message_parameter_t; + + class Header{ + public: + const char prologue[2]={'H','S'}; + u_int8_t message_type; + u_int8_t control_code; + message_parameter_t message_parameter; + u_int64_t payload_length; + + Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ + this->message_type=message_type; + } + Header(const void *buffer):message_parameter(0){ + assert(memcmp(this->prologue, buffer,2) == 0); + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + } + Header(const u_int8_t type, + const u_int8_t cce, + const message_parameter_t param, + const u_int64_t length):message_parameter(param.word){ + this->message_type=type; + this->control_code=cce; + this->payload_length=length; + } + void printf(void){ + ::printf("message type:%d\n",this->message_type); + ::printf("control_code:%d\n",this->control_code); + ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); + ::printf("payload length: %ld\n",this->payload_length); + // errlogPrintf("message type:%d\n",this->message_type); + // errlogPrintf("control_code:%d\n",this->control_code); + // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); + // errlogPrintf("payload length: %qd\n",this->payload_length); + } + + size_t send(int socket){ + char hbuf[HEADER_SIZE]; + ssize_t ssize; + + this->toRawData(hbuf); + ssize=::send(socket, hbuf, sizeof(hbuf), 0); + + return ssize; + } + + size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ + char buffer[HEADER_SIZE]; + ssize_t rsize; + rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + + if (rsize < HEADER_SIZE){ + //raise exception? + return -1; + } + else if (memcmp(this->prologue, buffer,2) != 0){ + return -1; + } + + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + + //this->printf(); + + if((expected_message_type == AnyMessages) || + (expected_message_type == this->message_type)){ + return rsize; + } + //error! + // in overlapped mode, should we keep it? + else if(this->message_type == nsHiSLIP::Error){ + return -(this->control_code+1); + } + else if(this->message_type == nsHiSLIP::FatalError){ + return -(this->control_code+1); + } + return -1; + } + + int fromRawData(void *buffer){ //DeSerialize + if (memcmp(this->prologue, buffer,2) != 0){ + //error + return -1; + } + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + return 0; + } + int toRawData(void *buffer){ //Serialize this as bytes data in buffer. + memcpy( buffer, this->prologue, 2); + *((char *) buffer + 2) = this->message_type; + *((char *) buffer + 3) = this->control_code; + //*((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); + *((u_int32_t *)((char *) buffer+4))=htonl(this->message_parameter.word); + *((u_int64_t *)((char *) buffer+8))=htobe64(this->payload_length); + return 0; + } + }; + + typedef class Message:public Header{ + public: + void *payload=NULL; + + Message(Message_Types_t message_type):Header(message_type){ + }; + Message(void *raw_header):Header(raw_header){ + //this->fromRawData(raw_header); + }; + Message(void *raw_header, void *payload):Message(raw_header){ + this->payload = calloc(this->payload_length, 1); + if (this->payload != NULL){ + memcpy(this->payload, payload, this->payload_length); + }; + } + Message(u_int8_t type, + u_int8_t cce, + message_parameter_t param, + u_int64_t length, + u_int8_t *payload):Header(type,cce,param,length),payload(payload) { + //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); + //memcpy(this->payload, payload, length); + //this->payload = payload; + } + size_t send(int socket){ + size_t ssize; + ssize=this->Header::send(socket); + if (ssize < HEADER_SIZE){ + return -1; + } + return (ssize + ::send(socket, this->payload, this->payload_length,0)); + } + + ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ + size_t rsize; + size_t status; + + rsize=this->Header::recv(socket, expected_message_type); + + if (rsize < 0){ + // Error! + return rsize; + } + + // now prepare for a pyload. + if (this->payload==NULL && this->payload_length > 0){ + this->payload = (void *) calloc(this->payload_length,1); + if (this->payload == NULL){ + perror("faile to allocate memory for payload."); + return -1; + } + } + + rsize=0; //returns size of recieved payload. + if (this->payload_length > 0){ + size_t bytestoread=this->payload_length; + + while (bytestoread){ + status = ::recv(socket, ((u_int8_t *)this->payload+rsize), + bytestoread, 0); + + if (status <= 0){ + perror("payload read error:"); + return -1; + } + rsize +=status; + if (status >= bytestoread){ + break; + } + bytestoread -=status; + } + } + return (rsize); + } + } Message_t; + + typedef class HiSLIP { + public: + unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; + unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + long socket_timeout=SOCKET_TIMEOUT; + long lock_timeout=LOCK_TIMEOUT; + int sync_channel; + int async_channel; + struct pollfd sync_poll; + struct pollfd async_poll; + int overlap_mode; + int session_id; + int server_protocol_version; + unsigned int server_vendorID; + + bool rmt_delivered=false; + u_int32_t message_id; + u_int32_t most_recent_message_id; + + void set_timeout( long timeout){ + this->socket_timeout=timeout; + }; + long get_timeout(void){ + return this->socket_timeout; + }; + void set_lock_timeout( long timeout){ + this->lock_timeout=timeout; + } + ; + long get_lock_timeout(void){ + return this->lock_timeout; + }; + + HiSLIP(){ + }; + void connect(char const* hostname){ + this->connect(hostname, + Default_device_name, + Default_Port); + }; + void connect(char const* hostname, + char const* dev_name, + int port); + long set_max_size(long message_size); + int device_clear(void); + u_int8_t status_query(void); + //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); + long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); + size_t ask(u_int8_t *data_str, size_t size, + u_int8_t **rbuffer, long wait_time=LOCK_TIMEOUT); + int read(size_t *received, long timeout=LOCK_TIMEOUT ); + int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); + int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); + long trigger_message(void); + long remote_local(u_int8_t request); + long request_lock(const char* lock_string=NULL); + long release_lock(void); + long request_srq_lock(void); + long release_srq_lock(void); + Message *get_Service_Request(void){ + Message *msg=new Message(AnyMessages); + long status; + this->request_srq_lock(); + + //status= msg->recv(this->async_channel, AsyncServiceRequest); + status= msg->recv(this->async_channel); + + if (status != 0){ + // should handle Error/Fatal Error/Async Interrupted messages. + perror(__FUNCTION__); + } + this->release_srq_lock(); + return msg; + }; + int wait_for_SRQ(int wait_time){ + return ::poll(&this->async_poll, 1, wait_time); + } + void disconnect(){ + if (this->sync_channel){ + close(this->sync_channel); + }; + if (this->async_channel){ + close(this->async_channel); + }; + }; + + private: + int wait_for_answer(int wait_time){ + return ::poll(&this->sync_poll, 1, wait_time); + } + void reset_message_id(void){ + this->most_recent_message_id=0; + this->message_id = 0xffffff00; + } + u_int32_t increment_message_id(void){ + this->most_recent_message_id=this->message_id; + this->message_id = (this->message_id +2) & 0xffffffff; + return this->message_id; + }; + } HiSLIP_t; +}; // namespace From 6f2aa4936821c33a9ff0f87ecab6064e09c54e4e Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 27 Jun 2020 14:54:35 +0900 Subject: [PATCH 17/67] rest rmt_delivered flag at init. --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 3 ++- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 28e08ec72..e46a230c5 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -123,7 +123,8 @@ namespace nsHiSLIP{ //now setup poll object this->reset_message_id(); - + this->rmt_delivered = false; + this->sync_poll.fd=this->sync_channel; this->sync_poll.events=POLLIN; this->sync_poll.revents=0; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index d2f5f24cc..d28039339 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -270,7 +270,8 @@ namespace nsHiSLIP{ memcpy( buffer, this->prologue, 2); *((char *) buffer + 2) = this->message_type; *((char *) buffer + 3) = this->control_code; - *((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); + //*((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); + *((u_int32_t *)((char *) buffer+4))=htonl(this->message_parameter.word); *((u_int64_t *)((char *) buffer+8))=htobe64(this->payload_length); return 0; } @@ -367,7 +368,7 @@ namespace nsHiSLIP{ int server_protocol_version; unsigned int server_vendorID; - bool rmt_delivered; + bool rmt_delivered=false; u_int32_t message_id; u_int32_t most_recent_message_id; @@ -385,7 +386,8 @@ namespace nsHiSLIP{ return this->lock_timeout; }; - HiSLIP(){}; + HiSLIP(){ + }; void connect(char const* hostname){ this->connect(hostname, Default_device_name, From b9fa77d6d1a84516f0850928b689688af250f929 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 27 Jun 2020 14:55:09 +0900 Subject: [PATCH 18/67] Delete HiSLIPMessage.cpp --- HiSLIPMessage.cpp | 484 ---------------------------------------------- 1 file changed, 484 deletions(-) delete mode 100644 HiSLIPMessage.cpp diff --git a/HiSLIPMessage.cpp b/HiSLIPMessage.cpp deleted file mode 100644 index e46a230c5..000000000 --- a/HiSLIPMessage.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ -#include "HiSLIPMessage.h" - -using nsHiSLIP::CC_request_t; -using nsHiSLIP::CC_Lock_t; -using nsHiSLIP::HiSLIP_t; -using nsHiSLIP::HiSLIP; -using nsHiSLIP::Message_t; - -#define MAX_PAYLOAD_CAPACITY 4096 -#define IDSTRING_CAPACITY 100 - -// HiSLIP methods -namespace nsHiSLIP{ - void HiSLIP::connect(const char *hostname, - const char *dev_name, - const int port //, - //const char vendor_id[2] - ){ - int status; - //const char vendor_id[]=Default_vendor_id; - - struct addrinfo hints, *res=NULL; - memset(&hints,0, sizeof(struct addrinfo)); - hints.ai_flags=AI_NUMERICSERV | AI_CANONNAME; - hints.ai_flags=AI_NUMERICSERV; - hints.ai_family=AF_INET; // IPv4 - hints.ai_socktype=SOCK_STREAM; - hints.ai_protocol=0; // any protocol - hints.ai_addrlen=0; - hints.ai_addr=NULL; - hints.ai_canonname=NULL; - hints.ai_next=NULL; - - { - char *service=NULL; - if (asprintf(&service, "%d",port)// "4880" for example. - > 0){ - status=getaddrinfo(hostname, service, &hints, &res); - free(service); - } - else{ - status=getaddrinfo(hostname, "hislip", &hints, &res); - perror("asprintf failes"); - } - } - - if ((status !=0) || res == NULL){ - char *msg; - if (asprintf(&msg, "getaddrinfo error status:%d res %p",status,res) >0){ - perror(msg); - free(msg); - } - else{ - perror("getaddrinfo"); - } - exit (9999); - } - - //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - - this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); - this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); - - if (res-> ai_addr == NULL || res->ai_addrlen == 0){ - perror("empty addinfo"); - freeaddrinfo(res); - exit (999); - }; - status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); - if (status!=0){ - // Error handling - perror(__FUNCTION__); - } - status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); - if (status!=0){ - // Error handling - perror(__FUNCTION__); - } - freeaddrinfo(res); - - { - Message msg(nsHiSLIP::Initialize, - 0, - message_parameter((u_int16_t) nsHiSLIP::PROTOCOL_VERSION_MAX, - (char *) Default_vendor_id), - (u_int64_t) 0, (u_int8_t *) NULL); - // errlogPrintf("sending message %d \n", msg.message_type); - msg.send(this->sync_channel); - } - - { Message resp(AnyMessages); - - resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); - - this->overlap_mode=resp.control_code; - this->session_id=resp.message_parameter.getSessionId(); - this->server_protocol_version=resp.message_parameter.getServerProtocolVersion(); - } - { - Message msg(nsHiSLIP::AsyncInitialize); - msg.message_parameter.word=this->session_id; - msg.send(this->async_channel); - } - { - Message resp(AnyMessages); - resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); - this->overlap_mode=resp.control_code; - this->server_vendorID=resp.message_parameter.word; - } - - //now setup poll object - this->reset_message_id(); - this->rmt_delivered = false; - - this->sync_poll.fd=this->sync_channel; - this->sync_poll.events=POLLIN; - this->sync_poll.revents=0; - - this->async_poll.fd=this->async_channel; - this->async_poll.events=POLLIN; - this->async_poll.revents=0; - }; - - long HiSLIP::set_max_size(long message_size){ - Message resp(AnyMessages); - u_int64_t msg_size=htobe64(message_size); - - Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, - 0, - message_parameter(0), - sizeof(msg_size), (u_int8_t *) &msg_size); - msg.send(this->async_channel); - - int ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - - resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); - //The 8-byte buffer size is sent in network order as a 64-bit integer. - this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); - this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; - return this->maximum_message_size; - }; - - int HiSLIP::device_clear(){ - Message resp(AnyMessages); - u_int8_t feature_preference; - int ready; - - Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, - 0, - 0, - 0,NULL); - - msg->send(this->async_channel); - - ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - - resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); - feature_preference=resp.control_code; - - msg=new Message(nsHiSLIP::DeviceClearComplete, - feature_preference, - 0, - 0, NULL); - - msg->send(this->sync_channel); - - ready=poll(&this->sync_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); - - this->overlap_mode=resp.control_code; - this->reset_message_id(); - this->rmt_delivered = false; - - return 0; - - }; - - u_int8_t HiSLIP::status_query(){ - u_int8_t status; - int ready; - - Message resp(AnyMessages); - - Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, - (u_int8_t) this->rmt_delivered, - message_parameter((u_int32_t) this->most_recent_message_id), - 0, NULL); - msg.send(this->async_channel); - - ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); - - status= resp.control_code &0xff; - return status; - } - - - // long HiSLIP::write(u_int8_t *data_str, long timeout){ - // return this->write(data_str, this->maximum_message_size,timeout); - // }; - - long HiSLIP::write(u_int8_t const* data_str, size_t const dsize, long timeout){ - - size_t max_payload_size = this->maximum_message_size - nsHiSLIP::HEADER_SIZE; - size_t bytestosend=dsize; - const u_int8_t *buffer=data_str; - size_t delivered=0; - size_t count; - - // errlogPrintf("HiSLIP::write sending data %s\n", data_str); - - while(bytestosend){ - if (bytestosend < max_payload_size){ - Message msg(nsHiSLIP::DataEnd, - this->rmt_delivered, - nsHiSLIP::message_parameter(this->message_id), - bytestosend, (u_int8_t *) buffer); - buffer += bytestosend; - // errlogPrintf("sending message %s\n",(char *) msg.payload); - count=msg.send(this->sync_channel); - count -=HEADER_SIZE; - bytestosend = 0; - delivered += count ; - } - else{ - Message msg(nsHiSLIP::Data, - this->rmt_delivered, - nsHiSLIP::message_parameter(this->message_id), - max_payload_size, (u_int8_t *) buffer); - count=msg.send(this->sync_channel); - count -= HEADER_SIZE; - bytestosend -=count; - delivered += count; - buffer += max_payload_size; - } - // errlogPrintf("data sent= %lu\n",count); - this->increment_message_id(); - } - return delivered; - }; - - int HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ - bool eom=false; - size_t rsize=0; - - // errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", - // buffer, timeout); - - *received=0; - this->rmt_delivered = false; - - while(!eom) { - int ready; - Message resp(AnyMessages); - - ready=poll(&this->sync_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - rsize=resp.recv(this->sync_channel); - // errlogPrintf("HiSLIP read rsize %ld\n",rsize); - if (rsize < resp.payload_length){ - //Error!! - return -2; - }; - - // may not be a good idea. - { u_int8_t *newbuf; - - newbuf=(u_int8_t *) reallocarray(*buffer, 1, - *received+resp.payload_length); - if (newbuf == NULL){ - // errlogPrintf("Cannot extend memory area\n"); - return -3; - } - else{ - *buffer=newbuf; - } - } - ::memcpy((*buffer + *received), resp.payload, resp.payload_length); - *received +=resp.payload_length; - if ( resp.message_type == nsHiSLIP::Data){ - continue; - } else if ( resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - return 0; - } else{ - // error unexpected message type. - return -999; - } - } - return -999; - }; - - int HiSLIP::read(size_t *received, - u_int8_t *buffer, size_t bsize, long timeout){ - bool eom=false; - size_t rsize=0; - - // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", - // buffer, bsize, timeout); - *received=0; - this->rmt_delivered = false; - - if (buffer==NULL || bsize <= 0){ - // errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", - // buffer, bsize, timeout); - return -1; - } - if (bsize < this->maximum_payload_size){ - // errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", - // bsize, this->maximum_payload_size); - } - while(!eom) { - int ready; - Message resp(AnyMessages); - - ready=::poll(&this->sync_poll, 1, timeout); - - if (ready == 0){ - // errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); - return -1; - } - - rsize=resp.recv(this->sync_channel); - - if (rsize < resp.payload_length){ - // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); - return -1; - }; - if (( (*received) + resp.payload_length) > bsize){ - // errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", - // *received, resp.payload_length, bsize); - - ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); - *received = bsize; - return 0; - } - else{ - // errlogPrintf("received message size %ld %ld data:%s mt:%d\n", - // rsize, *received, (char *) resp.payload, resp.message_type); - ::memcpy( (buffer + *received), resp.payload, resp.payload_length); - - *received +=resp.payload_length; - } - - if ( resp.message_type == nsHiSLIP::Data){ - continue; - } else if (resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - // errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", - // buffer, (char *) resp.payload, eom,this->rmt_delivered); - return 0; - } else{ - // errlogPrintf("Unexpected message type:%d\n", - // resp.message_type); - resp.printf(); - // error unexpected message type. - return -1; - } - } - return -1; - }; - - size_t HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, - u_int8_t **rbuffer, - long wait_time){ - size_t rsize=-1; - u_int8_t *buffer=NULL; - int status; - - // errlogPrintf("sending a command %s %lu",data_str, dsize); - - this->write(data_str, dsize); - if(this->wait_for_answer(wait_time) == 0){ - // error - return -1; - }; - status=this->read(&rsize, &buffer); - if (status !=0){ - rsize=-1; - } - *rbuffer=buffer; - return rsize; - }; - - long HiSLIP::trigger_message(void){ - Message msg(nsHiSLIP::Trigger, - (u_int8_t) this->rmt_delivered, - message_parameter((u_int32_t) this->most_recent_message_id), - 0, NULL); - msg.send(this->sync_channel); - this->increment_message_id(); - this->rmt_delivered=false; - return 0; - }; - - long HiSLIP::remote_local(u_int8_t request){ - Message msg(nsHiSLIP::AsyncRemoteLocalControl, - request, - message_parameter((u_int32_t) this->most_recent_message_id), - 0, NULL), resp(AnyMessages); - msg.send(this->async_channel); - resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); - return 0; - }; - - long HiSLIP::request_lock(const char* lock_string){ - Message msg(nsHiSLIP::AsyncLock, - 1, // request - this->lock_timeout, - strnlen(lock_string,256), (u_int8_t *) lock_string), - resp(AnyMessages); - - msg.send(this->async_channel); - - resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); - - return resp.control_code; - }; - - long HiSLIP::release_lock(void){ - long message_id =this->most_recent_message_id; - if ( message_id == nsHiSLIP::INITIAL_MESSAGE_ID){ - message_id=0; - } - Message msg(nsHiSLIP::AsyncLock, - 0, // release - message_id, - 0, NULL), - resp(AnyMessages); - - msg.send(this->async_channel); - - resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); - - return resp.control_code; - }; - - long HiSLIP::request_srq_lock(void){ - { - // errlogPrintf("request_srq_lock not implemented yet\n"); - return -1; - }; - return 0; - }; - - long HiSLIP::release_srq_lock(void){ - { - // errlogPrintf("release_srq_lock not implemented yet\n"); - return -1; - }; - return 0; - }; - -} // end of namespace HiSLIP - From f8920f11d245efa67f6cd344b8528e202cbbe746 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 27 Jun 2020 14:55:27 +0900 Subject: [PATCH 19/67] Delete HiSLIPMessage.h --- HiSLIPMessage.h | 456 ------------------------------------------------ 1 file changed, 456 deletions(-) delete mode 100644 HiSLIPMessage.h diff --git a/HiSLIPMessage.h b/HiSLIPMessage.h deleted file mode 100644 index d28039339..000000000 --- a/HiSLIPMessage.h +++ /dev/null @@ -1,456 +0,0 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ -//-*- coding:utf-8 -*- -#define NDEBUG 1 -#define DEBUG 1 - -#include -#include -//#define _GNU_SOURCE /* See feature_test_macros(7) */ -#include -#include -#include -#include //memcpy, etc -#include /* for MAXHOSTNAMELEN */ -#include /* close() and others */ - -#include -#include // network endian is "be". -#include -#include - -//#include -//#include -//#include -//#include -//#include -//#include - - - -template struct Property { - T& r; - operator T() {return r;} - void operator =(const T v){ r=v;} -}; - -namespace nsHiSLIP{ - - //constants - typedef enum CC_reuqest{ - RemoteDisable=0, - RemoteEnable=1, - RemoteDisableGTL=2, // disable remote and goto local - RemoteEnableGTR=3, // Enable remote and goto remote - RemoteEnableLLO=4, // Enable remote and lock out local - RemoteEnableGTRLLO=5, // - RTL=6 - } CC_request_t; - - typedef enum CC_Lock{ - release =0, - request =1 - } CC_Lock_t; - - typedef enum CC_LockResponse{ - fail=0, //Lock was requested but not granted - success=1, //release of exclusive lock - success_shared=2, //release of shared lock - error=3 // Invalide - } CC_LockResponse_t; - - static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 - static const long INITIAL_MESSAGE_ID = 0xffffff00 ; - static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; - static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes - static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept - static const long HEADER_SIZE=16; - static const long SOCKET_TIMEOUT = 1000; //# Socket timeout in msec - static const long LOCK_TIMEOUT = 3000;//# Lock timeout - static const long Default_Port = 4880; - static const char Default_device_name[]="hslip0"; - static const char Default_vendor_id[]={'E','P'}; - static const char Prologue[]={'H','S'}; - // - typedef enum Message_Types{ - Initialize = 0, - InitializeResponse = 1, - FatalError = 2, - Error = 3, - AsyncLock = 4, - AsyncLockResponse = 5, - Data = 6, - DataEnd = 7, - DeviceClearComplete = 8, - DeviceClearAcknowledge = 9, - AsyncRemoteLocalControl = 10, - AsyncRemoteLocalResponse = 11, - Trigger = 12, - Interrupted = 13, - AsyncInterrupted = 14, - AsyncMaximumMessageSize = 15, - AsyncMaximumMessageSizeResponse = 16, - AsyncInitialize = 17, - AsyncInitializeResponse = 18, - AsyncDeviceClear = 19, - AsyncServiceRequest = 20, - AsyncStatusQuery = 21, - AsyncStatusResponse = 22, - AsyncDeviceClearAcknowledge = 23, - AsyncLockInfo = 24, - AsyncLockInfoResponse = 25, - // 26-127 are reserved for future use. - // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. - AnyMessages=127 // 128-255 are reserved for vendor use. - } Message_Types_t; - - typedef enum Error_code{ - UnidentifiedError, - UnrecognizedMessageType, - UnrecognizedControlCode, - UnrecognizedVendorDefinedMessage, - MessageTooLarge - } Error_code_t; - static const char *Error_Messages[] = - { - "Unidentified error", - "Unrecognized Message Type", - "Unrecognized control code", - "Unrecognized Vendor Defined Message", - "Message too large" - }; - typedef enum Fatal_Error_code { - UnidentifiedFatalError, - PoorlyFormedMmessageHeader, - AttemptToUseConnectionWithoutBothChannels, - InvalidInitializationSequence, - ServerRefusedConnection - } Fatal_Erro_code_t; - static const char *Fatal_Error_Messages[] = - { - "Unidentified error", - "Poorly formed message header", - "Attempt to use connection without both channels established", - "Invalid Initialization Sequence", - "Server refused connection due to maximum number of clients exceeded" - }; - - typedef class message_parameter{ - public: - u_int32_t word; - // struct InitializeParameter{ - // u_int16_t protocol_version; - // char vendor_id[2]={0x00 ,0x00}; - // } initParm; - // struct InitializeResponseParameter{ - // u_int16_t session_id; - // u_int16_t protocol_version; - // } initResp; - message_parameter(u_int32_t word){this->word=word;}; - message_parameter(u_int16_t proto, char vers[2]){ - this->word= ((int32_t)proto << 16) + - (vers[1] << 8) + (vers[0]<<0); - }; - message_parameter(u_int16_t proto, u_int16_t sid){ - this->word = (proto << 16) + sid; - - }; - u_int16_t getServerProtocolVersion(){ - return (u_int16_t) (((this->word) & 0xffff0000)>>16); - } - u_int16_t getSessionId(){ - return ((u_int16_t) ((this->word) & 0xffff)); - } - } message_parameter_t; - - class Header{ - public: - const char prologue[2]={'H','S'}; - u_int8_t message_type; - u_int8_t control_code; - message_parameter_t message_parameter; - u_int64_t payload_length; - - Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ - this->message_type=message_type; - } - Header(const void *buffer):message_parameter(0){ - assert(memcmp(this->prologue, buffer,2) == 0); - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - } - Header(const u_int8_t type, - const u_int8_t cce, - const message_parameter_t param, - const u_int64_t length):message_parameter(param.word){ - this->message_type=type; - this->control_code=cce; - this->payload_length=length; - } - void printf(void){ - ::printf("message type:%d\n",this->message_type); - ::printf("control_code:%d\n",this->control_code); - ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %ld\n",this->payload_length); - // errlogPrintf("message type:%d\n",this->message_type); - // errlogPrintf("control_code:%d\n",this->control_code); - // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); - // errlogPrintf("payload length: %qd\n",this->payload_length); - } - - size_t send(int socket){ - char hbuf[HEADER_SIZE]; - ssize_t ssize; - - this->toRawData(hbuf); - ssize=::send(socket, hbuf, sizeof(hbuf), 0); - - return ssize; - } - - size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ - char buffer[HEADER_SIZE]; - ssize_t rsize; - rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - - if (rsize < HEADER_SIZE){ - //raise exception? - return -1; - } - else if (memcmp(this->prologue, buffer,2) != 0){ - return -1; - } - - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - - //this->printf(); - - if((expected_message_type == AnyMessages) || - (expected_message_type == this->message_type)){ - return rsize; - } - //error! - // in overlapped mode, should we keep it? - else if(this->message_type == nsHiSLIP::Error){ - return -(this->control_code+1); - } - else if(this->message_type == nsHiSLIP::FatalError){ - return -(this->control_code+1); - } - return -1; - } - - int fromRawData(void *buffer){ //DeSerialize - if (memcmp(this->prologue, buffer,2) != 0){ - //error - return -1; - } - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - return 0; - } - int toRawData(void *buffer){ //Serialize this as bytes data in buffer. - memcpy( buffer, this->prologue, 2); - *((char *) buffer + 2) = this->message_type; - *((char *) buffer + 3) = this->control_code; - //*((u_int32_t *)((char *) buffer+4))=htobe32(this->message_parameter.word); - *((u_int32_t *)((char *) buffer+4))=htonl(this->message_parameter.word); - *((u_int64_t *)((char *) buffer+8))=htobe64(this->payload_length); - return 0; - } - }; - - typedef class Message:public Header{ - public: - void *payload=NULL; - - Message(Message_Types_t message_type):Header(message_type){ - }; - Message(void *raw_header):Header(raw_header){ - //this->fromRawData(raw_header); - }; - Message(void *raw_header, void *payload):Message(raw_header){ - this->payload = calloc(this->payload_length, 1); - if (this->payload != NULL){ - memcpy(this->payload, payload, this->payload_length); - }; - } - Message(u_int8_t type, - u_int8_t cce, - message_parameter_t param, - u_int64_t length, - u_int8_t *payload):Header(type,cce,param,length),payload(payload) { - //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); - //memcpy(this->payload, payload, length); - //this->payload = payload; - } - size_t send(int socket){ - size_t ssize; - ssize=this->Header::send(socket); - if (ssize < HEADER_SIZE){ - return -1; - } - return (ssize + ::send(socket, this->payload, this->payload_length,0)); - } - - ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ - size_t rsize; - size_t status; - - rsize=this->Header::recv(socket, expected_message_type); - - if (rsize < 0){ - // Error! - return rsize; - } - - // now prepare for a pyload. - if (this->payload==NULL && this->payload_length > 0){ - this->payload = (void *) calloc(this->payload_length,1); - if (this->payload == NULL){ - perror("faile to allocate memory for payload."); - return -1; - } - } - - rsize=0; //returns size of recieved payload. - if (this->payload_length > 0){ - size_t bytestoread=this->payload_length; - - while (bytestoread){ - status = ::recv(socket, ((u_int8_t *)this->payload+rsize), - bytestoread, 0); - - if (status <= 0){ - perror("payload read error:"); - return -1; - } - rsize +=status; - if (status >= bytestoread){ - break; - } - bytestoread -=status; - } - } - return (rsize); - } - } Message_t; - - typedef class HiSLIP { - public: - unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; - unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; - long socket_timeout=SOCKET_TIMEOUT; - long lock_timeout=LOCK_TIMEOUT; - int sync_channel; - int async_channel; - struct pollfd sync_poll; - struct pollfd async_poll; - int overlap_mode; - int session_id; - int server_protocol_version; - unsigned int server_vendorID; - - bool rmt_delivered=false; - u_int32_t message_id; - u_int32_t most_recent_message_id; - - void set_timeout( long timeout){ - this->socket_timeout=timeout; - }; - long get_timeout(void){ - return this->socket_timeout; - }; - void set_lock_timeout( long timeout){ - this->lock_timeout=timeout; - } - ; - long get_lock_timeout(void){ - return this->lock_timeout; - }; - - HiSLIP(){ - }; - void connect(char const* hostname){ - this->connect(hostname, - Default_device_name, - Default_Port); - }; - void connect(char const* hostname, - char const* dev_name, - int port); - long set_max_size(long message_size); - int device_clear(void); - u_int8_t status_query(void); - //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); - long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); - size_t ask(u_int8_t *data_str, size_t size, - u_int8_t **rbuffer, long wait_time=LOCK_TIMEOUT); - int read(size_t *received, long timeout=LOCK_TIMEOUT ); - int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); - int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); - long trigger_message(void); - long remote_local(u_int8_t request); - long request_lock(const char* lock_string=NULL); - long release_lock(void); - long request_srq_lock(void); - long release_srq_lock(void); - Message *get_Service_Request(void){ - Message *msg=new Message(AnyMessages); - long status; - this->request_srq_lock(); - - //status= msg->recv(this->async_channel, AsyncServiceRequest); - status= msg->recv(this->async_channel); - - if (status != 0){ - // should handle Error/Fatal Error/Async Interrupted messages. - perror(__FUNCTION__); - } - this->release_srq_lock(); - return msg; - }; - int wait_for_SRQ(int wait_time){ - return ::poll(&this->async_poll, 1, wait_time); - } - void disconnect(){ - if (this->sync_channel){ - close(this->sync_channel); - }; - if (this->async_channel){ - close(this->async_channel); - }; - }; - - private: - int wait_for_answer(int wait_time){ - return ::poll(&this->sync_poll, 1, wait_time); - } - void reset_message_id(void){ - this->most_recent_message_id=0; - this->message_id = 0xffffff00; - } - u_int32_t increment_message_id(void){ - this->most_recent_message_id=this->message_id; - this->message_id = (this->message_id +2) & 0xffffffff; - return this->message_id; - }; - } HiSLIP_t; -}; // namespace From 91001d4a26614fb58910b28637166260a9e453e4 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 27 Jun 2020 17:04:55 +0900 Subject: [PATCH 20/67] add srq_lock related methods --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 48 +++++++++++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 39 ++++++++------- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 5 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 33 +++++++++++-- 4 files changed, 95 insertions(+), 30 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index e46a230c5..fe4b691a8 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -465,20 +465,50 @@ namespace nsHiSLIP{ }; long HiSLIP::request_srq_lock(void){ - { - // errlogPrintf("request_srq_lock not implemented yet\n"); + if (sem_wait(&(this->srq_lock)) == 0){ + return 0; + } + else{ + perror("request_srq_lock"); return -1; - }; - return 0; + } }; long HiSLIP::release_srq_lock(void){ - { - // errlogPrintf("release_srq_lock not implemented yet\n"); + int sval=this->check_srq_lock(); + if (sval != 0){ + return sval; + } + if (sem_post(&(this->srq_lock)) == 0){ + return 0; + } + else{ + perror("release_srq_lock"); return -1; - }; - return 0; + } }; - + int HiSLIP::check_srq_lock(void){ + int sval; + if (sem_getvalue(&(this->srq_lock),&sval) == 0){ + return sval; + } + else { + perror("check_srq_lock"); + return -1; + } + } + + int HiSLIP::check_and_lock_srq_lock(void){ + int rc=sem_trywait(&(this->srq_lock)); + switch (rc){ + case 0: + break; + case EAGAIN: + break; + default: + perror("check_and_lock_srq_lock"); + } + return rc; + } } // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index d28039339..3d9c5fdba 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -28,6 +28,7 @@ #include // network endian is "be". #include #include +#include //#include //#include @@ -36,8 +37,6 @@ //#include //#include - - template struct Property { T& r; operator T() {return r;} @@ -371,6 +370,20 @@ namespace nsHiSLIP{ bool rmt_delivered=false; u_int32_t message_id; u_int32_t most_recent_message_id; + sem_t srq_lock; + HiSLIP(){ + if (sem_init(&(this->srq_lock), 0, 1) !=0){ + perror(" HiSLIP srq_lock"); + } + }; + void connect(char const* hostname){ + this->connect(hostname, + Default_device_name, + Default_Port); + }; + void connect(char const* hostname, + char const* dev_name, + int port); void set_timeout( long timeout){ this->socket_timeout=timeout; @@ -386,16 +399,6 @@ namespace nsHiSLIP{ return this->lock_timeout; }; - HiSLIP(){ - }; - void connect(char const* hostname){ - this->connect(hostname, - Default_device_name, - Default_Port); - }; - void connect(char const* hostname, - char const* dev_name, - int port); long set_max_size(long message_size); int device_clear(void); u_int8_t status_query(void); @@ -412,24 +415,28 @@ namespace nsHiSLIP{ long release_lock(void); long request_srq_lock(void); long release_srq_lock(void); - Message *get_Service_Request(void){ + int check_srq_lock(void); + int check_and_lock_srq_lock(void); + u_int8_t get_Service_Request(void){ Message *msg=new Message(AnyMessages); long status; - this->request_srq_lock(); + //this->request_srq_lock(); //status= msg->recv(this->async_channel, AsyncServiceRequest); - status= msg->recv(this->async_channel); + status= msg->recv(this->async_channel,nsHiSLIP::AsyncServiceRequest); if (status != 0){ // should handle Error/Fatal Error/Async Interrupted messages. perror(__FUNCTION__); } this->release_srq_lock(); - return msg; + return msg->control_code; }; + int wait_for_SRQ(int wait_time){ return ::poll(&this->async_poll, 1, wait_time); } + void disconnect(){ if (this->sync_channel){ close(this->sync_channel); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 83cd270ea..2d358627b 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -58,7 +58,10 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": long request_lock(char *) long release_lock() long request_srq_lock() - long release_srq_loc() + long release_srq_lock() + int check_srq_lock() + int check_and_lock_srq_lock() + u_int8_t get_Service_Request() int wait_for_SRQ(int) void disconnect() diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 3b5c53782..359dab3c9 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -160,18 +160,43 @@ cdef class HiSLIP: """ Not implemented in .cpp yet. """ - cdef long rc=0 + cdef long rc=-1 + rc=self.thisobj.request_srq_lock() return rc - def release_srq_loc(self): + def release_srq_lock(self): """ Not implemented in .cpp yet. """ - cdef long rc=0 + cdef long rc=-1 + rc=self.thisobj.release_srq_lock() + return rc + + def check_srq_lock(self): + """ + 1: released + 0: locked + """ + cdef int rc=-1 + rc=self.thisobj.check_srq_lock() + return rc + + def check_and_lock_srq_lock(self): + """ + 1: released + 0: locked + """ + cdef int rc + rc=self.thisobj.check_and_lock_srq_lock() return rc + def get_Service_Request(self): + cdef u_int8_t rc=0 + rc=self.thisobj.get_Service_Request() + return rc + def wait_for_SRQ(self, wait_time): - cdef int rc + cdef int rc=-1 rc=self.thisobj.wait_for_SRQ(wait_time) return rc From 97a5e1099811d927cbc96b9547a00c88f1d36c09 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Mon, 29 Jun 2020 06:55:46 +0900 Subject: [PATCH 21/67] compiles on MacOSX --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 88 +++++++++++++------ asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 39 +++++--- asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile | 13 +++ asyn/drvAsynHiSLIP/cPyHiSLIP/README.md | 34 +++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst | 51 +++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 5 +- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 5 +- 7 files changed, 193 insertions(+), 42 deletions(-) create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/README.md create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index fe4b691a8..13eec136a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -44,23 +44,21 @@ namespace nsHiSLIP{ hints.ai_next=NULL; { - char *service=NULL; - if (asprintf(&service, "%d",port)// "4880" for example. + char service[256]={'\x0'}; + if (snprintf(service,256, "%d",port) // "4880" for example. > 0){ status=getaddrinfo(hostname, service, &hints, &res); - free(service); } else{ status=getaddrinfo(hostname, "hislip", &hints, &res); - perror("asprintf failes"); + perror("snprintf failes"); } } if ((status !=0) || res == NULL){ - char *msg; - if (asprintf(&msg, "getaddrinfo error status:%d res %p",status,res) >0){ + char msg[1024]={'\x0'}; + if (snprintf(msg, 1024, "getaddrinfo error status:%d res %p",status,res) >0){ perror(msg); - free(msg); } else{ perror("getaddrinfo"); @@ -292,8 +290,9 @@ namespace nsHiSLIP{ // may not be a good idea. { u_int8_t *newbuf; - newbuf=(u_int8_t *) reallocarray(*buffer, 1, - *received+resp.payload_length); + // newbuf=(u_int8_t *) reallocarray(*buffer, 1, + // *received+resp.payload_length); + newbuf = (u_int8_t *) realloc( *buffer, *received+resp.payload_length); if (newbuf == NULL){ // errlogPrintf("Cannot extend memory area\n"); return -3; @@ -436,7 +435,7 @@ namespace nsHiSLIP{ Message msg(nsHiSLIP::AsyncLock, 1, // request this->lock_timeout, - strnlen(lock_string,256), (u_int8_t *) lock_string), + strnlen(lock_string, 256), (u_int8_t *) lock_string), resp(AnyMessages); msg.send(this->async_channel); @@ -465,7 +464,14 @@ namespace nsHiSLIP{ }; long HiSLIP::request_srq_lock(void){ - if (sem_wait(&(this->srq_lock)) == 0){ + // if (sem_wait(&(this->srq_lock)) == 0){ + // return 0; + // } + // else{ + // perror("request_srq_lock"); + // return -1; + // } + if (pthread_mutex_lock(&(this->srq_lock)) == 0){ return 0; } else{ @@ -475,11 +481,18 @@ namespace nsHiSLIP{ }; long HiSLIP::release_srq_lock(void){ - int sval=this->check_srq_lock(); - if (sval != 0){ - return sval; - } - if (sem_post(&(this->srq_lock)) == 0){ + // int sval=this->check_srq_lock(); + // if (sval != 0){ + // return sval; + // } + // if (sem_post(&(this->srq_lock)) == 0){ + // return 0; + // } + // else{ + // perror("release_srq_lock"); + // return -1; + // } + if (pthread_mutex_unlock(&(this->srq_lock)) == 0){ return 0; } else{ @@ -488,27 +501,48 @@ namespace nsHiSLIP{ } }; int HiSLIP::check_srq_lock(void){ - int sval; - if (sem_getvalue(&(this->srq_lock),&sval) == 0){ - return sval; + // int sval; + // if (sem_getvalue(&(this->srq_lock),&sval) == 0){ + // return sval; + // } + // else { + // perror("check_srq_lock"); + // return -1; + // } + int rc=pthread_mutex_trylock(&(this->srq_lock)); + if (rc == 0){ + pthread_mutex_unlock(&(this->srq_lock)); + return 1; } - else { - perror("check_srq_lock"); - return -1; + else if (rc == EBUSY){ + return 0; } + perror("check_srq_lock"); + return -1; } int HiSLIP::check_and_lock_srq_lock(void){ - int rc=sem_trywait(&(this->srq_lock)); + // int rc=sem_trywait(&(this->srq_lock)); + // switch (rc){ + // case 0: + // break; + // case EAGAIN: + // break; + // default: + // perror("check_and_lock_srq_lock"); + // } + // return rc; + + int rc=pthread_mutex_trylock(&(this->srq_lock)); switch (rc){ case 0: - break; - case EAGAIN: - break; + return 1; + case EBUSY: + return 0; default: perror("check_and_lock_srq_lock"); + return -1; } - return rc; } } // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 3d9c5fdba..8f1442456 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -19,16 +19,30 @@ //#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include -#include +#include #include //memcpy, etc +#include #include /* for MAXHOSTNAMELEN */ #include /* close() and others */ #include -#include // network endian is "be". #include #include -#include +#include // for MacOS + +//#include + +#ifdef __linux__ +# include // network endian is "be". +#else +inline u_int64_t htobe64(u_int64_t q) { + return (htonl(q>>32) +((u_int64_t)htonl(q & 0x00000000ffffffff)<<32)) ; +}; + +inline u_int64_t be64toh(u_int64_t q) { + return (ntohl(q>>32) +((u_int64_t)ntohl(q & 0x00000000ffffffff)<<32)) ; +}; +#endif //#include //#include @@ -187,7 +201,7 @@ namespace nsHiSLIP{ assert(memcmp(this->prologue, buffer,2) == 0); this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); } Header(const u_int8_t type, @@ -202,7 +216,7 @@ namespace nsHiSLIP{ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %ld\n",this->payload_length); + ::printf("payload length: %llu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -261,7 +275,7 @@ namespace nsHiSLIP{ } this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); return 0; } @@ -278,11 +292,13 @@ namespace nsHiSLIP{ typedef class Message:public Header{ public: - void *payload=NULL; + void *payload; Message(Message_Types_t message_type):Header(message_type){ + this->payload=NULL; }; Message(void *raw_header):Header(raw_header){ + this->payload=NULL; //this->fromRawData(raw_header); }; Message(void *raw_header, void *payload):Message(raw_header){ @@ -370,11 +386,12 @@ namespace nsHiSLIP{ bool rmt_delivered=false; u_int32_t message_id; u_int32_t most_recent_message_id; - sem_t srq_lock; + //sem_t srq_lock; + pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; HiSLIP(){ - if (sem_init(&(this->srq_lock), 0, 1) !=0){ - perror(" HiSLIP srq_lock"); - } + // if (sem_init(&(this->srq_lock), 0, 1) !=0){ + // perror(" HiSLIP srq_lock"); + // } }; void connect(char const* hostname){ this->connect(hostname, diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile new file mode 100644 index 000000000..6836919f2 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile @@ -0,0 +1,13 @@ +#!make + +.phony: markdown +.SUFFIXES : .rst .md + + +.rst.md: + /usr/local/bin/pandoc -f rst -t markdown -o $@ $< + +markdown: README.md + +# README.md: README.rst +# /usr/local/bin/pandoc -f rst -t markdown -o README.md README.rst diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md new file mode 100644 index 000000000..6b9578ef3 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md @@ -0,0 +1,34 @@ +README for cPyHiSLIP +==================== + +Author + +: 山本 昇 Noboru Yamamoto + +Organization + +: 高エネルギー加速器研究機構 加速器研究施設 Accelerator Control Group, + Accelerator Laboratory, KEK, JAPAN J-PARCセンタ 加速器ディビジョン + 制御グループ Control Groups Accelerator Division JPARC Center + +Address + +: 〒305-0801 茨城県つくば市大穂1-1 1-1 Oho Tsukuba, Ibaraki, JAPAN + 〒319-1195 茨城県那珂郡東海村大字白方2-4 J-PARC中央制御棟 2-4 + Shirakata, Tokai, Naka Ibaraki, 319-1195 JAPAN + +How to install +-------------- + +you need cython to build cPyHiSLIP module from cPyHiSLIP.pyx and +cPyHiSLIP.pxd. If you dont have installed cython, try: + +> pip install cython + +or + +> python -m pip install cython + +To build and install the module, run: + +> python setup.py install diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst new file mode 100644 index 000000000..fb601d1cb --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst @@ -0,0 +1,51 @@ +README for cPyHiSLIP +====================== + + +:Author: 山本 昇 + Noboru Yamamoto + +:Organization: 高エネルギー加速器研究機構 + 加速器研究施設 + Accelerator Control Group, + Accelerator Laboratory, + KEK, JAPAN + J-PARCセンタ + 加速器ディビジョン + 制御グループ + Control Groups + Accelerator Division + JPARC Center + +:Address: 〒305-0801 + 茨城県つくば市大穂1-1 + 1-1 Oho + Tsukuba, Ibaraki, + JAPAN + 〒319-1195 + 茨城県那珂郡東海村大字白方2-4 + J-PARC中央制御棟 + 2-4 Shirakata, Tokai, Naka + Ibaraki, 319-1195 + JAPAN + + +How to install +-------------- +you need cython to build cPyHiSLIP module from cPyHiSLIP.pyx and cPyHiSLIP.pxd. +If you dont have installed cython, try: + + pip install cython + +or + + python -m pip install cython + + +To build and install the module, run: + + python setup.py install + + + + diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 359dab3c9..e068ae737 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -176,6 +176,7 @@ cdef class HiSLIP: """ 1: released 0: locked + -1: """ cdef int rc=-1 rc=self.thisobj.check_srq_lock() @@ -183,8 +184,8 @@ cdef class HiSLIP: def check_and_lock_srq_lock(self): """ - 1: released - 0: locked + 1: released and now locked. + 0: already locked """ cdef int rc rc=self.thisobj.check_and_lock_srq_lock() diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index bf1d76e2d..8126cfda8 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -81,8 +81,9 @@ ,depends=["cPyHiSLIP.pxd"] # Cython interface file ,language="c++" ,cython_cplus=True - ,undef_macros=["CFLAGS"] - ,extra_compile_args=[], + ,undef_macros=[] #["CFLAGS"] + ,define_macros=[] + ,extra_compile_args=["-std=gnu++11","-stdlib=libc++"], )) From 42ffd3a6d563d81f0a8942a8299ded494180bcbb Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Mon, 29 Jun 2020 20:27:34 +0900 Subject: [PATCH 22/67] adopot to change in HiSLIPMessage.cpp --- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index ac62e110d..3752000eb 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -109,14 +109,9 @@ interruptThread(void *arg) if (pdpvt == NULL){ errlogPrintf(" NULL drvPvt as an argument.\n"); } - Message_t *srqmsg=pdpvt->device->get_Service_Request(); - assert(srqmsg); - u_int8_t stb =srqmsg->control_code;// Ststus Byte - srqmsg->printf(); - + u_int8_t stb = pdpvt->device->get_Service_Request(); errlogPrintf("Get SRQ with STB: 0x%2x\n", stb); - if ((srqmsg->message_type == nsHiSLIP::AsyncServiceRequest) - && (stb != 0)){ // may need mask here. + if (stb != 0){ // may need mask here. ELLLIST *pclientList; interruptNode *pnode; @@ -152,13 +147,6 @@ interruptThread(void *arg) errlogPrintf("Finish SRQ process 0x%2x\n", stb); } } - else if (srqmsg->message_type == nsHiSLIP::AsyncStatusResponse){ - if (epicsMessageQueueTrySend(pdpvt->statusByteMessageQueue, - &stb, 1) != 0) { - errlogPrintf("----- WARNING ----- " - "Can't send status byte to worker thread!\n"); - } - } } } epicsMutexLock(pdpvt->interruptTidMutex); From 8e18540f3874c526e05fc04edbd6cd63c834e8d4 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Mon, 29 Jun 2020 20:30:02 +0900 Subject: [PATCH 23/67] read/ask returns just status --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 121 +++++++++++++----- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 83 +++++++----- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 4 +- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 4 files changed, 137 insertions(+), 73 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 13eec136a..1bc931105 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -19,7 +19,8 @@ using nsHiSLIP::HiSLIP; using nsHiSLIP::Message_t; #define MAX_PAYLOAD_CAPACITY 4096 -#define IDSTRING_CAPACITY 100 +#define IDSTRING_CAPACITY 100 +#define MAX_ERRMSG_CAPACITY 1024 // HiSLIP methods namespace nsHiSLIP{ @@ -44,8 +45,8 @@ namespace nsHiSLIP{ hints.ai_next=NULL; { - char service[256]={'\x0'}; - if (snprintf(service,256, "%d",port) // "4880" for example. + char service[IDSTRING_CAPACITY]={'\x0'}; + if (snprintf(service, IDSTRING_CAPACITY, "%d",port) // "4880" for example. > 0){ status=getaddrinfo(hostname, service, &hints, &res); } @@ -56,8 +57,8 @@ namespace nsHiSLIP{ } if ((status !=0) || res == NULL){ - char msg[1024]={'\x0'}; - if (snprintf(msg, 1024, "getaddrinfo error status:%d res %p",status,res) >0){ + char msg[MAX_ERRMSG_CAPACITY]={'\x0'}; + if (snprintf(msg, MAX_ERRMSG_CAPACITY, "getaddrinfo error status:%d res %p",status,res) >0){ perror(msg); } else{ @@ -99,9 +100,12 @@ namespace nsHiSLIP{ msg.send(this->sync_channel); } - { Message resp(AnyMessages); + { Message resp(AnyMessages); - resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); + int rc=resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); + if (rc !=0){ + //Error! + } this->overlap_mode=resp.control_code; this->session_id=resp.message_parameter.getSessionId(); @@ -114,7 +118,10 @@ namespace nsHiSLIP{ } { Message resp(AnyMessages); - resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + int rc=resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + if (rc !=0){ + // + } this->overlap_mode=resp.control_code; this->server_vendorID=resp.message_parameter.word; } @@ -147,7 +154,10 @@ namespace nsHiSLIP{ return -1; } - resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + int rc=resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + if (rc!=0){ + // + } //The 8-byte buffer size is sent in network order as a 64-bit integer. this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; @@ -157,7 +167,7 @@ namespace nsHiSLIP{ int HiSLIP::device_clear(){ Message resp(AnyMessages); u_int8_t feature_preference; - int ready; + int ready,rc; Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, 0, @@ -171,7 +181,10 @@ namespace nsHiSLIP{ return -1; } - resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncDeviceClearAcknowledge); + if (rc !=0){ + // Error! + } feature_preference=resp.control_code; msg=new Message(nsHiSLIP::DeviceClearComplete, @@ -185,8 +198,10 @@ namespace nsHiSLIP{ if ( ready == 0){ return -1; } - resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); - + rc=resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); + if (rc !=0){ + // Error! + } this->overlap_mode=resp.control_code; this->reset_message_id(); this->rmt_delivered = false; @@ -197,23 +212,31 @@ namespace nsHiSLIP{ u_int8_t HiSLIP::status_query(){ u_int8_t status; - int ready; + int ready,rc; Message resp(AnyMessages); - Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, (u_int8_t) this->rmt_delivered, message_parameter((u_int32_t) this->most_recent_message_id), 0, NULL); + if (this->message_id == 0xffffff00){ + msg.message_parameter=message_parameter((u_int32_t) 0xfffffefe); + } msg.send(this->async_channel); - + this->rmt_delivered=false; + ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } - resp.recv(this->async_channel,nsHiSLIP::AsyncStatusResponse); - + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncStatusResponse); + if (rc !=0){ + //Error! + } + resp.print(); + status= resp.control_code &0xff; + return status; } @@ -241,6 +264,7 @@ namespace nsHiSLIP{ buffer += bytestosend; // errlogPrintf("sending message %s\n",(char *) msg.payload); count=msg.send(this->sync_channel); + this->rmt_delivered=false; count -=HEADER_SIZE; bytestosend = 0; delivered += count ; @@ -251,6 +275,7 @@ namespace nsHiSLIP{ nsHiSLIP::message_parameter(this->message_id), max_payload_size, (u_int8_t *) buffer); count=msg.send(this->sync_channel); + this->rmt_delivered=false; count -= HEADER_SIZE; bytestosend -=count; delivered += count; @@ -262,7 +287,7 @@ namespace nsHiSLIP{ return delivered; }; - int HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ + long HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ bool eom=false; size_t rsize=0; @@ -271,7 +296,13 @@ namespace nsHiSLIP{ *received=0; this->rmt_delivered = false; - + if (*buffer == NULL){ + *buffer=(u_int8_t *) calloc(1,this->maximum_message_size); + } + if (*buffer == NULL){ + perror("buffer allocation error"); + return -1; + } while(!eom) { int ready; Message resp(AnyMessages); @@ -282,7 +313,7 @@ namespace nsHiSLIP{ } rsize=resp.recv(this->sync_channel); // errlogPrintf("HiSLIP read rsize %ld\n",rsize); - if (rsize < resp.payload_length){ + if (rsize < 0){ //Error!! return -2; }; @@ -292,9 +323,11 @@ namespace nsHiSLIP{ // newbuf=(u_int8_t *) reallocarray(*buffer, 1, // *received+resp.payload_length); - newbuf = (u_int8_t *) realloc( *buffer, *received+resp.payload_length); + newbuf = (u_int8_t *) realloc( *buffer, + *received + resp.payload_length); if (newbuf == NULL){ // errlogPrintf("Cannot extend memory area\n"); + *buffer=NULL; return -3; } else{ @@ -317,11 +350,11 @@ namespace nsHiSLIP{ return -999; }; - int HiSLIP::read(size_t *received, + long HiSLIP::read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout){ bool eom=false; size_t rsize=0; - + // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", // buffer, bsize, timeout); *received=0; @@ -333,7 +366,8 @@ namespace nsHiSLIP{ return -1; } if (bsize < this->maximum_payload_size){ - // errlogPrintf("exit HiSLIP::buffer size:%ld should be larger than maximum playload size:%ld \n", + // errlogPrintf("exit HiSLIP::buffer size:%ld should be " + // "larger than maximum playload size:%ld \n", // bsize, this->maximum_payload_size); } while(!eom) { @@ -349,7 +383,7 @@ namespace nsHiSLIP{ rsize=resp.recv(this->sync_channel); - if (rsize < resp.payload_length){ + if (rsize < 0){ // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); return -1; }; @@ -380,7 +414,7 @@ namespace nsHiSLIP{ } else{ // errlogPrintf("Unexpected message type:%d\n", // resp.message_type); - resp.printf(); + resp.print(); // error unexpected message type. return -1; } @@ -388,7 +422,7 @@ namespace nsHiSLIP{ return -1; }; - size_t HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, + long HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, u_int8_t **rbuffer, long wait_time){ size_t rsize=-1; @@ -400,13 +434,19 @@ namespace nsHiSLIP{ this->write(data_str, dsize); if(this->wait_for_answer(wait_time) == 0){ // error + buffer=NULL; return -1; }; - status=this->read(&rsize, &buffer); + status=this->read(&rsize, &buffer, wait_time); if (status !=0){ rsize=-1; } - *rbuffer=buffer; + if (rsize > 0){ + *rbuffer=buffer; + } + else { + buffer=NULL; + } return rsize; }; @@ -422,16 +462,21 @@ namespace nsHiSLIP{ }; long HiSLIP::remote_local(u_int8_t request){ + int rc; Message msg(nsHiSLIP::AsyncRemoteLocalControl, request, message_parameter((u_int32_t) this->most_recent_message_id), 0, NULL), resp(AnyMessages); msg.send(this->async_channel); - resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + if (rc !=0){ + return -1; + } return 0; }; long HiSLIP::request_lock(const char* lock_string){ + int rc; Message msg(nsHiSLIP::AsyncLock, 1, // request this->lock_timeout, @@ -440,12 +485,15 @@ namespace nsHiSLIP{ msg.send(this->async_channel); - resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); - + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + if (rc !=0){ + //error! + } return resp.control_code; }; long HiSLIP::release_lock(void){ + int rc=-1; long message_id =this->most_recent_message_id; if ( message_id == nsHiSLIP::INITIAL_MESSAGE_ID){ message_id=0; @@ -458,8 +506,11 @@ namespace nsHiSLIP{ msg.send(this->async_channel); - resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); - + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + if(rc != 0){ + //Error + return -1; + } return resp.control_code; }; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 8f1442456..fb89be5eb 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -212,11 +212,11 @@ namespace nsHiSLIP{ this->control_code=cce; this->payload_length=length; } - void printf(void){ + void print(void){ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %llu\n",this->payload_length); + ::printf("payload length: %lu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -233,7 +233,7 @@ namespace nsHiSLIP{ return ssize; } - size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ + size_t recv(int socket){ char buffer[HEADER_SIZE]; ssize_t rsize; rsize= ::recv(socket, buffer, HEADER_SIZE, 0); @@ -251,21 +251,7 @@ namespace nsHiSLIP{ this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); - //this->printf(); - - if((expected_message_type == AnyMessages) || - (expected_message_type == this->message_type)){ - return rsize; - } - //error! - // in overlapped mode, should we keep it? - else if(this->message_type == nsHiSLIP::Error){ - return -(this->control_code+1); - } - else if(this->message_type == nsHiSLIP::FatalError){ - return -(this->control_code+1); - } - return -1; + return 0; } int fromRawData(void *buffer){ //DeSerialize @@ -329,15 +315,14 @@ namespace nsHiSLIP{ size_t rsize; size_t status; - rsize=this->Header::recv(socket, expected_message_type); - - if (rsize < 0){ + status=this->Header::recv(socket); + if (status < 0){ // Error! - return rsize; + return status; } // now prepare for a pyload. - if (this->payload==NULL && this->payload_length > 0){ + if (this->payload == NULL && this->payload_length > 0){ this->payload = (void *) calloc(this->payload_length,1); if (this->payload == NULL){ perror("faile to allocate memory for payload."); @@ -345,7 +330,7 @@ namespace nsHiSLIP{ } } - rsize=0; //returns size of recieved payload. + rsize=0; //returns size of recieved payload. should be same as payload_length if (this->payload_length > 0){ size_t bytestoread=this->payload_length; @@ -363,8 +348,31 @@ namespace nsHiSLIP{ } bytestoread -=status; } - } - return (rsize); + } + // check if expected type or not + if((expected_message_type == AnyMessages) || + (expected_message_type == this->message_type)){ + return 0; + } + this->print(); + + if(this->message_type == nsHiSLIP::Error){ + ::printf("Fatal Error: %d %s\n", + this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); + if (this->payload_length >0){ + ::printf("Error msg: %s\n", (char *) this->payload); + } + return -(this->control_code+1); + } + else if(this->message_type == nsHiSLIP::FatalError){ + ::printf("Error: %d %s\n", + this->control_code, nsHiSLIP::Error_Messages[this->control_code]); + if (this->payload_length >0){ + ::printf("Error msg: %s\n", (char *) this->payload); + } + return -(this->control_code+1); + } + return -1; } } Message_t; @@ -383,12 +391,15 @@ namespace nsHiSLIP{ int server_protocol_version; unsigned int server_vendorID; - bool rmt_delivered=false; + bool rmt_delivered; u_int32_t message_id; u_int32_t most_recent_message_id; //sem_t srq_lock; pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; HiSLIP(){ + this->rmt_delivered=false; + this->sync_channel=0; + this->async_channel=0; // if (sem_init(&(this->srq_lock), 0, 1) !=0){ // perror(" HiSLIP srq_lock"); // } @@ -420,12 +431,15 @@ namespace nsHiSLIP{ int device_clear(void); u_int8_t status_query(void); //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); - long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); - size_t ask(u_int8_t *data_str, size_t size, - u_int8_t **rbuffer, long wait_time=LOCK_TIMEOUT); - int read(size_t *received, long timeout=LOCK_TIMEOUT ); - int read(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); - int read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); + long write(const u_int8_t *data_str, const size_t size, + long timeout=LOCK_TIMEOUT); + long ask(u_int8_t *data_str, size_t size, u_int8_t **rbuffer, + long wait_time=LOCK_TIMEOUT); + long read(size_t *received, long timeout=LOCK_TIMEOUT ); + long read(size_t *received, u_int8_t **buffer, + long timeout=LOCK_TIMEOUT); + long read(size_t *received, u_int8_t *buffer, size_t bsize, + long timeout=LOCK_TIMEOUT); long trigger_message(void); long remote_local(u_int8_t request); long request_lock(const char* lock_string=NULL); @@ -439,8 +453,7 @@ namespace nsHiSLIP{ long status; //this->request_srq_lock(); - //status= msg->recv(this->async_channel, AsyncServiceRequest); - status= msg->recv(this->async_channel,nsHiSLIP::AsyncServiceRequest); + status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); if (status != 0){ // should handle Error/Fatal Error/Async Interrupted messages. diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 2d358627b..41c6e9321 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -51,8 +51,8 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int device_clear() u_int8_t status_query() long write(u_int8_t *, size_t, long) - int read(size_t *, u_int8_t **, long) - size_t ask(u_int8_t *, size_t, u_int8_t **,long) + long read(size_t *, u_int8_t **, long) + long ask(u_int8_t *, size_t, u_int8_t **, long) long trigger_message() long remote_local(u_int8_t) long request_lock(char *) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index 8126cfda8..9485cf23d 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -83,7 +83,7 @@ ,cython_cplus=True ,undef_macros=[] #["CFLAGS"] ,define_macros=[] - ,extra_compile_args=["-std=gnu++11","-stdlib=libc++"], + ,extra_compile_args=["-std=gnu++11"], )) From e36d21dc51f938f1c55149c1924908c023aff383 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Tue, 30 Jun 2020 07:19:57 +0900 Subject: [PATCH 24/67] before merge with master --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 93 +++++++++++++------ asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 39 +++++--- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 5 +- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 5 +- 4 files changed, 98 insertions(+), 44 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index fe4b691a8..355882e8e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -44,23 +44,21 @@ namespace nsHiSLIP{ hints.ai_next=NULL; { - char *service=NULL; - if (asprintf(&service, "%d",port)// "4880" for example. + char service[256]={'\x0'}; + if (snprintf(service,256, "%d",port) // "4880" for example. > 0){ status=getaddrinfo(hostname, service, &hints, &res); - free(service); } else{ status=getaddrinfo(hostname, "hislip", &hints, &res); - perror("asprintf failes"); + perror("snprintf failes"); } } if ((status !=0) || res == NULL){ - char *msg; - if (asprintf(&msg, "getaddrinfo error status:%d res %p",status,res) >0){ + char msg[1024]={'\x0'}; + if (snprintf(msg, 1024, "getaddrinfo error status:%d res %p",status,res) >0){ perror(msg); - free(msg); } else{ perror("getaddrinfo"); @@ -173,7 +171,7 @@ namespace nsHiSLIP{ return -1; } - resp.recv(this->async_channel,nsHiSLIP::AsyncDeviceClearAcknowledge); + resp.recv(this->async_channel, nsHiSLIP::AsyncDeviceClearAcknowledge); feature_preference=resp.control_code; msg=new Message(nsHiSLIP::DeviceClearComplete, @@ -208,7 +206,8 @@ namespace nsHiSLIP{ message_parameter((u_int32_t) this->most_recent_message_id), 0, NULL); msg.send(this->async_channel); - + this->rmt_delivered = false; + ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; @@ -292,8 +291,9 @@ namespace nsHiSLIP{ // may not be a good idea. { u_int8_t *newbuf; - newbuf=(u_int8_t *) reallocarray(*buffer, 1, - *received+resp.payload_length); + // newbuf=(u_int8_t *) reallocarray(*buffer, 1, + // *received+resp.payload_length); + newbuf = (u_int8_t *) realloc( *buffer, *received+resp.payload_length); if (newbuf == NULL){ // errlogPrintf("Cannot extend memory area\n"); return -3; @@ -436,7 +436,7 @@ namespace nsHiSLIP{ Message msg(nsHiSLIP::AsyncLock, 1, // request this->lock_timeout, - strnlen(lock_string,256), (u_int8_t *) lock_string), + strnlen(lock_string, 256), (u_int8_t *) lock_string), resp(AnyMessages); msg.send(this->async_channel); @@ -465,7 +465,14 @@ namespace nsHiSLIP{ }; long HiSLIP::request_srq_lock(void){ - if (sem_wait(&(this->srq_lock)) == 0){ + // if (sem_wait(&(this->srq_lock)) == 0){ + // return 0; + // } + // else{ + // perror("request_srq_lock"); + // return -1; + // } + if (pthread_mutex_lock(&(this->srq_lock)) == 0){ return 0; } else{ @@ -475,11 +482,18 @@ namespace nsHiSLIP{ }; long HiSLIP::release_srq_lock(void){ - int sval=this->check_srq_lock(); - if (sval != 0){ - return sval; - } - if (sem_post(&(this->srq_lock)) == 0){ + // int sval=this->check_srq_lock(); + // if (sval != 0){ + // return sval; + // } + // if (sem_post(&(this->srq_lock)) == 0){ + // return 0; + // } + // else{ + // perror("release_srq_lock"); + // return -1; + // } + if (pthread_mutex_unlock(&(this->srq_lock)) == 0){ return 0; } else{ @@ -488,27 +502,48 @@ namespace nsHiSLIP{ } }; int HiSLIP::check_srq_lock(void){ - int sval; - if (sem_getvalue(&(this->srq_lock),&sval) == 0){ - return sval; + // int sval; + // if (sem_getvalue(&(this->srq_lock),&sval) == 0){ + // return sval; + // } + // else { + // perror("check_srq_lock"); + // return -1; + // } + int rc=pthread_mutex_trylock(&(this->srq_lock)); + if (rc == 0){ + pthread_mutex_unlock(&(this->srq_lock)); + return 1; } - else { - perror("check_srq_lock"); - return -1; + else if (rc == EBUSY){ + return 0; } + perror("check_srq_lock"); + return -1; } int HiSLIP::check_and_lock_srq_lock(void){ - int rc=sem_trywait(&(this->srq_lock)); + // int rc=sem_trywait(&(this->srq_lock)); + // switch (rc){ + // case 0: + // break; + // case EAGAIN: + // break; + // default: + // perror("check_and_lock_srq_lock"); + // } + // return rc; + + int rc=pthread_mutex_trylock(&(this->srq_lock)); switch (rc){ case 0: - break; - case EAGAIN: - break; + return 1; + case EBUSY: + return 0; default: perror("check_and_lock_srq_lock"); + return -1; } - return rc; } } // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 3d9c5fdba..8f1442456 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -19,16 +19,30 @@ //#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include -#include +#include #include //memcpy, etc +#include #include /* for MAXHOSTNAMELEN */ #include /* close() and others */ #include -#include // network endian is "be". #include #include -#include +#include // for MacOS + +//#include + +#ifdef __linux__ +# include // network endian is "be". +#else +inline u_int64_t htobe64(u_int64_t q) { + return (htonl(q>>32) +((u_int64_t)htonl(q & 0x00000000ffffffff)<<32)) ; +}; + +inline u_int64_t be64toh(u_int64_t q) { + return (ntohl(q>>32) +((u_int64_t)ntohl(q & 0x00000000ffffffff)<<32)) ; +}; +#endif //#include //#include @@ -187,7 +201,7 @@ namespace nsHiSLIP{ assert(memcmp(this->prologue, buffer,2) == 0); this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); } Header(const u_int8_t type, @@ -202,7 +216,7 @@ namespace nsHiSLIP{ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %ld\n",this->payload_length); + ::printf("payload length: %llu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -261,7 +275,7 @@ namespace nsHiSLIP{ } this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = be32toh(*(u_int32_t *) ((char *) buffer+4)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); return 0; } @@ -278,11 +292,13 @@ namespace nsHiSLIP{ typedef class Message:public Header{ public: - void *payload=NULL; + void *payload; Message(Message_Types_t message_type):Header(message_type){ + this->payload=NULL; }; Message(void *raw_header):Header(raw_header){ + this->payload=NULL; //this->fromRawData(raw_header); }; Message(void *raw_header, void *payload):Message(raw_header){ @@ -370,11 +386,12 @@ namespace nsHiSLIP{ bool rmt_delivered=false; u_int32_t message_id; u_int32_t most_recent_message_id; - sem_t srq_lock; + //sem_t srq_lock; + pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; HiSLIP(){ - if (sem_init(&(this->srq_lock), 0, 1) !=0){ - perror(" HiSLIP srq_lock"); - } + // if (sem_init(&(this->srq_lock), 0, 1) !=0){ + // perror(" HiSLIP srq_lock"); + // } }; void connect(char const* hostname){ this->connect(hostname, diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 359dab3c9..e068ae737 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -176,6 +176,7 @@ cdef class HiSLIP: """ 1: released 0: locked + -1: """ cdef int rc=-1 rc=self.thisobj.check_srq_lock() @@ -183,8 +184,8 @@ cdef class HiSLIP: def check_and_lock_srq_lock(self): """ - 1: released - 0: locked + 1: released and now locked. + 0: already locked """ cdef int rc rc=self.thisobj.check_and_lock_srq_lock() diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index bf1d76e2d..2b231d8ea 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -81,8 +81,9 @@ ,depends=["cPyHiSLIP.pxd"] # Cython interface file ,language="c++" ,cython_cplus=True - ,undef_macros=["CFLAGS"] - ,extra_compile_args=[], + ,undef_macros=[] #["CFLAGS"] + ,define_macros=[] + ,extra_compile_args=["-std=gnu++11",], )) From 9498ed4d79da9f3df569616f3d960ff3e82db34e Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Tue, 30 Jun 2020 07:48:00 +0900 Subject: [PATCH 25/67] add overlap_mode to public member of cHiSLIP in pxd --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 3 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 9 +++++ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 35 +++++++++++++++++--- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 28fe00dc8..c34d42062 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -216,7 +216,7 @@ namespace nsHiSLIP{ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %llu\n",this->payload_length); + ::printf("payload length: %lu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -397,6 +397,7 @@ namespace nsHiSLIP{ //sem_t srq_lock; pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; HiSLIP(){ + this->overlap_mode=false; this->rmt_delivered=false; this->sync_channel=0; this->async_channel=0; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 41c6e9321..ef9b28ae9 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -38,6 +38,15 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": cdef cppclass cHiSLIP "nsHiSLIP::HiSLIP": unsigned long maximum_message_size unsigned long maximum_payload_size + int overlap_mode; + int session_id; + int server_protocol_version; + unsigned int server_vendorID; + + int rmt_delivered; + u_int32_t message_id; + u_int32_t most_recent_message_id; + cHiSLIP() except+ void connect(char * hostname, char * dev_name, diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index e068ae737..f6307044a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -2,6 +2,7 @@ #-*- coding:utf-8 -*- # distutils: sources = HiSLIPMessage.cpp +# distutils: language=c++ from cython.operator cimport dereference as deref, preincrement as inc, address as addressof @@ -10,7 +11,7 @@ from cPyHiSLIP cimport cHiSLIP #from cPyHiSLIP cimport Default_device_name import logging from logging import info,debug,warn,log,fatal -#logging.root.setLevel(logging.DEBUG) +logging.root.setLevel(logging.DEBUG) cdef class HiSLIP: cdef cHiSLIP *thisobj @@ -55,7 +56,13 @@ cdef class HiSLIP: def ask(self, msg, wait_time=3000): rsize, result=self._ask(msg, wait_time) - return result[:rsize] + debug("ask res size: {}".format(rsize)) + if result == None: + return None + elif (rsize > 0): + return result[:rsize] + else: + return None cdef _ask(self, u_int8_t *msg, wait_time): cdef unsigned char *buffer=NULL @@ -64,7 +71,11 @@ cdef class HiSLIP: recieved=self.thisobj.ask(msg, len(msg), addressof(buffer), wait_time) - return (recieved, buffer) + debug("_ask recieved: {}".format(recieved)) + if (recieved > 0 and (buffer != NULL)): + return (recieved, buffer) + else: + return (recieved, None) def set_timeout(self,timeout): self.thisobj.set_timeout(timeout) @@ -104,6 +115,17 @@ cdef class HiSLIP: return rc def status_query(self): + """ + bit/weight/name + 0 1 Reserved + 1 2 Reserved + 2 4 Error/Event Queue + 3 8 Questionable Status Register (QUES) + 4 16 Message Available (MAV) + 5 32 Standard Event Status Bit Summary (ESB) + 6 64 Request Service (RQS)/Master Status Summary (MSS) + 7 128 Operation Status Register (OPER) + """ cdef u_int8_t rc rc=self.thisobj.status_query() return rc @@ -191,6 +213,11 @@ cdef class HiSLIP: rc=self.thisobj.check_and_lock_srq_lock() return rc + def get_overlap_mode(self): + cdef int ovm=self.thisobj.overlap_mode + return ovm + + def get_Service_Request(self): cdef u_int8_t rc=0 rc=self.thisobj.get_Service_Request() @@ -215,7 +242,7 @@ cdef class enumType: cdef class HiSLIPMessageType(enumType): Initialize=0 - InitializeResPonce=1 + InitializeResPonse=1 FatalError=2 Error=3 AsynLock=4 From 1ad6f8fa19741435f5e229ca1a06cde10d2c065a Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Tue, 30 Jun 2020 10:06:51 +0900 Subject: [PATCH 26/67] release setting for local --- configure/RELEASE | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/configure/RELEASE b/configure/RELEASE index cf8155d79..15bf8e135 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -1,22 +1,24 @@ #RELEASE Location of external products +SNCSEQ=/opt/epics/R7/modules/seq-2.2.7 +ASYN= /opt/epics/R7/modules/asyn-git +#STREAM=/opt/epics/R7/modules/StreamDevice-git -SUPPORT=/corvette/home/epics/devel +#SUPPORT=/corvette/home/epics/devel # IPAC is only necessary if support for Greensprings IP488 is required # IPAC release V2-7 or later is required. -IPAC=$(SUPPORT)/ipac-2-15 +#IPAC=$(SUPPORT)/ipac-2-15 # SEQ is required for testIPServer -SNCSEQ=$(SUPPORT)/seq-2-2-5 +#SNCSEQ=$(SUPPORT)/seq-2-2-5 +$SNCSEQ=/opt/epics/modules/soft/seq/seq-2.2.7 -## For sCalcout support in asynOctet - applications include asynCalc.dbd -#CALC=$(SUPPORT)/calc-3-7-3 - -# If CALC was built with SSCAN support then SSCAN must be defined for testEpicsApp +## for sCalcout support in asynOctet - applications include asynCalc.dbd +#CALC=$(SUPPORT)/calc-3-7-7 #SSCAN=$(SUPPORT)/sscan-2-11-3 # EPICS_BASE 3.14.6 or later is required -EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.4 +EPICS_BASE=/opt/epics/R7/base -include $(TOP)/../RELEASE.local -include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local From d8989fbf2a24f9f9c5f21a17a2373270de765931 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Thu, 2 Jul 2020 14:19:17 +0900 Subject: [PATCH 27/67] add message_types for HiSLIP2 --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 5 +++- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 23 ++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 1957b5ec3..6e4b6667c 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -318,7 +318,10 @@ namespace nsHiSLIP{ return -2; }; - // may not be a good idea. + // may not be a good idea to reallocate memory evertime. + // 'message_parameter' should be checkd + // aginst most_recent_message_id and overlap_mode + // { u_int8_t *newbuf; // newbuf=(u_int8_t *) reallocarray(*buffer, 1, diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index c34d42062..c1e97abbe 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -122,8 +122,25 @@ namespace nsHiSLIP{ AsyncDeviceClearAcknowledge = 23, AsyncLockInfo = 24, AsyncLockInfoResponse = 25, - // 26-127 are reserved for future use. - // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. + // for HiSLIP ver2 + GetDescriptors =26, + GetDescriptorsResponse =27, + StartTLS = 28, + AsyncStartTLS = 29, + AsyncStartTLSResponse = 30, + EndTLS = 31, + AsyncEndTLS = 32, + AsyncEndTLSResponse = 33, + GetSaslMechanismList = 34, + GetSaslMechanismListResponse = 35, + AuthenticationStart = 36, + AuthenticationExchange = 37, + AuthenticationResult = 38, + // 39-127 are reserved for future use. + // I don't watn to use negative value to + // represent ANY message. + // So I picked 127 from reserved values + // for this purpose. AnyMessages=127 // 128-255 are reserved for vendor use. } Message_Types_t; @@ -216,7 +233,7 @@ namespace nsHiSLIP{ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %lu\n",this->payload_length); + ::printf("payload length: %llu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); From 0ad49b248d4cada5b775130608ca65d4021bd073 Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Fri, 3 Jul 2020 13:57:51 +0900 Subject: [PATCH 28/67] Update README.txt --- asyn/drvAsynHiSLIP/README.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt index d35e2863f..0af2729e9 100644 --- a/asyn/drvAsynHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/README.txt @@ -4,6 +4,21 @@ Based on: 1) IVI-6.1: IVI High-Speed LAN Instument Protocol +Brief Description +================== +This module provides EPICS asyn Octet driver for HiSLIP protocol. +It should also work with Stream Device library as same as USBTMC and VXI11. +SRQ is supported also throu asyn octet driver. + +HiSLIP protocol is implemented in cPyHiSLIP/HiSLIPMessage.{cpp,h} files. +These files does not have direct dependency on EPICS, and can be used with any other +programs. As an example, cPyHiSLIP/cPyHiSLIP.{pxd,pyx} and setup.py are provided to +build python modules for HiSLIP device. + +How to use +============ +1) For EPICS +Build asyn with the variable DRV_HISLIP. Build Issues ============ From ad8b1502027f5e965c88f1717eb0b05c712f460e Mon Sep 17 00:00:00 2001 From: noboruatkek Date: Sat, 4 Jul 2020 16:14:27 +0900 Subject: [PATCH 29/67] a bit of tuning --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 41 ++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 45 +++++------ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 79 ++++++++++++-------- 3 files changed, 98 insertions(+), 67 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index c1e97abbe..d0356d242 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -82,11 +82,14 @@ namespace nsHiSLIP{ error=3 // Invalide } CC_LockResponse_t; - static const long PROTOCOL_VERSION_MAX = 257 ; // # = <1><1> that is 257 + static const long PROTOCOL_VERSION_MAX = 0x7f7f ; // # = <1><1> that is 257 static const long INITIAL_MESSAGE_ID = 0xffffff00 ; - static const long UNKNOWN_MESSAGE_ID = 0xffffffff ; - static const long MAXIMUM_MESSAGE_SIZE_VISA = 272;//Following VISA 256 bytes + header length 16 bytes - static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept + static const long INITIAL_LAST_MESSAGE_ID = 0xfffffefe; //i.e. 0xffffff00-2 + static const long UNKNOWN_MESSAGE_ID = 0xffffffff; + + //Following VISA 256 bytes + header length 16 bytes + static const long MAXIMUM_MESSAGE_SIZE_VISA = 272; + static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept more than this static const long HEADER_SIZE=16; static const long SOCKET_TIMEOUT = 1000; //# Socket timeout in msec static const long LOCK_TIMEOUT = 3000;//# Lock timeout @@ -141,7 +144,8 @@ namespace nsHiSLIP{ // represent ANY message. // So I picked 127 from reserved values // for this purpose. - AnyMessages=127 // 128-255 are reserved for vendor use. + AnyMessages=127 + // 128-255 are reserved for vendor use. } Message_Types_t; typedef enum Error_code{ @@ -233,7 +237,7 @@ namespace nsHiSLIP{ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %llu\n",this->payload_length); + ::printf("payload length: %lu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -253,7 +257,9 @@ namespace nsHiSLIP{ size_t recv(int socket){ char buffer[HEADER_SIZE]; ssize_t rsize; - rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + rsize= ::recvfrom(socket, buffer, HEADER_SIZE, 0, NULL, NULL); + // rsize= ::read(socket, buffer, HEADER_SIZE); if (rsize < HEADER_SIZE){ //raise exception? @@ -352,9 +358,13 @@ namespace nsHiSLIP{ size_t bytestoread=this->payload_length; while (bytestoread){ - status = ::recv(socket, ((u_int8_t *)this->payload+rsize), - bytestoread, 0); - + // status = ::recv(socket, ((u_int8_t *)this->payload+rsize), + // bytestoread, 0); + status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), + bytestoread, 0, NULL, NULL); + // status = ::read(socket, ((u_int8_t *)this->payload+rsize), + // bytestoread); + if (status <= 0){ perror("payload read error:"); return -1; @@ -371,7 +381,8 @@ namespace nsHiSLIP{ (expected_message_type == this->message_type)){ return 0; } - this->print(); + // for debug + // this->print(); if(this->message_type == nsHiSLIP::Error){ ::printf("Fatal Error: %d %s\n", @@ -404,6 +415,7 @@ namespace nsHiSLIP{ struct pollfd sync_poll; struct pollfd async_poll; int overlap_mode; + u_int8_t feature_setting; int session_id; int server_protocol_version; unsigned int server_vendorID; @@ -415,6 +427,7 @@ namespace nsHiSLIP{ pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; HiSLIP(){ this->overlap_mode=false; + this->feature_setting=0; this->rmt_delivered=false; this->sync_channel=0; this->async_channel=0; @@ -446,7 +459,7 @@ namespace nsHiSLIP{ }; long set_max_size(long message_size); - int device_clear(void); + int device_clear(u_int8_t); u_int8_t status_query(void); //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); long write(const u_int8_t *data_str, const size_t size, @@ -499,8 +512,8 @@ namespace nsHiSLIP{ return ::poll(&this->sync_poll, 1, wait_time); } void reset_message_id(void){ - this->most_recent_message_id=0; - this->message_id = 0xffffff00; + this->most_recent_message_id=INITIAL_LAST_MESSAGE_ID; + this->message_id = INITIAL_MESSAGE_ID; } u_int32_t increment_message_id(void){ this->most_recent_message_id=this->message_id; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index ef9b28ae9..b536954d5 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -39,6 +39,7 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": unsigned long maximum_message_size unsigned long maximum_payload_size int overlap_mode; + u_int8_t feature_setting int session_id; int server_protocol_version; unsigned int server_vendorID; @@ -50,27 +51,27 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": cHiSLIP() except+ void connect(char * hostname, char * dev_name, - int port) - void set_timeout(long) - long get_timeout() - void set_lock_timeout(long) - long get_lock_timeout() + int port) nogil + void set_timeout(long) nogil + long get_timeout() nogil + void set_lock_timeout(long) nogil + long get_lock_timeout() nogil - long set_max_size(long) - int device_clear() - u_int8_t status_query() - long write(u_int8_t *, size_t, long) - long read(size_t *, u_int8_t **, long) - long ask(u_int8_t *, size_t, u_int8_t **, long) - long trigger_message() - long remote_local(u_int8_t) - long request_lock(char *) - long release_lock() - long request_srq_lock() - long release_srq_lock() - int check_srq_lock() - int check_and_lock_srq_lock() - u_int8_t get_Service_Request() - int wait_for_SRQ(int) - void disconnect() + long set_max_size(long) nogil + int device_clear(u_int8_t) nogil + u_int8_t status_query() nogil + long write(u_int8_t *, size_t, long) nogil + long read(size_t *, u_int8_t **, long) nogil + long ask(u_int8_t *, size_t, u_int8_t **, long) nogil + long trigger_message() nogil + long remote_local(u_int8_t) nogil + long request_lock(char *) nogil + long release_lock() nogil + long request_srq_lock() nogil + long release_srq_lock() nogil + int check_srq_lock() nogil + int check_and_lock_srq_lock() nogil + u_int8_t get_Service_Request() nogil + int wait_for_SRQ(int) nogil + void disconnect() nogil diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index f6307044a..625ef83f0 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -11,7 +11,7 @@ from cPyHiSLIP cimport cHiSLIP #from cPyHiSLIP cimport Default_device_name import logging from logging import info,debug,warn,log,fatal -logging.root.setLevel(logging.DEBUG) +#logging.root.setLevel(logging.DEBUG) cdef class HiSLIP: cdef cHiSLIP *thisobj @@ -29,34 +29,36 @@ cdef class HiSLIP: debug("connect to {} {} {}".format(host,device, port)) self.thisobj.connect(host,device,port) - def write(self, msg, timeout=3000): + def write(self, msg, long timeout=3000): self.thisobj.write(msg, len(msg), timeout) - cdef _cread(self,timeout=3000): + cdef _cread(self,long timeout=3000): cdef unsigned char *buffer=NULL - cdef size_t recieved=0 + cdef unsigned char **pbuffer=&buffer + cdef size_t recieved=0, + cdef size_t *precieved=&recieved cdef int rt - debug("calling read in c++") - rt=self.thisobj.read(addressof(recieved), addressof(buffer), timeout) + # debug("calling read in c++") + rt=self.thisobj.read(precieved, pbuffer, timeout) if rt == -1: raise RuntimeError("Timeout") elif rt < 0: raise RuntimeError - elif (buffer == NULL): - raise RuntimeError("NULL pointer") if recieved == 0: return (recieved, None) else: + if (buffer == NULL): + raise RuntimeError("NULL pointer") return (recieved, buffer) - def read(self,timeout=3000): + def read(self, long timeout=3000): recieved, buffer=self._cread(timeout) - debug("cread result {} {}".format(recieved,len(buffer))) + # debug("cread result {} {}".format(recieved,len(buffer))) return (recieved, buffer[:recieved]) - def ask(self, msg, wait_time=3000): + def ask(self, msg, long wait_time=3000): rsize, result=self._ask(msg, wait_time) - debug("ask res size: {}".format(rsize)) + # debug("ask res size: {}".format(rsize)) if result == None: return None elif (rsize > 0): @@ -64,20 +66,25 @@ cdef class HiSLIP: else: return None - cdef _ask(self, u_int8_t *msg, wait_time): + cdef _ask(self, u_int8_t *msg, long wait_time): cdef unsigned char *buffer=NULL + cdef unsigned char **pbuffer=&buffer; cdef size_t recieved=0 cdef int rt + cdef size_t lmsg + #lmsg=len(msg) recieved=self.thisobj.ask(msg, len(msg), - addressof(buffer), + pbuffer, wait_time) - debug("_ask recieved: {}".format(recieved)) - if (recieved > 0 and (buffer != NULL)): + debug("_ask recieved: {}".format(hex(recieved))) + if (recieved & 0x8000000000000000L): + return (-1,None) + elif (recieved > 0 and (buffer != NULL)): return (recieved, buffer) else: return (recieved, None) - def set_timeout(self,timeout): + def set_timeout(self,long timeout): self.thisobj.set_timeout(timeout) return @@ -86,21 +93,22 @@ cdef class HiSLIP: to=self.thisobj.get_timeout() return to - def set_lock_timeout(self, to): - to=self.thisobj.set_lock_timeout(to) - + def set_lock_timeout(self, long to): + self.thisobj.set_lock_timeout(to) + return + def get_lock_timeout(self): cdef long to to=self.thisobj.get_lock_timeout() return to - def set_max_message_size(self, message_size): + def set_max_message_size(self, size_t message_size): cdef long ms ms=self.thisobj.set_max_size(message_size) return ms def get_max_message_size(self): - cdef long ms + cdef size_t ms ms=self.thisobj.maximum_message_size return ms @@ -109,9 +117,9 @@ cdef class HiSLIP: ms=self.thisobj.maximum_payload_size return ms - def device_clear(self): + def device_clear(self,int request=0): cdef long rc - rc=self.thisobj.device_clear() + rc=self.thisobj.device_clear(request) return rc def status_query(self): @@ -135,7 +143,7 @@ cdef class HiSLIP: rc=self.thisobj.trigger_message() return rc - def remote_local(self, request): + def remote_local(self, u_int8_t request): """ Table 18: Remote Local Control Transactions 0 - Disable remote @@ -147,13 +155,13 @@ cdef class HiSLIP: 6 - go to local without changing state of remote enable. """ cdef long rc - cdef u_int8_t _request=request + #cdef u_int8_t _request=request - rc=self.thisobj.remote_local(_request) + rc=self.thisobj.remote_local(request) return rc - def request_lock(self, lock_string): + def request_lock(self, char * lock_string): """ response to request: 0 - Failure @@ -161,9 +169,9 @@ cdef class HiSLIP: 3 - Error """ cdef long rc - cdef char *_lock_string=lock_string + #cdef char *_lock_string=lock_string - rc=self.thisobj.request_lock(_lock_string) + rc=self.thisobj.request_lock(lock_string) return rc @@ -217,13 +225,22 @@ cdef class HiSLIP: cdef int ovm=self.thisobj.overlap_mode return ovm + def get_feature_setting(self): + cdef int ovm=self.thisobj.feature_setting + return ovm + + def get_protocol_version(self): + cdef int spv=self.thisobj.server_protocol_version + major=(spv&0xff00)>>8 + minor=(spv & 0x00ff) + return (major,minor) def get_Service_Request(self): cdef u_int8_t rc=0 rc=self.thisobj.get_Service_Request() return rc - def wait_for_SRQ(self, wait_time): + def wait_for_SRQ(self, long wait_time): cdef int rc=-1 rc=self.thisobj.wait_for_SRQ(wait_time) return rc From 46590bf99741ac9f17ec16a14df9550c6b28436a Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 11 Jul 2020 09:37:01 +0900 Subject: [PATCH 30/67] accept single eos character --- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index 3752000eb..7af0bcdd4 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -32,13 +32,13 @@ typedef struct drvPvt { * HiSLIP private */ - HiSLIP_t *device; + HiSLIP_t *device; char *hostname; long port; bool isConnected; int termChar; - char deviceVendorID[IDSTRING_CAPACITY]; + char deviceVendorID[IDSTRING_CAPACITY]; /* * Asyn interfaces we provide @@ -492,14 +492,20 @@ asynOctetSetInputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen { drvPvt *pdpvt = (drvPvt *)pvt; - if (eoslen ==0) { + if (eoslen == 0) { pdpvt->termChar = -1; return asynSuccess; } + else if (eoslen == 1) { + pdpvt->termChar = *eos & 0xff; + return asynSuccess; + } else{ pdpvt->termChar = -1; epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support multiple terminating characters"); + "Device does not support multiple terminating characters %s %d", + eos, eoslen + ); return asynError; } } @@ -689,7 +695,7 @@ HiSLIPConfigure(const char *portName, */ static const iocshArg HiSLIPConfigureArg0 = {"port name", iocshArgString}; -static const iocshArg HiSLIPConfigureArg1 = {"HiSLIP host addressr", +static const iocshArg HiSLIPConfigureArg1 = {"HiSLIP host address", iocshArgString}; static const iocshArg HiSLIPConfigureArg2 = {"priority", iocshArgInt}; From 0f629ecc00edf055296a35e200b9804748830d05 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 11 Jul 2020 09:40:32 +0900 Subject: [PATCH 31/67] before merge --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 5 ++- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 38 +++++++++++++++---- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 1957b5ec3..6e4b6667c 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -318,7 +318,10 @@ namespace nsHiSLIP{ return -2; }; - // may not be a good idea. + // may not be a good idea to reallocate memory evertime. + // 'message_parameter' should be checkd + // aginst most_recent_message_id and overlap_mode + // { u_int8_t *newbuf; // newbuf=(u_int8_t *) reallocarray(*buffer, 1, diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index c34d42062..5de0ae245 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -122,8 +122,25 @@ namespace nsHiSLIP{ AsyncDeviceClearAcknowledge = 23, AsyncLockInfo = 24, AsyncLockInfoResponse = 25, - // 26-127 are reserved for future use. - // I don't watn to use negative value to represent ANY message. So I picked 127 from reserved values for this purpose. + // for HiSLIP ver2 + GetDescriptors =26, + GetDescriptorsResponse =27, + StartTLS = 28, + AsyncStartTLS = 29, + AsyncStartTLSResponse = 30, + EndTLS = 31, + AsyncEndTLS = 32, + AsyncEndTLSResponse = 33, + GetSaslMechanismList = 34, + GetSaslMechanismListResponse = 35, + AuthenticationStart = 36, + AuthenticationExchange = 37, + AuthenticationResult = 38, + // 39-127 are reserved for future use. + // I don't watn to use negative value to + // represent ANY message. + // So I picked 127 from reserved values + // for this purpose. AnyMessages=127 // 128-255 are reserved for vendor use. } Message_Types_t; @@ -216,7 +233,7 @@ namespace nsHiSLIP{ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); - ::printf("payload length: %lu\n",this->payload_length); + ::printf("payload length: %llu\n",this->payload_length); // errlogPrintf("message type:%d\n",this->message_type); // errlogPrintf("control_code:%d\n",this->control_code); // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); @@ -378,10 +395,10 @@ namespace nsHiSLIP{ typedef class HiSLIP { public: - unsigned long maximum_message_size=MAXIMUM_MESSAGE_SIZE; - unsigned long maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; - long socket_timeout=SOCKET_TIMEOUT; - long lock_timeout=LOCK_TIMEOUT; + unsigned long maximum_message_size; + unsigned long maximum_payload_size; + long socket_timeout; + long lock_timeout; int sync_channel; int async_channel; struct pollfd sync_poll; @@ -395,12 +412,17 @@ namespace nsHiSLIP{ u_int32_t message_id; u_int32_t most_recent_message_id; //sem_t srq_lock; - pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t srq_lock; HiSLIP(){ + this->maximum_message_size=MAXIMUM_MESSAGE_SIZE; + this->maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + this->socket_timeout=SOCKET_TIMEOUT; + this->lock_timeout=LOCK_TIMEOUT; this->overlap_mode=false; this->rmt_delivered=false; this->sync_channel=0; this->async_channel=0; + this->srq_lock=PTHREAD_MUTEX_INITIALIZER; // if (sem_init(&(this->srq_lock), 0, 1) !=0){ // perror(" HiSLIP srq_lock"); // } From 71a4ad36cdefa09edb846a5dbbe68292ff545009 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 11 Jul 2020 09:41:13 +0900 Subject: [PATCH 32/67] before merge --- asyn/drvAsynHiSLIP/README.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt index d35e2863f..978328970 100644 --- a/asyn/drvAsynHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/README.txt @@ -2,12 +2,17 @@ =============================================================================== Based on: + 1) IVI-6.1: IVI High-Speed LAN Instument Protocol Build Issues ============ - + HiSLIP portocol is implemented in HiSPLIPMessage.{cpp,h}. + cPyHiSLIP provides python module to access HiSLIP devices. It uses cython to wrap c/c++ librarlies. + It can be used without any componets from EPICS. + drvAsynHiSLIP provide asyOctet interface to access device. SRQ(IO Intr) is implemented also as asynOcted driver. So, only SI record can be used with SRQ. + Acknowledgements ================ This is based on USB TMC support by Eric Norum . From 5e6163210a1e614ae24d784a53a2694a043fc028 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 11 Jul 2020 18:59:00 +0900 Subject: [PATCH 33/67] SRQ handling bug fix --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 20 ++++------- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 33 +++++++------------ asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 31 +++++++++-------- 3 files changed, 36 insertions(+), 48 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 6e4b6667c..9f79de89e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -1,15 +1,3 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ #include "HiSLIPMessage.h" using nsHiSLIP::CC_request_t; @@ -149,6 +137,7 @@ namespace nsHiSLIP{ sizeof(msg_size), (u_int8_t *) &msg_size); msg.send(this->async_channel); + this->async_poll.revents=0; int ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; @@ -164,7 +153,7 @@ namespace nsHiSLIP{ return this->maximum_message_size; }; - int HiSLIP::device_clear(){ + int HiSLIP::device_clear(u_int8_t feature_request){ Message resp(AnyMessages); u_int8_t feature_preference; int ready,rc; @@ -176,6 +165,7 @@ namespace nsHiSLIP{ msg->send(this->async_channel); + this->async_poll.revents=0; ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; @@ -186,6 +176,7 @@ namespace nsHiSLIP{ // Error! } feature_preference=resp.control_code; + feature_preference &= feature_request; msg=new Message(nsHiSLIP::DeviceClearComplete, feature_preference, @@ -224,7 +215,8 @@ namespace nsHiSLIP{ } msg.send(this->async_channel); this->rmt_delivered = false; - + + this->async_poll.revents=0; ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index fd2d98ce7..1d4a2fb38 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -1,15 +1,3 @@ -/* - * ASYN support for HiSLIP - * - - *************************************************************************** - * Copyright (c) 2020 N. Yamamoto - * based on AsynUSBTMC supoort by - * Copyright (c) 2013 W. Eric Norum * - * This file is distributed subject to a Software License Agreement found * - * in the file LICENSE that is included with this distribution. * - *************************************************************************** - */ //-*- coding:utf-8 -*- #define NDEBUG 1 #define DEBUG 1 @@ -333,7 +321,7 @@ namespace nsHiSLIP{ return (ssize + ::send(socket, this->payload, this->payload_length,0)); } - ssize_t recv(int socket, Message_Types_t expected_message_type=AnyMessages){ + size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ size_t rsize; size_t status; @@ -368,7 +356,7 @@ namespace nsHiSLIP{ perror("payload read error:"); return -1; } - rsize +=status; + rsize += status; if (status >= bytestoread){ break; } @@ -381,11 +369,11 @@ namespace nsHiSLIP{ return 0; } // for debug - // this->print(); + //this->print(); if(this->message_type == nsHiSLIP::Error){ ::printf("Fatal Error: %d %s\n", - this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); + this->control_code, nsHiSLIP::Error_Messages[this->control_code]); if (this->payload_length >0){ ::printf("Error msg: %s\n", (char *) this->payload); } @@ -393,9 +381,9 @@ namespace nsHiSLIP{ } else if(this->message_type == nsHiSLIP::FatalError){ ::printf("Error: %d %s\n", - this->control_code, nsHiSLIP::Error_Messages[this->control_code]); + this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); if (this->payload_length >0){ - ::printf("Error msg: %s\n", (char *) this->payload); + ::printf("Fatal Error msg: %s\n", (char *) this->payload); } return -(this->control_code+1); } @@ -484,13 +472,15 @@ namespace nsHiSLIP{ int check_srq_lock(void); int check_and_lock_srq_lock(void); u_int8_t get_Service_Request(void){ - Message *msg=new Message(AnyMessages); + Message *msg=new Message(nsHiSLIP::AnyMessages); long status; - //this->request_srq_lock(); status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); + + // for debug + msg->print(); - if (status != 0){ + if ((status & 0x80000000) != 0){ // should handle Error/Fatal Error/Async Interrupted messages. perror(__FUNCTION__); } @@ -499,6 +489,7 @@ namespace nsHiSLIP{ }; int wait_for_SRQ(int wait_time){ + this->async_poll.revents=0; return ::poll(&this->async_poll, 1, wait_time); } diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index 7af0bcdd4..ce85b3c69 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -93,25 +93,22 @@ interruptThread(void *arg) { drvPvt *pdpvt = (drvPvt *)arg; int s; + assert(pdpvt); + if (pdpvt == NULL){ + errlogPrintf(" NULL drvPvt as an argument.\n"); + } while(true) { - s = pdpvt->device->wait_for_SRQ(65000); + s = pdpvt->device->wait_for_SRQ(60000); // wait for async-channel. if (s == 0){ errlogPrintf("timeout poll for async channel.\n"); continue; } - if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK) - break; - - if (s != 0 ){ - assert(pdpvt); - if (pdpvt == NULL){ - errlogPrintf(" NULL drvPvt as an argument.\n"); - } + if (s > 0 ){ u_int8_t stb = pdpvt->device->get_Service_Request(); errlogPrintf("Get SRQ with STB: 0x%2x\n", stb); - if (stb != 0){ // may need mask here. + if ((stb & 0x40) != 0){ // may need mask here. Just SRQ ELLLIST *pclientList; interruptNode *pnode; @@ -141,14 +138,22 @@ interruptThread(void *arg) ASYN_REASON_SRQ); } pnode = (interruptNode *)ellNext(&pnode->node); - } pasynManager->interruptEnd(pdpvt->asynOctetInterruptPvt); + stb = pdpvt->device->status_query(); errlogPrintf("Finish SRQ process 0x%2x\n", stb); } } + continue; } - } + else{ + errlogPrintf("srq poll return value:%d.\n",s); + } + if (epicsEventTryWait(pdpvt->pleaseTerminate) == epicsEventWaitOK){ + errlogPrintf("Terminate Interrupt Thread.\n"); + break; + } + }// while epicsMutexLock(pdpvt->interruptTidMutex); pdpvt->interruptTid = 0; epicsEventSignal(pdpvt->didTerminate); @@ -159,7 +164,7 @@ static void startInterruptThread(drvPvt *pdpvt) { epicsMutexLock(pdpvt->interruptTidMutex); - if ((pdpvt->interruptTid == 0)) { + if (pdpvt->interruptTid == 0) { epicsEventTryWait(pdpvt->pleaseTerminate); epicsEventTryWait(pdpvt->didTerminate); pdpvt->interruptTid = epicsThreadCreate(pdpvt->interruptThreadName, From 882c88dd91fdd2007a2ad57a979c487d9d90bcc6 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 11 Jul 2020 19:02:28 +0900 Subject: [PATCH 34/67] remove errlogPritf --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 32 ++----------------- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 6 +--- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 9f79de89e..f28287be9 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -84,7 +84,6 @@ namespace nsHiSLIP{ message_parameter((u_int16_t) nsHiSLIP::PROTOCOL_VERSION_MAX, (char *) Default_vendor_id), (u_int64_t) 0, (u_int8_t *) NULL); - // errlogPrintf("sending message %d \n", msg.message_type); msg.send(this->sync_channel); } @@ -225,7 +224,7 @@ namespace nsHiSLIP{ if (rc !=0){ //Error! } - resp.print(); + //resp.print(); status= resp.control_code &0xff; @@ -245,8 +244,6 @@ namespace nsHiSLIP{ size_t delivered=0; size_t count; - // errlogPrintf("HiSLIP::write sending data %s\n", data_str); - while(bytestosend){ if (bytestosend < max_payload_size){ Message msg(nsHiSLIP::DataEnd, @@ -254,7 +251,6 @@ namespace nsHiSLIP{ nsHiSLIP::message_parameter(this->message_id), bytestosend, (u_int8_t *) buffer); buffer += bytestosend; - // errlogPrintf("sending message %s\n",(char *) msg.payload); count=msg.send(this->sync_channel); this->rmt_delivered=false; count -=HEADER_SIZE; @@ -273,7 +269,6 @@ namespace nsHiSLIP{ delivered += count; buffer += max_payload_size; } - // errlogPrintf("data sent= %lu\n",count); this->increment_message_id(); } return delivered; @@ -283,8 +278,6 @@ namespace nsHiSLIP{ bool eom=false; size_t rsize=0; - // errlogPrintf("entered to HiSLIP::read(**buffer:%p, timeout:%ld)\n", - // buffer, timeout); *received=0; this->rmt_delivered = false; @@ -304,7 +297,6 @@ namespace nsHiSLIP{ return -1; } rsize=resp.recv(this->sync_channel); - // errlogPrintf("HiSLIP read rsize %ld\n",rsize); if (rsize < 0){ //Error!! return -2; @@ -322,7 +314,6 @@ namespace nsHiSLIP{ *received + resp.payload_length); if (newbuf == NULL){ - // errlogPrintf("Cannot extend memory area\n"); *buffer=NULL; return -3; } @@ -351,20 +342,13 @@ namespace nsHiSLIP{ bool eom=false; size_t rsize=0; - // errlogPrintf("entered to HiSLIP::read(buffer %p, bsize:%ld, timeout:%ld\n", - // buffer, bsize, timeout); *received=0; this->rmt_delivered = false; if (buffer==NULL || bsize <= 0){ - // errlogPrintf("exit HiSLIP::read improper input buffer:%p bsize:%lu, timeout:%ld\n", - // buffer, bsize, timeout); return -1; } if (bsize < this->maximum_payload_size){ - // errlogPrintf("exit HiSLIP::buffer size:%ld should be " - // "larger than maximum playload size:%ld \n", - // bsize, this->maximum_payload_size); } while(!eom) { int ready; @@ -373,27 +357,20 @@ namespace nsHiSLIP{ ready=::poll(&this->sync_poll, 1, timeout); if (ready == 0){ - // errlogPrintf("HiSLIP::read read timeout %d %ld \n", ready, lock_timeout); return -1; } rsize=resp.recv(this->sync_channel); if (rsize < 0){ - // errlogPrintf("read data too short %ld %qd \n", rsize, resp.payload_length); return -1; }; if (( (*received) + resp.payload_length) > bsize){ - // errlogPrintf("not enough space to store received:%ld resp.payload:%qd bsize:%ld\n", - // *received, resp.payload_length, bsize); - ::memcpy( (buffer + *received), resp.payload, (bsize - *received)); *received = bsize; return 0; } else{ - // errlogPrintf("received message size %ld %ld data:%s mt:%d\n", - // rsize, *received, (char *) resp.payload, resp.message_type); ::memcpy( (buffer + *received), resp.payload, resp.payload_length); *received +=resp.payload_length; @@ -404,13 +381,9 @@ namespace nsHiSLIP{ } else if (resp.message_type == nsHiSLIP::DataEnd){ eom=true; this->rmt_delivered=true; - // errlogPrintf("received message: %s %s ,eom:%d rmt:%d\n", - // buffer, (char *) resp.payload, eom,this->rmt_delivered); return 0; } else{ - // errlogPrintf("Unexpected message type:%d\n", - // resp.message_type); - resp.print(); + // resp.print(); // error unexpected message type. return -1; } @@ -425,7 +398,6 @@ namespace nsHiSLIP{ u_int8_t *buffer=NULL; int status; - // errlogPrintf("sending a command %s %lu",data_str, dsize); this->write(data_str, dsize); if(this->wait_for_answer(wait_time) == 0){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 1d4a2fb38..f287d3b0c 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -225,10 +225,6 @@ namespace nsHiSLIP{ ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); ::printf("payload length: %llu\n",this->payload_length); - // errlogPrintf("message type:%d\n",this->message_type); - // errlogPrintf("control_code:%d\n",this->control_code); - // errlogPrintf("message_parameter: 0x%0x\n",this->message_parameter.word); - // errlogPrintf("payload length: %qd\n",this->payload_length); } size_t send(int socket){ @@ -478,7 +474,7 @@ namespace nsHiSLIP{ status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); // for debug - msg->print(); + //msg->print(); if ((status & 0x80000000) != 0){ // should handle Error/Fatal Error/Async Interrupted messages. From 48493f6bc520f3e47cdbe2449f9f11cc88bbc6b6 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Wed, 15 Jul 2020 10:56:53 +0900 Subject: [PATCH 35/67] for PyPI upload --- asyn/drvAsynHiSLIP/cPyHiSLIP/.gitignore | 2 ++ asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST | 10 ++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST.in | 17 +++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile | 12 +++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt | 32 ++++++++++++++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 6 ++--- 6 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST.in create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/.gitignore b/asyn/drvAsynHiSLIP/cPyHiSLIP/.gitignore index 872447593..060bf7115 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/.gitignore +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/.gitignore @@ -1,3 +1,5 @@ +/build/ +/dist/ /cfg/ /bin/ /lib/ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST new file mode 100644 index 000000000..c079e4f11 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST @@ -0,0 +1,10 @@ +# file GENERATED by distutils, do NOT edit +HiSLIPMessage.cpp +HiSLIPMessage.h +MANIFEST.in +Makefile +README.rst +README.txt +cPyHiSLIP.pxd +cPyHiSLIP.pyx +setup.py diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST.in b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST.in new file mode 100644 index 000000000..bab5d4c47 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST.in @@ -0,0 +1,17 @@ +include MANIFEST.in +include setup.py +include Makefile +include README.rst +include HiSLIPMessage.h +include HiSLIPMessage.cpp +include cPyHiSLIP.pyx +include cPyHiSLIP.pxd +exclude cPyHiSLIP_*.* +include *.py +include *.txt +prune docs +prune build +prune dist +prune */build +prune ._* +exclude build/* diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile index 6836919f2..4241c187e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile @@ -1,13 +1,15 @@ #!make .phony: markdown -.SUFFIXES : .rst .md - +.SUFFIXES : .rst .md .txt .rst.md: /usr/local/bin/pandoc -f rst -t markdown -o $@ $< -markdown: README.md +.rst.txt: + /usr/local/bin/pandoc -f rst -t plain -o $@ $< + +markdown: README.md README.txt -# README.md: README.rst -# /usr/local/bin/pandoc -f rst -t markdown -o README.md README.rst +upload: + python3 -m twine upload dist/PyVXI11-$(shell hg parents --template '{latesttag}.{latesttagdistance}').tar.gz diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt new file mode 100644 index 000000000..70e178afd --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt @@ -0,0 +1,32 @@ +README for cPyHiSLIP + +Author + + 山本 昇 Noboru Yamamoto + +Organization + + 高エネルギー加速器研究機構 加速器研究施設 Accelerator Control Group, + Accelerator Laboratory, KEK, JAPAN J-PARCセンタ 加速器ディビジョン + 制御グループ Control Groups Accelerator Division JPARC Center + +Address + + 〒305-0801 茨城県つくば市大穂1-1 1-1 Oho Tsukuba, Ibaraki, JAPAN + 〒319-1195 茨城県那珂郡東海村大字白方2-4 J-PARC中央制御棟 2-4 + Shirakata, Tokai, Naka Ibaraki, 319-1195 JAPAN + +How to install + +you need cython to build cPyHiSLIP module from cPyHiSLIP.pyx and +cPyHiSLIP.pxd. If you dont have installed cython, try: + + pip install cython + +or + + python -m pip install cython + +To build and install the module, run: + + python setup.py install diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index 9631a80da..2e7f70597 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -2,9 +2,7 @@ """ Author:Noboru Yamamoto, KEK, Japan (c) 2020 -contact info: http://gofer.kek.jp/ -or https://plus.google.com/i/xW1BWwWsj3s:2rbmfOGOM4c - +contact info: https://souran.kek.jp/kss/top/ Revision Info: $Author: $ @@ -97,7 +95,7 @@ version=rev, author="Noboru Yamamoto, KEK, JAPAN", author_email = "Noboru.YAMAMOTO@kek.jp", - description='A Cython based Python module to control devices over HiSKIP protocol.', + description='A Cython based Python module to control devices over HiSLIP protocol.', url="http://www-cont.j-parc.jp/", classifiers=['Programming Language :: Python', 'Programming Language :: Cython', From 379533fbab62abdd0273edf232ccaac5732741d8 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sun, 19 Jul 2020 09:07:58 +0900 Subject: [PATCH 36/67] buffer allocation size was adjusted --- asyn/devGpib/devGpib.dbd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyn/devGpib/devGpib.dbd b/asyn/devGpib/devGpib.dbd index 2dbbe59a8..7190b542c 100644 --- a/asyn/devGpib/devGpib.dbd +++ b/asyn/devGpib/devGpib.dbd @@ -1 +1 @@ -device(ai,GPIB_IO,devGpib,"GPIB init/report") +device(ai, GPIB_IO, devGpib,"GPIB init/report") From 88e744aa6fa872b22a8037d7713bd813432a4b5d Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sun, 19 Jul 2020 09:08:22 +0900 Subject: [PATCH 37/67] buffer allocation size was adjusted --- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 57 ++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index ce85b3c69..9b6917ed7 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -225,17 +225,19 @@ report(void *pvt, FILE *fp, int details) showCount(fp, "Receive", pdpvt->bytesReceivedCount); // fprintf(fp, "HiSLIP device Info:\n"); - fprintf(fp, "%s: %x\n", "Terminator", pdpvt->termChar); - fprintf(fp, "HiSLIP device address:%s\n", + fprintf(fp, "\t" "%s: %lu\n", "maximum_message_size", pdpvt->device->maximum_message_size); + fprintf(fp, "\t" "%s: %lu\n", "maximum_payload_size", pdpvt->device->maximum_payload_size); + fprintf(fp, "\t" "%s: %x\n", "Terminator", pdpvt->termChar); + fprintf(fp, "\t" "HiSLIP device address:%s\n", pdpvt->hostname); - fprintf(fp, "overlap/sync. mode:%s\n", + fprintf(fp, "\t" "overlap/sync. mode:%s\n", pdpvt->device->overlap_mode?"ovelap":"synchronized"); - fprintf(fp, "Session ID:%d\n", + fprintf(fp, "\t" "Session ID:%d\n", pdpvt->device->session_id); - fprintf(fp, "server_protocol_version/server_vendorID : %#x %#x\n", + fprintf(fp, "\t" "server_protocol_version/server_vendorID : %#x %#x\n", pdpvt->device->server_protocol_version, pdpvt->device->server_vendorID); - fprintf(fp, "sync/async socket number %d/%d\n", + fprintf(fp, "\t" "sync/async socket number %d/%d\n", pdpvt->device->sync_channel, pdpvt->device->async_channel); fprintf(fp, "socket/locktime %ld/%ld\n", @@ -261,6 +263,7 @@ disconnectIfGone(drvPvt *pdpvt, asynUser *pasynUser, int s) static asynStatus connect(void *pvt, asynUser *pasynUser) { + long rstatus; drvPvt *pdpvt = (drvPvt *)pvt; if (!pdpvt->isConnected || (pdpvt->device == NULL)) { @@ -273,6 +276,12 @@ connect(void *pvt, asynUser *pasynUser) pdpvt->connectionCount +=1; // setup private buffer for read. + if (pdpvt->bufSize > 0){ + rstatus=pdpvt->device->set_max_size(pdpvt->bufSize); + } + else{ + rstatus=pdpvt->device->set_max_size(nsHiSLIP::MAXIMUM_MESSAGE_SIZE); + } pdpvt->bufSize=pdpvt->device->maximum_payload_size; if (pdpvt->bufSize <=0){ @@ -280,7 +289,8 @@ connect(void *pvt, asynUser *pasynUser) return asynError; } - pdpvt->buf=(unsigned char *)callocMustSucceed(1, + pdpvt->buf=(unsigned char *)callocMustSucceed( + 1, pdpvt->bufSize+1, pdpvt->portName); //ensure buffer ends with a null character. @@ -401,7 +411,7 @@ asynOctetRead(void *pvt, asynUser *pasynUser, assert(pdpvt->device); assert(nbytesTransfered); - if(eomReason) {*eomReason=eom=0;} + if(eomReason) {*eomReason=eom;} if(nbytesTransfered) {*nbytesTransfered = nout = 0;} // errlogPrintf("asynOctetRead timeout:%g host:%s maxchars:%ld bufCount:%ld reason:%x\n", @@ -421,7 +431,13 @@ asynOctetRead(void *pvt, asynUser *pasynUser, (u_int8_t *) pdpvt->buf, pdpvt->bufSize, timeout); - if (status != 0){ + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "HiSLIP-asynOctetRead" + " ioCount: %ld, buffer: %p, bffersize:%lu, timeout:%d status:%d\n", + ioCount, pdpvt->buf, pdpvt->bufSize, timeout, status); + + if (status != 0) { disconnectIfGone(pdpvt, pasynUser, 0); epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, @@ -433,9 +449,11 @@ asynOctetRead(void *pvt, asynUser *pasynUser, pdpvt->bufp=pdpvt->buf; pdpvt->bufCount = ioCount; pdpvt->bytesReceivedCount += ioCount; - errlogPrintf("asynOctetRead data:%s, " - "maxchars:%ld,nbytesTransfered:%ld, eomReason:%d\n", - data, maxchars, nout, eom); + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "HiSLIP-asynOctetRead data:%s, " + "maxchars:%ld, nbytesTransfered:%ld, eomReason:%d\n", + data, maxchars, nout, eom); } if (pdpvt->bufCount) { if (maxchars > pdpvt->bufCount){ @@ -596,6 +614,7 @@ static asynDrvUser drvUserMethods = { void HiSLIPConfigure(const char *portName, const char *hostInfo, + const int messagesize, int priority) { drvPvt *pdpvt; @@ -619,7 +638,8 @@ HiSLIPConfigure(const char *portName, strlen(hostInfo)+1, "HiSLIPConfigure"); strcpy(pdpvt->hostname, hostInfo); - + + pdpvt->bufSize=messagesize; pdpvt->termChar = 0; pdpvt->interruptTidMutex = epicsMutexMustCreate(); @@ -702,21 +722,26 @@ static const iocshArg HiSLIPConfigureArg0 = {"port name", iocshArgString}; static const iocshArg HiSLIPConfigureArg1 = {"HiSLIP host address", iocshArgString}; -static const iocshArg HiSLIPConfigureArg2 = {"priority", +static const iocshArg HiSLIPConfigureArg2 = {"MessageSize", + iocshArgInt}; +static const iocshArg HiSLIPConfigureArg3 = {"priority", iocshArgInt}; static const iocshArg *HiSLIPConfigureArgs[] = { &HiSLIPConfigureArg0 , &HiSLIPConfigureArg1 , &HiSLIPConfigureArg2 + , &HiSLIPConfigureArg3 }; static const iocshFuncDef HiSLIPConfigureFuncDef = - {"HiSLIPConfigure", 3, HiSLIPConfigureArgs}; + {"HiSLIPConfigure", 4, HiSLIPConfigureArgs}; static void HiSLIPConfigureCallFunc(const iocshArgBuf *args) { HiSLIPConfigure (args[0].sval, - args[1].sval, args[2].ival); + args[1].sval, + args[2].ival, + args[3].ival); } /* From 26aacafd1aa69952d2813210eaff24a70af6310a Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sun, 19 Jul 2020 09:09:12 +0900 Subject: [PATCH 38/67] buffer allocation size was adjusted --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 37 ++++++++++++++----- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 22 +++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 4 ++ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 20 ++++++++-- 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index f28287be9..4631bf332 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -124,6 +124,9 @@ namespace nsHiSLIP{ this->async_poll.fd=this->async_channel; this->async_poll.events=POLLIN; this->async_poll.revents=0; + + this->set_max_size(this->maximum_message_size); + }; long HiSLIP::set_max_size(long message_size){ @@ -149,6 +152,14 @@ namespace nsHiSLIP{ //The 8-byte buffer size is sent in network order as a 64-bit integer. this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; + if (message_size < maximum_message_size){ + this->current_message_size=message_size; + this->current_payload_size=message_size - HEADER_SIZE; + } + else{ + this->current_message_size = this->maximum_message_size; + this->current_payload_size = this->maximum_payload_size; + } return this->maximum_message_size; }; @@ -276,9 +287,8 @@ namespace nsHiSLIP{ long HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ bool eom=false; - size_t rsize=0; + long rstatus=0; - *received=0; this->rmt_delivered = false; if (*buffer == NULL){ @@ -296,12 +306,16 @@ namespace nsHiSLIP{ if ( ready == 0){ return -1; } - rsize=resp.recv(this->sync_channel); - if (rsize < 0){ + + rstatus=resp.recv(this->sync_channel); + if (rstatus < 0){ //Error!! return -2; }; + // ::printf("HiSLIP read() received status:%ld pay_load Size:%llu \n", + // rstatus, resp.payload_length); + // may not be a good idea to reallocate memory evertime. // 'message_parameter' should be checkd // aginst most_recent_message_id and overlap_mode @@ -338,9 +352,10 @@ namespace nsHiSLIP{ }; long HiSLIP::read(size_t *received, - u_int8_t *buffer, size_t bsize, long timeout){ + u_int8_t *buffer, size_t bsize, + long timeout){ bool eom=false; - size_t rsize=0; + long rstatus; *received=0; this->rmt_delivered = false; @@ -349,6 +364,7 @@ namespace nsHiSLIP{ return -1; } if (bsize < this->maximum_payload_size){ + ::printf("HiSLIP buffersize:%ld is smallerthan maximum_payload_size:%ld \n ",bsize,this->maximum_payload_size); } while(!eom) { int ready; @@ -360,9 +376,12 @@ namespace nsHiSLIP{ return -1; } - rsize=resp.recv(this->sync_channel); - - if (rsize < 0){ + rstatus=resp.recv(this->sync_channel); + + // ::printf("HiSLIP read() received status:%ld pay_load Size:%llu buffer size: %ld \n", + // rstatus, resp.payload_length, bsize); + + if (rstatus < 0){ return -1; }; if (( (*received) + resp.payload_length) > bsize){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index f287d3b0c..4e5c0eb22 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -77,7 +77,7 @@ namespace nsHiSLIP{ //Following VISA 256 bytes + header length 16 bytes static const long MAXIMUM_MESSAGE_SIZE_VISA = 272; - static const long MAXIMUM_MESSAGE_SIZE= 4096;//R&S accept more than this + static const long MAXIMUM_MESSAGE_SIZE= 8192;//R&S accept more than this static const long HEADER_SIZE=16; static const long SOCKET_TIMEOUT = 1000; //# Socket timeout in msec static const long LOCK_TIMEOUT = 3000;//# Lock timeout @@ -238,20 +238,24 @@ namespace nsHiSLIP{ } size_t recv(int socket){ - char buffer[HEADER_SIZE]; + unsigned char buffer[HEADER_SIZE]; + return this->recv(socket,buffer); + } + + size_t recv(int socket, void *buffer){ ssize_t rsize; //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - rsize= ::recvfrom(socket, buffer, HEADER_SIZE, 0, NULL, NULL); + rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, NULL, NULL); // rsize= ::read(socket, buffer, HEADER_SIZE); - + if (rsize < HEADER_SIZE){ //raise exception? return -1; } - else if (memcmp(this->prologue, buffer,2) != 0){ + + if (memcmp(this->prologue, buffer, 2) != 0){ return -1; } - this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); @@ -261,7 +265,7 @@ namespace nsHiSLIP{ } int fromRawData(void *buffer){ //DeSerialize - if (memcmp(this->prologue, buffer,2) != 0){ + if (memcmp(this->prologue, buffer, 2) != 0){ //error return -1; } @@ -389,8 +393,10 @@ namespace nsHiSLIP{ typedef class HiSLIP { public: - unsigned long maximum_message_size; + unsigned long maximum_message_size; // max message size server accept unsigned long maximum_payload_size; + unsigned long current_message_size; // current max message size setting + unsigned long current_payload_size; long socket_timeout; long lock_timeout; int sync_channel; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index b536954d5..64003d8da 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -28,6 +28,7 @@ cdef extern from "HiSLIPMessage.h": cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": + cdef const long MAXIMUM_MESSAGE_SIZE "nsHiSLIP::MAXIMUM_MESSAGE_SIZE" cdef char * Default_device_name "nsHiSLIP::Default_device_name" cdef int HiSLIPPort "nsHiSLIP::Default_Port" # not in /etc/services @@ -38,6 +39,9 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": cdef cppclass cHiSLIP "nsHiSLIP::HiSLIP": unsigned long maximum_message_size unsigned long maximum_payload_size + unsigned long current_message_size + unsigned long current_payload_size + int overlap_mode; u_int8_t feature_setting int session_id; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 625ef83f0..e9ef9499e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -20,6 +20,7 @@ cdef class HiSLIP: self.thisobj=new cHiSLIP() if host: self.thisobj.connect(host, Default_device_name, HiSLIPPort) + self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) def __dealloc__(self): del self.thisobj @@ -28,7 +29,8 @@ cdef class HiSLIP: def connect(self, host, device=Default_device_name, port=HiSLIPPort): debug("connect to {} {} {}".format(host,device, port)) self.thisobj.connect(host,device,port) - + self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) + def write(self, msg, long timeout=3000): self.thisobj.write(msg, len(msg), timeout) @@ -49,11 +51,11 @@ cdef class HiSLIP: else: if (buffer == NULL): raise RuntimeError("NULL pointer") - return (recieved, buffer) + return (recieved, buffer[:recieved]) # to avoid truncated string by \x00 in rawdata def read(self, long timeout=3000): recieved, buffer=self._cread(timeout) - # debug("cread result {} {}".format(recieved,len(buffer))) + debug("cread result {} {}".format(recieved,len(buffer))) return (recieved, buffer[:recieved]) def ask(self, msg, long wait_time=3000): @@ -80,7 +82,7 @@ cdef class HiSLIP: if (recieved & 0x8000000000000000L): return (-1,None) elif (recieved > 0 and (buffer != NULL)): - return (recieved, buffer) + return (recieved, buffer[:recieved]) else: return (recieved, None) @@ -117,6 +119,16 @@ cdef class HiSLIP: ms=self.thisobj.maximum_payload_size return ms + def get_message_size(self): + cdef size_t ms + ms=self.thisobj.current_message_size + return ms + + def get_payload_size(self): + cdef long ms + ms=self.thisobj.current_payload_size + return ms + def device_clear(self,int request=0): cdef long rc rc=self.thisobj.device_clear(request) From a5cdb328cbe9ba81ca2f13d5d5f371e84dac9040 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sun, 19 Jul 2020 13:32:50 +0900 Subject: [PATCH 39/67] set TCP_NODELAY to sockets --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 15 +++++++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 7 ++++--- asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile | 2 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 3 +-- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 4631bf332..ca57f233a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -60,7 +60,14 @@ namespace nsHiSLIP{ this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); - + { + int flag=1, reta, rets; + rets = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); + reta = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); + if ((rets == -1) || (reta == -1)){ + perror("Couldn't set sockopt(TCP_DELAY).\n"); + } + } if (res-> ai_addr == NULL || res->ai_addrlen == 0){ perror("empty addinfo"); freeaddrinfo(res); @@ -129,7 +136,7 @@ namespace nsHiSLIP{ }; - long HiSLIP::set_max_size(long message_size){ + long HiSLIP::set_max_size(unsigned long message_size){ Message resp(AnyMessages); u_int64_t msg_size=htobe64(message_size); @@ -152,7 +159,7 @@ namespace nsHiSLIP{ //The 8-byte buffer size is sent in network order as a 64-bit integer. this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; - if (message_size < maximum_message_size){ + if (message_size < this->maximum_message_size){ this->current_message_size=message_size; this->current_payload_size=message_size - HEADER_SIZE; } @@ -292,7 +299,7 @@ namespace nsHiSLIP{ *received=0; this->rmt_delivered = false; if (*buffer == NULL){ - *buffer=(u_int8_t *) calloc(1,this->maximum_message_size); + *buffer=(u_int8_t *) calloc(1,this->current_message_size); } if (*buffer == NULL){ perror("buffer allocation error"); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 4e5c0eb22..bb4e9d0d0 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -15,6 +15,7 @@ #include #include +#include #include #include // for MacOS @@ -415,8 +416,8 @@ namespace nsHiSLIP{ //sem_t srq_lock; pthread_mutex_t srq_lock; HiSLIP(){ - this->maximum_message_size=MAXIMUM_MESSAGE_SIZE; - this->maximum_payload_size=MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + this->maximum_message_size=this->current_message_size= MAXIMUM_MESSAGE_SIZE; + this->maximum_payload_size=this->current_payload_size= MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; this->socket_timeout=SOCKET_TIMEOUT; this->lock_timeout=LOCK_TIMEOUT; this->overlap_mode=false; @@ -452,7 +453,7 @@ namespace nsHiSLIP{ return this->lock_timeout; }; - long set_max_size(long message_size); + long set_max_size(unsigned long message_size); int device_clear(u_int8_t); u_int8_t status_query(void); //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile index 4241c187e..a58cd2a45 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile @@ -12,4 +12,4 @@ markdown: README.md README.txt upload: - python3 -m twine upload dist/PyVXI11-$(shell hg parents --template '{latesttag}.{latesttagdistance}').tar.gz + python3 -m twine upload dist/cPyHiSLIP-0.1.3.tar.gz diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index e9ef9499e..af6dc335a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -73,8 +73,7 @@ cdef class HiSLIP: cdef unsigned char **pbuffer=&buffer; cdef size_t recieved=0 cdef int rt - cdef size_t lmsg - #lmsg=len(msg) + recieved=self.thisobj.ask(msg, len(msg), pbuffer, wait_time) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index 2e7f70597..bf0565531 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -48,7 +48,7 @@ release=HGTag #rev=HGTag[HGTag.index(":")+1:HGTag.index("-")].strip() #rev=HGTagShort.strip() -rev="0.1.1" +rev="0.1.4" # sysname=platform.system() From cfe7d5b04d838aa40cf6200e964d490b87f1dba9 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Mon, 20 Jul 2020 11:06:33 +0900 Subject: [PATCH 40/67] send whole message with one socket.send call. --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 11 +++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 16 +++++++++++----- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 4 ++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index ca57f233a..8c45999b7 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -55,19 +55,22 @@ namespace nsHiSLIP{ exit (9999); } - //this->sync_channel= ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - //this->async_channel=::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - this->sync_channel= ::socket(AF_INET, SOCK_STREAM , 0); this->async_channel=::socket(AF_INET, SOCK_STREAM , 0); + // now Message::send put both header portion and pyload portion as single transaction. So we dont need to use this + // portion of codes(?). +# ifdef USE_TCP_NODELAY { + // disable the Nagle algorithm on socket to improve responce with small packet size + // this may increase number of small packets. So may degrade overall network performance. int flag=1, reta, rets; rets = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); reta = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); if ((rets == -1) || (reta == -1)){ - perror("Couldn't set sockopt(TCP_DELAY).\n"); + perror("Couldn't set sockopt(TCP_DELAY).\n"); } } +# endif if (res-> ai_addr == NULL || res->ai_addrlen == 0){ perror("empty addinfo"); freeaddrinfo(res); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index bb4e9d0d0..0b65d6f22 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -315,11 +315,17 @@ namespace nsHiSLIP{ } size_t send(int socket){ size_t ssize; - ssize=this->Header::send(socket); - if (ssize < HEADER_SIZE){ - return -1; - } - return (ssize + ::send(socket, this->payload, this->payload_length,0)); + // ssize=this->Header::send(socket); + // if (ssize < HEADER_SIZE){ + // return -1; + // } + // return (ssize + ::send(socket, this->payload, this->payload_length,0)); + u_int8_t *buffer = (u_int8_t *) calloc(sizeof(Header)+this->payload_length, 1); + this->toRawData(buffer); + memcpy(buffer+sizeof(Header),this->payload, this->payload_length); + ssize= ::send(socket, buffer, sizeof(Header)+this->payload_length,0); + free(buffer); + return ssize; } size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index bf0565531..580b07a90 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -79,8 +79,8 @@ ,depends=["cPyHiSLIP.pxd"] # Cython interface file ,language="c++" ,cython_cplus=True - ,undef_macros=[] #["CFLAGS"] - ,define_macros=[] + ,undef_macros=[] # ["CFLAGS"] + ,define_macros=[] # [("USE_TCP_NODELAY",1)] ,extra_compile_args=["-std=gnu++11", "-O3"], )) From cf0fa12cc361b8c1b3f968ea46cd2b45145df5ca Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Wed, 22 Jul 2020 18:30:17 +0900 Subject: [PATCH 41/67] USE_TCP_NODLAY envrionment variable is instroduced but not used as default --- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index 580b07a90..c755ca2a4 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -79,7 +79,7 @@ ,depends=["cPyHiSLIP.pxd"] # Cython interface file ,language="c++" ,cython_cplus=True - ,undef_macros=[] # ["CFLAGS"] + ,undef_macros =[] # ["CFLAGS"] ,define_macros=[] # [("USE_TCP_NODELAY",1)] ,extra_compile_args=["-std=gnu++11", "-O3"], )) From edfa0768cff52e72b85d2eb784f27b31489fd253 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 24 Jul 2020 10:00:11 +0900 Subject: [PATCH 42/67] apply nogil where appropriate --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 20 +----- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 64 +++++++++++++------ 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 8c45999b7..2a1c57689 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -548,15 +548,8 @@ namespace nsHiSLIP{ return -1; } }; + int HiSLIP::check_srq_lock(void){ - // int sval; - // if (sem_getvalue(&(this->srq_lock),&sval) == 0){ - // return sval; - // } - // else { - // perror("check_srq_lock"); - // return -1; - // } int rc=pthread_mutex_trylock(&(this->srq_lock)); if (rc == 0){ pthread_mutex_unlock(&(this->srq_lock)); @@ -570,17 +563,6 @@ namespace nsHiSLIP{ } int HiSLIP::check_and_lock_srq_lock(void){ - // int rc=sem_trywait(&(this->srq_lock)); - // switch (rc){ - // case 0: - // break; - // case EAGAIN: - // break; - // default: - // perror("check_and_lock_srq_lock"); - // } - // return rc; - int rc=pthread_mutex_trylock(&(this->srq_lock)); switch (rc){ case 0: diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index af6dc335a..9d1edff72 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -16,8 +16,10 @@ from logging import info,debug,warn,log,fatal cdef class HiSLIP: cdef cHiSLIP *thisobj - def __cinit__(self,host=None): + def __cinit__(self): self.thisobj=new cHiSLIP() + + def __init__(self, host=None): if host: self.thisobj.connect(host, Default_device_name, HiSLIPPort) self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) @@ -30,7 +32,14 @@ cdef class HiSLIP: debug("connect to {} {} {}".format(host,device, port)) self.thisobj.connect(host,device,port) self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) - + + @property + def session_id(self): + """ + a getter function for the property session_id. + """ + return self.thisobj.session_id + def write(self, msg, long timeout=3000): self.thisobj.write(msg, len(msg), timeout) @@ -100,12 +109,14 @@ cdef class HiSLIP: def get_lock_timeout(self): cdef long to - to=self.thisobj.get_lock_timeout() + with nogil: + to=self.thisobj.get_lock_timeout() return to def set_max_message_size(self, size_t message_size): cdef long ms - ms=self.thisobj.set_max_size(message_size) + with nogil: + ms=self.thisobj.set_max_size(message_size) return ms def get_max_message_size(self): @@ -130,7 +141,8 @@ cdef class HiSLIP: def device_clear(self,int request=0): cdef long rc - rc=self.thisobj.device_clear(request) + with nogil: + rc=self.thisobj.device_clear(request) return rc def status_query(self): @@ -146,12 +158,14 @@ cdef class HiSLIP: 7 128 Operation Status Register (OPER) """ cdef u_int8_t rc - rc=self.thisobj.status_query() + with nogil: + rc=self.thisobj.status_query() return rc def trigger_message(self): cdef long rc - rc=self.thisobj.trigger_message() + with nogil: + rc=self.thisobj.trigger_message() return rc def remote_local(self, u_int8_t request): @@ -167,9 +181,8 @@ cdef class HiSLIP: """ cdef long rc #cdef u_int8_t _request=request - - rc=self.thisobj.remote_local(request) - + with nogil: + rc=self.thisobj.remote_local(request) return rc def request_lock(self, char * lock_string): @@ -181,8 +194,8 @@ cdef class HiSLIP: """ cdef long rc #cdef char *_lock_string=lock_string - - rc=self.thisobj.request_lock(lock_string) + with nogil: + rc=self.thisobj.request_lock(lock_string) return rc @@ -194,23 +207,30 @@ cdef class HiSLIP: 3 - Error """ cdef long rc - rc=self.thisobj.release_lock() + with nogil: + rc=self.thisobj.release_lock() return rc def request_srq_lock(self): """ - Not implemented in .cpp yet. + implemented in HiSLIPMessage.cpp. + rc :0 success + :others error """ cdef long rc=-1 - rc=self.thisobj.request_srq_lock() + with nogil: + rc=self.thisobj.request_srq_lock() return rc def release_srq_lock(self): """ Not implemented in .cpp yet. + 0: success + other: error """ cdef long rc=-1 - rc=self.thisobj.release_srq_lock() + with nogil: + rc=self.thisobj.release_srq_lock() return rc def check_srq_lock(self): @@ -220,7 +240,8 @@ cdef class HiSLIP: -1: """ cdef int rc=-1 - rc=self.thisobj.check_srq_lock() + with nogil: + rc=self.thisobj.check_srq_lock() return rc def check_and_lock_srq_lock(self): @@ -229,7 +250,8 @@ cdef class HiSLIP: 0: already locked """ cdef int rc - rc=self.thisobj.check_and_lock_srq_lock() + with nogil: + rc=self.thisobj.check_and_lock_srq_lock() return rc def get_overlap_mode(self): @@ -248,12 +270,14 @@ cdef class HiSLIP: def get_Service_Request(self): cdef u_int8_t rc=0 - rc=self.thisobj.get_Service_Request() + with nogil: + rc=self.thisobj.get_Service_Request() return rc def wait_for_SRQ(self, long wait_time): cdef int rc=-1 - rc=self.thisobj.wait_for_SRQ(wait_time) + with nogil: + rc=self.thisobj.wait_for_SRQ(wait_time) return rc cdef class enumType: From 901a93a9a622546019a9e4115350c090b6169a26 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 24 Jul 2020 12:45:40 +0900 Subject: [PATCH 43/67] patches memoleaks. --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 5 +++-- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 17 +++++++++++++- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 2 ++ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 22 +++++++++++++++++-- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 1 - 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 2a1c57689..5f640cd11 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -311,7 +311,7 @@ namespace nsHiSLIP{ while(!eom) { int ready; Message resp(AnyMessages); - + ready=poll(&this->sync_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; @@ -434,7 +434,7 @@ namespace nsHiSLIP{ buffer=NULL; return -1; }; - status=this->read(&rsize, &buffer, wait_time); + status=this->read(&rsize, &buffer, wait_time); // read will allocate memory area pointed by buffer. if (status !=0){ rsize=-1; } @@ -442,6 +442,7 @@ namespace nsHiSLIP{ *rbuffer=buffer; } else { + if (buffer != NULL) free(buffer); buffer=NULL; } return rsize; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 0b65d6f22..5eeaf1f75 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -290,16 +290,28 @@ namespace nsHiSLIP{ typedef class Message:public Header{ public: void *payload; - + int clean_on_exit; + + ~Message(){ + if ((this->payload != NULL) && (this->clean_on_exit==1)){ + ::free(this->payload); + this->payload=NULL; + this->clean_on_exit=0; + } + }; + Message(Message_Types_t message_type):Header(message_type){ this->payload=NULL; + this->clean_on_exit=0; }; Message(void *raw_header):Header(raw_header){ this->payload=NULL; + this->clean_on_exit=0; //this->fromRawData(raw_header); }; Message(void *raw_header, void *payload):Message(raw_header){ this->payload = calloc(this->payload_length, 1); + this->clean_on_exit=1; if (this->payload != NULL){ memcpy(this->payload, payload, this->payload_length); }; @@ -309,6 +321,7 @@ namespace nsHiSLIP{ message_parameter_t param, u_int64_t length, u_int8_t *payload):Header(type,cce,param,length),payload(payload) { + this->clean_on_exit=0; //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); //memcpy(this->payload, payload, length); //this->payload = payload; @@ -345,6 +358,7 @@ namespace nsHiSLIP{ perror("faile to allocate memory for payload."); return -1; } + this->clean_on_exit=1; } rsize=0; //returns size of recieved payload. should be same as payload_length @@ -396,6 +410,7 @@ namespace nsHiSLIP{ } return -1; } + } Message_t; typedef class HiSLIP { diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 64003d8da..80dca8359 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -5,6 +5,8 @@ cdef int SCPIRawSocketPort=5025 # both udp/tcp cdef int SCPITelnetPort=5024 # both udp/tcp +cdef extern from "stdlib.h": + cdef void free (void *) cdef extern from "HiSLIPMessage.h": # you don’t need to match the type exactly, diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 9d1edff72..8cc44a811 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -52,15 +52,27 @@ cdef class HiSLIP: # debug("calling read in c++") rt=self.thisobj.read(precieved, pbuffer, timeout) if rt == -1: + if (buffer != NULL): + free(buffer) + buffer=NULL raise RuntimeError("Timeout") elif rt < 0: + if (buffer != NULL): + free(buffer) + buffer=NULL raise RuntimeError if recieved == 0: + if (buffer != NULL): + free(buffer) + buffer=NULL return (recieved, None) else: if (buffer == NULL): raise RuntimeError("NULL pointer") - return (recieved, buffer[:recieved]) # to avoid truncated string by \x00 in rawdata + rval=(recieved, buffer[:recieved]) # to avoid truncated string by \x00 in rawdata + free(buffer) + buffer=NULL + return rval def read(self, long timeout=3000): recieved, buffer=self._cread(timeout) @@ -88,9 +100,15 @@ cdef class HiSLIP: wait_time) debug("_ask recieved: {}".format(hex(recieved))) if (recieved & 0x8000000000000000L): + if (buffer != NULL): + free(buffer) + buffer=NULL return (-1,None) elif (recieved > 0 and (buffer != NULL)): - return (recieved, buffer[:recieved]) + rval=(recieved, buffer[:recieved]) + free(buffer) + buffer=NULL + return rval else: return (recieved, None) diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index 9b6917ed7..534b1141d 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -315,7 +315,6 @@ static asynStatus disconnect(void *pvt, asynUser *pasynUser) int pass = 0; epicsThreadId tid; for (;;) { - epicsMutexLock(pdpvt->interruptTidMutex); tid = pdpvt->interruptTid; epicsMutexUnlock(pdpvt->interruptTidMutex); From 3d5cd5886a683c9dd8c5fb06e6792666b6b6d414 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 24 Jul 2020 15:42:10 +0900 Subject: [PATCH 44/67] more nogis --- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 41 +++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 8cc44a811..8cd9271b2 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -20,18 +20,24 @@ cdef class HiSLIP: self.thisobj=new cHiSLIP() def __init__(self, host=None): + cdef char *chost=host if host: - self.thisobj.connect(host, Default_device_name, HiSLIPPort) - self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) + with nogil: + self.thisobj.connect(chost, Default_device_name, HiSLIPPort) + self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) def __dealloc__(self): del self.thisobj pass def connect(self, host, device=Default_device_name, port=HiSLIPPort): + cdef char *chost=host + cdef char *cdevice =device + cdef int cport =port debug("connect to {} {} {}".format(host,device, port)) - self.thisobj.connect(host,device,port) - self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) + with nogil: + self.thisobj.connect(chost,cdevice,cport) + self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) @property def session_id(self): @@ -41,7 +47,10 @@ cdef class HiSLIP: return self.thisobj.session_id def write(self, msg, long timeout=3000): - self.thisobj.write(msg, len(msg), timeout) + cdef u_int8_t *cmsg=msg + cdef size_t ssize=len(msg) + with nogil: + self.thisobj.write(cmsg, ssize, timeout) cdef _cread(self,long timeout=3000): cdef unsigned char *buffer=NULL @@ -50,7 +59,8 @@ cdef class HiSLIP: cdef size_t *precieved=&recieved cdef int rt # debug("calling read in c++") - rt=self.thisobj.read(precieved, pbuffer, timeout) + with nogil: + rt=self.thisobj.read(precieved, pbuffer, timeout) if rt == -1: if (buffer != NULL): free(buffer) @@ -94,10 +104,12 @@ cdef class HiSLIP: cdef unsigned char **pbuffer=&buffer; cdef size_t recieved=0 cdef int rt - - recieved=self.thisobj.ask(msg, len(msg), - pbuffer, - wait_time) + cdef size_t msgsz=len(msg) + + with nogil: + recieved=self.thisobj.ask(msg, msgsz, + pbuffer, + wait_time) debug("_ask recieved: {}".format(hex(recieved))) if (recieved & 0x8000000000000000L): if (buffer != NULL): @@ -113,16 +125,19 @@ cdef class HiSLIP: return (recieved, None) def set_timeout(self,long timeout): - self.thisobj.set_timeout(timeout) + with nogil: + self.thisobj.set_timeout(timeout) return def get_timeout(self): cdef long to - to=self.thisobj.get_timeout() + with nogil: + to=self.thisobj.get_timeout() return to def set_lock_timeout(self, long to): - self.thisobj.set_lock_timeout(to) + with nogil: + self.thisobj.set_lock_timeout(to) return def get_lock_timeout(self): From 2bf9458034568a108e16141f6cd54d769925ac24 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 25 Jul 2020 13:04:51 +0900 Subject: [PATCH 45/67] prepare for push --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 26 +++++++++++++++----- asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST | 1 + asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile | 2 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 2 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 21 +++++++++++++--- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 5eeaf1f75..ee26eacb2 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -68,7 +68,7 @@ namespace nsHiSLIP{ fail=0, //Lock was requested but not granted success=1, //release of exclusive lock success_shared=2, //release of shared lock - error=3 // Invalide + error=3 // Invalid } CC_LockResponse_t; static const long PROTOCOL_VERSION_MAX = 0x7f7f ; // # = <1><1> that is 257 @@ -222,7 +222,7 @@ namespace nsHiSLIP{ this->payload_length=length; } void print(void){ - ::printf("message type:%d\n",this->message_type); + ::printf("message type:%d\n",this->message_type,); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); ::printf("payload length: %llu\n",this->payload_length); @@ -423,6 +423,7 @@ namespace nsHiSLIP{ long lock_timeout; int sync_channel; int async_channel; + pthread_mutex_t async_lock; struct pollfd sync_poll; struct pollfd async_poll; int overlap_mode; @@ -446,6 +447,8 @@ namespace nsHiSLIP{ this->rmt_delivered=false; this->sync_channel=0; this->async_channel=0; + this->async_lock=PTHREAD_MUTEX_INITIALIZER; + // this->srq_lock=PTHREAD_MUTEX_INITIALIZER; // if (sem_init(&(this->srq_lock), 0, 1) !=0){ // perror(" HiSLIP srq_lock"); @@ -456,6 +459,7 @@ namespace nsHiSLIP{ Default_device_name, Default_Port); }; + void connect(char const* hostname, char const* dev_name, int port); @@ -463,9 +467,11 @@ namespace nsHiSLIP{ void set_timeout( long timeout){ this->socket_timeout=timeout; }; + long get_timeout(void){ return this->socket_timeout; }; + void set_lock_timeout( long timeout){ this->lock_timeout=timeout; } @@ -495,6 +501,7 @@ namespace nsHiSLIP{ long release_srq_lock(void); int check_srq_lock(void); int check_and_lock_srq_lock(void); + // u_int8_t get_Service_Request(void){ Message *msg=new Message(nsHiSLIP::AnyMessages); long status; @@ -502,17 +509,21 @@ namespace nsHiSLIP{ status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); // for debug - //msg->print(); + // msg->print(); if ((status & 0x80000000) != 0){ // should handle Error/Fatal Error/Async Interrupted messages. perror(__FUNCTION__); + msg->print(); + return 0; + } + else{ + this->release_srq_lock(); + return msg->control_code; } - this->release_srq_lock(); - return msg->control_code; }; - int wait_for_SRQ(int wait_time){ + int wait_for_Async(int wait_time){ this->async_poll.revents=0; return ::poll(&this->async_poll, 1, wait_time); } @@ -525,6 +536,9 @@ namespace nsHiSLIP{ close(this->async_channel); }; }; + + void Fatal_Error_handler(Message *msg); + void Error_handler(Message *msg); private: int wait_for_answer(int wait_time){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST index c079e4f11..0d427c0e4 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST @@ -7,4 +7,5 @@ README.rst README.txt cPyHiSLIP.pxd cPyHiSLIP.pyx +memleak_test.py setup.py diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile index a58cd2a45..53ed7aa9b 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile @@ -12,4 +12,4 @@ markdown: README.md README.txt upload: - python3 -m twine upload dist/cPyHiSLIP-0.1.3.tar.gz + python3 -m twine upload dist/cPyHiSLIP-0.1.4.tar.gz diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 80dca8359..6f5ff8efb 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -78,6 +78,6 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int check_srq_lock() nogil int check_and_lock_srq_lock() nogil u_int8_t get_Service_Request() nogil - int wait_for_SRQ(int) nogil + int wait_for_Async(int) nogil void disconnect() nogil diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 8cd9271b2..554b1d5bc 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -10,7 +10,7 @@ from cPyHiSLIP cimport cHiSLIP #from cPyHiSLIP cimport HiSLIPPort #from cPyHiSLIP cimport Default_device_name import logging -from logging import info,debug,warn,log,fatal +from logging import info,debug,warn,log,fatal,warning #logging.root.setLevel(logging.DEBUG) cdef class HiSLIP: @@ -307,12 +307,25 @@ cdef class HiSLIP: rc=self.thisobj.get_Service_Request() return rc - def wait_for_SRQ(self, long wait_time): + def wait_for_Async(self, long wait_time): cdef int rc=-1 with nogil: - rc=self.thisobj.wait_for_SRQ(wait_time) + rc=self.thisobj.wait_for_Async(wait_time) return rc - + + def run_svc(self,wait=1000): + cdef int rc=-1 + cdef u_int8_t st + cdef int cwait=wait + with nogil: + while 1: + rc=self.thisobj.wait_for_Async(cwait) # msec , wait_for_SRQ does not release GIL so we use shorter time + if rc: + st=self.thisobj.get_Service_Request() # will release lock + if not self.thisobj.session_id: + break + return + cdef class enumType: @classmethod def getKey(cls, v): From cb6ecd8132f9cacfd53057f1b03a277f78acb80f Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 31 Jul 2020 10:06:22 +0900 Subject: [PATCH 46/67] add wait_service_request --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 44 +++++++++++++++++++- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 1 + asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 10 +++++ asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 2 +- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index ee26eacb2..cf9eaae53 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -19,6 +19,9 @@ #include #include // for MacOS +#include +using namespace std::chrono; + //#include #ifdef __linux__ @@ -222,7 +225,7 @@ namespace nsHiSLIP{ this->payload_length=length; } void print(void){ - ::printf("message type:%d\n",this->message_type,); + ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); ::printf("payload length: %llu\n",this->payload_length); @@ -523,6 +526,45 @@ namespace nsHiSLIP{ } }; + u_int8_t wait_Service_Request(int wait_time){ + using FpMilliseconds = + std::chrono::duration; + + static_assert(std::chrono::treat_as_floating_point::value, + "Rep required to be floating point"); + + steady_clock::time_point clk_begin = steady_clock::now(); + + Message *msg=new Message(nsHiSLIP::AnyMessages); + long status; + + this->async_poll.revents=0; + while (::poll(&this->async_poll, 1, wait_time > 0)){ + steady_clock::time_point clk_now = steady_clock::now(); + // Note that implicit conversion is allowed here + auto time_spent = FpMilliseconds(clk_now - clk_begin); + status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); + // for debug + // msg->print(); + + if ((status & 0x80000000) != 0){ + // should handle Error/Fatal Error/Async Interrupted messages. + perror(__FUNCTION__); + msg->print(); + wait_time -= (time_spent.count()); + if (wait_time <= 0){ + return 0xff; + } + continue; + } + else{ + this->release_srq_lock(); + return msg->control_code; + }; + }; + return 0xfe; + }; + int wait_for_Async(int wait_time){ this->async_poll.revents=0; return ::poll(&this->async_poll, 1, wait_time); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 6f5ff8efb..551c0ed70 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -78,6 +78,7 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int check_srq_lock() nogil int check_and_lock_srq_lock() nogil u_int8_t get_Service_Request() nogil + u_int8_t wait_Service_Request(int wait_time) nogil int wait_for_Async(int) nogil void disconnect() nogil diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 554b1d5bc..80d15032d 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -191,8 +191,10 @@ cdef class HiSLIP: 7 128 Operation Status Register (OPER) """ cdef u_int8_t rc + with nogil: rc=self.thisobj.status_query() + return rc def trigger_message(self): @@ -306,6 +308,14 @@ cdef class HiSLIP: with nogil: rc=self.thisobj.get_Service_Request() return rc + + def wait_Service_Request(self, int wait_time): + cdef u_int8_t rc=0 + + with nogil: + rc=self.thisobj.wait_Service_Request(wait_time) + + return rc def wait_for_Async(self, long wait_time): cdef int rc=-1 diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index 534b1141d..c0b36606d 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -99,7 +99,7 @@ interruptThread(void *arg) } while(true) { - s = pdpvt->device->wait_for_SRQ(60000); // wait for async-channel. + s = pdpvt->device->wait_for_Async(60000); // wait for async-channel. if (s == 0){ errlogPrintf("timeout poll for async channel.\n"); From 90c92c2cacc41cab4d0af2f567c7edaa886b24e1 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 31 Jul 2020 18:17:17 +0900 Subject: [PATCH 47/67] in wait_Service_request, accept anyMessages type then check it --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index cf9eaae53..003994701 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -539,15 +539,20 @@ namespace nsHiSLIP{ long status; this->async_poll.revents=0; - while (::poll(&this->async_poll, 1, wait_time > 0)){ + while (::poll(&this->async_poll, 1, wait_time ) > 0){ steady_clock::time_point clk_now = steady_clock::now(); // Note that implicit conversion is allowed here auto time_spent = FpMilliseconds(clk_now - clk_begin); - status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); + //status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); + status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); // for debug - // msg->print(); + //msg->print(); - if ((status & 0x80000000) != 0){ + if (msg->message_type == nsHiSLIP::AsyncServiceRequest) { + this->release_srq_lock(); + return msg->control_code; + } + else if ((status & 0x80000000) != 0){ // should handle Error/Fatal Error/Async Interrupted messages. perror(__FUNCTION__); msg->print(); @@ -556,10 +561,6 @@ namespace nsHiSLIP{ return 0xff; } continue; - } - else{ - this->release_srq_lock(); - return msg->control_code; }; }; return 0xfe; From f82b78918728a1176f8afd6cf687acc382b6677b Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sun, 2 Aug 2020 19:50:27 +0900 Subject: [PATCH 48/67] rearange locations of method definitions between .cpp an .h --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 152 ++++++++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 152 ++---------------- 2 files changed, 169 insertions(+), 135 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 5f640cd11..60f478679 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -12,6 +12,76 @@ using nsHiSLIP::Message_t; // HiSLIP methods namespace nsHiSLIP{ + size_t Message::recv(int socket, Message_Types_t expected_message_type){ + size_t rsize; + size_t status; + + status=this->Header::recv(socket); + if (status < 0){ + // Error! + return status; + } + + // now prepare for a pyload. + if (this->payload == NULL && this->payload_length > 0){ + this->payload = (void *) calloc(this->payload_length,1); + if (this->payload == NULL){ + perror("faile to allocate memory for payload."); + return -1; + } + this->clean_on_exit=1; + } + + rsize=0; //returns size of recieved payload. should be same as payload_length + if (this->payload_length > 0){ + size_t bytestoread=this->payload_length; + + while (bytestoread){ + // status = ::recv(socket, ((u_int8_t *)this->payload+rsize), + // bytestoread, 0); + status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), + bytestoread, 0, NULL, NULL); + // status = ::read(socket, ((u_int8_t *)this->payload+rsize), + // bytestoread); + + if (status <= 0){ + perror("payload read error:"); + return -1; + } + rsize += status; + if (status >= bytestoread){ + break; + } + bytestoread -=status; + } + } + // check if expected type or not + if((expected_message_type == AnyMessages) || + (expected_message_type == this->message_type)){ + return 0; + } + // for debug + //this->print(); + + if(this->message_type == nsHiSLIP::Error){ + ::printf("Fatal Error: %d %s\n", + this->control_code, nsHiSLIP::Error_Messages[this->control_code]); + if (this->payload_length >0){ + ::printf("Error msg: %s\n", (char *) this->payload); + } + return -(this->control_code+1); + } + else if(this->message_type == nsHiSLIP::FatalError){ + ::printf("Error: %d %s\n", + this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); + if (this->payload_length >0){ + ::printf("Fatal Error msg: %s\n", (char *) this->payload); + } + return -(this->control_code+1); + } + return -1; + } + void HiSLIP::connect(const char *hostname, const char *dev_name, const int port //, @@ -575,5 +645,87 @@ namespace nsHiSLIP{ return -1; } } + u_int8_t HiSLIP::get_Service_Request(void){ + Message *msg=new Message(nsHiSLIP::AnyMessages); + long status; + + status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); + + // for debug + // msg->print(); + + if ((status & 0x80000000) != 0){ + // should handle Error/Fatal Error/Async Interrupted messages. + perror(__FUNCTION__); + msg->print(); + return 0; + } + else{ + this->release_srq_lock(); + return msg->control_code; + } + }; + u_int8_t HiSLIP::wait_Service_Request(int wait_time){ + using FpMilliseconds = + std::chrono::duration; + + static_assert(std::chrono::treat_as_floating_point::value, + "Rep required to be floating point"); + + steady_clock::time_point clk_begin = steady_clock::now(); + + Message *msg=new Message(nsHiSLIP::AnyMessages); + long status; + + this->async_poll.revents=0; + while (::poll(&this->async_poll, 1, wait_time ) ){ + steady_clock::time_point clk_now = steady_clock::now(); + // Note that implicit conversion is allowed here + auto time_spent = FpMilliseconds(clk_now - clk_begin); + status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); + //msg->print(); // for debug + + switch (msg->message_type ){ + case nsHiSLIP::AsyncServiceRequest: + this->release_srq_lock(); + return msg->control_code; + case nsHiSLIP::FatalError: + case nsHiSLIP::Error: + perror(__FUNCTION__); + msg->print(); // for debug + case nsHiSLIP::AsyncLockResponse: + case nsHiSLIP::AsyncRemoteLocalResponse: + case nsHiSLIP::AsyncStatusResponse: + case nsHiSLIP::AsyncMaximumMessageSizeResponse: + case nsHiSLIP::AsyncDeviceClearAcknowledge: + case nsHiSLIP::AsyncLockInfoResponse: + case nsHiSLIP::AsyncStartTLSResponse: + case nsHiSLIP::AsyncEndTLSResponse: + + default: + wait_time -= (time_spent.count()); + if (wait_time <= 0){ + return 0xff; + } + break; + } + continue; // wile-loop. + // if (msg->message_type == nsHiSLIP::AsyncServiceRequest) { + // this->release_srq_lock(); + // return msg->control_code; + // } + // else if ((status & 0x80000000) != 0){ + // // should handle Error/Fatal Error/Async Interrupted messages. + // perror(__FUNCTION__); + // msg->print(); + // wait_time -= (time_spent.count()); + // if (wait_time <= 0){ + // return 0xff; + // } + // continue; + // }; + }; + return 0xfe; + }; } // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 003994701..ae74fc522 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -26,7 +26,7 @@ using namespace std::chrono; #ifdef __linux__ # include // network endian is "be". -#else +#else // i.e. macOSX inline u_int64_t htobe64(u_int64_t q) { return (htonl(q>>32) +((u_int64_t)htonl(q & 0x00000000ffffffff)<<32)) ; }; @@ -205,10 +205,11 @@ namespace nsHiSLIP{ u_int8_t control_code; message_parameter_t message_parameter; u_int64_t payload_length; - + // Header(Message_Types_t message_type):control_code(0),message_parameter(0),payload_length(0){ this->message_type=message_type; } + // Header(const void *buffer):message_parameter(0){ assert(memcmp(this->prologue, buffer,2) == 0); this->message_type=*((u_int8_t *) ((char *) buffer+2)); @@ -216,6 +217,7 @@ namespace nsHiSLIP{ this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); } + // Header(const u_int8_t type, const u_int8_t cce, const message_parameter_t param, @@ -224,13 +226,14 @@ namespace nsHiSLIP{ this->control_code=cce; this->payload_length=length; } + // void print(void){ ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); ::printf("payload length: %llu\n",this->payload_length); } - + // size_t send(int socket){ char hbuf[HEADER_SIZE]; ssize_t ssize; @@ -240,12 +243,12 @@ namespace nsHiSLIP{ return ssize; } - + // size_t recv(int socket){ unsigned char buffer[HEADER_SIZE]; return this->recv(socket,buffer); } - + // size_t recv(int socket, void *buffer){ ssize_t rsize; //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); @@ -329,6 +332,7 @@ namespace nsHiSLIP{ //memcpy(this->payload, payload, length); //this->payload = payload; } + // size_t send(int socket){ size_t ssize; // ssize=this->Header::send(socket); @@ -344,75 +348,7 @@ namespace nsHiSLIP{ return ssize; } - size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages){ - size_t rsize; - size_t status; - - status=this->Header::recv(socket); - if (status < 0){ - // Error! - return status; - } - - // now prepare for a pyload. - if (this->payload == NULL && this->payload_length > 0){ - this->payload = (void *) calloc(this->payload_length,1); - if (this->payload == NULL){ - perror("faile to allocate memory for payload."); - return -1; - } - this->clean_on_exit=1; - } - - rsize=0; //returns size of recieved payload. should be same as payload_length - if (this->payload_length > 0){ - size_t bytestoread=this->payload_length; - - while (bytestoread){ - // status = ::recv(socket, ((u_int8_t *)this->payload+rsize), - // bytestoread, 0); - status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), - bytestoread, 0, NULL, NULL); - // status = ::read(socket, ((u_int8_t *)this->payload+rsize), - // bytestoread); - - if (status <= 0){ - perror("payload read error:"); - return -1; - } - rsize += status; - if (status >= bytestoread){ - break; - } - bytestoread -=status; - } - } - // check if expected type or not - if((expected_message_type == AnyMessages) || - (expected_message_type == this->message_type)){ - return 0; - } - // for debug - //this->print(); - - if(this->message_type == nsHiSLIP::Error){ - ::printf("Fatal Error: %d %s\n", - this->control_code, nsHiSLIP::Error_Messages[this->control_code]); - if (this->payload_length >0){ - ::printf("Error msg: %s\n", (char *) this->payload); - } - return -(this->control_code+1); - } - else if(this->message_type == nsHiSLIP::FatalError){ - ::printf("Error: %d %s\n", - this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); - if (this->payload_length >0){ - ::printf("Fatal Error msg: %s\n", (char *) this->payload); - } - return -(this->control_code+1); - } - return -1; - } + size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages); } Message_t; @@ -465,7 +401,7 @@ namespace nsHiSLIP{ void connect(char const* hostname, char const* dev_name, - int port); + int port); void set_timeout( long timeout){ this->socket_timeout=timeout; @@ -500,72 +436,16 @@ namespace nsHiSLIP{ long remote_local(u_int8_t request); long request_lock(const char* lock_string=NULL); long release_lock(void); + long handle_error_msg(void); + // long request_srq_lock(void); long release_srq_lock(void); int check_srq_lock(void); int check_and_lock_srq_lock(void); // - u_int8_t get_Service_Request(void){ - Message *msg=new Message(nsHiSLIP::AnyMessages); - long status; - - status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); - - // for debug - // msg->print(); - - if ((status & 0x80000000) != 0){ - // should handle Error/Fatal Error/Async Interrupted messages. - perror(__FUNCTION__); - msg->print(); - return 0; - } - else{ - this->release_srq_lock(); - return msg->control_code; - } - }; + u_int8_t get_Service_Request(void); + u_int8_t wait_Service_Request(int wait_time); - u_int8_t wait_Service_Request(int wait_time){ - using FpMilliseconds = - std::chrono::duration; - - static_assert(std::chrono::treat_as_floating_point::value, - "Rep required to be floating point"); - - steady_clock::time_point clk_begin = steady_clock::now(); - - Message *msg=new Message(nsHiSLIP::AnyMessages); - long status; - - this->async_poll.revents=0; - while (::poll(&this->async_poll, 1, wait_time ) > 0){ - steady_clock::time_point clk_now = steady_clock::now(); - // Note that implicit conversion is allowed here - auto time_spent = FpMilliseconds(clk_now - clk_begin); - //status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); - status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); - // for debug - //msg->print(); - - if (msg->message_type == nsHiSLIP::AsyncServiceRequest) { - this->release_srq_lock(); - return msg->control_code; - } - else if ((status & 0x80000000) != 0){ - // should handle Error/Fatal Error/Async Interrupted messages. - perror(__FUNCTION__); - msg->print(); - wait_time -= (time_spent.count()); - if (wait_time <= 0){ - return 0xff; - } - continue; - }; - }; - return 0xfe; - }; - int wait_for_Async(int wait_time){ this->async_poll.revents=0; return ::poll(&this->async_poll, 1, wait_time); @@ -587,10 +467,12 @@ namespace nsHiSLIP{ int wait_for_answer(int wait_time){ return ::poll(&this->sync_poll, 1, wait_time); } + void reset_message_id(void){ this->most_recent_message_id=INITIAL_LAST_MESSAGE_ID; this->message_id = INITIAL_MESSAGE_ID; } + u_int32_t increment_message_id(void){ this->most_recent_message_id=this->message_id; this->message_id = (this->message_id +2) & 0xffffffff; From ee66f9d1cff52263669e02c4f321e9c28aaf8964 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Thu, 6 Aug 2020 16:33:18 +0900 Subject: [PATCH 49/67] add lock_info function --- asyn/drvAsynHiSLIP/Makefile | 12 +++ asyn/drvAsynHiSLIP/README.md | 51 +++++++++++ asyn/drvAsynHiSLIP/README.rst | 84 +++++++++++++++++ asyn/drvAsynHiSLIP/README.txt | 61 ++++++++----- .../cPyHiSLIP/HiSLIPFunctionTest.py | 91 +++++++++++++++++++ .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 30 ++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 17 ++-- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 1 + asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 42 +++++++-- 9 files changed, 348 insertions(+), 41 deletions(-) create mode 100644 asyn/drvAsynHiSLIP/Makefile create mode 100644 asyn/drvAsynHiSLIP/README.md create mode 100644 asyn/drvAsynHiSLIP/README.rst create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py diff --git a/asyn/drvAsynHiSLIP/Makefile b/asyn/drvAsynHiSLIP/Makefile new file mode 100644 index 000000000..ed03db663 --- /dev/null +++ b/asyn/drvAsynHiSLIP/Makefile @@ -0,0 +1,12 @@ +#!make + +.phony: markdown +.SUFFIXES : .rst .md .txt + +.rst.md: + /usr/local/bin/pandoc -f rst -t markdown -o $@ $< + +.rst.txt: + /usr/local/bin/pandoc -f rst -t plain -o $@ $< + +markdown: README.md README.txt diff --git a/asyn/drvAsynHiSLIP/README.md b/asyn/drvAsynHiSLIP/README.md new file mode 100644 index 000000000..24364ef5f --- /dev/null +++ b/asyn/drvAsynHiSLIP/README.md @@ -0,0 +1,51 @@ +EPICS ASYN support for HiSLIP device +==================================== + +What is this? +------------- + +This module provides EPICS asyn Octet driver for HiSLIP protocol. + +It should work with Stream Device library as sameway as USBTMC and +VXI11. SRQ is supported also throgh asyn octet driver. + +HiSLIP protocol is implemented in cPyHiSLIP/HiSLIPMessage.{cpp,h} files. +These files does not have direct dependency on EPICS, and can be used +with any other programs. As an example, cPyHiSLIP/cPyHiSLIP.{pxd,pyx} +and setup.py are provided to build python modules for HiSLIP device. + +This moduled is based on the specification descibed in: + +> IVI-6.1: IVI High-Speed LAN Instument Protocol (Rev. 1.1, Feb.24, +> 2011)[^1] + +How to use +---------- + +### For EPICS + +It is assumed that this module will be used togather with the Stream +Deivce. To add this drvAsynHiSLIP support into StreamApp. You must add +the following line to the Makefile in the StreamApp directory: + +> streamApp\_DBD += drvAsynHiSLIP.dbd + +Build Issues +------------ + +> HiSLIP portocol is implemented in HiSPLIPMessage.{cpp,h}. cPyHiSLIP +> provides python module to access HiSLIP devices. It uses cython to +> wrap c/c++ librarlies. It can be used without any componets from +> EPICS. drvAsynHiSLIP provide asyOctet interface to access device. +> SRQ(IO Intr) is implemented also as asynOcted driver. So, only SI +> record can be used with SRQ. + +Acknowledgements +---------------- + +This is based on USB TMC support by Eric Norum \<\>. +And also PyHiSLIP modules by Levshinovskiy +Mikhail() is used as a reference +for the implementation. + +[^1]: IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. diff --git a/asyn/drvAsynHiSLIP/README.rst b/asyn/drvAsynHiSLIP/README.rst new file mode 100644 index 000000000..1a29bdccd --- /dev/null +++ b/asyn/drvAsynHiSLIP/README.rst @@ -0,0 +1,84 @@ +=============================================================================== +EPICS ASYN support for HiSLIP device +=============================================================================== + +What is this? +================== +This module provides EPICS asyn Octet driver for HiSLIP protocol. + +It should work with Stream Device library as sameway as USBTMC and VXI11. +SRQ is supported also throgh asyn octet driver. + + +HiSLIP protocol is implemented in cPyHiSLIP/HiSLIPMessage.{cpp,h} files. +These files does not have direct dependency on EPICS, and can be used with any other +programs. As an example, cPyHiSLIP/cPyHiSLIP.{pxd,pyx} and setup.py are provided to +build python modules for HiSLIP device. + +This moduled is based on the specification descibed in: + + IVI-6.1: IVI High-Speed LAN Instument Protocol (Rev. 1.1, Feb.24, 2011)[#]_ + + +.. [#] The latest version IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. New features, "Encrypted connections" and "Client and server authentication" are not supported by this version of drAsynHiSLIP library. + + +How to use +============= + +For EPICS +-------------- + +It is assumed that this module will be used togather with the Stream Deivce. +To add this drvAsynHiSLIP support into StreamApp. After building a libasyn library +with drvAsynHiSLIP, you must add the following +line to the Makefile in the StreamApp directory: + + streamApp_DBD += drvAsynHiSLIP.dbd + +In the iocsh start up command, you neeed to configure asyn port +for HiSLIP device. The "HiSLIPConfigure" command, like "vxi11Configure" for +VXI-11 devices is provided.: + + # HiSLIPConfigure "port name", "host address", max_message_size, "priority" + HiSLIPConfigure "L0","172.28.68.228", 1048560, 0 # Keysight DSOX1204A + +A port name can be any ID string if you just uses Stream driver. +However, if you may want to use SRQ with this suppor, you better to +stick with devGPIB/asyn port name convention, i.e. "L". + + +As Python module +---------------------- +At first, you need to build and install Python module based on this library. +To do so, go to the cPyHiSLIP directory under asyn/drvAsynHiSLIP directory, then +issue: + + python3 -m pip build clean install + +You must have pip module and Cython tool installed. You might need to give +appropriate priviledge to install the module in the proper location. + + + + +Build Issues +============ + HiSLIP portocol is implemented in HiSPLIPMessage.{cpp,h}. + cPyHiSLIP provides python module to access HiSLIP devices. It uses cython to wrap c/c++ librarlies. + It can be used without any componets from EPICS. + drvAsynHiSLIP provide asyOctet interface to access device. SRQ(IO Intr) is implemented also as asynOcted driver. So, only SI record can be used with SRQ. + +Acknowledgements +================ +This is based on USB TMC support by Eric Norum . +And also PyHiSLIP modules by Levshinovskiy Mikhail(https://github.com/llemish/PyHiSLIP) is used +as a reference for the implementation. + + +LXI Ports, Protocols, and Services + +https://www.lxistandard.org/About/LXI-Protocols.aspx + + +LXI_HiSLIP_Extended_Function_Test_Procedures_v1_01.pdf diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt index 6afc7aa10..57d791e63 100644 --- a/asyn/drvAsynHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/README.txt @@ -1,35 +1,46 @@ - EPICS ASYN support for HiSLIP device -=============================================================================== +EPICS ASYN support for HiSLIP device -Based on: +What is this? - 1) IVI-6.1: IVI High-Speed LAN Instument Protocol - -Brief Description -================== This module provides EPICS asyn Octet driver for HiSLIP protocol. -It should also work with Stream Device library as same as USBTMC and VXI11. -SRQ is supported also throu asyn octet driver. + +It should work with Stream Device library as sameway as USBTMC and +VXI11. SRQ is supported also throgh asyn octet driver. HiSLIP protocol is implemented in cPyHiSLIP/HiSLIPMessage.{cpp,h} files. -These files does not have direct dependency on EPICS, and can be used with any other -programs. As an example, cPyHiSLIP/cPyHiSLIP.{pxd,pyx} and setup.py are provided to -build python modules for HiSLIP device. +These files does not have direct dependency on EPICS, and can be used +with any other programs. As an example, cPyHiSLIP/cPyHiSLIP.{pxd,pyx} +and setup.py are provided to build python modules for HiSLIP device. + +This moduled is based on the specification descibed in: + + IVI-6.1: IVI High-Speed LAN Instument Protocol (Rev. 1.1, Feb.24, + 2011)[1] How to use -============ -1) For EPICS -Build asyn with the variable DRV_HISLIP. + +For EPICS + +It is assumed that this module will be used togather with the Stream +Deivce. To add this drvAsynHiSLIP support into StreamApp. You must add +the following line to the Makefile in the StreamApp directory: + + streamApp_DBD += drvAsynHiSLIP.dbd Build Issues -============ - HiSLIP portocol is implemented in HiSPLIPMessage.{cpp,h}. - cPyHiSLIP provides python module to access HiSLIP devices. It uses cython to wrap c/c++ librarlies. - It can be used without any componets from EPICS. - drvAsynHiSLIP provide asyOctet interface to access device. SRQ(IO Intr) is implemented also as asynOcted driver. So, only SI record can be used with SRQ. - + + HiSLIP portocol is implemented in HiSPLIPMessage.{cpp,h}. cPyHiSLIP + provides python module to access HiSLIP devices. It uses cython to + wrap c/c++ librarlies. It can be used without any componets from + EPICS. drvAsynHiSLIP provide asyOctet interface to access device. + SRQ(IO Intr) is implemented also as asynOcted driver. So, only SI + record can be used with SRQ. + Acknowledgements -================ -This is based on USB TMC support by Eric Norum . -And also PyHiSLIP modules by Levshinovskiy Mikhail(https://github.com/llemish/PyHiSLIP) is used -as a reference for the implementation. + +This is based on USB TMC support by Eric Norum . And +also PyHiSLIP modules by Levshinovskiy +Mikhail(https://github.com/llemish/PyHiSLIP) is used as a reference for +the implementation. + +[1] IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py new file mode 100644 index 000000000..c25976b93 --- /dev/null +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py @@ -0,0 +1,91 @@ +#!python3 +# -*- coding:utf-8 -*- +""" + +""" +import unittest + +import os,sys + +from cPyHiSLIP import HiSLIP + +class HiSLIPFunctionTestMethods(unittest.TestCase): + Query1=b"*IDN?" + Query2=b"*OPC?" + EnableSRQ=b"*ESE 32;*SRE 48" + + @classmethod + def setUpClass(cls): + cls.hostname=b"172.28.68.228" + + def test_connection(self): + dev=HiSLIP() + dev.connect(self.hostname) + dev.write(self.Query1) + self.assertTrue(dev.read() != None) + del dev + + def test_SRQ_status_byte(self): + dev=HiSLIP(self.hostname) + dev.write(self.EnableSRQ) + dev.write(self.Query2) + dev.wait_Service_Request(10000) + st=dev.status_query() + self.assertEqual(st&0x20,0x20) + dev.read() + st=dev.status_query() + self.assertEqual(st&0x20,0x00) + del dev + + def test_deivce_celar(self): + dev=HiSLIP(self.hostname) + dev.write(self.Query1) + dev.device_clear() + asserRaises(dev.read(timeout=3000),RuntimeError) + del dev + + def test_Interrupt(self): + dev=HiSLIP(self.hostname) + idn=dev.ask(self.Query1)[1] + if not dev.get_overlap_mode( ): + dev.write(self.Query1) + dev.write(self.Query2) + r=dev.read() + self.assertEqual(r, "1") + else: + dev.write(self.Query1) + dev.write(self.Query2) + r=dev.read() + self.assertEqual(r, idn) + self.assertEqual(dev.read(), "1") + del dev + + # def test_locking(self): + # with HiSLIP(self.hostname) as dev: + # dev.request_lock() + # if os.fork(): + # del dev + # dev=HiSLIP(self.hostname) + # dev.write(Query1) + # dev.read() + # dev.status_query() + # else: + # os.wait() + + def test_lock_info(self): + dev=HiSLIP(self.hostname) + ret=dev.request_lock(b"shared") + self.assertEqual(ret,1) + ret=dev.request_lock() + self.assertEqual(ret,0) + ret=dev.release_lock() + self.assertEqual(ret,1) + ret=dev.release_lock() + self.assertEqual(ret,2) + del dev + +if __name__ == "__main__": + unittest.main() + + + diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 60f478679..a2687263f 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -556,6 +556,7 @@ namespace nsHiSLIP{ rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); if (rc !=0){ //error! + return -1; } return resp.control_code; }; @@ -582,6 +583,35 @@ namespace nsHiSLIP{ return resp.control_code; }; + long HiSLIP::lock_info(void){ + u_int8_t lock_exclusive=0; + long lock_shared=0; + int ready=0, rc=0; + + Message resp(AnyMessages); + Message msg((u_int8_t) nsHiSLIP::AsyncLockInfo, + 0, + 0, + 0, NULL); + msg.send(this->async_channel); + this->rmt_delivered = false; + + this->async_poll.revents=0; + ready=poll(&this->async_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockInfoResponse); + if (rc !=0){ + return -1; //Error! + } + //resp.print(); + + lock_exclusive = resp.control_code & 0xff; + lock_shared = resp.message_parameter.word; + return ((lock_shared << 8) & 0xffffffff00 )+ lock_exclusive; + } + long HiSLIP::request_srq_lock(void){ // if (sem_wait(&(this->srq_lock)) == 0){ // return 0; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index ae74fc522..f551a38a1 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -67,12 +67,17 @@ namespace nsHiSLIP{ request =1 } CC_Lock_t; - typedef enum CC_LockResponse{ + typedef enum CC_LockRequestResponse{ fail=0, //Lock was requested but not granted success=1, //release of exclusive lock + locK_error=3 // Invalid + } CC_LockRequestResponse_t; + + typedef enum CC_LockReleaseResponse{ + success_exclusive=1, //release of exclusive lock success_shared=2, //release of shared lock - error=3 // Invalid - } CC_LockResponse_t; + release_error=3 // Invalid + } CC_LockReleaseResponse_t; static const long PROTOCOL_VERSION_MAX = 0x7f7f ; // # = <1><1> that is 257 static const long INITIAL_MESSAGE_ID = 0xffffff00 ; @@ -328,9 +333,6 @@ namespace nsHiSLIP{ u_int64_t length, u_int8_t *payload):Header(type,cce,param,length),payload(payload) { this->clean_on_exit=0; - //this->payload= (void *) callocMustSucceed(1, length, "HiSLIP pyload buffer"); - //memcpy(this->payload, payload, length); - //this->payload = payload; } // size_t send(int socket){ @@ -434,8 +436,9 @@ namespace nsHiSLIP{ long timeout=LOCK_TIMEOUT); long trigger_message(void); long remote_local(u_int8_t request); - long request_lock(const char* lock_string=NULL); + long request_lock(const char* lock_string = NULL); long release_lock(void); + long lock_info(void); long handle_error_msg(void); // long request_srq_lock(void); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 551c0ed70..7cdea92a7 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -75,6 +75,7 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": long release_lock() nogil long request_srq_lock() nogil long release_srq_lock() nogil + long lock_info() nogil int check_srq_lock() nogil int check_and_lock_srq_lock() nogil u_int8_t get_Service_Request() nogil diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 80d15032d..5054ad8e4 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -1,6 +1,5 @@ #!cython #-*- coding:utf-8 -*- - # distutils: sources = HiSLIPMessage.cpp # distutils: language=c++ @@ -16,10 +15,10 @@ from logging import info,debug,warn,log,fatal,warning cdef class HiSLIP: cdef cHiSLIP *thisobj - def __cinit__(self): + def __cinit__(self, char *host=NULL): self.thisobj=new cHiSLIP() - def __init__(self, host=None): + def __init__(self, char *host=NULL): cdef char *chost=host if host: with nogil: @@ -34,7 +33,7 @@ cdef class HiSLIP: cdef char *chost=host cdef char *cdevice =device cdef int cport =port - debug("connect to {} {} {}".format(host,device, port)) + debug("connect to {} {} {}".format(host, device, port)) with nogil: self.thisobj.connect(chost,cdevice,cport) self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) @@ -220,7 +219,7 @@ cdef class HiSLIP: rc=self.thisobj.remote_local(request) return rc - def request_lock(self, char * lock_string): + def request_lock(self, lock_string=None): """ response to request: 0 - Failure @@ -228,10 +227,14 @@ cdef class HiSLIP: 3 - Error """ cdef long rc - #cdef char *_lock_string=lock_string - with nogil: - rc=self.thisobj.request_lock(lock_string) - + cdef char *c_lock_string + if lock_string != None: + c_lock_string=lock_string + with nogil: + rc=self.thisobj.request_lock(c_lock_string) + else: + with nogil: + rc=self.thisobj.request_lock(b"") return rc def release_lock(self): @@ -246,6 +249,27 @@ cdef class HiSLIP: rc=self.thisobj.release_lock() return rc + def lock_info(self): + """ + return (lock_exclusiv, lock_shared) pair. + where: + lock_exclusive: 1 if exclusively locked + lock_shared: number of clients has sahred lock. + """ + cdef long rc=0 + cdef long lock_shared=0 + cdef u_int8_t lock_exclusive=0 + + with nogil: + rc=self.thisobj.lock_info() + #debug ("rc: {}".format(rc)) + if rc >= 0: + lock_exclusive= rc & 0xff + lock_shared = (rc >> 8) & 0xffffffff + #debug ("rc: {} {}".format(lock_exclusive, lock_shared)) + return (lock_exclusive, lock_shared) + + def request_srq_lock(self): """ implemented in HiSLIPMessage.cpp. From cbe6cd939126701fc994e4d5276bd6e37ab8964e Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Thu, 20 Aug 2020 09:34:52 +0900 Subject: [PATCH 50/67] prepare to push --- .../cPyHiSLIP/HiSLIPFunctionTest.py | 110 ++++++-- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 244 +++++++++++++----- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 47 ++-- asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile | 7 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 6 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 72 +++++- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 13 +- asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp | 6 +- 8 files changed, 347 insertions(+), 158 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py index c25976b93..11fed0585 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py @@ -1,22 +1,35 @@ #!python3 # -*- coding:utf-8 -*- """ - +LXI HiSLIP Test Procedures +LXI HiSLIP Extended Function +Revision 1.01 +20 October, 2011 Edition """ import unittest -import os,sys +import os,sys,time from cPyHiSLIP import HiSLIP class HiSLIPFunctionTestMethods(unittest.TestCase): + """ + ESE 0:OPC/(1:Reqest Control)/2:Query Error/3:Dev.Dep.Error/4:Execution Error/5:Command Error/(6:User Request)/7:PowerOn + ESE=32=0x20 : Command Error + SRE/STB bit 4(0x10):Message Avairlable bit 5(0x20):ESB bit, bit 6(0x40) RQS + + bit 2:0x04 Error/Event Available for some device. or MSG + bit 3:Questionable Data + https://studfile.net/preview/6372846/page:24/ + """ Query1=b"*IDN?" Query2=b"*OPC?" - EnableSRQ=b"*ESE 32;*SRE 48" + EnableSRQ=b"*ESE 32;*SRE 48;" # command Error , MAV/ESB @classmethod def setUpClass(cls): - cls.hostname=b"172.28.68.228" + cls.hostname=b"172.28.68.228" # Keysight + # cls.hostname=b"169.254.100.192" # Kikusui def test_connection(self): dev=HiSLIP() @@ -24,46 +37,76 @@ def test_connection(self): dev.write(self.Query1) self.assertTrue(dev.read() != None) del dev - + time.sleep(1) + return 0 + def test_SRQ_status_byte(self): dev=HiSLIP(self.hostname) + dev.device_clear(0) + time.sleep(1) dev.write(self.EnableSRQ) dev.write(self.Query2) dev.wait_Service_Request(10000) + #dev.check_SRQ() st=dev.status_query() - self.assertEqual(st&0x20,0x20) + print (hex(st)) + self.assertEqual(st & 0x70, 80) # SRQ(64)+ MAV(16) dev.read() st=dev.status_query() - self.assertEqual(st&0x20,0x00) + self.assertEqual(st &0x70, 0) del dev - - def test_deivce_celar(self): + time.sleep(1) + return 0 + + def test_device_clear(self): dev=HiSLIP(self.hostname) dev.write(self.Query1) - dev.device_clear() - asserRaises(dev.read(timeout=3000),RuntimeError) + dev.device_clear(0) + time.sleep(1) + with self.assertRaises(RuntimeError): + dev.read(timeout=3000) del dev - - def test_Interrupt(self): + time.sleep(1) + return 0 + + def test_Interrupted(self): dev=HiSLIP(self.hostname) - idn=dev.ask(self.Query1)[1] - if not dev.get_overlap_mode( ): + idn=dev.ask(self.Query1) + dev.device_clear(0) + time.sleep(1) + if dev.get_overlap_mode() == 0: dev.write(self.Query1) dev.write(self.Query2) r=dev.read() - self.assertEqual(r, "1") - else: + self.assertEqual(int(r[1]), 1) + dev.device_clear(0) + del dev + time.sleep(1) + return 0 + + def test_OverlappedMode(self): + dev=HiSLIP(self.hostname) + idn=dev.ask(self.Query1) + dev.device_clear(1) + time.sleep(1) + if dev.get_overlap_mode() == 1: dev.write(self.Query1) dev.write(self.Query2) - r=dev.read() - self.assertEqual(r, idn) - self.assertEqual(dev.read(), "1") + self.assertEqual(dev.read()[1], idn) + self.assertEqual(int(dev.read()[1]), 1) + dev.device_clear(0) del dev - + time.sleep(1) + return 0 + import subprocess + # def test_locking(self): - # with HiSLIP(self.hostname) as dev: - # dev.request_lock() - # if os.fork(): + # def check1(): + # dev=HiSLIP(self.hostname) + + # dev=HiSLIP(self.hostname) + # dev.request_lock() + # c.subprocess( # del dev # dev=HiSLIP(self.hostname) # dev.write(Query1) @@ -76,14 +119,25 @@ def test_lock_info(self): dev=HiSLIP(self.hostname) ret=dev.request_lock(b"shared") self.assertEqual(ret,1) + info=dev.lock_info() + self.assertEqual(info, (0,1)) ret=dev.request_lock() - self.assertEqual(ret,0) + self.assertEqual(ret,1) + info=dev.lock_info() + self.assertEqual(info, (1,1)) + ret=dev.release_lock() - self.assertEqual(ret,1) + self.assertEqual(ret,1) + info=dev.lock_info() + self.assertEqual(info, (0,1)) ret=dev.release_lock() - self.assertEqual(ret,2) + self.assertEqual(ret,2) + info=dev.lock_info() + self.assertEqual(info, (0,0)) del dev - + time.sleep(1) + return 0 + if __name__ == "__main__": unittest.main() diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index a2687263f..27760bce2 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -12,7 +12,31 @@ using nsHiSLIP::Message_t; // HiSLIP methods namespace nsHiSLIP{ - size_t Message::recv(int socket, Message_Types_t expected_message_type){ + + ssize_t Header::recv(int socket, void *buffer){ + ssize_t rsize; + + //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); + rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, NULL, NULL); + // rsize= ::read(socket, buffer, HEADER_SIZE); + + if (rsize < HEADER_SIZE){ + //raise exception? + return -1; + } + + if (memcmp(this->prologue, buffer, 2) != 0){ + return -1; + } + this->message_type=*((u_int8_t *) ((char *) buffer+2)); + this->control_code=*((u_int8_t *) ((char *) buffer+3)); + this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); + this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + + return rsize; // should be HEADER_SIZE + } + + ssize_t Message::recv(int socket, Message_Types_t expected_message_type){ size_t rsize; size_t status; @@ -55,30 +79,37 @@ namespace nsHiSLIP{ bytestoread -=status; } } - // check if expected type or not - if((expected_message_type == AnyMessages) || - (expected_message_type == this->message_type)){ - return 0; + // handle error + if(this->message_type == nsHiSLIP::FatalError){ + ::printf("Error: %d %s\n", + this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); + if (this->payload_length >0){ + ::printf("Fatal Error msg: %s\n", (char *) this->payload); + } + return -(this->control_code+1); } - // for debug - //this->print(); - - if(this->message_type == nsHiSLIP::Error){ + else if(this->message_type == nsHiSLIP::Error){ ::printf("Fatal Error: %d %s\n", this->control_code, nsHiSLIP::Error_Messages[this->control_code]); if (this->payload_length >0){ ::printf("Error msg: %s\n", (char *) this->payload); } - return -(this->control_code+1); + return -(this->control_code+2); } - else if(this->message_type == nsHiSLIP::FatalError){ - ::printf("Error: %d %s\n", - this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); - if (this->payload_length >0){ - ::printf("Fatal Error msg: %s\n", (char *) this->payload); - } - return -(this->control_code+1); + else if( (this->message_type == nsHiSLIP::Interrupted) || + (this->message_type == nsHiSLIP::AsyncInterrupted)) + { + ::printf("Interrupted %d %s\n", + this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); + return -1; } + // check if expected type or not + if((expected_message_type == AnyMessages) || + (expected_message_type == this->message_type)){ + return 0; + } + // for debug + // this->print(); return -1; } @@ -244,8 +275,8 @@ namespace nsHiSLIP{ }; int HiSLIP::device_clear(u_int8_t feature_request){ + // feature_rueust: bit 0: overlapped(1)/synchronized(0) bit1: encription mode, bit2:Initial Encryption Message resp(AnyMessages); - u_int8_t feature_preference; int ready,rc; Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, @@ -265,64 +296,94 @@ namespace nsHiSLIP{ if (rc !=0){ // Error! } - feature_preference=resp.control_code; - feature_preference &= feature_request; + + //resp.print(); + + this->feature_preference=resp.control_code; msg=new Message(nsHiSLIP::DeviceClearComplete, - feature_preference, + feature_request, 0, 0, NULL); - + //msg->print(); + msg->send(this->sync_channel); ready=poll(&this->sync_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } + rc=resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); + + //resp.print(); + if (rc !=0){ // Error! } - this->overlap_mode=resp.control_code; + + this->overlap_mode=resp.control_code & 0x01; + this->feature_setting = resp.control_code; + this->reset_message_id(); this->rmt_delivered = false; return 0; - }; - u_int8_t HiSLIP::status_query(){ + int HiSLIP::status_query(){ u_int8_t status; int ready,rc; - Message resp(AnyMessages); Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, (u_int8_t) this->rmt_delivered, - message_parameter((u_int32_t) this->most_recent_message_id), - 0, NULL); + message_parameter((u_int32_t) this->most_recent_message_id), + 0, NULL); + // if (this->overlap_mode){ + // //msg.message_parameter=message_parameter((u_int32_t) this->most_recent_received_message_id); + // msg.message_parameter=message_parameter((u_int32_t) this->most_recent_message_id); + // } if (this->message_id == 0xffffff00){ - msg.message_parameter=message_parameter((u_int32_t) 0xfffffefe); + msg.message_parameter=message_parameter((u_int32_t) INITIAL_LAST_MESSAGE_ID); } msg.send(this->async_channel); this->rmt_delivered = false; - + this->async_poll.revents=0; ready=poll(&this->async_poll, 1, this->socket_timeout); if ( ready == 0){ return -1; } rc=resp.recv(this->async_channel, nsHiSLIP::AsyncStatusResponse); + //resp.print(); if (rc !=0){ - //Error! + switch (resp.message_type ){ + case nsHiSLIP::AsyncServiceRequest: + this->release_srq_lock(); + return resp.control_code; + break; + case nsHiSLIP::FatalError: + case nsHiSLIP::Error: + perror(__FUNCTION__); + resp.print("Error/Fatal Error"); // for debug + return -1; + break; + case nsHiSLIP::AsyncLockResponse: + case nsHiSLIP::AsyncRemoteLocalResponse: + case nsHiSLIP::AsyncMaximumMessageSizeResponse: + case nsHiSLIP::AsyncDeviceClearAcknowledge: + case nsHiSLIP::AsyncLockInfoResponse: + case nsHiSLIP::AsyncStartTLSResponse: + case nsHiSLIP::AsyncEndTLSResponse: + default: + resp.print("unexpected responce"); // for debug + return -1; + } } - //resp.print(); - - status= resp.control_code &0xff; - + status= resp.control_code & 0xff; return status; } - // long HiSLIP::write(u_int8_t *data_str, long timeout){ // return this->write(data_str, this->maximum_message_size,timeout); // }; @@ -417,12 +478,40 @@ namespace nsHiSLIP{ } ::memcpy((*buffer + *received), resp.payload, resp.payload_length); *received +=resp.payload_length; + u_int32_t messageid = resp.message_parameter.word; + //resp.print(); + if ( resp.message_type == nsHiSLIP::Data){ - continue; + if ( this->overlap_mode || + ( ( messageid == UNKNOWN_MESSAGE_ID) || (messageid == this->most_recent_message_id))){ + this->most_recent_received_message_id=this->most_recent_message_id; + continue; + } + else{ + *received=0; + continue; + } } else if ( resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - return 0; + if (( this->overlap_mode || + ( messageid == UNKNOWN_MESSAGE_ID) || (messageid == this->most_recent_message_id))){ + eom=true; + this->rmt_delivered=true; + this->most_recent_received_message_id=this->most_recent_message_id; + return 0; + } + else{ + *received=0; + continue; + } + } else if (( resp.message_type == nsHiSLIP::Interrupted)|| + ( resp.message_type == nsHiSLIP::AsyncInterrupted)){ + if (this->overlap_mode){ + continue; + } + else{ + *received=0; + continue; + } } else{ // error unexpected message type. return -999; @@ -474,13 +563,39 @@ namespace nsHiSLIP{ *received +=resp.payload_length; } - + u_int32_t messageid = resp.message_parameter.word; + resp.print(); if ( resp.message_type == nsHiSLIP::Data){ - continue; + if ( this->overlap_mode || + ( ( messageid == UNKNOWN_MESSAGE_ID) || (messageid == this->most_recent_message_id))){ + this->most_recent_received_message_id=this->most_recent_message_id; + continue; + } + else{ + *received=0; + continue; + } } else if (resp.message_type == nsHiSLIP::DataEnd){ - eom=true; - this->rmt_delivered=true; - return 0; + if (( this->overlap_mode || + ( messageid == UNKNOWN_MESSAGE_ID) || (messageid == this->most_recent_message_id))){ + eom=true; + this->rmt_delivered=true; + this->most_recent_received_message_id=this->most_recent_message_id; + return 0; + } + else{ + *received=0; + continue; + } + } else if (( resp.message_type == nsHiSLIP::Interrupted)|| + ( resp.message_type == nsHiSLIP::AsyncInterrupted)){ + if (this->overlap_mode){ + continue; + } + else{ + *received=0; + continue; + } } else{ // resp.print(); // error unexpected message type. @@ -521,7 +636,7 @@ namespace nsHiSLIP{ long HiSLIP::trigger_message(void){ Message msg(nsHiSLIP::Trigger, (u_int8_t) this->rmt_delivered, - message_parameter((u_int32_t) this->most_recent_message_id), + message_parameter((u_int32_t) this->message_id), 0, NULL); msg.send(this->sync_channel); this->increment_message_id(); @@ -675,7 +790,7 @@ namespace nsHiSLIP{ return -1; } } - u_int8_t HiSLIP::get_Service_Request(void){ + int HiSLIP::get_Service_Request(void){ Message *msg=new Message(nsHiSLIP::AnyMessages); long status; @@ -684,10 +799,11 @@ namespace nsHiSLIP{ // for debug // msg->print(); - if ((status & 0x80000000) != 0){ + //if ((status & 0x80000000) != 0){ + if (status <0){ // should handle Error/Fatal Error/Async Interrupted messages. perror(__FUNCTION__); - msg->print(); + msg->print("SRQ handler:"); return 0; } else{ @@ -695,7 +811,8 @@ namespace nsHiSLIP{ return msg->control_code; } }; - u_int8_t HiSLIP::wait_Service_Request(int wait_time){ + + int HiSLIP::wait_Service_Request(int wait_time){ using FpMilliseconds = std::chrono::duration; @@ -719,10 +836,13 @@ namespace nsHiSLIP{ case nsHiSLIP::AsyncServiceRequest: this->release_srq_lock(); return msg->control_code; + break; case nsHiSLIP::FatalError: case nsHiSLIP::Error: perror(__FUNCTION__); - msg->print(); // for debug + msg->print("Error/Fatal Error"); // for debug + return -1; + break; case nsHiSLIP::AsyncLockResponse: case nsHiSLIP::AsyncRemoteLocalResponse: case nsHiSLIP::AsyncStatusResponse: @@ -731,31 +851,17 @@ namespace nsHiSLIP{ case nsHiSLIP::AsyncLockInfoResponse: case nsHiSLIP::AsyncStartTLSResponse: case nsHiSLIP::AsyncEndTLSResponse: - + msg->print("unexpected responce"); // for debug default: wait_time -= (time_spent.count()); if (wait_time <= 0){ - return 0xff; + return -1; } break; } - continue; // wile-loop. - // if (msg->message_type == nsHiSLIP::AsyncServiceRequest) { - // this->release_srq_lock(); - // return msg->control_code; - // } - // else if ((status & 0x80000000) != 0){ - // // should handle Error/Fatal Error/Async Interrupted messages. - // perror(__FUNCTION__); - // msg->print(); - // wait_time -= (time_spent.count()); - // if (wait_time <= 0){ - // return 0xff; - // } - // continue; - // }; + continue; }; - return 0xfe; + return -2; }; } // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index f551a38a1..22b4317e1 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -232,14 +232,17 @@ namespace nsHiSLIP{ this->payload_length=length; } // - void print(void){ + void print(const char *msg=NULL){ + if (msg != NULL){ + ::printf("Header dump for: %s\n", msg); + } ::printf("message type:%d\n",this->message_type); ::printf("control_code:%d\n",this->control_code); ::printf("message_parameter: 0x%0x\n",this->message_parameter.word); ::printf("payload length: %llu\n",this->payload_length); } // - size_t send(int socket){ + ssize_t send(int socket){ char hbuf[HEADER_SIZE]; ssize_t ssize; @@ -249,33 +252,13 @@ namespace nsHiSLIP{ return ssize; } // - size_t recv(int socket){ + ssize_t recv(int socket){ unsigned char buffer[HEADER_SIZE]; - return this->recv(socket,buffer); + return this->recv(socket, buffer); } // - size_t recv(int socket, void *buffer){ - ssize_t rsize; - //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, NULL, NULL); - // rsize= ::read(socket, buffer, HEADER_SIZE); - - if (rsize < HEADER_SIZE){ - //raise exception? - return -1; - } - - if (memcmp(this->prologue, buffer, 2) != 0){ - return -1; - } - this->message_type=*((u_int8_t *) ((char *) buffer+2)); - this->control_code=*((u_int8_t *) ((char *) buffer+3)); - this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); - this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + ssize_t recv(int socket, void *buffer); - return 0; - } - int fromRawData(void *buffer){ //DeSerialize if (memcmp(this->prologue, buffer, 2) != 0){ //error @@ -350,7 +333,7 @@ namespace nsHiSLIP{ return ssize; } - size_t recv(int socket, Message_Types_t expected_message_type = AnyMessages); + ssize_t recv(int socket, Message_Types_t expected_message_type = AnyMessages); } Message_t; @@ -369,6 +352,7 @@ namespace nsHiSLIP{ struct pollfd async_poll; int overlap_mode; u_int8_t feature_setting; + u_int8_t feature_preference; int session_id; int server_protocol_version; unsigned int server_vendorID; @@ -376,6 +360,7 @@ namespace nsHiSLIP{ bool rmt_delivered; u_int32_t message_id; u_int32_t most_recent_message_id; + u_int32_t most_recent_received_message_id; //sem_t srq_lock; pthread_mutex_t srq_lock; HiSLIP(){ @@ -383,8 +368,9 @@ namespace nsHiSLIP{ this->maximum_payload_size=this->current_payload_size= MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; this->socket_timeout=SOCKET_TIMEOUT; this->lock_timeout=LOCK_TIMEOUT; - this->overlap_mode=false; + this->feature_preference=0; this->feature_setting=0; + this->overlap_mode=false; //can be delived from feature_setting. this->rmt_delivered=false; this->sync_channel=0; this->async_channel=0; @@ -423,7 +409,7 @@ namespace nsHiSLIP{ long set_max_size(unsigned long message_size); int device_clear(u_int8_t); - u_int8_t status_query(void); + int status_query(void); //long write(u_int8_t *data_str, long timeout=LOCK_TIMEOUT); long write(const u_int8_t *data_str, const size_t size, long timeout=LOCK_TIMEOUT); @@ -446,8 +432,8 @@ namespace nsHiSLIP{ int check_srq_lock(void); int check_and_lock_srq_lock(void); // - u_int8_t get_Service_Request(void); - u_int8_t wait_Service_Request(int wait_time); + int get_Service_Request(void); + int wait_Service_Request(int wait_time); int wait_for_Async(int wait_time){ this->async_poll.revents=0; @@ -473,6 +459,7 @@ namespace nsHiSLIP{ void reset_message_id(void){ this->most_recent_message_id=INITIAL_LAST_MESSAGE_ID; + this->most_recent_received_message_id=INITIAL_MESSAGE_ID; this->message_id = INITIAL_MESSAGE_ID; } diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile index 53ed7aa9b..30cc9070e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/Makefile @@ -1,4 +1,7 @@ #!make +#HGVERSION:= $(shell hg parents --template 'HGTagShort = \\\"{latesttag}.{latesttagdistance}\\\"') +VERSIONGIT:= $(shell git describe --tags) +VERSION:= $(shell python3 setup.py --version) .phony: markdown .SUFFIXES : .rst .md .txt @@ -11,5 +14,5 @@ markdown: README.md README.txt -upload: - python3 -m twine upload dist/cPyHiSLIP-0.1.4.tar.gz +upload: + python3 -m twine upload dist/cPyHiSLIP-$(VERSION).tar.gz diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 7cdea92a7..10d340b8f 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -46,6 +46,7 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int overlap_mode; u_int8_t feature_setting + u_int8_t feature_preference int session_id; int server_protocol_version; unsigned int server_vendorID; @@ -53,6 +54,7 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int rmt_delivered; u_int32_t message_id; u_int32_t most_recent_message_id; + u_int32_t most_recent_received_message_id; cHiSLIP() except+ void connect(char * hostname, @@ -78,8 +80,8 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": long lock_info() nogil int check_srq_lock() nogil int check_and_lock_srq_lock() nogil - u_int8_t get_Service_Request() nogil - u_int8_t wait_Service_Request(int wait_time) nogil + int get_Service_Request() nogil + int wait_Service_Request(int wait_time) nogil int wait_for_Async(int) nogil void disconnect() nogil diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 5054ad8e4..0e4053a1f 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -45,6 +45,30 @@ cdef class HiSLIP: """ return self.thisobj.session_id + @property + def message_id(self): + """ + """ + return self.thisobj.message_id + + @property + def most_recent_message_id(self): + """ + """ + return self.thisobj.most_recent_message_id + + @property + def most_recent_received_message_id(self): + """ + """ + return self.thisobj.most_recent_received_message_id + + @property + def overlap_mode(self): + """ + """ + return self.thisobj.overlap_mode + def write(self, msg, long timeout=3000): cdef u_int8_t *cmsg=msg cdef size_t ssize=len(msg) @@ -171,7 +195,7 @@ cdef class HiSLIP: ms=self.thisobj.current_payload_size return ms - def device_clear(self,int request=0): + def device_clear(self, u_int8_t request=0): cdef long rc with nogil: rc=self.thisobj.device_clear(request) @@ -188,12 +212,21 @@ cdef class HiSLIP: 5 32 Standard Event Status Bit Summary (ESB) 6 64 Request Service (RQS)/Master Status Summary (MSS) 7 128 Operation Status Register (OPER) + + SCPI/IEEE4882/Tektronix: + -/RQS(64)/ESB(32)/MAV(16)/---- + STB for Agilent/Keysight: + OPER(128)/RQS(64)/ESB(32)/MAV(16)/-/MSG(4)/USR(2)/TRG(1) + STB for Kikusui PWR01 + OPER(128)/RQS(64)/ESB(32)/MAV(16)/QUES(8)/ERR(4)/-/- """ + cdef u_int8_t rc + # if self.thisobj.wait_for_Async(1): + # self.thisobj.get_Service_Request() with nogil: rc=self.thisobj.status_query() - return rc def trigger_message(self): @@ -219,7 +252,7 @@ cdef class HiSLIP: rc=self.thisobj.remote_local(request) return rc - def request_lock(self, lock_string=None): + def request_lock(self, char *lock_string=b""): """ response to request: 0 - Failure @@ -228,13 +261,13 @@ cdef class HiSLIP: """ cdef long rc cdef char *c_lock_string - if lock_string != None: + if lock_string != b"": c_lock_string=lock_string with nogil: rc=self.thisobj.request_lock(c_lock_string) else: with nogil: - rc=self.thisobj.request_lock(b"") + rc=self.thisobj.request_lock(lock_string) return rc def release_lock(self): @@ -318,36 +351,51 @@ cdef class HiSLIP: return ovm def get_feature_setting(self): - cdef int ovm=self.thisobj.feature_setting - return ovm + cdef int fs=self.thisobj.feature_setting + return fs + + def get_feature_preference(self): + cdef int fp=self.thisobj.feature_preference + return fp def get_protocol_version(self): cdef int spv=self.thisobj.server_protocol_version major=(spv&0xff00)>>8 minor=(spv & 0x00ff) - return (major,minor) + return (major, minor) def get_Service_Request(self): cdef u_int8_t rc=0 with nogil: rc=self.thisobj.get_Service_Request() return rc + + def check_SRQ(self): + cdef u_int8_t rc=0 + with nogil: + rc=self.thisobj.wait_for_Async(0) + if rc: + rc=self.thisobj.get_Service_Request() + return rc def wait_Service_Request(self, int wait_time): - cdef u_int8_t rc=0 + cdef int8_t rc=0 with nogil: rc=self.thisobj.wait_Service_Request(wait_time) return rc - def wait_for_Async(self, long wait_time): + def wait_for_Async(self, long wait_time=1000): + """ + return 1 if async port is ready to read + """ cdef int rc=-1 with nogil: rc=self.thisobj.wait_for_Async(wait_time) return rc - def run_svc(self,wait=1000): + def run_svc(self,int wait=1000): cdef int rc=-1 cdef u_int8_t st cdef int cwait=wait @@ -385,7 +433,7 @@ cdef class HiSLIPMessageType(enumType): DeviceCLearAcknowledge=9 AsyncRemoteLocalContro=10 AsyncRemoteLocalResponcse=11 - Trigger=12 + Trigger=12 Interrupted=13 AsyncInterrupted=14 AsyncMaximumMessageSize=15 diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index c755ca2a4..f252a58da 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -36,19 +36,8 @@ from distutils.core import setup #from distutils.extension import Extension - -# macros managedd by mercurial keyword extension # -HGTag="$HGTag: $" -HGdate="$HGdate: $" #(rfc822date) -HGlastlog="$lastlog: $" -HGchangelog="$changelog$" - -HGcheckedin="$checked in by:$" -release=HGTag -#rev=HGTag[HGTag.index(":")+1:HGTag.index("-")].strip() -#rev=HGTagShort.strip() -rev="0.1.4" +rev="0.1.5" # sysname=platform.system() diff --git a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp index c0b36606d..0310f9235 100644 --- a/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp +++ b/asyn/drvAsynHiSLIP/drvAsynHiSLIP.cpp @@ -106,8 +106,8 @@ interruptThread(void *arg) continue; } if (s > 0 ){ - u_int8_t stb = pdpvt->device->get_Service_Request(); - errlogPrintf("Get SRQ with STB: 0x%2x\n", stb); + int stb = pdpvt->device->get_Service_Request(); + errlogPrintf("Get SRQ with STB: 0x%2x\n", stb ); if ((stb & 0x40) != 0){ // may need mask here. Just SRQ ELLLIST *pclientList; interruptNode *pnode; @@ -141,7 +141,7 @@ interruptThread(void *arg) } pasynManager->interruptEnd(pdpvt->asynOctetInterruptPvt); stb = pdpvt->device->status_query(); - errlogPrintf("Finish SRQ process 0x%2x\n", stb); + errlogPrintf("Finish SRQ process 0x%2x\n", stb & 0xff); } } continue; From 73ddadf1db2bbcd06f7af9c7bb8ac707d51433f7 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Thu, 20 Aug 2020 09:38:39 +0900 Subject: [PATCH 51/67] update README.rst ,then README.md and README.txt with make markdown --- asyn/drvAsynHiSLIP/README.md | 40 ++++++++++++++++++++++++++++++++--- asyn/drvAsynHiSLIP/README.txt | 39 +++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/asyn/drvAsynHiSLIP/README.md b/asyn/drvAsynHiSLIP/README.md index 24364ef5f..1e9e422d0 100644 --- a/asyn/drvAsynHiSLIP/README.md +++ b/asyn/drvAsynHiSLIP/README.md @@ -25,11 +25,36 @@ How to use ### For EPICS It is assumed that this module will be used togather with the Stream -Deivce. To add this drvAsynHiSLIP support into StreamApp. You must add -the following line to the Makefile in the StreamApp directory: +Deivce. To add this drvAsynHiSLIP support into StreamApp. After building +a libasyn library with drvAsynHiSLIP, you must add the following line to +the Makefile in the StreamApp directory: > streamApp\_DBD += drvAsynHiSLIP.dbd +In the iocsh start up command, you neeed to configure asyn port for +HiSLIP device. The \"HiSLIPConfigure\" command, like \"vxi11Configure\" +for VXI-11 devices is provided.: + +> \# HiSLIPConfigure \"port name\", \"host address\", +> max\_message\_size, \"priority\" HiSLIPConfigure +> \"L0\",\"172.28.68.228\", 1048560, 0 \# Keysight DSOX1204A + +A port name can be any ID string if you just uses Stream driver. +However, if you may want to use SRQ with this suppor, you better to +stick with devGPIB/asyn port name convention, i.e. \"L\\". + +### As Python module + +At first, you need to build and install Python module based on this +library. To do so, go to the cPyHiSLIP directory under +asyn/drvAsynHiSLIP directory, then issue: + +> python3 -m pip build clean install + +You must have pip module and Cython tool installed. You might need to +give appropriate priviledge to install the module in the proper +location. + Build Issues ------------ @@ -48,4 +73,13 @@ And also PyHiSLIP modules by Levshinovskiy Mikhail() is used as a reference for the implementation. -[^1]: IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. +LXI Ports, Protocols, and Services + + + +LXI\_HiSLIP\_Extended\_Function\_Test\_Procedures\_v1\_01.pdf + +[^1]: The latest version IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. + New features, \"Encrypted connections\" and \"Client and server + authentication\" are not supported by this version of drAsynHiSLIP + library. diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt index 57d791e63..ddf092e85 100644 --- a/asyn/drvAsynHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/README.txt @@ -22,11 +22,36 @@ How to use For EPICS It is assumed that this module will be used togather with the Stream -Deivce. To add this drvAsynHiSLIP support into StreamApp. You must add -the following line to the Makefile in the StreamApp directory: +Deivce. To add this drvAsynHiSLIP support into StreamApp. After building +a libasyn library with drvAsynHiSLIP, you must add the following line to +the Makefile in the StreamApp directory: streamApp_DBD += drvAsynHiSLIP.dbd +In the iocsh start up command, you neeed to configure asyn port for +HiSLIP device. The "HiSLIPConfigure" command, like "vxi11Configure" for +VXI-11 devices is provided.: + + # HiSLIPConfigure "port name", "host address", max_message_size, + "priority" HiSLIPConfigure "L0","172.28.68.228", 1048560, 0 # Keysight + DSOX1204A + +A port name can be any ID string if you just uses Stream driver. +However, if you may want to use SRQ with this suppor, you better to +stick with devGPIB/asyn port name convention, i.e. "L". + +As Python module + +At first, you need to build and install Python module based on this +library. To do so, go to the cPyHiSLIP directory under +asyn/drvAsynHiSLIP directory, then issue: + + python3 -m pip build clean install + +You must have pip module and Cython tool installed. You might need to +give appropriate priviledge to install the module in the proper +location. + Build Issues HiSLIP portocol is implemented in HiSPLIPMessage.{cpp,h}. cPyHiSLIP @@ -43,4 +68,12 @@ also PyHiSLIP modules by Levshinovskiy Mikhail(https://github.com/llemish/PyHiSLIP) is used as a reference for the implementation. -[1] IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. +LXI Ports, Protocols, and Services + +https://www.lxistandard.org/About/LXI-Protocols.aspx + +LXI_HiSLIP_Extended_Function_Test_Procedures_v1_01.pdf + +[1] The latest version IVI-6.1 Rev.2.0 was publised in Feb.23, 2020. New +features, "Encrypted connections" and "Client and server authentication" +are not supported by this version of drAsynHiSLIP library. From ccd3753b5ccce26f0f904b972b84f3666f3cd2a8 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Fri, 30 Oct 2020 20:01:45 +0900 Subject: [PATCH 52/67] avoid compiler warnings --- asyn/drvAsynHiSLIP/README.md | 9 +- asyn/drvAsynHiSLIP/README.rst | 6 + asyn/drvAsynHiSLIP/README.txt | 8 +- .../cPyHiSLIP/HiSLIPFunctionTest.py | 9 +- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 205 ++++++++++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 39 +++- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 8 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 8 +- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 9 files changed, 237 insertions(+), 57 deletions(-) diff --git a/asyn/drvAsynHiSLIP/README.md b/asyn/drvAsynHiSLIP/README.md index 1e9e422d0..837701c1a 100644 --- a/asyn/drvAsynHiSLIP/README.md +++ b/asyn/drvAsynHiSLIP/README.md @@ -25,8 +25,13 @@ How to use ### For EPICS It is assumed that this module will be used togather with the Stream -Deivce. To add this drvAsynHiSLIP support into StreamApp. After building -a libasyn library with drvAsynHiSLIP, you must add the following line to +Deivce. You may need to adjust configure/RELEASE adn +configure/CONFIG\_SITE files for your environment. In some Linux +systems, you need to turn on TIRPC switch to true in +configure/CONFIG\_SITE. + +To add this drvAsynHiSLIP support into StreamApp. After building a +libasyn library with drvAsynHiSLIP, you must add the following line to the Makefile in the StreamApp directory: > streamApp\_DBD += drvAsynHiSLIP.dbd diff --git a/asyn/drvAsynHiSLIP/README.rst b/asyn/drvAsynHiSLIP/README.rst index 1a29bdccd..3569b7a66 100644 --- a/asyn/drvAsynHiSLIP/README.rst +++ b/asyn/drvAsynHiSLIP/README.rst @@ -29,7 +29,13 @@ How to use For EPICS -------------- + + It is assumed that this module will be used togather with the Stream Deivce. +You may need to adjust configure/RELEASE adn configure/CONFIG_SITE files +for your environment. In some Linux systems, you need to turn on TIRPC switch to true +in configure/CONFIG_SITE. + To add this drvAsynHiSLIP support into StreamApp. After building a libasyn library with drvAsynHiSLIP, you must add the following line to the Makefile in the StreamApp directory: diff --git a/asyn/drvAsynHiSLIP/README.txt b/asyn/drvAsynHiSLIP/README.txt index ddf092e85..026e45b7b 100644 --- a/asyn/drvAsynHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/README.txt @@ -22,8 +22,12 @@ How to use For EPICS It is assumed that this module will be used togather with the Stream -Deivce. To add this drvAsynHiSLIP support into StreamApp. After building -a libasyn library with drvAsynHiSLIP, you must add the following line to +Deivce. You may need to adjust configure/RELEASE adn +configure/CONFIG_SITE files for your environment. In some Linux systems, +you need to turn on TIRPC switch to true in configure/CONFIG_SITE. + +To add this drvAsynHiSLIP support into StreamApp. After building a +libasyn library with drvAsynHiSLIP, you must add the following line to the Makefile in the StreamApp directory: streamApp_DBD += drvAsynHiSLIP.dbd diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py index 11fed0585..d1ab49bca 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py @@ -28,16 +28,19 @@ class HiSLIPFunctionTestMethods(unittest.TestCase): @classmethod def setUpClass(cls): - cls.hostname=b"172.28.68.228" # Keysight + #cls.hostname=b"172.28.68.228" # Keysight + cls.hostname=b"169.254.29.115" # Keysight # cls.hostname=b"169.254.100.192" # Kikusui def test_connection(self): + print("test_connection") dev=HiSLIP() dev.connect(self.hostname) dev.write(self.Query1) self.assertTrue(dev.read() != None) del dev time.sleep(1) + print("end of test_connection") return 0 def test_SRQ_status_byte(self): @@ -47,9 +50,9 @@ def test_SRQ_status_byte(self): dev.write(self.EnableSRQ) dev.write(self.Query2) dev.wait_Service_Request(10000) - #dev.check_SRQ() + dev.check_SRQ() st=dev.status_query() - print (hex(st)) + print ("Status Query:",hex(st),hex(st&0x70)) self.assertEqual(st & 0x70, 80) # SRQ(64)+ MAV(16) dev.read() st=dev.status_query() diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 27760bce2..8f785c535 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -22,7 +22,7 @@ namespace nsHiSLIP{ if (rsize < HEADER_SIZE){ //raise exception? - return -1; + throw Error_t("Too Short Header in HiSLIP Message"); } if (memcmp(this->prologue, buffer, 2) != 0){ @@ -79,14 +79,19 @@ namespace nsHiSLIP{ bytestoread -=status; } } - // handle error + + // handle error / or urgent messages: Error/FatalError /interrupted/AsyncInterrupted/AsyncServiceRequest + // + // for debug + // this->print(); if(this->message_type == nsHiSLIP::FatalError){ ::printf("Error: %d %s\n", this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); if (this->payload_length >0){ ::printf("Fatal Error msg: %s\n", (char *) this->payload); } - return -(this->control_code+1); + //return -(this->control_code+1); + throw FatalError_t((char *) this->payload); } else if(this->message_type == nsHiSLIP::Error){ ::printf("Fatal Error: %d %s\n", @@ -94,14 +99,20 @@ namespace nsHiSLIP{ if (this->payload_length >0){ ::printf("Error msg: %s\n", (char *) this->payload); } - return -(this->control_code+2); + //return -(this->control_code+2); + throw HiSLIP_Error((char *) this->payload); } else if( (this->message_type == nsHiSLIP::Interrupted) || (this->message_type == nsHiSLIP::AsyncInterrupted)) { ::printf("Interrupted %d %s\n", this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); - return -1; + throw HiSLIP_Interrupted((char *) this->payload); + } + else if(this->message_type == nsHiSLIP::AsyncServiceRequest){ + ::printf("SRQ received : %d\n", this->control_code); + throw SRQ_t("Service Request"); + //return -(this->control_code); } // check if expected type or not if((expected_message_type == AnyMessages) || @@ -109,7 +120,7 @@ namespace nsHiSLIP{ return 0; } // for debug - // this->print(); + this->print(); return -1; } @@ -216,7 +227,14 @@ namespace nsHiSLIP{ } { Message resp(AnyMessages); - int rc=resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + int rc=-1; + try{ + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncInitializeResponse); + } + catch (...){ + ::printf("uncaught exception\n"); + } + if (rc !=0){ // } @@ -256,7 +274,13 @@ namespace nsHiSLIP{ return -1; } - int rc=resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + int rc=-1; + try{ + rc=resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + } + catch (...){ + ::printf("uncaught exception"); + } if (rc!=0){ // } @@ -292,7 +316,12 @@ namespace nsHiSLIP{ return -1; } - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncDeviceClearAcknowledge); + try{ + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncDeviceClearAcknowledge); + } + catch (...){ + ::printf("Uncaught exception"); + } if (rc !=0){ // Error! } @@ -354,7 +383,31 @@ namespace nsHiSLIP{ if ( ready == 0){ return -1; } - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncStatusResponse); + + try{ + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncStatusResponse); + } + catch(SRQ_t &e){ + this->release_srq_lock(); + return resp.control_code; + } + catch (FatalError_t &e){ + this->Fatal_Error_handler(&resp); + return -1; + } + catch (Error_t &e){ + this->Error_handler(&resp); + return -1; + } + catch (Interrupted_t &e){ + this->Error_handler(&resp); + return -1; + } + catch(...){ + ::printf("uncahugt exception"); + return -1; + } + //resp.print(); if (rc !=0){ switch (resp.message_type ){ @@ -363,9 +416,15 @@ namespace nsHiSLIP{ return resp.control_code; break; case nsHiSLIP::FatalError: + this->Fatal_Error_handler(&resp); + return -1; + break; case nsHiSLIP::Error: - perror(__FUNCTION__); - resp.print("Error/Fatal Error"); // for debug + this->Error_handler(&resp); + return -1; + break; + case nsHiSLIP::AsyncInterrupted: + this->Error_handler(&resp); return -1; break; case nsHiSLIP::AsyncLockResponse: @@ -651,7 +710,14 @@ namespace nsHiSLIP{ message_parameter((u_int32_t) this->most_recent_message_id), 0, NULL), resp(AnyMessages); msg.send(this->async_channel); - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + + try{ + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + } + catch(...){ + return -1; + } + if (rc !=0){ return -1; } @@ -668,7 +734,12 @@ namespace nsHiSLIP{ msg.send(this->async_channel); - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + try{ + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + } + catch (...){ + return -1; + } if (rc !=0){ //error! return -1; @@ -690,7 +761,12 @@ namespace nsHiSLIP{ msg.send(this->async_channel); - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + try { + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + } + catch (...){ + return -1; + } if(rc != 0){ //Error return -1; @@ -716,7 +792,12 @@ namespace nsHiSLIP{ if ( ready == 0){ return -1; } - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockInfoResponse); + try{ + rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockInfoResponse); + } + catch (...){ + return -1; //Error! + } if (rc !=0){ return -1; //Error! } @@ -793,22 +874,29 @@ namespace nsHiSLIP{ int HiSLIP::get_Service_Request(void){ Message *msg=new Message(nsHiSLIP::AnyMessages); long status; - - status= msg->recv(this->async_channel, nsHiSLIP::AsyncServiceRequest); - - // for debug - // msg->print(); - - //if ((status & 0x80000000) != 0){ - if (status <0){ - // should handle Error/Fatal Error/Async Interrupted messages. - perror(__FUNCTION__); - msg->print("SRQ handler:"); - return 0; + + try{ + status= msg->recv(this->async_channel, nsHiSLIP::AnyMessages);// Service Request cause SRQ_t exception. + msg->print(); // other async response should be handled separately. + return status; } - else{ - this->release_srq_lock(); - return msg->control_code; + catch(SRQ_t &e){ // Recieved SRT + // for debug + msg->print(); + //if ((status & 0x80000000) != 0){ + if (status < 0){ + // should handle Error/Fatal Error/Async Interrupted messages. + perror(__FUNCTION__); + msg->print("SRQ handler:"); + return 0; + } + else{ + this->release_srq_lock(); + return msg->control_code; + } + } + catch(...){ + return -1; } }; @@ -829,20 +917,32 @@ namespace nsHiSLIP{ steady_clock::time_point clk_now = steady_clock::now(); // Note that implicit conversion is allowed here auto time_spent = FpMilliseconds(clk_now - clk_begin); - status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); + try{ + status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); + } + catch(SRQ_t &e){ + this->release_srq_lock(); + return msg->control_code; + } + catch (FatalError_t &e){ + this->Fatal_Error_handler(msg); + return -1; + } + catch (Error_t &e){ + this->Error_handler(msg); + return -1; + } + catch (Interrupted_t &e){ + this->Error_handler(msg); + return -1; + } + catch(...){ + ::printf("uncahugt exception"); + return -1; + } //msg->print(); // for debug switch (msg->message_type ){ - case nsHiSLIP::AsyncServiceRequest: - this->release_srq_lock(); - return msg->control_code; - break; - case nsHiSLIP::FatalError: - case nsHiSLIP::Error: - perror(__FUNCTION__); - msg->print("Error/Fatal Error"); // for debug - return -1; - break; case nsHiSLIP::AsyncLockResponse: case nsHiSLIP::AsyncRemoteLocalResponse: case nsHiSLIP::AsyncStatusResponse: @@ -862,6 +962,25 @@ namespace nsHiSLIP{ continue; }; return -2; - }; + }; + // + void HiSLIP::Fatal_Error_handler(Message *msg){ + msg->print("Fatal Error"); // for debug + }; + void HiSLIP::Error_handler(Message *msg){ + msg->print("Error"); // for debug + }; + + void HiSLIP::report_Fatal_Error(const u_int8_t erc, const char *errmsg){ + Message + msg(nsHiSLIP::FatalError, erc, 0, strnlen(errmsg,256), (u_int8_t *) errmsg); + msg.send(this->async_channel); + }; + + void HiSLIP::report_Error(const u_int8_t erc, const char *errmsg){ + Message + msg(nsHiSLIP::Error, erc, 0, strnlen(errmsg,256), (u_int8_t *) errmsg); + msg.send(this->async_channel); + }; } // end of namespace HiSLIP diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 22b4317e1..34f4c15a9 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -8,7 +8,7 @@ #include #include #include -#include //memcpy, etc +#include //memcpy, strlen, etc #include #include /* for MAXHOSTNAMELEN */ #include /* close() and others */ @@ -18,6 +18,7 @@ #include #include #include // for MacOS +#include //for std::exception #include using namespace std::chrono; @@ -50,6 +51,37 @@ template struct Property { }; namespace nsHiSLIP{ + typedef class HiSLIP_FatalError:std::exception { + char *msg; + public: + HiSLIP_FatalError(char * const msg){ + this->msg=msg; + } + } FatalError_t; + + typedef class HiSLIP_Error:std::exception { + const char *msg; + public: + HiSLIP_Error(const char * const msg){ + this->msg=msg; + } + } Error_t; + + typedef class HiSLIP_Interrupted:std::exception { + const char *msg; + public: + HiSLIP_Interrupted(const char * const msg){ + this->msg=msg; + } + } Interrupted_t; + + typedef class HiSLIP_SRQ:std::exception { + const char *msg; + public: + HiSLIP_SRQ(const char * const msg){ + this->msg=msg; + } + } SRQ_t; //constants typedef enum CC_reuqest{ @@ -434,7 +466,7 @@ namespace nsHiSLIP{ // int get_Service_Request(void); int wait_Service_Request(int wait_time); - + // int wait_for_Async(int wait_time){ this->async_poll.revents=0; return ::poll(&this->async_poll, 1, wait_time); @@ -451,6 +483,9 @@ namespace nsHiSLIP{ void Fatal_Error_handler(Message *msg); void Error_handler(Message *msg); + void report_Fatal_Error(const u_int8_t erc, const char *errmsg); + void report_Error(const u_int8_t erc, const char *errmsg); + // private: int wait_for_answer(int wait_time){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 10d340b8f..2d3594263 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -62,7 +62,7 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int port) nogil void set_timeout(long) nogil long get_timeout() nogil - void set_lock_timeout(long) nogil + void set_lock_timeout(long) nogil long get_lock_timeout() nogil long set_max_size(long) nogil @@ -82,6 +82,8 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": int check_and_lock_srq_lock() nogil int get_Service_Request() nogil int wait_Service_Request(int wait_time) nogil - int wait_for_Async(int) nogil + int wait_for_Async(int) nogil void disconnect() nogil - + void report_Fatal_Error(const u_int8_t erc, const char *errmsg) nogil + void report_Error(const u_int8_t erc, const char *errmsg) nogil + diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 0e4053a1f..73a0cd2c0 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -229,7 +229,7 @@ cdef class HiSLIP: rc=self.thisobj.status_query() return rc - def trigger_message(self): + def trigger_device(self): cdef long rc with nogil: rc=self.thisobj.trigger_message() @@ -408,6 +408,12 @@ cdef class HiSLIP: break return + def report_FatalError(self, u_int8_t erc, char * errmsg): + self.thisobj.report_Fatal_Error(erc, errmsg) + + def report_Error(self, u_int8_t erc, char * errmsg): + self.thisobj.report_Error(erc, errmsg) + cdef class enumType: @classmethod def getKey(cls, v): diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index f252a58da..a1fad834a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -70,7 +70,7 @@ ,cython_cplus=True ,undef_macros =[] # ["CFLAGS"] ,define_macros=[] # [("USE_TCP_NODELAY",1)] - ,extra_compile_args=["-std=gnu++11", "-O3"], + ,extra_compile_args=["-std=c++11", "-O3"], )) From de8078eac5b496d9235c8e0b804108589688a6cb Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 9 Jan 2021 15:50:04 +0900 Subject: [PATCH 53/67] introduce std:async for sync_channel --- asyn/Makefile | 3 +- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 32 ++++++++++--- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 31 +++++++++---- asyn/drvAsynHiSLIP/cPyHiSLIP/README.md | 31 +++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst | 46 +++++++++++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt | 30 ++++++++++++ 6 files changed, 157 insertions(+), 16 deletions(-) diff --git a/asyn/Makefile b/asyn/Makefile index 384960d92..1d95d135e 100644 --- a/asyn/Makefile +++ b/asyn/Makefile @@ -12,8 +12,9 @@ include $(TOP)/configure/CONFIG ASYN = $(TOP)/asyn #USR_CFLAGS += -DDEBUG -USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET +USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET USR_CPPFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET +USR_CXXFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET --std=c++11 USR_INCLUDES_cygwin32 += -I/usr/include/tirpc diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 8f785c535..aff2ae4df 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -17,8 +17,14 @@ namespace nsHiSLIP{ ssize_t rsize; //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, NULL, NULL); // rsize= ::read(socket, buffer, HEADER_SIZE); + //rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, nullptr, nullptr); + auto f=std::async(std::launch::async, + ::recvfrom , + socket, buffer, + HEADER_SIZE, 0, + nullptr, nullptr); + rsize=f.get(); if (rsize < HEADER_SIZE){ //raise exception? @@ -484,6 +490,10 @@ namespace nsHiSLIP{ } return delivered; }; + + long HiSLIP::aread(size_t *received, u_int8_t **buffer, long timeout){ + return this->read(received, buffer, timeout); + }; long HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ bool eom=false; @@ -664,13 +674,11 @@ namespace nsHiSLIP{ return -1; }; - long HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, - u_int8_t **rbuffer, - long wait_time){ + long HiSLIP::ask(u_int8_t *const data_str, size_t const dsize, + u_int8_t **rbuffer, + long wait_time){ size_t rsize=-1; u_int8_t *buffer=NULL; - int status; - this->write(data_str, dsize); if(this->wait_for_answer(wait_time) == 0){ @@ -678,7 +686,17 @@ namespace nsHiSLIP{ buffer=NULL; return -1; }; - status=this->read(&rsize, &buffer, wait_time); // read will allocate memory area pointed by buffer. + + // long status=this->read(&rsize, &buffer, wait_time); + // + auto fut=std::async(std::launch::async, + &nsHiSLIP::HiSLIP::aread, + this, + &rsize, &buffer, + wait_time); + long status=fut.get(); + + // read will allocate memory area pointed by buffer. if (status !=0){ rsize=-1; } diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 34f4c15a9..326709e82 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -19,10 +19,14 @@ #include #include // for MacOS #include //for std::exception +#include #include using namespace std::chrono; +// for async +#include + //#include #ifdef __linux__ @@ -379,22 +383,24 @@ namespace nsHiSLIP{ long lock_timeout; int sync_channel; int async_channel; - pthread_mutex_t async_lock; + pthread_mutex_t async_lock=PTHREAD_MUTEX_INITIALIZER;; struct pollfd sync_poll; struct pollfd async_poll; - int overlap_mode; u_int8_t feature_setting; u_int8_t feature_preference; int session_id; int server_protocol_version; unsigned int server_vendorID; + bool overlap_mode; // false for synchronized mode, true for overlapped mode + bool interrupted; + bool async_interrupted; bool rmt_delivered; u_int32_t message_id; u_int32_t most_recent_message_id; u_int32_t most_recent_received_message_id; //sem_t srq_lock; - pthread_mutex_t srq_lock; + pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; HiSLIP(){ this->maximum_message_size=this->current_message_size= MAXIMUM_MESSAGE_SIZE; this->maximum_payload_size=this->current_payload_size= MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; @@ -402,13 +408,15 @@ namespace nsHiSLIP{ this->lock_timeout=LOCK_TIMEOUT; this->feature_preference=0; this->feature_setting=0; - this->overlap_mode=false; //can be delived from feature_setting. + this->overlap_mode=false; //i.e. synchronized mode. can be delived from feature_setting. + this->interrupted=false; + this->async_interrupted=false; this->rmt_delivered=false; this->sync_channel=0; this->async_channel=0; - this->async_lock=PTHREAD_MUTEX_INITIALIZER; + //this->async_lock=PTHREAD_MUTEX_INITIALIZER; // - this->srq_lock=PTHREAD_MUTEX_INITIALIZER; + //this->srq_lock=PTHREAD_MUTEX_INITIALIZER; // if (sem_init(&(this->srq_lock), 0, 1) !=0){ // perror(" HiSLIP srq_lock"); // } @@ -433,8 +441,8 @@ namespace nsHiSLIP{ void set_lock_timeout( long timeout){ this->lock_timeout=timeout; - } - ; + }; + long get_lock_timeout(void){ return this->lock_timeout; }; @@ -452,6 +460,13 @@ namespace nsHiSLIP{ long timeout=LOCK_TIMEOUT); long read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); + + long aread(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); + + long async_ask(u_int8_t *data_str, size_t size, long wait_time=LOCK_TIMEOUT); + long async_read( size_t *received, u_int8_t *buffer, size_t bsize, + long timeout=LOCK_TIMEOUT); + long trigger_message(void); long remote_local(u_int8_t request); long request_lock(const char* lock_string = NULL); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md index 6b9578ef3..b6baeb2fd 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md @@ -32,3 +32,34 @@ or To build and install the module, run: > python setup.py install + +Async designe memo +------------------ + +async channelを送受信されるメッセージ + +c\ Error \<-\> FatalError + +c\>s AsyncLock c\s AsynLockInfo c\s AsyncRemoteLocalControl c\s AsyncDeviceClear c\s AsyncMaximumMessageSize c\s GetDescriptors c\s AsyncInitialize c\s AsyncStatusQuery c\s AsyncStartTLS c\s AsyncEndTLS c\s VendorSpecific diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst index fb601d1cb..7a1d3d965 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst @@ -47,5 +47,51 @@ To build and install the module, run: python setup.py install + + +Async designe memo +---------------------- + +async channelを送受信されるメッセージ + +c Error +<-> FatalError + +c>s AsyncLock +cs AsynLockInfo +cs AsyncRemoteLocalControl +cs AsyncDeviceClear +cs AsyncMaximumMessageSize +cs GetDescriptors +cs AsyncInitialize +cs AsyncStatusQuery +cs AsyncStartTLS +cs AsyncEndTLS +cs VendorSpecific diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt index 70e178afd..39a2b3142 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt @@ -30,3 +30,33 @@ or To build and install the module, run: python setup.py install + +Async designe memo + +async channelを送受信されるメッセージ + +c Error <-> FatalError + +c>s AsyncLock cs AsynLockInfo cs AsyncRemoteLocalControl cs AsyncDeviceClear cs AsyncMaximumMessageSize cs GetDescriptors cs AsyncInitialize cs AsyncStatusQuery cs AsyncStartTLS cs AsyncEndTLS cs VendorSpecific From 70cce8bdb7f7440a49beaff5f632199d4c91255c Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 9 Jan 2021 16:30:32 +0900 Subject: [PATCH 54/67] use std::async for sending/recving data to/from socket --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 25 +++++++++++-------- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 8 +++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index aff2ae4df..de977c13e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -17,15 +17,16 @@ namespace nsHiSLIP{ ssize_t rsize; //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); - // rsize= ::read(socket, buffer, HEADER_SIZE); + //rsize= ::read(socket, buffer, HEADER_SIZE); //rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, nullptr, nullptr); - auto f=std::async(std::launch::async, + { + auto f=std::async(std::launch::async, ::recvfrom , socket, buffer, HEADER_SIZE, 0, nullptr, nullptr); - rsize=f.get(); - + rsize=f.get(); + } if (rsize < HEADER_SIZE){ //raise exception? throw Error_t("Too Short Header in HiSLIP Message"); @@ -67,12 +68,16 @@ namespace nsHiSLIP{ size_t bytestoread=this->payload_length; while (bytestoread){ - // status = ::recv(socket, ((u_int8_t *)this->payload+rsize), - // bytestoread, 0); - status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), - bytestoread, 0, NULL, NULL); - // status = ::read(socket, ((u_int8_t *)this->payload+rsize), - // bytestoread); + // status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), + // bytestoread, 0, nullptr, nullptr); + { + auto f=std::async(std::launch::async, + ::recvfrom , + socket, + ((u_int8_t *)this->payload+rsize), + bytestoread, 0, nullptr, nullptr); + status=f.get(); + }; if (status <= 0){ perror("payload read error:"); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 326709e82..442fafe39 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -283,8 +283,14 @@ namespace nsHiSLIP{ ssize_t ssize; this->toRawData(hbuf); - ssize=::send(socket, hbuf, sizeof(hbuf), 0); + //ssize=::send(socket, hbuf, sizeof(hbuf), 0); + { + auto fut=std::async(std::launch::async, + ::send, + socket,hbuf,sizeof(hbuf),0); + ssize= fut.get(); + } return ssize; } // From 15b7796100b2c6ccb903e791df31635cba4d0a48 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 9 Jan 2021 16:37:56 +0900 Subject: [PATCH 55/67] use std::async for sending/recving data to/from socket --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index de977c13e..a013876ed 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -496,10 +496,6 @@ namespace nsHiSLIP{ return delivered; }; - long HiSLIP::aread(size_t *received, u_int8_t **buffer, long timeout){ - return this->read(received, buffer, timeout); - }; - long HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ bool eom=false; long rstatus=0; @@ -692,15 +688,8 @@ namespace nsHiSLIP{ return -1; }; - // long status=this->read(&rsize, &buffer, wait_time); - // - auto fut=std::async(std::launch::async, - &nsHiSLIP::HiSLIP::aread, - this, - &rsize, &buffer, - wait_time); - long status=fut.get(); - + long status=this->read(&rsize, &buffer, wait_time); + // read will allocate memory area pointed by buffer. if (status !=0){ rsize=-1; From 07f07fa9cd6a82ec26db471b1260c4b0de80bb32 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 9 Jan 2021 16:38:43 +0900 Subject: [PATCH 56/67] use std::async for sending/recving data to/from socket --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 442fafe39..869319a0a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -467,8 +467,6 @@ namespace nsHiSLIP{ long read(size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); - long aread(size_t *received, u_int8_t **buffer, long timeout=LOCK_TIMEOUT); - long async_ask(u_int8_t *data_str, size_t size, long wait_time=LOCK_TIMEOUT); long async_read( size_t *received, u_int8_t *buffer, size_t bsize, long timeout=LOCK_TIMEOUT); From 595a055af27920c8f3ed425ea830a09e67d61870 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 30 Jan 2021 13:51:30 +0900 Subject: [PATCH 57/67] member initialvalues --- .../cPyHiSLIP/HiSLIPFunctionTest.py | 4 +- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 5 +- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 50 +++++++------------ asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST | 1 + asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 7 +-- 5 files changed, 29 insertions(+), 38 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py index d1ab49bca..2d7abc61e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py @@ -29,8 +29,8 @@ class HiSLIPFunctionTestMethods(unittest.TestCase): @classmethod def setUpClass(cls): #cls.hostname=b"172.28.68.228" # Keysight - cls.hostname=b"169.254.29.115" # Keysight - # cls.hostname=b"169.254.100.192" # Kikusui + #cls.hostname=b"169.254.29.115" # Keysight + cls.hostname=b"169.254.100.192" # Kikusui def test_connection(self): print("test_connection") diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index a013876ed..aa183487a 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -53,7 +53,7 @@ namespace nsHiSLIP{ return status; } - // now prepare for a pyload. + // now prepare for a payload. if (this->payload == NULL && this->payload_length > 0){ this->payload = (void *) calloc(this->payload_length,1); if (this->payload == NULL){ @@ -90,7 +90,8 @@ namespace nsHiSLIP{ bytestoread -=status; } } - + + // should be handled in HiSLIP class not in Message class // handle error / or urgent messages: Error/FatalError /interrupted/AsyncInterrupted/AsyncServiceRequest // // for debug diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 869319a0a..61112f3a3 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -381,48 +381,36 @@ namespace nsHiSLIP{ typedef class HiSLIP { public: - unsigned long maximum_message_size; // max message size server accept - unsigned long maximum_payload_size; - unsigned long current_message_size; // current max message size setting - unsigned long current_payload_size; - long socket_timeout; - long lock_timeout; - int sync_channel; - int async_channel; + unsigned long maximum_message_size = MAXIMUM_MESSAGE_SIZE; // max message size server accept + unsigned long maximum_payload_size = MAXIMUM_MESSAGE_SIZE; + unsigned long current_message_size = MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; // current max message size setting + unsigned long current_payload_size = MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + long socket_timeout = SOCKET_TIMEOUT; + long lock_timeout = LOCK_TIMEOUT; + int sync_channel = 0 ; + int async_channel = 0 ; pthread_mutex_t async_lock=PTHREAD_MUTEX_INITIALIZER;; struct pollfd sync_poll; struct pollfd async_poll; - u_int8_t feature_setting; - u_int8_t feature_preference; + // + u_int8_t feature_setting = 0; + u_int8_t feature_preference = 0 ; int session_id; int server_protocol_version; unsigned int server_vendorID; - - bool overlap_mode; // false for synchronized mode, true for overlapped mode - bool interrupted; - bool async_interrupted; - bool rmt_delivered; + // + bool overlap_mode = false; // false for synchronized mode, true for overlapped mode + bool interrupted = false; + bool async_interrupted = false; + bool rmt_delivered = false; + // u_int32_t message_id; u_int32_t most_recent_message_id; u_int32_t most_recent_received_message_id; //sem_t srq_lock; pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; - HiSLIP(){ - this->maximum_message_size=this->current_message_size= MAXIMUM_MESSAGE_SIZE; - this->maximum_payload_size=this->current_payload_size= MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; - this->socket_timeout=SOCKET_TIMEOUT; - this->lock_timeout=LOCK_TIMEOUT; - this->feature_preference=0; - this->feature_setting=0; - this->overlap_mode=false; //i.e. synchronized mode. can be delived from feature_setting. - this->interrupted=false; - this->async_interrupted=false; - this->rmt_delivered=false; - this->sync_channel=0; - this->async_channel=0; - //this->async_lock=PTHREAD_MUTEX_INITIALIZER; - // - //this->srq_lock=PTHREAD_MUTEX_INITIALIZER; + // + HiSLIP() { // if (sem_init(&(this->srq_lock), 0, 1) !=0){ // perror(" HiSLIP srq_lock"); // } diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST index 0d427c0e4..73084f10c 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST @@ -1,4 +1,5 @@ # file GENERATED by distutils, do NOT edit +HiSLIPFunctionTest.py HiSLIPMessage.cpp HiSLIPMessage.h MANIFEST.in diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index a1fad834a..a3ece3031 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -37,7 +37,7 @@ from distutils.core import setup #from distutils.extension import Extension # -rev="0.1.5" +rev="0.2.1" # sysname=platform.system() @@ -70,11 +70,12 @@ ,cython_cplus=True ,undef_macros =[] # ["CFLAGS"] ,define_macros=[] # [("USE_TCP_NODELAY",1)] - ,extra_compile_args=["-std=c++11", "-O3"], + ,extra_compile_args=["-std=c++14", "-O3"], + # c++98/c++11/c++14/c++17/c++2a + # py2 : c++14,py3:c++2a )) - ext_modules=cythonize( # generate .c files. ext_modules, compiler_directives={"language_level":"3" if PY3 else "2"}, # "2","3","3str" From 49f21034d18964840bb33d599e39eb3f14c26a41 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 15:08:38 +0900 Subject: [PATCH 58/67] use promise/future in HiSLIPMessage --- .../cPyHiSLIP/HiSLIPFunctionTest.py | 190 +++-- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 779 +++++++++++------- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 270 +++--- asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST | 1 + asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst | 2 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c | 1 + asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html | 478 +++++++++++ asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd | 73 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 100 ++- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 10 files changed, 1359 insertions(+), 537 deletions(-) create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c create mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py index 2d7abc61e..1f6b56bfe 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPFunctionTest.py @@ -9,6 +9,7 @@ import unittest import os,sys,time +import subprocess from cPyHiSLIP import HiSLIP @@ -22,6 +23,7 @@ class HiSLIPFunctionTestMethods(unittest.TestCase): bit 3:Questionable Data https://studfile.net/preview/6372846/page:24/ """ + Query1=b"*IDN?" Query2=b"*OPC?" EnableSRQ=b"*ESE 32;*SRE 48;" # command Error , MAV/ESB @@ -32,117 +34,141 @@ def setUpClass(cls): #cls.hostname=b"169.254.29.115" # Keysight cls.hostname=b"169.254.100.192" # Kikusui + def setUp(self): + self.dev=HiSLIP() + self.dev.connect(self.hostname) + + def tearDown(self): + self.dev.device_clear(0) + del self.dev + time.sleep(3) + def test_connection(self): print("test_connection") - dev=HiSLIP() - dev.connect(self.hostname) - dev.write(self.Query1) - self.assertTrue(dev.read() != None) - del dev - time.sleep(1) + self.dev.write(self.Query1) + self.assertTrue(self.dev.read() != None) print("end of test_connection") return 0 def test_SRQ_status_byte(self): - dev=HiSLIP(self.hostname) - dev.device_clear(0) - time.sleep(1) - dev.write(self.EnableSRQ) - dev.write(self.Query2) - dev.wait_Service_Request(10000) - dev.check_SRQ() - st=dev.status_query() + print("test_SRQ_status_byte") + print("test_SRQ_status_byte:EnableSRQ") + self.dev.write(self.EnableSRQ) + print("test_SRQ_status_byte:sendQuery{}".format(self.Query2)) + self.dev.write(self.Query2) + print("test_SRQ_status_byte:waitSRQ") + self.dev.wait_Service_Request(10000) + # print("test_SRQ_status_byte:checkSRQ") + # self.dev.check_SRQ() + print("test_SRQ_status_byte:status_Query") + st=self.dev.status_query() print ("Status Query:",hex(st),hex(st&0x70)) self.assertEqual(st & 0x70, 80) # SRQ(64)+ MAV(16) - dev.read() - st=dev.status_query() + print("test_SRQ_status_byte:readResutl") + r=self.dev.read() + print("test_SRQ_status_byte:readResutl {}".format(r)) + print("test_SRQ_status_byte:statusQuery") + st=self.dev.status_query() self.assertEqual(st &0x70, 0) - del dev - time.sleep(1) + print("end test_SRQ_status_byte") return 0 - def test_device_clear(self): - dev=HiSLIP(self.hostname) - dev.write(self.Query1) - dev.device_clear(0) - time.sleep(1) - with self.assertRaises(RuntimeError): - dev.read(timeout=3000) - del dev - time.sleep(1) + def test_lock_info(self): + print("test_lock_info") + ret=self.dev.request_lock(b"shared") # shared lock + self.assertEqual(ret,1) + info=self.dev.lock_info() + self.assertEqual(info, (0,1)) + + ret=self.dev.request_lock()# get exclusive lock + self.assertEqual(ret,1) + + info=self.dev.lock_info() + self.assertEqual(info, (1,1)) + + ret=self.dev.request_lock()# try to get lock already locked + self.assertEqual(ret,3) # error! + + info=self.dev.lock_info() + self.assertEqual(info, (1,1)) + + ret=self.dev.release_lock() # release exclusive lock + self.assertEqual(ret,1) + info=self.dev.lock_info() + self.assertEqual(info, (0,1)) + + ret=self.dev.release_lock() # release shared lock + self.assertEqual(ret,2) + info=self.dev.lock_info() + self.assertEqual(info, (0,0)) + print("end test_lock_info") return 0 - - def test_Interrupted(self): - dev=HiSLIP(self.hostname) - idn=dev.ask(self.Query1) - dev.device_clear(0) + + def test_InterruptedMode(self): + print("test_InterruptedMode") + idn=self.dev.ask(self.Query1) + self.dev.device_clear(0) time.sleep(1) - if dev.get_overlap_mode() == 0: - dev.write(self.Query1) - dev.write(self.Query2) - r=dev.read() + if self.dev.get_overlap_mode() == 0: + self.dev.write(self.Query1) + self.dev.write(self.Query2) + r=self.dev.read() self.assertEqual(int(r[1]), 1) - dev.device_clear(0) - del dev - time.sleep(1) + print("end test_Interrupted") return 0 def test_OverlappedMode(self): - dev=HiSLIP(self.hostname) - idn=dev.ask(self.Query1) - dev.device_clear(1) - time.sleep(1) - if dev.get_overlap_mode() == 1: - dev.write(self.Query1) - dev.write(self.Query2) - self.assertEqual(dev.read()[1], idn) - self.assertEqual(int(dev.read()[1]), 1) - dev.device_clear(0) - del dev + print("test_OverlappedMode") + idn=self.dev.ask(self.Query1) + self.dev.device_clear(1) time.sleep(1) + if self.dev.get_overlap_mode() == 1: + self.dev.write(self.Query1) + self.dev.write(self.Query2) + self.assertEqual(self.dev.read()[1], idn) + self.assertEqual(int(self.dev.read()[1]), 1) + print("end test_OverlappedMode") return 0 - import subprocess + # def test_locking(self): # def check1(): - # dev=HiSLIP(self.hostname) - - # dev=HiSLIP(self.hostname) - # dev.request_lock() + # self.dev.request_lock() # c.subprocess( # del dev # dev=HiSLIP(self.hostname) - # dev.write(Query1) - # dev.read() - # dev.status_query() + # self.dev.write(Query1) + # self.dev.read() + # self.dev.status_query() # else: # os.wait() - def test_lock_info(self): - dev=HiSLIP(self.hostname) - ret=dev.request_lock(b"shared") - self.assertEqual(ret,1) - info=dev.lock_info() - self.assertEqual(info, (0,1)) - ret=dev.request_lock() - self.assertEqual(ret,1) - info=dev.lock_info() - self.assertEqual(info, (1,1)) - - ret=dev.release_lock() - self.assertEqual(ret,1) - info=dev.lock_info() - self.assertEqual(info, (0,1)) - ret=dev.release_lock() - self.assertEqual(ret,2) - info=dev.lock_info() - self.assertEqual(info, (0,0)) - del dev + def test_device_clear(self): + print("test_device_clear") + print("device_clear:Query") + self.dev.write(self.Query1) + print("device_clear",self.dev.read()) + self.dev.device_clear(0) + print("device_clear done") time.sleep(1) + with self.assertRaises(RuntimeError): + self.dev.read(timeout=3000) + print("end test_device_clear") return 0 + +def suite(): + suite = unittest.TestSuite() + suite.addTest(HiSLIPFunctionTestMethods("test_connection")) + suite.addTest(HiSLIPFunctionTestMethods("test_device_clear")) + suite.addTest(HiSLIPFunctionTestMethods("test_SRQ_status_byte")) + # suite.addTest(HiSLIPFunctionTestMethods("test_OverlappedMode")) + # suite.addTest(HiSLIPFunctionTestMethods("test_lock_info")) + # suite.addTest(HiSLIPFunctionTestMethods("test_InterruptedMode")) + return suite -if __name__ == "__main__": - unittest.main() - - +if __name__ == '__main__': + #unittest.main() + runner = unittest.TextTestRunner() + runner.run(suite()) + diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index aa183487a..e9aa8a3e1 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -8,7 +8,10 @@ using nsHiSLIP::Message_t; #define MAX_PAYLOAD_CAPACITY 4096 #define IDSTRING_CAPACITY 100 -#define MAX_ERRMSG_CAPACITY 1024 +#define MAX_ERRMSG_CAPACITY 1024 + +#define SUCCESS 0 +#define FAIL -1 // HiSLIP methods namespace nsHiSLIP{ @@ -18,15 +21,7 @@ namespace nsHiSLIP{ //rsize= ::recv(socket, buffer, HEADER_SIZE, 0); //rsize= ::read(socket, buffer, HEADER_SIZE); - //rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, nullptr, nullptr); - { - auto f=std::async(std::launch::async, - ::recvfrom , - socket, buffer, - HEADER_SIZE, 0, - nullptr, nullptr); - rsize=f.get(); - } + rsize = ::recvfrom(socket, buffer, HEADER_SIZE, 0, nullptr, nullptr); if (rsize < HEADER_SIZE){ //raise exception? throw Error_t("Too Short Header in HiSLIP Message"); @@ -35,11 +30,13 @@ namespace nsHiSLIP{ if (memcmp(this->prologue, buffer, 2) != 0){ return -1; } + this->message_type=*((u_int8_t *) ((char *) buffer+2)); this->control_code=*((u_int8_t *) ((char *) buffer+3)); this->message_parameter.word = ntohl(*(u_int32_t *) ((char *) buffer+4)); this->payload_length = be64toh(*(u_int64_t *) ((char *) buffer+8)); + assert(rsize == HEADER_SIZE); return rsize; // should be HEADER_SIZE } @@ -58,44 +55,39 @@ namespace nsHiSLIP{ this->payload = (void *) calloc(this->payload_length,1); if (this->payload == NULL){ perror("faile to allocate memory for payload."); - return -1; + throw std::runtime_error("faile to allocate memory for payload."); + //return -1; } - this->clean_on_exit=1; + //this->clean_on_exit=1; + this->clean_on_exit=0; } rsize=0; //returns size of recieved payload. should be same as payload_length if (this->payload_length > 0){ size_t bytestoread=this->payload_length; - + + ::printf("reading data payload 0x%p, length:%zu recvd:%zu\n", this->payload, bytestoread, rsize); while (bytestoread){ - // status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), - // bytestoread, 0, nullptr, nullptr); - { - auto f=std::async(std::launch::async, - ::recvfrom , - socket, - ((u_int8_t *)this->payload+rsize), - bytestoread, 0, nullptr, nullptr); - status=f.get(); - }; - - if (status <= 0){ - perror("payload read error:"); - return -1; - } - rsize += status; - if (status >= bytestoread){ - break; - } - bytestoread -=status; - } + status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), + bytestoread, 0, nullptr, nullptr); + if (status <= 0){ + perror("payload read error:"); + throw std::runtime_error("payload read error"); + return -1; + } + rsize += status; + if (status >= bytestoread){ + break; + } + bytestoread -=status; + } + ::printf("reading data payload 0x%p, length:%zu\n",this->payload, bytestoread); } - // should be handled in HiSLIP class not in Message class // handle error / or urgent messages: Error/FatalError /interrupted/AsyncInterrupted/AsyncServiceRequest // - // for debug - // this->print(); + this->print("msg::recv:"); // for debug + ::printf("reading data payload 0x%p...\n",this->payload); // for debug if(this->message_type == nsHiSLIP::FatalError){ ::printf("Error: %d %s\n", this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); @@ -132,7 +124,8 @@ namespace nsHiSLIP{ return 0; } // for debug - this->print(); + this->print("msg:recv failed"); + throw std::runtime_error("msg:recv failed"); return -1; } @@ -188,8 +181,10 @@ namespace nsHiSLIP{ // disable the Nagle algorithm on socket to improve responce with small packet size // this may increase number of small packets. So may degrade overall network performance. int flag=1, reta, rets; - rets = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); - reta = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); + rets = setsockopt( this->sync_channel, IPPROTO_TCP, TCP_NODELAY, + (char *)&flag, sizeof(flag) ); + reta = setsockopt( this->async_channel, IPPROTO_TCP, TCP_NODELAY, + (char *)&flag, sizeof(flag) ); if ((rets == -1) || (reta == -1)){ perror("Couldn't set sockopt(TCP_DELAY).\n"); } @@ -203,13 +198,18 @@ namespace nsHiSLIP{ status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); if (status!=0){ // Error handling + ::printf("connection to sync_channel failed\n"); perror(__FUNCTION__); + throw std::runtime_error("cannot connect to sync_channel"); } status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); if (status!=0){ // Error handling + ::printf("connection to async_channel failed\n"); perror(__FUNCTION__); + throw std::runtime_error("cannot connect to async_channel"); } + freeaddrinfo(res); { @@ -226,6 +226,7 @@ namespace nsHiSLIP{ int rc=resp.recv(this->sync_channel, nsHiSLIP::InitializeResponse); if (rc !=0){ //Error! + throw std::runtime_error("Error to recieve InitializeResponse"); } this->overlap_mode=resp.control_code; @@ -237,6 +238,7 @@ namespace nsHiSLIP{ msg.message_parameter.word=this->session_id; msg.send(this->async_channel); } + { Message resp(AnyMessages); int rc=-1; @@ -248,10 +250,10 @@ namespace nsHiSLIP{ } if (rc !=0){ - // + throw std::runtime_error("Error to recieve AsyncInitializeResponse"); } - this->overlap_mode=resp.control_code; this->server_vendorID=resp.message_parameter.word; + this->overlap_mode=resp.control_code; } //now setup poll object @@ -266,116 +268,126 @@ namespace nsHiSLIP{ this->async_poll.events=POLLIN; this->async_poll.revents=0; + // start a thread to recieve async channel. + this->start_async_receiver_thread(); this->set_max_size(this->maximum_message_size); }; long HiSLIP::set_max_size(unsigned long message_size){ - Message resp(AnyMessages); + //this routine may be called before starting async_server . + //Message resp(AnyMessages); + int rc=-1; u_int64_t msg_size=htobe64(message_size); Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, 0, message_parameter(0), sizeof(msg_size), (u_int8_t *) &msg_size); - msg.send(this->async_channel); - - this->async_poll.revents=0; - int ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - - int rc=-1; + + auto fut_resp = this->async_send_msg(msg, nsHiSLIP::AsyncMaximumMessageSizeResponse); + // ::printf("wait future\n"); try{ - rc=resp.recv(this->async_channel,nsHiSLIP::AsyncMaximumMessageSizeResponse); + Message resp=fut_resp.get(); + // ::printf("got response\n"); + // resp.print("response from future"); + // ::printf("get payload@%p v:%llu\n",resp.payload, be64toh(*((u_int64_t *)(resp.payload)))); + rc=0; + // ::printf("get payload@%p v:%llu\n",resp.payload, be64toh(*((u_int64_t *)(resp.payload)))); + //The 8-byte buffer size is sent in network order as a 64-bit integer. + this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); + this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; + //::printf("get max message size %ld\n",this->maximum_message_size); + if (message_size < this->maximum_message_size){ + this->current_message_size=message_size; + this->current_payload_size=message_size - HEADER_SIZE; + } + else{ + this->current_message_size = this->maximum_message_size; + this->current_payload_size = this->maximum_payload_size; + } + //::printf("get max message size %ld\n",this->maximum_message_size); + return this->maximum_message_size; } catch (...){ ::printf("uncaught exception"); + throw std::runtime_error("uncaught exception"); } - if (rc!=0){ - // - } - //The 8-byte buffer size is sent in network order as a 64-bit integer. - this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); - this->maximum_payload_size = this->maximum_message_size - HEADER_SIZE; - if (message_size < this->maximum_message_size){ - this->current_message_size=message_size; - this->current_payload_size=message_size - HEADER_SIZE; - } - else{ - this->current_message_size = this->maximum_message_size; - this->current_payload_size = this->maximum_payload_size; - } - return this->maximum_message_size; }; int HiSLIP::device_clear(u_int8_t feature_request){ // feature_rueust: bit 0: overlapped(1)/synchronized(0) bit1: encription mode, bit2:Initial Encryption - Message resp(AnyMessages); int ready,rc; Message *msg=new Message(nsHiSLIP::AsyncDeviceClear, 0, 0, 0,NULL); - - msg->send(this->async_channel); - - this->async_poll.revents=0; - ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - - try{ - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncDeviceClearAcknowledge); - } - catch (...){ - ::printf("Uncaught exception"); - } - if (rc !=0){ - // Error! + auto fut_resp = this->async_send_msg(*msg, nsHiSLIP::AsyncDeviceClearAcknowledge); + { + Message resp=fut_resp.get(); + resp.print("received message"); + this->feature_preference=resp.control_code; } - //resp.print(); + // msg->send(this->async_channel); + // this->async_poll.revents=0; + // ready=poll(&this->async_poll, 1, this->socket_timeout); + // if ( ready == 0){ + // return -1; + // } + // try{ + // rc=resp.recv(this->async_channel, nsHiSLIP::AsyncDeviceClearAcknowledge); + // } + // catch (...){ + // ::printf("Uncaught exception"); + // } + // if (rc !=0){ + // // Error! + // } + + // resp.print("received message"); - this->feature_preference=resp.control_code; + // this->feature_preference=resp.control_code; - msg=new Message(nsHiSLIP::DeviceClearComplete, + { + Message resp(AnyMessages); + msg=new Message(nsHiSLIP::DeviceClearComplete, feature_request, 0, 0, NULL); - //msg->print(); + //msg->print(); - msg->send(this->sync_channel); - - ready=poll(&this->sync_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - - rc=resp.recv(this->sync_channel,nsHiSLIP::DeviceClearAcknowledge); + msg->send(this->sync_channel); + + ready=poll(&this->sync_poll, 1, this->socket_timeout); + if ( ready == 0){ + return -1; + } + + rc=resp.recv(this->sync_channel, nsHiSLIP::DeviceClearAcknowledge); - //resp.print(); - - if (rc !=0){ - // Error! + resp.print("Device Clear Acknowledge"); + + if (rc !=0){ + // Error! + } + + this->overlap_mode=resp.control_code & 0x01; + this->feature_setting = resp.control_code; } - this->overlap_mode=resp.control_code & 0x01; - this->feature_setting = resp.control_code; - this->reset_message_id(); this->rmt_delivered = false; - + + this->clear_srq_stacks(); + return 0; }; int HiSLIP::status_query(){ u_int8_t status; - int ready,rc; - Message resp(AnyMessages); + //Message resp(AnyMessages); Message msg((u_int8_t) nsHiSLIP::AsyncStatusQuery, (u_int8_t) this->rmt_delivered, message_parameter((u_int32_t) this->most_recent_message_id), @@ -387,70 +399,11 @@ namespace nsHiSLIP{ if (this->message_id == 0xffffff00){ msg.message_parameter=message_parameter((u_int32_t) INITIAL_LAST_MESSAGE_ID); } - msg.send(this->async_channel); - this->rmt_delivered = false; - - this->async_poll.revents=0; - ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } - - try{ - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncStatusResponse); - } - catch(SRQ_t &e){ - this->release_srq_lock(); - return resp.control_code; - } - catch (FatalError_t &e){ - this->Fatal_Error_handler(&resp); - return -1; - } - catch (Error_t &e){ - this->Error_handler(&resp); - return -1; - } - catch (Interrupted_t &e){ - this->Error_handler(&resp); - return -1; - } - catch(...){ - ::printf("uncahugt exception"); - return -1; - } + auto fut_resp = this->async_send_msg(msg, nsHiSLIP::AsyncStatusResponse); + + Message resp=fut_resp.get(); - //resp.print(); - if (rc !=0){ - switch (resp.message_type ){ - case nsHiSLIP::AsyncServiceRequest: - this->release_srq_lock(); - return resp.control_code; - break; - case nsHiSLIP::FatalError: - this->Fatal_Error_handler(&resp); - return -1; - break; - case nsHiSLIP::Error: - this->Error_handler(&resp); - return -1; - break; - case nsHiSLIP::AsyncInterrupted: - this->Error_handler(&resp); - return -1; - break; - case nsHiSLIP::AsyncLockResponse: - case nsHiSLIP::AsyncRemoteLocalResponse: - case nsHiSLIP::AsyncMaximumMessageSizeResponse: - case nsHiSLIP::AsyncDeviceClearAcknowledge: - case nsHiSLIP::AsyncLockInfoResponse: - case nsHiSLIP::AsyncStartTLSResponse: - case nsHiSLIP::AsyncEndTLSResponse: - default: - resp.print("unexpected responce"); // for debug - return -1; - } - } + resp.print(); status= resp.control_code & 0xff; return status; } @@ -500,6 +453,7 @@ namespace nsHiSLIP{ long HiSLIP::read(size_t *received, u_int8_t **buffer, long timeout){ bool eom=false; long rstatus=0; + Message resp(AnyMessages); *received=0; this->rmt_delivered = false; @@ -512,16 +466,19 @@ namespace nsHiSLIP{ } while(!eom) { int ready; - Message resp(AnyMessages); ready=poll(&this->sync_poll, 1, this->socket_timeout); if ( ready == 0){ + throw std::runtime_error("HiSLIP::read poll:" "timeout"); + //throw nsHiSLIP::HiSLIP_TimeoutError("HiSLIP::read poll:" "timeout"); return -1; } rstatus=resp.recv(this->sync_channel); - if (rstatus < 0){ - //Error!! + if (rstatus < 0){ // would be -1 + perror(__FUNCTION__); + throw std::runtime_error("HiSLIP::read recv:" "timeout"); + //throw nsHiSLIP::HiSLIP_RuntimeError(__FUNCTION__); return -2; }; @@ -550,7 +507,8 @@ namespace nsHiSLIP{ ::memcpy((*buffer + *received), resp.payload, resp.payload_length); *received +=resp.payload_length; u_int32_t messageid = resp.message_parameter.word; - //resp.print(); + + resp.print(); if ( resp.message_type == nsHiSLIP::Data){ if ( this->overlap_mode || @@ -683,7 +641,8 @@ namespace nsHiSLIP{ u_int8_t *buffer=NULL; this->write(data_str, dsize); - if(this->wait_for_answer(wait_time) == 0){ + + if(::poll(&this->sync_poll, 1, wait_time) == 0){ // error buffer=NULL; return -1; @@ -717,51 +676,74 @@ namespace nsHiSLIP{ }; long HiSLIP::remote_local(u_int8_t request){ - int rc; + //int rc; Message msg(nsHiSLIP::AsyncRemoteLocalControl, request, message_parameter((u_int32_t) this->most_recent_message_id), 0, NULL), resp(AnyMessages); - msg.send(this->async_channel); + + auto fut_resp = this->async_send_msg(msg, nsHiSLIP::AsyncRemoteLocalResponse); try{ - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + Message resp=fut_resp.get(); } catch(...){ return -1; } + resp.print(); - if (rc !=0){ - return -1; - } + return 0; + + // msg.send(this->async_channel); + + // try{ + // rc=resp.recv(this->async_channel, nsHiSLIP::AsyncRemoteLocalResponse); + // } + // catch(...){ + // return -1; + // } + + // if (rc !=0){ + // return -1; + // } return 0; }; long HiSLIP::request_lock(const char* lock_string){ - int rc; + //int rc; Message msg(nsHiSLIP::AsyncLock, 1, // request this->lock_timeout, - strnlen(lock_string, 256), (u_int8_t *) lock_string), - resp(AnyMessages); - - msg.send(this->async_channel); + strnlen(lock_string, 256), (u_int8_t *) lock_string); + auto fut_resp = this->async_send_msg(msg, nsHiSLIP::AsyncLockResponse); + try{ - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); - } - catch (...){ - return -1; + Message resp=fut_resp.get(); + resp.print("reuqest_lock"); + return resp.control_code; } - if (rc !=0){ - //error! - return -1; + catch(...){ + throw std::runtime_error("request lock failed"); + return 3; } - return resp.control_code; + // msg.send(this->async_channel); + + // try{ + // rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + // } + // catch (...){ + // return -1; + // } + // if (rc !=0){ + // //error! + // return -1; + // } + // return resp.control_code; }; long HiSLIP::release_lock(void){ - int rc=-1; + //int rc=-1; long message_id =this->most_recent_message_id; if ( message_id == nsHiSLIP::INITIAL_MESSAGE_ID){ message_id=0; @@ -769,56 +751,58 @@ namespace nsHiSLIP{ Message msg(nsHiSLIP::AsyncLock, 0, // release message_id, - 0, NULL), - resp(AnyMessages); - - msg.send(this->async_channel); + 0, NULL); - try { - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); - } - catch (...){ - return -1; + auto fut_resp = this->async_send_msg(msg, nsHiSLIP::AsyncLockResponse); + + try{ + Message resp=fut_resp.get(); + resp.print(); + return resp.control_code; } - if(rc != 0){ - //Error - return -1; + catch(...){ + throw std::runtime_error("request lock failed"); + return 3; } - return resp.control_code; + // msg.send(this->async_channel); + + // try { + // rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockResponse); + // } + // catch (...){ + // return -1; + // } + // if(rc != 0){ + // //Error + // return -1; + // } + // return resp.control_code; }; long HiSLIP::lock_info(void){ u_int8_t lock_exclusive=0; long lock_shared=0; - int ready=0, rc=0; + //int ready=0, rc=0; - Message resp(AnyMessages); + //Message resp(AnyMessages); Message msg((u_int8_t) nsHiSLIP::AsyncLockInfo, 0, 0, 0, NULL); - msg.send(this->async_channel); - this->rmt_delivered = false; - this->async_poll.revents=0; - ready=poll(&this->async_poll, 1, this->socket_timeout); - if ( ready == 0){ - return -1; - } + auto fut_resp = this->async_send_msg(msg, nsHiSLIP::AsyncLockInfoResponse); + try{ - rc=resp.recv(this->async_channel, nsHiSLIP::AsyncLockInfoResponse); - } - catch (...){ - return -1; //Error! + Message resp=fut_resp.get(); + resp.print("lock_info"); + lock_exclusive = resp.control_code & 0xff; + lock_shared = resp.message_parameter.word; + return ((lock_shared << 8) & 0xffffffff00 )+ lock_exclusive; } - if (rc !=0){ - return -1; //Error! + catch(...){ + throw std::runtime_error("lock info"); + //return -1; } - //resp.print(); - - lock_exclusive = resp.control_code & 0xff; - lock_shared = resp.message_parameter.word; - return ((lock_shared << 8) & 0xffffffff00 )+ lock_exclusive; } long HiSLIP::request_srq_lock(void){ @@ -834,28 +818,23 @@ namespace nsHiSLIP{ } else{ perror("request_srq_lock"); - return -1; + throw std::runtime_error("request_srq_lock"); + //return -1; } }; long HiSLIP::release_srq_lock(void){ - // int sval=this->check_srq_lock(); - // if (sval != 0){ - // return sval; - // } - // if (sem_post(&(this->srq_lock)) == 0){ - // return 0; - // } - // else{ - // perror("release_srq_lock"); - // return -1; - // } - if (pthread_mutex_unlock(&(this->srq_lock)) == 0){ + int rc=pthread_mutex_unlock(&(this->srq_lock)); + if ( rc == 0){ return 0; } + else if (rc == EPERM){ + return rc; + } else{ perror("release_srq_lock"); - return -1; + throw std::runtime_error("release_srq_lock"); + //return -1; } }; @@ -869,7 +848,7 @@ namespace nsHiSLIP{ return 0; } perror("check_srq_lock"); - return -1; + throw std::runtime_error("check_srq_lock"); } int HiSLIP::check_and_lock_srq_lock(void){ @@ -881,100 +860,324 @@ namespace nsHiSLIP{ return 0; default: perror("check_and_lock_srq_lock"); - return -1; + throw std::runtime_error("check_and_lock_srq_lock"); + //return -1; } } + // used in asyn/drvAsynHiSLIP : int HiSLIP::get_Service_Request(void){ - Message *msg=new Message(nsHiSLIP::AnyMessages); - long status; + // register promise for SRT and wait SRQ using future. + if (! this->srq_msg_stack.empty()){ + Message msg=this->pop_srq_msg(); + return msg.control_code; + } + else{ + std::promise p; + std::future f = p.get_future(); + this->push_srq_promise(std::move(p)); + Message msg=f.get(); + return msg.control_code; + } - try{ - status= msg->recv(this->async_channel, nsHiSLIP::AnyMessages);// Service Request cause SRQ_t exception. - msg->print(); // other async response should be handled separately. - return status; + + // Message *msg=new Message(nsHiSLIP::AnyMessages); + // long status; + + // try{ + // status= msg->recv(this->async_channel, nsHiSLIP::AnyMessages);// Service Request cause SRQ_t exception. + // msg->print(); // other async response should be handled separately. + // return status; + // } + // catch(SRQ_t &e){ // Recieved SRT + // // for debug + // msg->print(); + // //if ((status & 0x80000000) != 0){ + // if (status < 0){ + // // should handle Error/Fatal Error/Async Interrupted messages. + // perror(__FUNCTION__); + // msg->print("SRQ handler:"); + // return 0; + // } + // else{ + // this->release_srq_lock(); + // return msg->control_code; + // } + // } + // catch(...){ + // return -1; + // } + }; + // + void HiSLIP::register_async_promise( + Message_Types_t responseType, + std::promise p ){ + + std::lock_guard guard(this->promise_map_mutex);//create lock==lock mutex + if (this->promise_map.count(responseType) == 0){ + this->promise_map.emplace(responseType, std::move(p)); } - catch(SRQ_t &e){ // Recieved SRT - // for debug - msg->print(); - //if ((status & 0x80000000) != 0){ - if (status < 0){ - // should handle Error/Fatal Error/Async Interrupted messages. - perror(__FUNCTION__); - msg->print("SRQ handler:"); - return 0; - } - else{ - this->release_srq_lock(); - return msg->control_code; - } + else{ + this->promise_map[responseType]= std::move(p); } - catch(...){ - return -1; + }; + + void HiSLIP::remove_async_promise(Message_Types_t responseType){ + std::lock_guard guard(this->promise_map_mutex);//create lock==lock mutex + this->promise_map.erase(responseType); + }; + // + void HiSLIP::push_srq_promise(std::promise p){ + std::lock_guard guard(this->srq_promise_mutex);//create lock==lock mutex + this->srq_promise_stack.push(std::move(p)); + }; + + std::promise HiSLIP::pop_srq_promise(void){ + std::lock_guard guard(this->srq_promise_mutex);//create lock==lock mutex + std::promise msg; + msg=std::move(this->srq_promise_stack.top()); this->srq_promise_stack.pop(); + return msg; + + }; // use .top() and .pop() of stack class. + void HiSLIP::clear_srq_promise(void){ + std::lock_guard guard(this->srq_promise_mutex);//create lock==lock mutex + while(! this->srq_promise_stack.empty()){ + this->srq_promise_stack.pop(); + } + }; + // + void HiSLIP::push_srq_msg(Message msg){ + std::lock_guard guard(this->srq_msg_mutex);//create lock==lock mutex + this->srq_msg_stack.push(std::move(msg)); + }; + Message HiSLIP::pop_srq_msg(void){ + std::lock_guard guard(this->srq_msg_mutex);//create lock==lock mutex + Message msg=this->srq_msg_stack.top(); this->srq_msg_stack.pop(); + return msg; + }; // use .top() and .pop() of stack class. + void HiSLIP::clear_srq_msg(void){ + std::lock_guard guard(this->srq_msg_mutex);//create lock==lock mutex + while(! this->srq_msg_stack.empty()){ + this->srq_msg_stack.pop(); + } + }; + void HiSLIP::clear_srq_stacks(void){ + auto futprm = std::async(std::launch::async, [this]{ this->clear_srq_promise();} ); + auto futmsg = std::async(std::launch::async, [this]{ this->clear_srq_msg();} ); + }; +// + std::future HiSLIP::async_send_msg(Message msg, + Message_Types_t responseType) + { + std::promise p; + std::future f = p.get_future(); + + ::printf("sending async message\n"); + + msg.send(this->async_channel); + ::printf("message sent\n"); + if (responseType != AnyMessages) { + this->register_async_promise(responseType, std::move(p)); + this->rmt_delivered = false; + } + else{ + ::printf("no response is expected\n"); + p.set_value(std::move(msg)); + //p.set_value(msg); } + ::printf("return future\n"); + return f; + }; + + void HiSLIP::start_async_receiver_thread(void){ + + // use lambda expression. + this->async_receiver_thread= new std::thread([this](){this->async_receiver_loop();} ); + this->async_recceiver_active=true; }; - int HiSLIP::wait_Service_Request(int wait_time){ + void HiSLIP::async_receiver_loop(void){ + // should be executed in other thread. using FpMilliseconds = std::chrono::duration; static_assert(std::chrono::treat_as_floating_point::value, "Rep required to be floating point"); - steady_clock::time_point clk_begin = steady_clock::now(); - Message *msg=new Message(nsHiSLIP::AnyMessages); long status; - this->async_poll.revents=0; - while (::poll(&this->async_poll, 1, wait_time ) ){ - steady_clock::time_point clk_now = steady_clock::now(); + while (this->async_recceiver_active){ // Note that implicit conversion is allowed here - auto time_spent = FpMilliseconds(clk_now - clk_begin); + this->async_poll.revents=0; + //::poll(&this->async_poll, 1, -1 /* forever*/ ); + { // with time limit to wait. + int rc=::poll(&this->async_poll, 1, 500 /* m sec*/ ); + if ( rc == 0){ /* time limit expires */ + continue; + } + else if (rc < 0){ // Error EBADF/EFAULT/EINTR/EINVAL/ENOMEM + ::printf("return code : %d\n",rc); + ::perror(__FUNCTION__); + //continue; + throw std::runtime_error(__FUNCTION__); + } + }; + ::printf("receiver got data\n"); //for debug try{ status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); } catch(SRQ_t &e){ + if(this->srq_promise_stack.empty()){ + this->push_srq_msg(std::move(msg)); + } + else{ + std::promise p = this->pop_srq_promise(); + p.set_value(std::move(msg)); + } this->release_srq_lock(); - return msg->control_code; } catch (FatalError_t &e){ this->Fatal_Error_handler(msg); - return -1; } catch (Error_t &e){ this->Error_handler(msg); - return -1; } catch (Interrupted_t &e){ this->Error_handler(msg); - return -1; } catch(...){ - ::printf("uncahugt exception"); - return -1; + ::printf("uncahugt exception, ignored"); } //msg->print(); // for debug switch (msg->message_type ){ case nsHiSLIP::AsyncLockResponse: + case nsHiSLIP::AsyncLockInfoResponse: case nsHiSLIP::AsyncRemoteLocalResponse: - case nsHiSLIP::AsyncStatusResponse: - case nsHiSLIP::AsyncMaximumMessageSizeResponse: case nsHiSLIP::AsyncDeviceClearAcknowledge: - case nsHiSLIP::AsyncLockInfoResponse: + case nsHiSLIP::AsyncMaximumMessageSizeResponse: + case nsHiSLIP::GetDescriptorsResponse: + case nsHiSLIP::AsyncStatusResponse: case nsHiSLIP::AsyncStartTLSResponse: case nsHiSLIP::AsyncEndTLSResponse: - msg->print("unexpected responce"); // for debug + msg->print("Asycn Responce"); // for debug + if (this->promise_map.count(msg->message_type) ==0){ + msg->print("No promise"); // for debug + } + else{ + // get promise and set message to promise + this->promise_map[msg->message_type].set_value(std::move(*msg)); + this->remove_async_promise(msg->message_type); + } + break; + case nsHiSLIP::AsyncInitializeResponse://should be handleld in connect. + break; + case nsHiSLIP::FatalError: + case nsHiSLIP::Error: + case nsHiSLIP::AsyncInterrupted: + case nsHiSLIP::AsyncServiceRequest: + // should be handled in Message::recv. + //throw std::runtime_error("asyn_recv loop exception"); + break; default: - wait_time -= (time_spent.count()); - if (wait_time <= 0){ - return -1; + msg->print("Asycn Other/Vendor Specific(?)"); // for debug + if (this->promise_map.count(msg->message_type) == 0){ + msg->print("No promise"); // for debug + } + else{ + this->promise_map[msg->message_type].set_value(std::move(*msg)); + this->remove_async_promise(msg->message_type); } break; } continue; }; - return -2; + + } + + int HiSLIP::wait_Service_Request(int wait_time){ + // register promise for SRT and wait SRQ using future. with-timeout. + // + // register promise for SRT and wait SRQ using future. + if (! this->srq_msg_stack.empty()){ + Message msg=this->pop_srq_msg(); + return msg.control_code; + } + else{ + std::promise p; + std::future f = p.get_future(); + + this->push_srq_promise(std::move(p)); + std::future_status rst=f.wait_for(std::chrono::milliseconds(wait_time)); + if (rst != std::future_status::timeout) { + Message msg=f.get(); + return msg.control_code; + } + return -1; + } + + // using FpMilliseconds = + // std::chrono::duration; + + // static_assert(std::chrono::treat_as_floating_point::value, + // "Rep required to be floating point"); + + // steady_clock::time_point clk_begin = steady_clock::now(); + + // Message *msg=new Message(nsHiSLIP::AnyMessages); + // long status; + + // // check srq_msg_stack if stack is not empty + // this->async_poll.revents=0; + // while (::poll(&this->async_poll, 1, wait_time ) ){ + // steady_clock::time_point clk_now = steady_clock::now(); + // // Note that implicit conversion is allowed here + // auto time_spent = FpMilliseconds(clk_now - clk_begin); + // try{ + // status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); + // } + // catch(SRQ_t &e){ + // this->release_srq_lock(); + // return msg->control_code; + // } + // catch (FatalError_t &e){ + // this->Fatal_Error_handler(msg); + // return -1; + // } + // catch (Error_t &e){ + // this->Error_handler(msg); + // return -1; + // } + // catch (Interrupted_t &e){ + // this->Error_handler(msg); + // return -1; + // } + // catch(...){ + // ::printf("uncahugt exception"); + // return -1; + // } + // //msg->print(); // for debug + + // switch (msg->message_type ){ + // case nsHiSLIP::AsyncLockResponse: + // case nsHiSLIP::AsyncRemoteLocalResponse: + // case nsHiSLIP::AsyncStatusResponse: + // case nsHiSLIP::AsyncMaximumMessageSizeResponse: + // case nsHiSLIP::AsyncDeviceClearAcknowledge: + // case nsHiSLIP::AsyncLockInfoResponse: + // case nsHiSLIP::AsyncStartTLSResponse: + // case nsHiSLIP::AsyncEndTLSResponse: + // msg->print("unexpected responce"); // for debug + // default: + // wait_time -= (time_spent.count()); + // if (wait_time <= 0){ + // return -1; + // } + // break; + // } + // continue; + // }; + // return -2; }; // void HiSLIP::Fatal_Error_handler(Message *msg){ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index 61112f3a3..b3b98b916 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -4,29 +4,41 @@ #include #include + //#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include #include #include //memcpy, strlen, etc #include -#include /* for MAXHOSTNAMELEN */ -#include /* close() and others */ +#include //* for MAXHOSTNAMELEN */ +#include //* close() and others */ #include #include #include #include #include // for MacOS -#include //for std::exception -#include + +#include +#include +#include #include using namespace std::chrono; +namespace chrono = std::chrono; + +#include +#include //for std::exception +#include +#include // for async #include +//#include +// #include + //#include #ifdef __linux__ @@ -55,11 +67,10 @@ template struct Property { }; namespace nsHiSLIP{ - typedef class HiSLIP_FatalError:std::exception { - char *msg; + typedef class HiSLIP_FatalError:std::runtime_error { public: - HiSLIP_FatalError(char * const msg){ - this->msg=msg; + HiSLIP_FatalError(const std::string& msg):std::runtime_error(msg){}; + HiSLIP_FatalError(const char * msg):std::runtime_error(msg){ } } FatalError_t; @@ -87,32 +98,44 @@ namespace nsHiSLIP{ } } SRQ_t; + typedef class HiSLIP_TimeoutError:std::runtime_error{ + public: + HiSLIP_TimeoutError(const std::string& msg):std::runtime_error(msg){}; + HiSLIP_TimeoutError(const char * msg):std::runtime_error(msg){} + } TimeoutError_t; + + typedef class HiSLIP_RuntimeError:std::runtime_error{ + public: + HiSLIP_RuntimeError(const std::string& msg):std::runtime_error(msg){}; + HiSLIP_RuntimeError(const char * msg):std::runtime_error(msg){} + } RuntimeoutError_t; + //constants typedef enum CC_reuqest{ - RemoteDisable=0, - RemoteEnable=1, - RemoteDisableGTL=2, // disable remote and goto local - RemoteEnableGTR=3, // Enable remote and goto remote - RemoteEnableLLO=4, // Enable remote and lock out local - RemoteEnableGTRLLO=5, // - RTL=6 + RemoteDisable=0, + RemoteEnable=1, + RemoteDisableGTL=2, // disable remote and goto local + RemoteEnableGTR=3, // Enable remote and goto remote + RemoteEnableLLO=4, // Enable remote and lock out local + RemoteEnableGTRLLO=5, // + RTL=6 } CC_request_t; typedef enum CC_Lock{ - release =0, - request =1 + release =0, + request =1 } CC_Lock_t; typedef enum CC_LockRequestResponse{ - fail=0, //Lock was requested but not granted - success=1, //release of exclusive lock - locK_error=3 // Invalid + fail=0, //Lock was requested but not granted + success=1, //release of exclusive lock + locK_error=3 // Invalid } CC_LockRequestResponse_t; typedef enum CC_LockReleaseResponse{ - success_exclusive=1, //release of exclusive lock - success_shared=2, //release of shared lock - release_error=3 // Invalid + success_exclusive=1, //release of exclusive lock + success_shared=2, //release of shared lock + release_error=3 // Invalid } CC_LockReleaseResponse_t; static const long PROTOCOL_VERSION_MAX = 0x7f7f ; // # = <1><1> that is 257 @@ -132,60 +155,62 @@ namespace nsHiSLIP{ static const char Prologue[]={'H','S'}; // typedef enum Message_Types{ - Initialize = 0, - InitializeResponse = 1, - FatalError = 2, - Error = 3, - AsyncLock = 4, - AsyncLockResponse = 5, - Data = 6, - DataEnd = 7, - DeviceClearComplete = 8, - DeviceClearAcknowledge = 9, - AsyncRemoteLocalControl = 10, - AsyncRemoteLocalResponse = 11, - Trigger = 12, - Interrupted = 13, - AsyncInterrupted = 14, - AsyncMaximumMessageSize = 15, - AsyncMaximumMessageSizeResponse = 16, - AsyncInitialize = 17, - AsyncInitializeResponse = 18, - AsyncDeviceClear = 19, - AsyncServiceRequest = 20, - AsyncStatusQuery = 21, - AsyncStatusResponse = 22, - AsyncDeviceClearAcknowledge = 23, - AsyncLockInfo = 24, - AsyncLockInfoResponse = 25, - // for HiSLIP ver2 - GetDescriptors =26, - GetDescriptorsResponse =27, - StartTLS = 28, - AsyncStartTLS = 29, - AsyncStartTLSResponse = 30, - EndTLS = 31, - AsyncEndTLS = 32, - AsyncEndTLSResponse = 33, - GetSaslMechanismList = 34, - GetSaslMechanismListResponse = 35, - AuthenticationStart = 36, - AuthenticationExchange = 37, - AuthenticationResult = 38, - // 39-127 are reserved for future use. - // I don't watn to use negative value to - // represent ANY message. - // So I picked 127 from reserved values - // for this purpose. - AnyMessages=127 // 128-255 are reserved for vendor use. - } Message_Types_t; - + Initialize = 0, // SC + InitializeResponse = 1, //SR + FatalError = 2, // E + Error = 3, // E + AsyncLock = 4,// AC + AsyncLockResponse = 5, //AR + Data = 6, + DataEnd = 7, + DeviceClearComplete = 8, + DeviceClearAcknowledge = 9, + AsyncRemoteLocalControl = 10, //AC + AsyncRemoteLocalResponse = 11, //AR + Trigger = 12, + Interrupted = 13, + AsyncInterrupted = 14, + AsyncMaximumMessageSize = 15, //AC + AsyncMaximumMessageSizeResponse = 16, //AR + AsyncInitialize = 17, //AC + AsyncInitializeResponse = 18, //AR + AsyncDeviceClear = 19, //AC + AsyncServiceRequest = 20, + AsyncStatusQuery = 21, //AC + AsyncStatusResponse = 22, //AR + AsyncDeviceClearAcknowledge = 23, + AsyncLockInfo = 24, //AC + AsyncLockInfoResponse = 25, //AR + // for HiSLIP ver2 + GetDescriptors =26, + GetDescriptorsResponse =27, + StartTLS = 28, + AsyncStartTLS = 29, + AsyncStartTLSResponse = 30, + EndTLS = 31, + AsyncEndTLS = 32, + AsyncEndTLSResponse = 33, + GetSaslMechanismList = 34, + GetSaslMechanismListResponse = 35, + AuthenticationStart = 36, + AuthenticationExchange = 37, + AuthenticationResult = 38, + // 39-127 are reserved for future use. + // I don't watn to use negative value to + // represent ANY message. + // So I picked 127 from reserved values + // for this purpose. + AnyMessages=127 // 128-255 are reserved for vendor use. + } _Message_Types_t; + + typedef u_int8_t Message_Types_t; + typedef enum Error_code{ - UnidentifiedError, - UnrecognizedMessageType, - UnrecognizedControlCode, - UnrecognizedVendorDefinedMessage, - MessageTooLarge + UnidentifiedError, + UnrecognizedMessageType, + UnrecognizedControlCode, + UnrecognizedVendorDefinedMessage, + MessageTooLarge } Error_code_t; static const char *Error_Messages[] = { @@ -196,11 +221,11 @@ namespace nsHiSLIP{ "Message too large" }; typedef enum Fatal_Error_code { - UnidentifiedFatalError, - PoorlyFormedMmessageHeader, - AttemptToUseConnectionWithoutBothChannels, - InvalidInitializationSequence, - ServerRefusedConnection + UnidentifiedFatalError, + PoorlyFormedMmessageHeader, + AttemptToUseConnectionWithoutBothChannels, + InvalidInitializationSequence, + ServerRefusedConnection } Fatal_Erro_code_t; static const char *Fatal_Error_Messages[] = { @@ -229,7 +254,6 @@ namespace nsHiSLIP{ }; message_parameter(u_int16_t proto, u_int16_t sid){ this->word = (proto << 16) + sid; - }; u_int16_t getServerProtocolVersion(){ return (u_int16_t) (((this->word) & 0xffff0000)>>16); @@ -325,8 +349,8 @@ namespace nsHiSLIP{ typedef class Message:public Header{ public: - void *payload; - int clean_on_exit; + void *payload=NULL; + int clean_on_exit=0; ~Message(){ if ((this->payload != NULL) && (this->clean_on_exit==1)){ @@ -356,7 +380,11 @@ namespace nsHiSLIP{ u_int8_t cce, message_parameter_t param, u_int64_t length, - u_int8_t *payload):Header(type,cce,param,length),payload(payload) { + u_int8_t *payload):Header(type, + cce, + param, + length), + payload(payload) { this->clean_on_exit=0; } // @@ -385,11 +413,11 @@ namespace nsHiSLIP{ unsigned long maximum_payload_size = MAXIMUM_MESSAGE_SIZE; unsigned long current_message_size = MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; // current max message size setting unsigned long current_payload_size = MAXIMUM_MESSAGE_SIZE - HEADER_SIZE; + // long socket_timeout = SOCKET_TIMEOUT; long lock_timeout = LOCK_TIMEOUT; int sync_channel = 0 ; int async_channel = 0 ; - pthread_mutex_t async_lock=PTHREAD_MUTEX_INITIALIZER;; struct pollfd sync_poll; struct pollfd async_poll; // @@ -398,7 +426,7 @@ namespace nsHiSLIP{ int session_id; int server_protocol_version; unsigned int server_vendorID; - // + //mode variables for HiSLIP protocols. bool overlap_mode = false; // false for synchronized mode, true for overlapped mode bool interrupted = false; bool async_interrupted = false; @@ -410,11 +438,26 @@ namespace nsHiSLIP{ //sem_t srq_lock; pthread_mutex_t srq_lock=PTHREAD_MUTEX_INITIALIZER; // - HiSLIP() { - // if (sem_init(&(this->srq_lock), 0, 1) !=0){ - // perror(" HiSLIP srq_lock"); - // } - }; + std::mutex srq_promise_mutex; + std::stack> srq_promise_stack; + // + std::mutex srq_msg_mutex; + std::stack srq_msg_stack; + // + std::mutex promise_map_mutex; + std::map> promise_map; + // + bool async_recceiver_active; + std::thread *async_receiver_thread=NULL; + // + ~HiSLIP(){ + ::printf("destructor for HiSLIP\n"); + this->stop_async_receiver_thread(); + if (this->check_srq_lock()){ + this->release_srq_lock(); + } + } + // void connect(char const* hostname){ this->connect(hostname, Default_device_name, @@ -424,7 +467,34 @@ namespace nsHiSLIP{ void connect(char const* hostname, char const* dev_name, int port); - + // + void start_async_receiver_thread(void); + void stop_async_receiver_thread(void){ + this->async_recceiver_active=false; + if (this->async_receiver_thread !=NULL){ + this->async_receiver_thread->join(); + }; + }; + void restart_async_receiver_thread(void){ + this->stop_async_receiver_thread(); + this->start_async_receiver_thread(); + }; + void async_receiver_loop(void); + std::future async_send_msg(Message msg, + Message_Types_t responseType=AnyMessages); + void register_async_promise(Message_Types_t responseType, + std::promise p); + void remove_async_promise(Message_Types_t responseType); + // + void push_srq_promise(std::promise p); + std::promise pop_srq_promise(void); + void clear_srq_promise(void); + // + void push_srq_msg(Message msg); + Message pop_srq_msg(void); + void clear_srq_msg(void); + void clear_srq_stacks(void); + // void set_timeout( long timeout){ this->socket_timeout=timeout; }; @@ -475,16 +545,22 @@ namespace nsHiSLIP{ int wait_Service_Request(int wait_time); // int wait_for_Async(int wait_time){ + // just used in EPICS device support. + // shoudl use promise-future. + // create promise and retister it to async-promise list. + // then wait future. this->async_poll.revents=0; return ::poll(&this->async_poll, 1, wait_time); } void disconnect(){ - if (this->sync_channel){ + if (this->sync_channel != 0){ close(this->sync_channel); + this->sync_channel=0; }; - if (this->async_channel){ + if (this->async_channel != 0){ close(this->async_channel); + this->async_channel=0; }; }; @@ -495,10 +571,6 @@ namespace nsHiSLIP{ // private: - int wait_for_answer(int wait_time){ - return ::poll(&this->sync_poll, 1, wait_time); - } - void reset_message_id(void){ this->most_recent_message_id=INITIAL_LAST_MESSAGE_ID; this->most_recent_received_message_id=INITIAL_MESSAGE_ID; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST index 73084f10c..692f97851 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/MANIFEST @@ -2,6 +2,7 @@ HiSLIPFunctionTest.py HiSLIPMessage.cpp HiSLIPMessage.h +Kikusui_PWR401MH_test_for_cPyHiSLIP.py MANIFEST.in Makefile README.rst diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst index 7a1d3d965..41e19af49 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst @@ -54,7 +54,7 @@ To build and install the module, run: Async designe memo ---------------------- -async channelを送受信されるメッセージ +async channelで送受信されるメッセージ c + + + + + Cython: cPyHiSLIP.pxd + + + +

Generated by Cython 0.29.21

+

+ Yellow lines hint at Python interaction.
+ Click on a line that starts with a "+" to see the C code that Cython generated for it. +

+

Raw output: cPyHiSLIP.c

+
 001: #!cython
+
 002: # -*- coding:utf-8 -*-
+
 003: # distutils: language=c++
+
 004: 
+
+005: cdef int SCPIRawSocketPort=5025 # both udp/tcp
+
  __pyx_v_9cPyHiSLIP_SCPIRawSocketPort = 0x13A1;
+
+006: cdef int SCPITelnetPort=5024    # both udp/tcp
+
  __pyx_v_9cPyHiSLIP_SCPITelnetPort = 0x13A0;
+
 007: 
+
 008: cdef extern from "stdlib.h":
+
 009:    cdef void free (void *)
+
 010: 
+
 011: cdef extern from "HiSLIPMessage.h":
+
 012:   # you don’t need to match the type exactly,
+
 013:   # just use something of the right general kind (int, float, etc).
+
 014: 
+
 015:   ctypedef unsigned long  u_long
+
 016:   ctypedef unsigned int   u_int
+
 017:   ctypedef unsigned short u_short
+
 018:   ctypedef unsigned char  u_char
+
 019:   ctypedef int            bool_t
+
 020: 
+
 021:   ctypedef signed char int8_t
+
 022:   ctypedef signed short int int16_t
+
 023:   ctypedef signed       int int32_t
+
 024:   ctypedef signed long  int int64_t
+
 025: 
+
 026:   ctypedef unsigned char      u_int8_t
+
 027:   ctypedef unsigned short int u_int16_t
+
 028:   ctypedef unsigned       int u_int32_t
+
 029:   ctypedef unsigned long  int u_int64_t
+
 030: 
+
 031: cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP":
+
 032:   # exceptions
+
 033:   cdef cppclass HiSLIP_Error "nsHiSLIP:HiSLIP_Error"
+
 034:   cdef cppclass HiSLIP_FatalError "nsHiSLIP:HiSLIP_FatalError"
+
 035:   cdef cppclass HiSLIP_Interrupted "nsHiSLIP:HiSLIP_Interrupted"
+
 036:   cdef cppclass HiSLIP_TimeoutError "nsHiSLIP:HiSLIP_TimeoutError"
+
 037:   cdef cppclass HiSLIP_RutimeError "nsHiSLIP:HiSLIP_RuntimeError"
+
 038:   # static variables
+
 039:   cdef const long  MAXIMUM_MESSAGE_SIZE "nsHiSLIP::MAXIMUM_MESSAGE_SIZE"
+
 040:   cdef char *   Default_device_name "nsHiSLIP::Default_device_name"
+
 041:   cdef int HiSLIPPort "nsHiSLIP::Default_Port"       # not in /etc/services
+
 042:   # classes
+
 043:   cdef cppclass message_parameter "nsHiSLIP::message_parameter"
+
 044:   cdef cppclass Header  "nsHiSLIP::Header"
+
 045:   cdef cppclass Message "nsHiSLIP::Message"
+
 046: 
+
 047:   cdef cppclass cHiSLIP "nsHiSLIP::HiSLIP":
+
 048:     # members
+
 049:     unsigned long maximum_message_size
+
 050:     unsigned long maximum_payload_size
+
 051:     unsigned long current_message_size
+
 052:     unsigned long current_payload_size
+
 053: 
+
 054:     int overlap_mode;
+
 055:     u_int8_t feature_setting
+
 056:     u_int8_t feature_preference
+
 057:     int session_id;
+
 058:     int server_protocol_version;
+
 059:     unsigned int server_vendorID;
+
 060: 
+
 061:     int rmt_delivered;
+
 062:     u_int32_t message_id;
+
 063:     u_int32_t most_recent_message_id;
+
 064:     u_int32_t most_recent_received_message_id;
+
 065:     # methods
+
 066:     cHiSLIP() except+*
+
 067: 
+
 068:     void connect(char * hostname,
+
 069:                  char * dev_name,
+
 070:                  int    port) nogil except+*
+
 071: 
+
 072:     void start_async_receiver_thread() nogil except+*
+
 073:     void stop_async_receiver_thread() nogil except+*
+
 074:     void restart_async_receiver_thread() nogil except+*
+
 075: 
+
 076:     void set_timeout(long) nogil except+*
+
 077:     long get_timeout() nogil except+*
+
 078:     void set_lock_timeout(long) nogil except+*
+
 079:     long get_lock_timeout() nogil except+*
+
 080: 
+
 081:     long set_max_size(long) nogil except+*
+
 082:     int device_clear(u_int8_t) nogil except+*
+
 083:     u_int8_t status_query() nogil except+*
+
 084:     long write(u_int8_t *,  size_t, long) nogil except+*
+
 085:     long read(size_t *, u_int8_t **, long) nogil except+*
+
 086:     long ask(u_int8_t *, size_t, u_int8_t **, long) nogil except+*
+
 087:     long trigger_message() nogil except+*
+
 088:     long remote_local(u_int8_t) nogil except+*
+
 089:     long request_lock(char *) nogil except+*
+
 090:     long release_lock() nogil except+*
+
 091:     long lock_info() nogil except+*
+
 092: 
+
 093:     long request_srq_lock() nogil except+*
+
 094:     long release_srq_lock() nogil except+*
+
 095:     int check_srq_lock() nogil except+*
+
 096:     int check_and_lock_srq_lock() nogil except+*
+
 097:     int get_Service_Request() nogil except+*
+
 098:     int wait_Service_Request(int wait_time) nogil except+*
+
 099:     void clear_srq_stacks() nogil except+*
+
 100:     # int wait_for_Async(int) nogil except+*
+
 101:     void disconnect() nogil except+*
+
 102:     void report_Fatal_Error(const u_int8_t erc, const char *errmsg) nogil except+*
+
 103:     void report_Error(const u_int8_t erc, const char *errmsg)  nogil except+*
+
 104: 
+
diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd index 2d3594263..0426a0d4d 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pxd @@ -28,17 +28,24 @@ cdef extern from "HiSLIPMessage.h": ctypedef unsigned int u_int32_t ctypedef unsigned long int u_int64_t - cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": + # exceptions + cdef cppclass HiSLIP_Error "nsHiSLIP:HiSLIP_Error" + cdef cppclass HiSLIP_FatalError "nsHiSLIP:HiSLIP_FatalError" + cdef cppclass HiSLIP_Interrupted "nsHiSLIP:HiSLIP_Interrupted" + cdef cppclass HiSLIP_TimeoutError "nsHiSLIP:HiSLIP_TimeoutError" + cdef cppclass HiSLIP_RutimeError "nsHiSLIP:HiSLIP_RuntimeError" + # static variables cdef const long MAXIMUM_MESSAGE_SIZE "nsHiSLIP::MAXIMUM_MESSAGE_SIZE" cdef char * Default_device_name "nsHiSLIP::Default_device_name" cdef int HiSLIPPort "nsHiSLIP::Default_Port" # not in /etc/services - + # classes cdef cppclass message_parameter "nsHiSLIP::message_parameter" cdef cppclass Header "nsHiSLIP::Header" cdef cppclass Message "nsHiSLIP::Message" cdef cppclass cHiSLIP "nsHiSLIP::HiSLIP": + # members unsigned long maximum_message_size unsigned long maximum_payload_size unsigned long current_message_size @@ -55,35 +62,43 @@ cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP": u_int32_t message_id; u_int32_t most_recent_message_id; u_int32_t most_recent_received_message_id; - + # methods cHiSLIP() except+ + void connect(char * hostname, char * dev_name, - int port) nogil - void set_timeout(long) nogil - long get_timeout() nogil - void set_lock_timeout(long) nogil - long get_lock_timeout() nogil + int port) nogil except+ + + void start_async_receiver_thread() nogil except+ + void stop_async_receiver_thread() nogil except+ + void restart_async_receiver_thread() nogil except+ + + void set_timeout(long) nogil except+ + long get_timeout() nogil except+ + void set_lock_timeout(long) nogil except+ + long get_lock_timeout() nogil except+ - long set_max_size(long) nogil - int device_clear(u_int8_t) nogil - u_int8_t status_query() nogil - long write(u_int8_t *, size_t, long) nogil - long read(size_t *, u_int8_t **, long) nogil - long ask(u_int8_t *, size_t, u_int8_t **, long) nogil - long trigger_message() nogil - long remote_local(u_int8_t) nogil - long request_lock(char *) nogil - long release_lock() nogil - long request_srq_lock() nogil - long release_srq_lock() nogil - long lock_info() nogil - int check_srq_lock() nogil - int check_and_lock_srq_lock() nogil - int get_Service_Request() nogil - int wait_Service_Request(int wait_time) nogil - int wait_for_Async(int) nogil - void disconnect() nogil - void report_Fatal_Error(const u_int8_t erc, const char *errmsg) nogil - void report_Error(const u_int8_t erc, const char *errmsg) nogil + long set_max_size(long) nogil except+ + int device_clear(u_int8_t) nogil except+ + u_int8_t status_query() nogil except+ + long write(u_int8_t *, size_t, long) nogil except+ + long read(size_t *, u_int8_t **, long) nogil except+ + long ask(u_int8_t *, size_t, u_int8_t **, long) nogil except+ + long trigger_message() nogil except+ + long remote_local(u_int8_t) nogil except+ + long request_lock(char *) nogil except+ + long release_lock() nogil except+ + long lock_info() nogil except+ + + long request_srq_lock() nogil except+ + long release_srq_lock() nogil except+ + int check_srq_lock() nogil except+ + int check_and_lock_srq_lock() nogil except+ + int get_Service_Request() nogil except+ + int wait_Service_Request(int wait_time) nogil except+ + void clear_srq_stacks() nogil except+ + # int wait_for_Async(int) nogil except+ + void disconnect() nogil except+ + void report_Fatal_Error(const u_int8_t erc, const char *errmsg) nogil except+ + void report_Error(const u_int8_t erc, const char *errmsg) nogil except+ diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 73a0cd2c0..20eee3188 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -5,12 +5,15 @@ from cython.operator cimport dereference as deref, preincrement as inc, address as addressof +# +import sys + from cPyHiSLIP cimport cHiSLIP #from cPyHiSLIP cimport HiSLIPPort #from cPyHiSLIP cimport Default_device_name import logging from logging import info,debug,warn,log,fatal,warning -#logging.root.setLevel(logging.DEBUG) +logging.root.setLevel(logging.DEBUG) cdef class HiSLIP: cdef cHiSLIP *thisobj @@ -21,12 +24,11 @@ cdef class HiSLIP: def __init__(self, char *host=NULL): cdef char *chost=host if host: - with nogil: - self.thisobj.connect(chost, Default_device_name, HiSLIPPort) - self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) + self.connect(host) def __dealloc__(self): del self.thisobj + debug("dealloced cHiSLIP object") pass def connect(self, host, device=Default_device_name, port=HiSLIPPort): @@ -34,10 +36,19 @@ cdef class HiSLIP: cdef char *cdevice =device cdef int cport =port debug("connect to {} {} {}".format(host, device, port)) + with nogil: self.thisobj.connect(chost,cdevice,cport) - self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) + + # debug("start async_receiver to {} {} {}".format(host, device, port)) + # with nogil: + # self.thisobj.start_async_receiver_thread() + # debug("setmaxsize to {} {} {}".format(host, device, port)) + # with nogil: + # self.thisobj.set_max_size(MAXIMUM_MESSAGE_SIZE) + + @property def session_id(self): """ @@ -75,15 +86,24 @@ cdef class HiSLIP: with nogil: self.thisobj.write(cmsg, ssize, timeout) - cdef _cread(self,long timeout=3000): + cdef _cread(self,long timeout=3000) except+: cdef unsigned char *buffer=NULL cdef unsigned char **pbuffer=&buffer cdef size_t recieved=0, cdef size_t *precieved=&recieved cdef int rt # debug("calling read in c++") - with nogil: - rt=self.thisobj.read(precieved, pbuffer, timeout) + try: + with nogil: + rt=self.thisobj.read(precieved, pbuffer, timeout) + except RuntimeError as e: + debug("catch c++ exception error: {}".format(sys.exc_info())) + print (e) + raise + except: + debug("Unexpected error: {}".format(sys.exc_info()[0])) + raise + if rt == -1: if (buffer != NULL): free(buffer) @@ -109,7 +129,10 @@ cdef class HiSLIP: def read(self, long timeout=3000): recieved, buffer=self._cread(timeout) - debug("cread result {} {}".format(recieved,len(buffer))) + debug("cread result {} {} {}".format(recieved,len(buffer), + buffer[:recieved] + ) + ) return (recieved, buffer[:recieved]) def ask(self, msg, long wait_time=3000): @@ -370,43 +393,46 @@ cdef class HiSLIP: rc=self.thisobj.get_Service_Request() return rc - def check_SRQ(self): - cdef u_int8_t rc=0 - with nogil: - rc=self.thisobj.wait_for_Async(0) - if rc: - rc=self.thisobj.get_Service_Request() - return rc + # def check_SRQ(self): + # cdef u_int8_t rc=0 + # with nogil: + # rc=self.thisobj.wait_for_Async(0) + # if rc: + # rc=self.thisobj.get_Service_Request() + # return rc def wait_Service_Request(self, int wait_time): cdef int8_t rc=0 with nogil: rc=self.thisobj.wait_Service_Request(wait_time) - - return rc - - def wait_for_Async(self, long wait_time=1000): - """ - return 1 if async port is ready to read - """ - cdef int rc=-1 - with nogil: - rc=self.thisobj.wait_for_Async(wait_time) return rc - def run_svc(self,int wait=1000): - cdef int rc=-1 - cdef u_int8_t st - cdef int cwait=wait + def clear_srq_stacks(self): with nogil: - while 1: - rc=self.thisobj.wait_for_Async(cwait) # msec , wait_for_SRQ does not release GIL so we use shorter time - if rc: - st=self.thisobj.get_Service_Request() # will release lock - if not self.thisobj.session_id: - break - return + self.thisobj.clear_srq_stacks() + + # def wait_for_Async(self, long wait_time=1000): + # """ + # return 1 if async port is ready to read + # """ + # cdef int rc=-1 + # with nogil: + # rc=self.thisobj.wait_for_Async(wait_time) + # return rc + + # def run_svc(self,int wait=1000): + # cdef int rc=-1 + # cdef u_int8_t st + # cdef int cwait=wait + # with nogil: + # while 1: + # rc=self.thisobj.wait_for_Async(cwait) # msec , wait_for_SRQ does not release GIL so we use shorter time + # if rc: + # st=self.thisobj.get_Service_Request() # will release lock + # if not self.thisobj.session_id: + # break + # return def report_FatalError(self, u_int8_t erc, char * errmsg): self.thisobj.report_Fatal_Error(erc, errmsg) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index a3ece3031..6a8683141 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -37,7 +37,7 @@ from distutils.core import setup #from distutils.extension import Extension # -rev="0.2.1" +rev="0.2.2" # sysname=platform.system() From c7d38d2b2a4fbdccb847955ab7240aac156c089f Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 15:13:41 +0900 Subject: [PATCH 59/67] clear cPyHiSLIP.c and cPyHiSLIP.html --- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c | 1 - asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html | 478 -------------------- 2 files changed, 479 deletions(-) delete mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c delete mode 100644 asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c deleted file mode 100644 index 06f2230dd..000000000 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.c +++ /dev/null @@ -1 +0,0 @@ -#error Do not use this file, it is the result of a failed Cython compilation. diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html deleted file mode 100644 index bd27928f3..000000000 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.html +++ /dev/null @@ -1,478 +0,0 @@ - - - - - - Cython: cPyHiSLIP.pxd - - - -

Generated by Cython 0.29.21

-

- Yellow lines hint at Python interaction.
- Click on a line that starts with a "+" to see the C code that Cython generated for it. -

-

Raw output: cPyHiSLIP.c

-
 001: #!cython
-
 002: # -*- coding:utf-8 -*-
-
 003: # distutils: language=c++
-
 004: 
-
+005: cdef int SCPIRawSocketPort=5025 # both udp/tcp
-
  __pyx_v_9cPyHiSLIP_SCPIRawSocketPort = 0x13A1;
-
+006: cdef int SCPITelnetPort=5024    # both udp/tcp
-
  __pyx_v_9cPyHiSLIP_SCPITelnetPort = 0x13A0;
-
 007: 
-
 008: cdef extern from "stdlib.h":
-
 009:    cdef void free (void *)
-
 010: 
-
 011: cdef extern from "HiSLIPMessage.h":
-
 012:   # you don’t need to match the type exactly,
-
 013:   # just use something of the right general kind (int, float, etc).
-
 014: 
-
 015:   ctypedef unsigned long  u_long
-
 016:   ctypedef unsigned int   u_int
-
 017:   ctypedef unsigned short u_short
-
 018:   ctypedef unsigned char  u_char
-
 019:   ctypedef int            bool_t
-
 020: 
-
 021:   ctypedef signed char int8_t
-
 022:   ctypedef signed short int int16_t
-
 023:   ctypedef signed       int int32_t
-
 024:   ctypedef signed long  int int64_t
-
 025: 
-
 026:   ctypedef unsigned char      u_int8_t
-
 027:   ctypedef unsigned short int u_int16_t
-
 028:   ctypedef unsigned       int u_int32_t
-
 029:   ctypedef unsigned long  int u_int64_t
-
 030: 
-
 031: cdef extern from "HiSLIPMessage.h" namespace "nsHiSLIP":
-
 032:   # exceptions
-
 033:   cdef cppclass HiSLIP_Error "nsHiSLIP:HiSLIP_Error"
-
 034:   cdef cppclass HiSLIP_FatalError "nsHiSLIP:HiSLIP_FatalError"
-
 035:   cdef cppclass HiSLIP_Interrupted "nsHiSLIP:HiSLIP_Interrupted"
-
 036:   cdef cppclass HiSLIP_TimeoutError "nsHiSLIP:HiSLIP_TimeoutError"
-
 037:   cdef cppclass HiSLIP_RutimeError "nsHiSLIP:HiSLIP_RuntimeError"
-
 038:   # static variables
-
 039:   cdef const long  MAXIMUM_MESSAGE_SIZE "nsHiSLIP::MAXIMUM_MESSAGE_SIZE"
-
 040:   cdef char *   Default_device_name "nsHiSLIP::Default_device_name"
-
 041:   cdef int HiSLIPPort "nsHiSLIP::Default_Port"       # not in /etc/services
-
 042:   # classes
-
 043:   cdef cppclass message_parameter "nsHiSLIP::message_parameter"
-
 044:   cdef cppclass Header  "nsHiSLIP::Header"
-
 045:   cdef cppclass Message "nsHiSLIP::Message"
-
 046: 
-
 047:   cdef cppclass cHiSLIP "nsHiSLIP::HiSLIP":
-
 048:     # members
-
 049:     unsigned long maximum_message_size
-
 050:     unsigned long maximum_payload_size
-
 051:     unsigned long current_message_size
-
 052:     unsigned long current_payload_size
-
 053: 
-
 054:     int overlap_mode;
-
 055:     u_int8_t feature_setting
-
 056:     u_int8_t feature_preference
-
 057:     int session_id;
-
 058:     int server_protocol_version;
-
 059:     unsigned int server_vendorID;
-
 060: 
-
 061:     int rmt_delivered;
-
 062:     u_int32_t message_id;
-
 063:     u_int32_t most_recent_message_id;
-
 064:     u_int32_t most_recent_received_message_id;
-
 065:     # methods
-
 066:     cHiSLIP() except+*
-
 067: 
-
 068:     void connect(char * hostname,
-
 069:                  char * dev_name,
-
 070:                  int    port) nogil except+*
-
 071: 
-
 072:     void start_async_receiver_thread() nogil except+*
-
 073:     void stop_async_receiver_thread() nogil except+*
-
 074:     void restart_async_receiver_thread() nogil except+*
-
 075: 
-
 076:     void set_timeout(long) nogil except+*
-
 077:     long get_timeout() nogil except+*
-
 078:     void set_lock_timeout(long) nogil except+*
-
 079:     long get_lock_timeout() nogil except+*
-
 080: 
-
 081:     long set_max_size(long) nogil except+*
-
 082:     int device_clear(u_int8_t) nogil except+*
-
 083:     u_int8_t status_query() nogil except+*
-
 084:     long write(u_int8_t *,  size_t, long) nogil except+*
-
 085:     long read(size_t *, u_int8_t **, long) nogil except+*
-
 086:     long ask(u_int8_t *, size_t, u_int8_t **, long) nogil except+*
-
 087:     long trigger_message() nogil except+*
-
 088:     long remote_local(u_int8_t) nogil except+*
-
 089:     long request_lock(char *) nogil except+*
-
 090:     long release_lock() nogil except+*
-
 091:     long lock_info() nogil except+*
-
 092: 
-
 093:     long request_srq_lock() nogil except+*
-
 094:     long release_srq_lock() nogil except+*
-
 095:     int check_srq_lock() nogil except+*
-
 096:     int check_and_lock_srq_lock() nogil except+*
-
 097:     int get_Service_Request() nogil except+*
-
 098:     int wait_Service_Request(int wait_time) nogil except+*
-
 099:     void clear_srq_stacks() nogil except+*
-
 100:     # int wait_for_Async(int) nogil except+*
-
 101:     void disconnect() nogil except+*
-
 102:     void report_Fatal_Error(const u_int8_t erc, const char *errmsg) nogil except+*
-
 103:     void report_Error(const u_int8_t erc, const char *errmsg)  nogil except+*
-
 104: 
-
From 35489c37d6179547ffe48bacb3afb5c70c6faf6d Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 15:46:10 +0900 Subject: [PATCH 60/67] disable debug messages --- .../drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 26 +++++++++---------- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h | 2 +- asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx | 4 +-- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index e9aa8a3e1..0dc4a1878 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -66,7 +66,7 @@ namespace nsHiSLIP{ if (this->payload_length > 0){ size_t bytestoread=this->payload_length; - ::printf("reading data payload 0x%p, length:%zu recvd:%zu\n", this->payload, bytestoread, rsize); + //::printf("reading data payload 0x%p, length:%zu recvd:%zu\n", this->payload, bytestoread, rsize); while (bytestoread){ status = ::recvfrom(socket, ((u_int8_t *)this->payload+rsize), bytestoread, 0, nullptr, nullptr); @@ -81,13 +81,13 @@ namespace nsHiSLIP{ } bytestoread -=status; } - ::printf("reading data payload 0x%p, length:%zu\n",this->payload, bytestoread); + //::printf("reading data payload 0x%p, length:%zu\n",this->payload, bytestoread); } // should be handled in HiSLIP class not in Message class // handle error / or urgent messages: Error/FatalError /interrupted/AsyncInterrupted/AsyncServiceRequest // this->print("msg::recv:"); // for debug - ::printf("reading data payload 0x%p...\n",this->payload); // for debug + //::printf("reading data payload 0x%p...\n",this->payload); // for debug if(this->message_type == nsHiSLIP::FatalError){ ::printf("Error: %d %s\n", this->control_code, nsHiSLIP::Fatal_Error_Messages[this->control_code]); @@ -114,7 +114,7 @@ namespace nsHiSLIP{ throw HiSLIP_Interrupted((char *) this->payload); } else if(this->message_type == nsHiSLIP::AsyncServiceRequest){ - ::printf("SRQ received : %d\n", this->control_code); + //::printf("SRQ received : %d\n", this->control_code); throw SRQ_t("Service Request"); //return -(this->control_code); } @@ -124,7 +124,7 @@ namespace nsHiSLIP{ return 0; } // for debug - this->print("msg:recv failed"); + //this->print("msg:recv failed"); throw std::runtime_error("msg:recv failed"); return -1; } @@ -198,14 +198,14 @@ namespace nsHiSLIP{ status = ::connect(this->sync_channel, res->ai_addr, res->ai_addrlen); if (status!=0){ // Error handling - ::printf("connection to sync_channel failed\n"); + //::printf("connection to sync_channel failed\n"); perror(__FUNCTION__); throw std::runtime_error("cannot connect to sync_channel"); } status = ::connect(this->async_channel, res->ai_addr,res->ai_addrlen); if (status!=0){ // Error handling - ::printf("connection to async_channel failed\n"); + //::printf("connection to async_channel failed\n"); perror(__FUNCTION__); throw std::runtime_error("cannot connect to async_channel"); } @@ -277,7 +277,7 @@ namespace nsHiSLIP{ long HiSLIP::set_max_size(unsigned long message_size){ //this routine may be called before starting async_server . //Message resp(AnyMessages); - int rc=-1; + //int rc=-1; u_int64_t msg_size=htobe64(message_size); Message msg=Message(nsHiSLIP::AsyncMaximumMessageSize, @@ -292,7 +292,7 @@ namespace nsHiSLIP{ // ::printf("got response\n"); // resp.print("response from future"); // ::printf("get payload@%p v:%llu\n",resp.payload, be64toh(*((u_int64_t *)(resp.payload)))); - rc=0; + // rc=0; // ::printf("get payload@%p v:%llu\n",resp.payload, be64toh(*((u_int64_t *)(resp.payload)))); //The 8-byte buffer size is sent in network order as a 64-bit integer. this->maximum_message_size=be64toh(*((u_int64_t *)(resp.payload))); @@ -1016,13 +1016,13 @@ namespace nsHiSLIP{ continue; } else if (rc < 0){ // Error EBADF/EFAULT/EINTR/EINVAL/ENOMEM - ::printf("return code : %d\n",rc); + //::printf("return code : %d\n",rc); ::perror(__FUNCTION__); //continue; throw std::runtime_error(__FUNCTION__); } }; - ::printf("receiver got data\n"); //for debug + //::printf("receiver got data\n"); //for debug try{ status = msg->recv(this->async_channel, nsHiSLIP::AnyMessages); } @@ -1060,7 +1060,7 @@ namespace nsHiSLIP{ case nsHiSLIP::AsyncStatusResponse: case nsHiSLIP::AsyncStartTLSResponse: case nsHiSLIP::AsyncEndTLSResponse: - msg->print("Asycn Responce"); // for debug + //msg->print("Asycn Responce"); // for debug if (this->promise_map.count(msg->message_type) ==0){ msg->print("No promise"); // for debug } @@ -1080,7 +1080,7 @@ namespace nsHiSLIP{ //throw std::runtime_error("asyn_recv loop exception"); break; default: - msg->print("Asycn Other/Vendor Specific(?)"); // for debug + //msg->print("Asycn Other/Vendor Specific(?)"); // for debug if (this->promise_map.count(msg->message_type) == 0){ msg->print("No promise"); // for debug } diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h index b3b98b916..888068add 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.h @@ -451,7 +451,7 @@ namespace nsHiSLIP{ std::thread *async_receiver_thread=NULL; // ~HiSLIP(){ - ::printf("destructor for HiSLIP\n"); + //::printf("destructor for HiSLIP\n"); this->stop_async_receiver_thread(); if (this->check_srq_lock()){ this->release_srq_lock(); diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx index 20eee3188..52fa53afe 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/cPyHiSLIP.pyx @@ -13,7 +13,7 @@ from cPyHiSLIP cimport cHiSLIP #from cPyHiSLIP cimport Default_device_name import logging from logging import info,debug,warn,log,fatal,warning -logging.root.setLevel(logging.DEBUG) +#logging.root.setLevel(logging.DEBUG) cdef class HiSLIP: cdef cHiSLIP *thisobj @@ -98,7 +98,7 @@ cdef class HiSLIP: rt=self.thisobj.read(precieved, pbuffer, timeout) except RuntimeError as e: debug("catch c++ exception error: {}".format(sys.exc_info())) - print (e) + #print (e) raise except: debug("Unexpected error: {}".format(sys.exc_info()[0])) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index 6a8683141..919ee4905 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -37,7 +37,7 @@ from distutils.core import setup #from distutils.extension import Extension # -rev="0.2.2" +rev="0.2.2.1" # sysname=platform.system() From 2750bdd6bdfc4c0d7bc02cc39afe093fb1716669 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 15:52:18 +0900 Subject: [PATCH 61/67] disagle debug messages, again --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 0dc4a1878..4a7f1d955 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -86,7 +86,7 @@ namespace nsHiSLIP{ // should be handled in HiSLIP class not in Message class // handle error / or urgent messages: Error/FatalError /interrupted/AsyncInterrupted/AsyncServiceRequest // - this->print("msg::recv:"); // for debug + //this->print("msg::recv:"); // for debug //::printf("reading data payload 0x%p...\n",this->payload); // for debug if(this->message_type == nsHiSLIP::FatalError){ ::printf("Error: %d %s\n", @@ -1082,7 +1082,7 @@ namespace nsHiSLIP{ default: //msg->print("Asycn Other/Vendor Specific(?)"); // for debug if (this->promise_map.count(msg->message_type) == 0){ - msg->print("No promise"); // for debug + //msg->print("No promise"); // for debug } else{ this->promise_map[msg->message_type].set_value(std::move(*msg)); From dec17a3314547028a204ee61853fae87ca5953ca Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 15:58:20 +0900 Subject: [PATCH 62/67] diable remaining print statement for debug --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 16 ++++++++-------- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 4a7f1d955..56aba9522 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -367,7 +367,7 @@ namespace nsHiSLIP{ rc=resp.recv(this->sync_channel, nsHiSLIP::DeviceClearAcknowledge); - resp.print("Device Clear Acknowledge"); + //resp.print("Device Clear Acknowledge"); if (rc !=0){ // Error! @@ -403,7 +403,7 @@ namespace nsHiSLIP{ Message resp=fut_resp.get(); - resp.print(); + //resp.print(); status= resp.control_code & 0xff; return status; } @@ -508,7 +508,7 @@ namespace nsHiSLIP{ *received +=resp.payload_length; u_int32_t messageid = resp.message_parameter.word; - resp.print(); + //resp.print(); if ( resp.message_type == nsHiSLIP::Data){ if ( this->overlap_mode || @@ -593,7 +593,7 @@ namespace nsHiSLIP{ *received +=resp.payload_length; } u_int32_t messageid = resp.message_parameter.word; - resp.print(); + //resp.print(); if ( resp.message_type == nsHiSLIP::Data){ if ( this->overlap_mode || ( ( messageid == UNKNOWN_MESSAGE_ID) || (messageid == this->most_recent_message_id))){ @@ -690,7 +690,7 @@ namespace nsHiSLIP{ catch(...){ return -1; } - resp.print(); + //resp.print(); return 0; @@ -720,7 +720,7 @@ namespace nsHiSLIP{ try{ Message resp=fut_resp.get(); - resp.print("reuqest_lock"); + //resp.print("reuqest_lock"); return resp.control_code; } catch(...){ @@ -757,7 +757,7 @@ namespace nsHiSLIP{ try{ Message resp=fut_resp.get(); - resp.print(); + //resp.print(); return resp.control_code; } catch(...){ @@ -794,7 +794,7 @@ namespace nsHiSLIP{ try{ Message resp=fut_resp.get(); - resp.print("lock_info"); + //resp.print("lock_info"); lock_exclusive = resp.control_code & 0xff; lock_shared = resp.message_parameter.word; return ((lock_shared << 8) & 0xffffffff00 )+ lock_exclusive; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index 919ee4905..d94116bca 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -37,7 +37,7 @@ from distutils.core import setup #from distutils.extension import Extension # -rev="0.2.2.1" +rev="0.2.2.2" # sysname=platform.system() From 14a27d0e6afca9d38b41c62089f5bcd4cafd6b90 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 16:05:48 +0900 Subject: [PATCH 63/67] diable remaining print statement for debug, again --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 5 +++-- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index 56aba9522..d77ba3a6e 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -971,10 +971,11 @@ namespace nsHiSLIP{ std::promise p; std::future f = p.get_future(); - ::printf("sending async message\n"); + //::printf("sending async message\n"); msg.send(this->async_channel); - ::printf("message sent\n"); + //::printf("message sent\n"); + if (responseType != AnyMessages) { this->register_async_promise(responseType, std::move(p)); this->rmt_delivered = false; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index d94116bca..d945ebac9 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -37,7 +37,7 @@ from distutils.core import setup #from distutils.extension import Extension # -rev="0.2.2.2" +rev="0.2.2.3" # sysname=platform.system() From 8c3f86c235f952f5e95b84357d987308aea23319 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Sat, 6 Feb 2021 16:11:52 +0900 Subject: [PATCH 64/67] diable remaining print statement for debug,one more --- asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp | 6 +++--- asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp index d77ba3a6e..47aef56a7 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/HiSLIPMessage.cpp @@ -326,7 +326,7 @@ namespace nsHiSLIP{ auto fut_resp = this->async_send_msg(*msg, nsHiSLIP::AsyncDeviceClearAcknowledge); { Message resp=fut_resp.get(); - resp.print("received message"); + //resp.print("received message"); this->feature_preference=resp.control_code; } @@ -562,7 +562,7 @@ namespace nsHiSLIP{ return -1; } if (bsize < this->maximum_payload_size){ - ::printf("HiSLIP buffersize:%ld is smallerthan maximum_payload_size:%ld \n ",bsize,this->maximum_payload_size); + ::printf("HiSLIP buffersize:%ld is smaller than maximum_payload_size:%ld \n ",bsize,this->maximum_payload_size); } while(!eom) { int ready; @@ -985,7 +985,7 @@ namespace nsHiSLIP{ p.set_value(std::move(msg)); //p.set_value(msg); } - ::printf("return future\n"); + //::printf("return future\n"); return f; }; diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py index d945ebac9..b01faaf19 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/setup.py @@ -37,7 +37,7 @@ from distutils.core import setup #from distutils.extension import Extension # -rev="0.2.2.3" +rev="0.2.2.4" # sysname=platform.system() From 2e5883811c124adebde5fb05cc02e042a03c26c4 Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Mon, 8 Feb 2021 18:46:31 +0900 Subject: [PATCH 65/67] add conditions in asyn/configure/CONFIG_SITE --- asyn/drvAsynHiSLIP/cPyHiSLIP/README.md | 32 +++++++++++++++++++++--- asyn/drvAsynHiSLIP/cPyHiSLIP/README.rst | 33 ++++++++++++++++++++++--- asyn/drvAsynHiSLIP/cPyHiSLIP/README.txt | 31 ++++++++++++++++++++--- configure/CONFIG_SITE | 12 +++++++-- 4 files changed, 97 insertions(+), 11 deletions(-) diff --git a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md index b6baeb2fd..6c12349cb 100644 --- a/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md +++ b/asyn/drvAsynHiSLIP/cPyHiSLIP/README.md @@ -25,18 +25,44 @@ cPyHiSLIP.pxd. If you dont have installed cython, try: > pip install cython -or +or (I personally recomend this way): > python -m pip install cython To build and install the module, run: -> python setup.py install +> python setup.py build install + +You may need a privilege for installation. + +How to Use +---------- + +A very Simple example: + +> import cPyHiSLIP device=cPyHiSLIP.HiSLIP(b\"xxx.yyy.zzz.ttt\") print +> (dev.ask(b\"\*IDN?\") + +Note that arguments to the method are given as bytes, but not strings. A +return value from the method is also anbyte array, not strings. + +Methods , .write(), .read() and .ask() , are provided for the +communication through sync channe. + +For the communication throug async channel, specfied methods are +privided, such as, device\_clear, status\_query, trigger\_device, +remote-local, request\_lock, release\_lock, lock\_info. + +An interrupt mode can be actiavated by: + +> dev.device\_clear(1) + +### SRQ support Async designe memo ------------------ -async channelを送受信されるメッセージ +async channelで送受信されるメッセージ c\ Date: Wed, 10 Feb 2021 17:52:02 +0900 Subject: [PATCH 66/67] put HiSLIP flag into CONFIG_SITE.darwin-x86.Common etc. --- configure/CONFIG_SITE.darwin-x86.Common | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 configure/CONFIG_SITE.darwin-x86.Common diff --git a/configure/CONFIG_SITE.darwin-x86.Common b/configure/CONFIG_SITE.darwin-x86.Common new file mode 100644 index 000000000..2494e8e48 --- /dev/null +++ b/configure/CONFIG_SITE.darwin-x86.Common @@ -0,0 +1,14 @@ +# If you have libusb-1.0 and libftdi, and want FTDI support, set DRV_FTDI=YES +#DRV_FTDI=YES + +# If your system has libftdi1, set the following to YES. If it has libftdi, set it to NO +#DRV_FTDI_USE_LIBFTDI1=YES + + +ifeq (linux-x86_64, $(T_A)) + DRV_HISLIP=YES +else + ifeq (darwin-x86, $(T_A)) + DRV_HISLIP=YES + endif +endif From a487400a5804be2640816a97e2a86bab0b2f0edd Mon Sep 17 00:00:00 2001 From: Noboru Yamamoto Date: Wed, 10 Feb 2021 17:52:43 +0900 Subject: [PATCH 67/67] put HiSLIP flag into CONFIG_SITE.darwin-x86.Common etc. --- configure/CONFIG_SITE | 12 ------------ configure/CONFIG_SITE.linux-x86_64.Common | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index 3a87a79a6..ea2b8af8c 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -39,18 +39,6 @@ CHECK_RELEASE = YES # If you have libusb-1.0 revision 16 or newer and want the USB TMC support set DRV_USBTMC=YES #DRV_USBTMC=YES - -ifeq (linux-x86_64, $(T_A)) - DRV_USBTMC=YES - DRV_HISLIP=YES -else - ifeq (darwin-x86, $(T_A)) - DRV_USBTMC=YES - DRV_HISLIP=YES - endif -endif - - # You can also define this on a per-architecture basis. # In this example DRV_USBTMC would be built only for linux-x86_64, and not for other architectures #ifeq (linux-x86_64, $(T_A)) diff --git a/configure/CONFIG_SITE.linux-x86_64.Common b/configure/CONFIG_SITE.linux-x86_64.Common index e24205eaf..ee2a01494 100644 --- a/configure/CONFIG_SITE.linux-x86_64.Common +++ b/configure/CONFIG_SITE.linux-x86_64.Common @@ -3,3 +3,15 @@ # If your system has libftdi1, set the following to YES. If it has libftdi, set it to NO #DRV_FTDI_USE_LIBFTDI1=YES + + +# asyn/asyn/drvHiSLIP support +# ifeq (linux-x86_64, $(T_A)) +# DRV_HISLIP=YES +# else +# ifeq (darwin-x86, $(T_A)) +# DRV_HISLIP=YES +# endif +# endif + +