RS485Driver/HLApp/rs485_hl_driver.c (113 lines of code) (raw):

/* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. */ #include <errno.h> #include <string.h> #include <sys/time.h> #include <sys/socket.h> #include <applibs/log.h> #include <applibs/application.h> #include "../common_defs.h" #include "eventloop_timer_utilities.h" #include "rs485_hl_driver.h" static int rtAppSockFd = -1; static EventLoop *rs485eventLoop; static EventRegistration *socketEventReg = NULL; static Rs485ReceiveCallback *userCallback = NULL; static uint8_t *rs485rxBuffer = NULL; static size_t rs485rxBufferSize = 0; static void RTAppSocketEventHandler(EventLoop *el, int fd, EventLoop_IoEvents events, void *context); int Rs485_Init(EventLoop *eventLoop, uint8_t *rxBuffer, size_t rxBufferSize, Rs485ReceiveCallback *callback) { if (rtAppSockFd >= 0) { Log_Debug("ERROR: RS-485 driver already initialized! Call Rs485_Close() before re-initializing.\n"); return -1; } else { // Open a connection to the RS-485 driver RTApp. rtAppSockFd = Application_Connect(rtAppComponentId); if (rtAppSockFd == -1) { Log_Debug("ERROR: Unable to create socket: %d (%s)\n", errno, strerror(errno)); return -1; } // Set the socket's timeout, to handle cases where real-time capable application does not respond. static const struct timeval recvTimeout = { .tv_sec = 5, .tv_usec = 0 }; int result = setsockopt(rtAppSockFd, SOL_SOCKET, SO_RCVTIMEO, &recvTimeout, sizeof(recvTimeout)); if (result == -1) { Log_Debug("ERROR: Unable to set socket timeout: %d (%s)\n", errno, strerror(errno)); return -1; } // Register the handler for incoming messages from real-time RS-485 driver. socketEventReg = EventLoop_RegisterIo(eventLoop, rtAppSockFd, EventLoop_Input, RTAppSocketEventHandler, /* context */ NULL); if (socketEventReg == NULL) { Log_Debug("ERROR: Unable to register socket event: %d (%s)\n", errno, strerror(errno)); return -1; } // Setup the user-callback userCallback = callback; // Setup the RX buffer if (NULL == rxBuffer || rxBufferSize < 32) { Log_Debug("ERROR: RX buffer not defined or too small: %p (%zu bytes)\n", rxBuffer, rxBufferSize); return -1; } else { rs485rxBuffer = rxBuffer; rs485rxBufferSize = rxBufferSize; } } return 0; } void Rs485_Close(void) { EventLoop_UnregisterIo(rs485eventLoop, socketEventReg); if (rtAppSockFd >= 0) { int result = close(rtAppSockFd); if (result != 0) { Log_Debug("ERROR: Could not close rtAppSockFd %s: %s (%d).\n", "RTApp socket", strerror(errno), errno); } } rtAppSockFd = -1; userCallback = NULL; rs485rxBuffer = NULL; rs485rxBufferSize = 0; } int Rs485_Send(const void *data, size_t dataLen) { // Prepare the block if (dataLen > MAX_HLAPP_MESSAGE_SIZE) { Log_Debug("ERROR: data buffer too big: %d (> %d)\n", dataLen, MAX_HLAPP_MESSAGE_SIZE); return -1; } // Log the bytes to be sent Log_Debug("Rs485_Driver: sending %ld bytes: ", dataLen); for (int i = 0; i < dataLen; ++i) { Log_Debug("%02x", ((char*)data)[i]); if (i != dataLen - 1) { Log_Debug(":"); } } Log_Debug("\n"); // Send the block to the RS-485 RTApp driver int bytesSent = send(rtAppSockFd, data, dataLen, 0); if (bytesSent == -1) { Log_Debug("ERROR: Unable to send message to the RS-485 driver: %d (%s)\n", errno, strerror(errno)); return -1; } return bytesSent; } void RTAppSocketEventHandler(EventLoop *el, int fd, EventLoop_IoEvents events, void *context) { if (NULL != rs485rxBuffer) { // Read response from real-time capable application. // If the RTApp has sent more than rs485rxBufferSize, then truncate. int bytesReceived = recv(fd, rs485rxBuffer, rs485rxBufferSize, 0); if (bytesReceived == -1) { Log_Debug("ERROR: Unable to receive message from the RS-485 driver: %d (%s)\n", errno, strerror(errno)); return; } // Log the received bytes Log_Debug("Rs485_Driver: received %d bytes: ", bytesReceived); for (int i = 0; i < bytesReceived; ++i) { Log_Debug("%02x", rs485rxBuffer[i]); if (i != bytesReceived - 1) { Log_Debug(":"); } } Log_Debug("\n"); if (NULL != userCallback) { userCallback(bytesReceived); } } }