static void read_remote(ph_sock_t *sock, ph_iomask_t why, void *data) { ph_buf_t *buf; ph_unused_parameter(data); if (why & (PH_IOMASK_TIME|PH_IOMASK_ERR)) { ph_log(PH_LOG_ERR, "disconnecting `P{sockaddr:%p}", (void*)&sock->peername); ph_sock_shutdown(sock, PH_SOCK_SHUT_RDWR); ph_sock_free(sock); remote_sock = NULL; ph_sched_stop(); return; } while (1) { buf = ph_sock_read_line(sock); if (!buf) { // Not available yet, we'll try again later return; } ph_ignore_result(write(STDOUT_FILENO, ph_buf_mem(buf), ph_buf_len(buf))); ph_buf_delref(buf); } }
int uei_508_read_bytes(int m_port, char *m_buf, size_t m_bytes) { ph_buf_t *tmp_buf; if ((tmp_buf = ph_bufq_consume_bytes(SL508_read_buffer[m_port], m_bytes))) { memcpy(m_buf, ph_buf_mem(tmp_buf), m_bytes); ph_buf_delref(tmp_buf); return m_bytes; } else { return 0; } }
// Called each time the session wakes up. // The `why` parameter indicates why we were woken up static void echo_processor(ph_sock_t *sock, ph_iomask_t why, void *arg) { struct echo_state *state = arg; ph_buf_t *buf; // If the socket encountered an error, or if the timeout was reached // (there's a default timeout, even if we didn't override it), then // we tear down the session if (why & (PH_IOMASK_ERR|PH_IOMASK_TIME)) { ph_log(PH_LOG_ERR, "disconnecting `P{sockaddr:%p}", (void*)&sock->peername); ph_sock_shutdown(sock, PH_SOCK_SHUT_RDWR); ph_mem_free(mt_state, state); ph_sock_free(sock); return; } // We loop because echo_processor is only triggered by newly arriving // data or events from the kernel. If we have data buffered and only // partially consume it, we won't get woken up until the next data // arrives, if ever. while (1) { // Try to read a line of text. // This returns a slice over the underlying buffer (if the line was // smaller than a buffer) or a freshly made contiguous buffer (if the // line was larger than our buffer segment size). Either way, we // own a reference to the returned buffer and should treat it as // a read-only slice. buf = ph_sock_read_line(sock); if (!buf) { // Not available yet, we'll try again later return; } // We got a line; update our state state->num_lines++; // Send our response. The data is buffered and automatically sent // to the client as it becomes writable, so we don't need to handle // partial writes or EAGAIN here. // If this was a "real" server, we would still check the return value // from the writes and proceed to tear down the session if things failed. // Note that buf includes the trailing CRLF, so our response // will implicitly end with CRLF too. ph_stm_printf(sock->stream, "You said [%d]: ", state->num_lines); ph_stm_write(sock->stream, ph_buf_mem(buf), ph_buf_len(buf), NULL); // We're done with buf, so we must release it ph_buf_delref(buf); } }
int uei_508_read_record(int m_port, char *m_buf, size_t m_buflen, const char *m_delim, uint32_t m_delimlen) { ph_buf_t *tmp_buf; if ((tmp_buf = ph_bufq_consume_record(SL508_read_buffer[m_port], m_delim, m_delimlen))) { size_t len = min((size_t)ph_buf_len(tmp_buf), m_buflen); if (len) memcpy(m_buf, ph_buf_mem(tmp_buf), len); ph_buf_delref(tmp_buf); return len; } else { return 0; } }
static void debug_con_processor(ph_sock_t *sock, ph_iomask_t why, void *arg) { if (why & (PH_IOMASK_ERR|PH_IOMASK_TIME)) { done: ph_sock_shutdown(sock, PH_SOCK_SHUT_RDWR); ph_sock_free(sock); return; } if (arg && (why & PH_IOMASK_WRITE) && ph_bufq_len(sock->wbuf) == 0) { goto done; } if (arg == NULL && (why & PH_IOMASK_READ)) { ph_buf_t *buf; char *cmd; int len; uint32_t i; buf = ph_sock_read_line(sock); if (!buf) { return; } sock->job.data = buf; ph_sock_shutdown(sock, PH_SOCK_SHUT_RD); cmd = (char*)ph_buf_mem(buf); len = ph_buf_len(buf); /* replace CRLF with NUL termination */ cmd[len - 2] = '\0'; for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) { if (strcmp(funcs[i].name, cmd)) { continue; } funcs[i].func(sock); break; } } }
void *uei_508_loop(void *m_arg) { struct timespec next; uint64_t periodns = ((double)(NSEC_PER_SEC) / 10); int ret; int channel_list_508[8] = {0, 1, 2, 3, 4, 5, 6, 7}; uint32_t channel_cfg_508[8] = { CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600) }; int channel_flags_508[8] = { 0 }; ph_library_init(); ph_thread_set_name("UEI508"); blast_startup("Starting UEI 508 loop"); // set channel configuration for (int i = 0; i < 8; i++) { if ((ret = DqAdv501SetChannelCfg(hd_508, 4, i, channel_cfg_508[i])) < 0) { blast_err("Error in DqAdv501SetChannelCfg()"); } } ret = DqRtVmapAddChannel(hd_508, vmapid_508, 4, DQ_SS0IN, channel_list_508, channel_flags_508, 8); ret = DqRtVmapAddChannel(hd_508, vmapid_508, 4, DQ_SS0OUT, channel_list_508, channel_flags_508, 8); ret = DqRtVmapStart(hd_508, vmapid_508); clock_gettime(CLOCK_MONOTONIC, &next); while (!shutdown_mcp) { for (int i = 0; i < 8; i++) { size_t num_bytes; ph_buf_t *outbuf = NULL; if ((num_bytes = ph_bufq_len(SL508_write_buffer[i]))) { outbuf = ph_bufq_consume_bytes(SL508_write_buffer[i], num_bytes); DqRtVmapWriteOutput(hd_508, vmapid_508, 4, i, num_bytes, ph_buf_mem(outbuf)); ph_buf_delref(outbuf); } DqRtVmapRequestInput(hd_508, vmapid_508, 4, i, 128); } // Write output data to each TX port FIFO and Read each RX port FIFO ret = DqRtVmapRefresh(hd_508, vmapid_508, 0); // Read data received during the last refresh for (int i = 0; i < 8; i++) { uint8_t read_buffer[128]; int read_len; DqRtVmapReadInput(hd_508, vmapid_508, 4, i, sizeof(read_buffer), &read_len, read_buffer); if (read_len > 0) { ph_bufq_append(SL508_read_buffer[i], read_buffer, read_len, NULL); } } timespec_add_ns(&next, periodns); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); } DqRtVmapStop(hd_508, vmapid_508); DqRtVmapClose(hd_508, vmapid_508); return NULL; }