URL
https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk
Subversion Repositories riscv_vhdl
Compare Revisions
- This comparison shows the changes necessary to convert path
/riscv_vhdl/trunk/debugger/src/libdbg64g/services
- from Rev 4 to Rev 5
- ↔ Reverse comparison
Rev 4 → Rev 5
/.gitignore
0,0 → 1,?rev2len?
!debug |
/debug/edcl.cpp
0,0 → 1,218
/** |
* @file |
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved. |
* @author Sergey Khabarov - sergeykhbr@gmail.com |
* @brief Access to a hardware via Ethernet EDCL interface implementaion. |
*/ |
|
#include "edcl_types.h" |
#include "edcl.h" |
|
namespace debugger { |
|
/** Class registration in the Core */ |
REGISTER_CLASS(EdclService) |
|
EdclService::EdclService(const char *name) : IService(name) { |
registerInterface(static_cast<ITap *>(this)); |
registerAttribute("Transport", &transport_); |
registerAttribute("seq_cnt", &seq_cnt_); |
seq_cnt_.make_uint64(0); |
itransport_ = 0; |
|
dbgRdTRansactionCnt_ = 0; |
} |
|
void EdclService::postinitService() { |
IService *iserv = |
static_cast<IService *>(RISCV_get_service(transport_.to_string())); |
if (!iserv) { |
RISCV_error("Transport service '%'s not found", |
transport_.to_string()); |
} |
itransport_ = static_cast<ILink *>(iserv->getInterface(IFACE_LINK)); |
if (!itransport_) { |
RISCV_error("UDP interface '%s' not found", |
transport_.to_string()); |
} |
} |
|
int EdclService::read(uint64_t addr, int bytes, uint8_t *obuf) { |
int txoff, rxoff; |
UdpEdclCommonType req = {0}; |
UdpEdclCommonType rsp; |
|
if (!itransport_) { |
RISCV_error("UDP transport not defined, addr=%x", addr); |
return TAP_ERROR; |
} |
|
int rd_bytes = 0; |
while (rd_bytes < bytes && rd_bytes != TAP_ERROR) { |
req.control.request.seqidx = |
static_cast<uint32_t>(seq_cnt_.to_uint64()); |
req.control.request.write = 0; |
req.address = static_cast<uint32_t>(addr + rd_bytes); |
if ((bytes - rd_bytes) > EDCL_PAYLOAD_MAX_BYTES) { |
req.control.request.len = |
static_cast<uint32_t>(EDCL_PAYLOAD_MAX_BYTES); |
} else { |
req.control.request.len = static_cast<uint32_t>(bytes - rd_bytes); |
} |
|
txoff = write16(tx_buf_, 0, req.offset); |
txoff = write32(tx_buf_, txoff, req.control.word); |
txoff = write32(tx_buf_, txoff, req.address); |
|
txoff = itransport_->sendData(tx_buf_, txoff); |
if (txoff == -1) { |
RISCV_error("Data sending error", NULL); |
rd_bytes = TAP_ERROR; |
break; |
} |
|
dbgRdTRansactionCnt_++; |
rxoff = itransport_->readData(rx_buf_, sizeof(rx_buf_)); |
if (rxoff == -1) { |
RISCV_error("Data receiving error", NULL); |
rd_bytes = TAP_ERROR; |
break; |
} |
if (rxoff == 0) { |
RISCV_error("No response. Break read transaction[%d] at %08x", |
dbgRdTRansactionCnt_, req.address); |
rd_bytes = TAP_ERROR; |
break; |
} |
|
rsp.control.word = read32(&rx_buf_[2]); |
|
const char *NAK[2] = {"ACK", "NAK"}; |
RISCV_debug("EDCL read: %s[%d], len = %d", |
NAK[rsp.control.response.nak], |
rsp.control.response.seqidx, |
rsp.control.response.len); |
|
// Retry with new sequence counter. |
if (rsp.control.response.nak) { |
RISCV_info("Sequence counter detected %d. Re-sending transaction.", |
rsp.control.response.seqidx); |
seq_cnt_.make_uint64(rsp.control.response.seqidx); |
continue; |
} |
|
// Try to receive next packet: |
if (rsp.control.response.seqidx != seq_cnt_.to_uint32()) { |
RISCV_error("Wrong ID received %d != %d. Try again.", |
seq_cnt_.to_uint32(), rsp.control.response.seqidx); |
|
rxoff = itransport_->readData(rx_buf_, sizeof(rx_buf_)); |
if (rxoff <= 0) { |
rd_bytes = TAP_ERROR; |
break; |
} |
rsp.control.word = read32(&rx_buf_[2]); |
if (rsp.control.response.seqidx != seq_cnt_.to_uint32()) { |
rd_bytes = TAP_ERROR; |
break; |
} |
} |
|
memcpy(&obuf[rd_bytes], &rx_buf_[10], rsp.control.response.len); |
rd_bytes += rsp.control.response.len; |
seq_cnt_.make_uint64((seq_cnt_.to_uint64() + 1) & 0x3FFF); |
} |
return rd_bytes; |
} |
|
int EdclService::write(uint64_t addr, int bytes, uint8_t *ibuf) { |
int off; |
UdpEdclCommonType req = {0}; |
UdpEdclCommonType rsp; |
|
if (!itransport_) { |
RISCV_error("UDP transport not defined, addr=%x", addr); |
return TAP_ERROR; |
} |
|
int wr_bytes = 0; |
while (wr_bytes < bytes && wr_bytes != -1) { |
req.control.request.seqidx = |
static_cast<uint32_t>(seq_cnt_.to_uint64()); |
req.control.request.write = 1; |
req.address = static_cast<uint32_t>(addr + wr_bytes); |
if ((bytes - wr_bytes) > EDCL_PAYLOAD_MAX_BYTES) { |
req.control.request.len = |
static_cast<uint32_t>(EDCL_PAYLOAD_MAX_BYTES); |
} else { |
req.control.request.len = static_cast<uint32_t>(bytes - wr_bytes); |
} |
|
off = write16(tx_buf_, 0, req.offset); |
off = write32(tx_buf_, off, req.control.word); |
off = write32(tx_buf_, off, req.address); |
memcpy(&tx_buf_[off], &ibuf[wr_bytes], req.control.request.len); |
|
|
off = itransport_->sendData(tx_buf_, off + req.control.request.len); |
if (off == -1) { |
RISCV_error("Data sending error", NULL); |
wr_bytes = -1; |
break; |
} |
|
off = itransport_->readData(rx_buf_, sizeof(rx_buf_)); |
if (off == -1) { |
RISCV_error("Data receiving error", NULL); |
wr_bytes = -1; |
break; |
} |
if (off == 0) { |
RISCV_error("No response. Break write transaction.", NULL); |
wr_bytes = -1; |
break; |
} |
|
rsp.control.word = read32(&rx_buf_[2]); |
|
// Warning: |
// response length = 0; |
const char *NAK[2] = {"ACK", "NAK"}; |
RISCV_debug("EDCL write: %s[%d], len = %d", |
NAK[rsp.control.response.nak], |
rsp.control.response.seqidx, |
req.control.request.len); |
|
// Retry with new sequence counter. |
if (rsp.control.response.nak) { |
RISCV_info("Sequence counter detected %d. Re-sending transaction.", |
rsp.control.response.seqidx); |
seq_cnt_.make_uint64(rsp.control.response.seqidx); |
continue; |
} |
|
wr_bytes += req.control.request.len; |
seq_cnt_.make_uint64(seq_cnt_.to_uint64() + 1); |
} |
return wr_bytes; |
} |
|
int EdclService::write16(uint8_t *buf, int off, uint16_t v) { |
buf[off++] = (uint8_t)((v >> 8) & 0xFF); |
buf[off++] = (uint8_t)(v & 0xFF); |
return off; |
} |
|
int EdclService::write32(uint8_t *buf, int off, uint32_t v) { |
buf[off++] = (uint8_t)((v >> 24) & 0xFF); |
buf[off++] = (uint8_t)((v >> 16) & 0xFF); |
buf[off++] = (uint8_t)((v >> 8) & 0xFF); |
buf[off++] = (uint8_t)(v & 0xFF); |
return off; |
} |
|
uint32_t EdclService::read32(uint8_t *buf) { |
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0); |
} |
|
} // namespace debugger |
debug/edcl.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: debug/edcl.h
===================================================================
--- debug/edcl.h (nonexistent)
+++ debug/edcl.h (revision 5)
@@ -0,0 +1,55 @@
+/**
+ * @file
+ * @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief Access to a hardware via Ethernet EDCL interface implementaion.
+ */
+
+#ifndef __DEBUGGER_EDCL_H__
+#define __DEBUGGER_EDCL_H__
+
+#include "iclass.h"
+#include "iservice.h"
+#include "coreservices/itap.h"
+#include "coreservices/ilink.h"
+#include
+
+namespace debugger {
+
+class EdclService : public IService,
+ public ITap {
+public:
+ EdclService(const char *name);
+
+ /** IService interface */
+ virtual void postinitService();
+
+ /** ITap interface */
+ virtual int read(uint64_t addr, int bytes, uint8_t *obuf);
+ virtual int write(uint64_t addr, int bytes, uint8_t *ibuf);
+
+private:
+ int write16(uint8_t *buf, int off, uint16_t v);
+ int write32(uint8_t *buf, int off, uint32_t v);
+ uint32_t read32(uint8_t *buf);
+
+private:
+ /** This is limitation of the MAC fifo. Protocol allows increase the
+ * following value up to 242 words. */
+ static const int EDCL_PAYLOAD_MAX_WORDS32 = 8;
+ static const int EDCL_PAYLOAD_MAX_BYTES = 4*EDCL_PAYLOAD_MAX_WORDS32;
+
+ uint8_t tx_buf_[4096];
+ uint8_t rx_buf_[4096];
+ ILink *itransport_;
+ AttributeType transport_;
+ AttributeType seq_cnt_;
+
+ int dbgRdTRansactionCnt_;
+};
+
+DECLARE_CLASS(EdclService)
+
+} // namespace debugger
+
+#endif // __DEBUGGER_EDCL_H__
debug/edcl.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: debug/edcl_types.h
===================================================================
--- debug/edcl_types.h (nonexistent)
+++ debug/edcl_types.h (revision 5)
@@ -0,0 +1,49 @@
+/**
+ * @file
+ * @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief EDCL user defined transport structure.
+ */
+
+ #ifndef __DEBUGGER_EDCL_TYPES_H__
+ #define __DEBUGGER_EDCL_TYPES_H__
+
+ #include
+
+ namespace debugger {
+
+struct EdclControlRequestType {
+ // 32 bits fields:
+ uint32_t unused : 7;
+ uint32_t len : 10;
+ uint32_t write : 1; // read = 0; write = 1
+ uint32_t seqidx : 14; // sequence id
+ //uint32 data; // 0 to 242 words
+};
+
+
+struct EdclControlResponseType {
+ // 32 bits fields:
+ uint32_t unused : 7;
+ uint32_t len : 10;
+ uint32_t nak : 1; // ACK = 0; NAK = 1
+ uint32_t seqidx : 14; // sequence id
+ //uint32 data; // 0 to 242 words
+};
+
+#pragma pack(1)
+struct UdpEdclCommonType {
+ uint16_t offset;
+ union ControlType {
+ uint32_t word;
+ EdclControlRequestType request;
+ EdclControlResponseType response;
+ } control;
+ uint32_t address;
+ //uint32 data; // 0 to 242 words
+};
+#pragma pack()
+
+} // namespace debugger
+
+#endif // __DEBUGGER_EDCL_TYPES_H__
debug/edcl_types.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: debug/serial_dbglink.cpp
===================================================================
--- debug/serial_dbglink.cpp (nonexistent)
+++ debug/serial_dbglink.cpp (revision 5)
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @details
+ * Write command:
+ * Send [11.Length-1].Addr[63:0].Data[31:0]*(x Length)
+ * Read command:
+ * Send [10.Length-1].Addr[63:0]
+ * Receive Data[31:0]*(x Length)
+ */
+
+#include "api_core.h"
+#include "serial_dbglink.h"
+
+namespace debugger {
+
+/** Class registration in the Core */
+REGISTER_CLASS(SerialDbgService)
+
+SerialDbgService::SerialDbgService(const char *name)
+ : IService(name) {
+ registerInterface(static_cast(this));
+ registerAttribute("Timeout", &timeout_);
+ registerAttribute("Port", &port_);
+
+ RISCV_event_create(&event_block_, "SerialDbg_event_block");
+}
+
+SerialDbgService::~SerialDbgService() {
+ RISCV_event_close(&event_block_);
+}
+
+void SerialDbgService::postinitService() {
+ iserial_ = static_cast(
+ RISCV_get_service_iface(port_.to_string(), IFACE_SERIAL));
+ if (!iserial_) {
+ RISCV_error("Can't find ISerial interface %s", port_.to_string());
+ return;
+ }
+ iserial_->registerRawListener(static_cast(this));
+#if 1 // hardcoded scale in tapuart, no need in clock detection
+ /** Automatic baudrate definition on hardware side:
+ * [0] 0x55 - to init baud rate detector
+ * [1] 0x55 - to confirm baud rate value.
+ */
+ char tbuf[5] = {0x55, 0x55, 0x55, 0x55};
+ iserial_->writeData(tbuf, 4);
+#endif
+}
+
+void SerialDbgService::predeleteService() {
+ if (iserial_) {
+ iserial_->unregisterRawListener(static_cast(this));
+ }
+}
+
+int SerialDbgService::read(uint64_t addr, int bytes, uint8_t *obuf) {
+ if (!iserial_) {
+ return TAP_ERROR;
+ }
+ if (bytes <= 0 || (bytes & 0x3) != 0) {
+ RISCV_error("Unaligned read %d", bytes);
+ return TAP_ERROR;
+ }
+ addr &= 0xFFFFFFFFull;
+ int bytes_to_read = bytes;
+ uint8_t *tout = obuf;
+ pkt_.fields.magic = MAGIC_ID;
+ pkt_.fields.addr = addr;
+ while (bytes_to_read) {
+ pkt_.fields.cmd = (0x2 << 6);
+ if (bytes_to_read > 4 * UART_MST_BURST_MAX) {
+ req_count_ = 4 * UART_MST_BURST_MAX;
+ pkt_.fields.cmd |= 0x3F;
+ } else {
+ req_count_ = bytes_to_read;
+ pkt_.fields.cmd |= ((bytes_to_read / 4) - 1) & 0x3F;
+ }
+ rd_count_ = 0;
+ wait_bytes_ = req_count_;
+ RISCV_event_clear(&event_block_);
+ iserial_->writeData(pkt_.buf, UART_REQ_HEADER_SZ);
+
+ if (RISCV_event_wait_ms(&event_block_, timeout_.to_int()) != 0) {
+ RISCV_error("Reading [%08" RV_PRI64 "x] failed", addr);
+ return TAP_ERROR;
+ }
+ if (rd_count_ != req_count_) {
+ RISCV_error("Read bytes %d of %d", rd_count_, req_count_);
+ return TAP_ERROR;
+ }
+
+ memcpy(tout, rxbuf_[0].buf, rd_count_);
+ tout += rd_count_;
+ pkt_.fields.addr += static_cast(rd_count_);
+ bytes_to_read -= rd_count_;
+ }
+ return bytes;
+}
+
+int SerialDbgService::write(uint64_t addr, int bytes, uint8_t *ibuf) {
+ if (!iserial_) {
+ return TAP_ERROR;
+ }
+ if (bytes <= 0 || (bytes & 0x3) != 0) {
+ RISCV_error("Unaligned write %d", bytes);
+ return TAP_ERROR;
+ }
+ addr &= 0xFFFFFFFFull;
+ int bytes_to_write = bytes;
+ uint8_t *tin = ibuf;
+ pkt_.fields.magic = MAGIC_ID;
+ pkt_.fields.addr = addr;
+ while (bytes_to_write) {
+ pkt_.fields.cmd = (0x3 << 6);
+ if (bytes_to_write > 4 * UART_MST_BURST_MAX) {
+ req_count_ = 4 * UART_MST_BURST_MAX;
+ pkt_.fields.cmd |= 0x3F;
+ } else {
+ req_count_ = bytes_to_write;
+ pkt_.fields.cmd |= ((bytes_to_write / 4) - 1) & 0x3F;
+ }
+ memcpy(pkt_.fields.data, tin, req_count_);
+
+ wait_bytes_ = 4;
+ rd_count_ = 0;
+ RISCV_event_clear(&event_block_);
+ iserial_->writeData(pkt_.buf, UART_REQ_HEADER_SZ + req_count_);
+
+ // Waiting "ACK\n" handshake
+ if (RISCV_event_wait_ms(&event_block_, timeout_.to_int()) != 0) {
+ RISCV_error("Writing [%08" RV_PRI64 "x] failed", addr);
+ return TAP_ERROR;
+ }
+
+ tin += req_count_;
+ bytes_to_write -= req_count_;
+ pkt_.fields.addr += static_cast(req_count_);
+ }
+ return bytes;
+}
+
+void SerialDbgService::updateData(const char *buf, int buflen) {
+ uint8_t *tbuf = &rxbuf_[0].buf[rd_count_];
+ memcpy(tbuf, buf, buflen);
+ rd_count_ += buflen;
+ if (rd_count_ < wait_bytes_) {
+ return;
+ }
+ RISCV_event_set(&event_block_);
+}
+
+} // namespace debugger
debug/serial_dbglink.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: debug/serial_dbglink.h
===================================================================
--- debug/serial_dbglink.h (nonexistent)
+++ debug/serial_dbglink.h (revision 5)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DEBUGGER_SERIAL_DBGLINK_SERVICE_H__
+#define __DEBUGGER_SERIAL_DBGLINK_SERVICE_H__
+
+#include "iclass.h"
+#include "iservice.h"
+#include "coreservices/itap.h"
+#include "coreservices/iserial.h"
+#include "coreservices/irawlistener.h"
+
+namespace debugger {
+
+#define MAGIC_ID 0x31
+static const int UART_REQ_HEADER_SZ = 10;
+static const int UART_MST_BURST_MAX = 64;
+
+#pragma pack(1)
+struct UartMstPacketType {
+ uint8_t magic;
+ uint8_t cmd;
+ uint64_t addr;
+ uint32_t data[UART_MST_BURST_MAX];
+};
+#pragma pack()
+
+union PacketType {
+ UartMstPacketType fields;
+ char buf[1];
+};
+
+class SerialDbgService : public IService,
+ public ITap,
+ public IRawListener {
+public:
+ SerialDbgService(const char *name);
+ ~SerialDbgService();
+
+ /** IService interface */
+ virtual void postinitService();
+ virtual void predeleteService();
+
+ /** ITap interface */
+ virtual int read(uint64_t addr, int bytes, uint8_t *obuf);
+ virtual int write(uint64_t addr, int bytes, uint8_t *ibuf);
+
+ /** IRawListener interface */
+ virtual void updateData(const char *buf, int buflen);
+
+private:
+ AttributeType timeout_;
+ AttributeType port_;
+
+ ISerial *iserial_;
+ event_def event_block_;
+ PacketType pkt_;
+ int rd_count_;
+ int req_count_;
+ int wait_bytes_;
+ Reg64Type rxbuf_[UART_MST_BURST_MAX];
+};
+
+DECLARE_CLASS(SerialDbgService)
+
+} // namespace debugger
+
+#endif // __DEBUGGER_SERIAL_DBGLINK_SERVICE_H__
debug/serial_dbglink.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: debug/udp_dbglink.cpp
===================================================================
--- debug/udp_dbglink.cpp (nonexistent)
+++ debug/udp_dbglink.cpp (revision 5)
@@ -0,0 +1,259 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief UDP transport level implementation.
+ */
+
+#include "api_core.h"
+#include "udp_dbglink.h"
+
+namespace debugger {
+
+/** Class registration in the Core */
+REGISTER_CLASS(UdpService)
+
+UdpService::UdpService(const char *name)
+ : IService(name) {
+ registerInterface(static_cast(this));
+ registerAttribute("Timeout", &timeout_);
+ registerAttribute("BlockingMode", &blockmode_);
+ registerAttribute("HostIP", &hostIP_);
+ registerAttribute("BoardIP", &boardIP_);
+
+ timeout_.make_int64(0);
+ blockmode_.make_boolean(true);
+ hostIP_.make_string("192.168.0.53");
+ boardIP_.make_string("192.168.0.51");
+}
+
+UdpService::~UdpService() {
+ closeDatagramSocket();
+}
+
+void UdpService::postinitService() {
+ createDatagramSocket();
+ // define hardcoded remote address:
+ remote_sockaddr_ipv4_ = sockaddr_ipv4_;
+ remote_sockaddr_ipv4_.sin_addr.s_addr = inet_addr(boardIP_.to_string());
+
+ if (timeout_.to_int64()) {
+ struct timeval tv;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ /** On windows timeout of the setsockopt() function is the DWORD
+ * size variable in msec, so we use only the first field in timeval
+ * struct and directly assgign argument.
+ */
+ tv.tv_usec = 0;
+ tv.tv_sec = static_cast(timeout_.to_int64());
+#else
+ tv.tv_usec = (timeout_.to_int64() % 1000) * 1000;
+ tv.tv_sec = static_cast(timeout_.to_int64()/1000);
+#endif
+
+ setsockopt(hsock_, SOL_SOCKET, SO_RCVTIMEO,
+ (char *)&tv, sizeof(struct timeval));
+ }
+
+ /** By default socket was created with Blocking mode */
+ if (!blockmode_.to_bool()) {
+ setBlockingMode(false);
+ }
+}
+
+int UdpService::createDatagramSocket() {
+ char hostName[256];
+ if (gethostname(hostName, sizeof(hostName)) < 0) {
+ return -1;
+ }
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ /**
+ * Check availability of IPv4 address assigned via attribute 'hostIP'.
+ * If it woudn't be found use the last avaialble IP address.
+ */
+ bool host_ip_found = false;
+ int retval;
+ struct addrinfo *result = NULL;
+ struct addrinfo *ptr = NULL;
+ retval = getaddrinfo(hostName, "0", &hints, &result);
+ if (retval != 0) {
+ return -1;
+ }
+
+ for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
+ // Find only IPV4 address, ignore others.
+ if (ptr->ai_family != AF_INET) {
+ continue;
+ }
+ sockaddr_ipv4_ = *((struct sockaddr_in *)ptr->ai_addr);
+ RISCV_sprintf(sockaddr_ipv4_str_, sizeof(sockaddr_ipv4_str_),
+ "%s", inet_ntoa(sockaddr_ipv4_.sin_addr));
+
+ if (strcmp(inet_ntoa(sockaddr_ipv4_.sin_addr),
+ hostIP_.to_string()) == 0) {
+ host_ip_found = true;
+ break;
+ }
+ }
+
+ if (!host_ip_found) {
+ RISCV_info("Selected IPv4 %s", inet_ntoa(sockaddr_ipv4_.sin_addr));
+ } else {
+#if 1
+ /** jrkk proposal to hardcode IP address in a such way. No difference. */
+ memset(&sockaddr_ipv4_, 0, sizeof (sockaddr_ipv4_));
+ sockaddr_ipv4_.sin_family = AF_INET;
+ inet_pton(AF_INET, hostIP_.to_string(), &(sockaddr_ipv4_.sin_addr));
+#endif
+ }
+
+ hsock_ = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (hsock_ < 0) {
+ RISCV_error("%s", "Error: socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)");
+ return -1;
+ }
+
+ int res = bind(hsock_, (struct sockaddr *)&sockaddr_ipv4_,
+ sizeof(sockaddr_ipv4_));
+ if (res != 0) {
+ RISCV_error("Error: bind(hsock_, \"%s\", ...)", hostIP_.to_string());
+ return -1;
+ }
+
+ addr_size_t addr_sz = sizeof(sockaddr_ipv4_);
+ res = getsockname(hsock_, (struct sockaddr *)&sockaddr_ipv4_, &addr_sz);
+ sockaddr_ipv4_port_ = ntohs(sockaddr_ipv4_.sin_port);
+
+ RISCV_info("\tIPv4 address %s:%d . . . opened",
+ sockaddr_ipv4_str_, sockaddr_ipv4_port_);
+
+ return 0;
+}
+
+void UdpService::closeDatagramSocket() {
+ if (hsock_ < 0)
+ return;
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ closesocket(hsock_);
+#else
+ shutdown(hsock_, SHUT_RDWR);
+ close(hsock_);
+#endif
+ hsock_ = -1;
+}
+
+void UdpService::getConnectionSettings(AttributeType *settings) {
+ settings->make_dict();
+ (*settings)["IP"] = AttributeType(inet_ntoa(sockaddr_ipv4_.sin_addr));
+ (*settings)["Port"] = AttributeType(Attr_UInteger,
+ static_cast(sockaddr_ipv4_.sin_port));
+}
+
+void UdpService::setConnectionSettings(const AttributeType *target) {
+ if (!target->is_dict()) {
+ return;
+ }
+ remote_sockaddr_ipv4_.sin_addr.s_addr =
+ inet_addr((*target)["IP"].to_string());
+ remote_sockaddr_ipv4_.sin_port =
+ static_cast((*target)["Port"].to_uint64());
+}
+
+bool UdpService::setBlockingMode(bool mode) {
+ int ret;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ u_long arg = mode ? 0 : 1;
+ ret = ioctlsocket(hsock_, FIONBIO, &arg);
+#else
+ int flags = fcntl(hsock_, F_GETFL, 0);
+ if (flags < 0) {
+ return false;
+ }
+ flags = mode ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
+ ret = fcntl(hsock_, F_SETFL, flags);
+#endif
+ if (ret == 0) {
+ // success
+ blockmode_.make_boolean(mode);
+ return true;
+ }
+ return false;
+}
+
+int UdpService::sendData(const uint8_t *msg, int len) {
+ int tx_bytes = sendto(hsock_, reinterpret_cast(msg), len, 0,
+ reinterpret_cast(&remote_sockaddr_ipv4_),
+ static_cast(sizeof(remote_sockaddr_ipv4_)));
+
+ if (tx_bytes < 0) {
+#if defined(_WIN32) || defined(__CYGWIN__)
+ RISCV_error("sendto() failed with error: %d\n", WSAGetLastError());
+#else
+ RISCV_error("sendto() failed\n", NULL);
+#endif
+ return 1;
+ } else if (logLevel_.to_int() >= LOG_DEBUG) {
+ char dbg[1024];
+ int pos = RISCV_sprintf(dbg, sizeof(dbg), "send %d bytes to %s:%d: ",
+ tx_bytes,
+ inet_ntoa(remote_sockaddr_ipv4_.sin_addr),
+ ntohs(remote_sockaddr_ipv4_.sin_port));
+
+ if (tx_bytes < 64) {
+ for (int i = 0; i < len; i++) {
+ pos += RISCV_sprintf(&dbg[pos], sizeof(dbg) - pos,
+ "%02x", msg[i] & 0xFF);
+ }
+ }
+ RISCV_debug("%s", dbg);
+ }
+ return tx_bytes;
+}
+
+int UdpService::readData(const uint8_t *buf, int maxlen) {
+ int sockerr;
+ addr_size_t sockerr_len = sizeof(sockerr);
+ addr_size_t addr_sz = sizeof(sockaddr_ipv4_);
+
+ int res = recvfrom(hsock_, rcvbuf, sizeof(rcvbuf),
+ 0, (struct sockaddr *)&sockaddr_ipv4_, &addr_sz);
+ getsockopt(hsock_, SOL_SOCKET, SO_ERROR,
+ (char *)&sockerr, &sockerr_len);
+
+ if (res < 0 && sockerr < 0) {
+ RISCV_error("Socket error %x", sockerr);
+ res = -1;
+ } else if (res < 0 && sockerr == 0) {
+ // Timeout:
+ res = 0;
+ } else if (res > 0) {
+ if (maxlen < res) {
+ res = maxlen;
+ RISCV_error("Receiver's buffer overflow maxlen = %d", maxlen);
+ }
+ memcpy(const_cast(buf), rcvbuf, res);
+
+ if (logLevel_.to_int() >= LOG_DEBUG) {
+ char dbg[1024];
+ int pos = RISCV_sprintf(dbg, sizeof(dbg),
+ "received %d Bytes: ", res);
+ if (res < 64) {
+ for (int i = 0; i < res; i++) {
+ pos += RISCV_sprintf(&dbg[pos], sizeof(dbg) - pos,
+ "%02x", rcvbuf[i] & 0xFF);
+ }
+ }
+ RISCV_debug("%s", dbg);
+ }
+ }
+ return res;
+}
+
+} // namespace debugger
debug/udp_dbglink.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: debug/udp_dbglink.h
===================================================================
--- debug/udp_dbglink.h (nonexistent)
+++ debug/udp_dbglink.h (revision 5)
@@ -0,0 +1,56 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief UDP transport level implementation.
+ */
+
+#ifndef __DEBUGGER_UDP_DBGLINK_SERVICE_H__
+#define __DEBUGGER_UDP_DBGLINK_SERVICE_H__
+
+#include "iclass.h"
+#include "iservice.h"
+#include "coreservices/ilink.h"
+#include "coreservices/itap.h"
+
+namespace debugger {
+
+class UdpService : public IService,
+ public ILink {
+public:
+ UdpService(const char *name);
+ ~UdpService();
+
+ /** IService interface */
+ virtual void postinitService();
+
+ /** ILink interface */
+ virtual void getConnectionSettings(AttributeType *settings);
+ virtual void setConnectionSettings(const AttributeType *target);
+ virtual int sendData(const uint8_t *msg, int len);
+ virtual int readData(const uint8_t *buf, int maxlen);
+
+protected:
+ int createDatagramSocket();
+ void closeDatagramSocket();
+ bool setBlockingMode(bool mode);
+
+private:
+ AttributeType timeout_;
+ AttributeType blockmode_;
+ AttributeType hostIP_;
+ AttributeType boardIP_;
+
+ struct sockaddr_in sockaddr_ipv4_;
+ char sockaddr_ipv4_str_[16]; // 3 dots + 4 digits each 3 symbols + '\0' = 4*3 + 3 + 1;
+ unsigned short sockaddr_ipv4_port_;
+ struct sockaddr_in remote_sockaddr_ipv4_;
+ socket_def hsock_;
+ char rcvbuf[4096];
+};
+
+DECLARE_CLASS(UdpService)
+
+} // namespace debugger
+
+#endif // __DEBUGGER_UDP_DBGLINK_SERVICE_H__
debug/udp_dbglink.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: exec/cmd/cmd_loadbin.cpp
===================================================================
--- exec/cmd/cmd_loadbin.cpp (nonexistent)
+++ exec/cmd/cmd_loadbin.cpp (revision 5)
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "iservice.h"
+#include "cmd_loadbin.h"
+#include
+
+namespace debugger {
+
+CmdLoadBin::CmdLoadBin(ITap *tap, ISocInfo *info)
+ : ICommand ("loadbin", tap, info) {
+
+ briefDescr_.make_string("Load binary file");
+ detailedDescr_.make_string(
+ "Description:\n"
+ " Load BIN-file to SOC target memory with specified address.\n"
+ "Example:\n"
+ " loadsrec /home/hc08/image.bin 0x04000\n");
+}
+
+bool CmdLoadBin::isValid(AttributeType *args) {
+ if ((*args)[0u].is_equal("loadbin")
+ && args->size() == 3) {
+ return CMD_VALID;
+ }
+ return CMD_INVALID;
+}
+
+void CmdLoadBin::exec(AttributeType *args, AttributeType *res) {
+ res->make_nil();
+ if (!isValid(args)) {
+ generateError(res, "Wrong argument list");
+ return;
+ }
+
+ const char *filename = (*args)[1].to_string();
+ FILE *fp = fopen(filename, "rb");
+ if (!fp) {
+ generateError(res, "File not found");
+ return;
+ }
+ fseek(fp, 0, SEEK_END);
+ int sz = ftell(fp);
+ rewind(fp);
+ uint8_t *image = new uint8_t[sz];
+ fread(image, 1, sz, fp);
+ fclose(fp);
+
+ uint64_t addr = (*args)[2].to_uint64();
+ tap_->write(addr, sz, image);
+ delete [] image;
+}
+
+} // namespace debugger
exec/cmd/cmd_loadbin.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: exec/cmd/cmd_loadbin.h
===================================================================
--- exec/cmd/cmd_loadbin.h (nonexistent)
+++ exec/cmd/cmd_loadbin.h (revision 5)
@@ -0,0 +1,30 @@
+/**
+ * @file
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief Binary-file loader command.
+ */
+
+#ifndef __DEBUGGER_SERVICES_EXEC_CMD_LOADBIN_H__
+#define __DEBUGGER_SERVICES_EXEC_CMD_LOADBIN_H__
+
+#include "api_core.h"
+#include "coreservices/itap.h"
+#include "coreservices/isocinfo.h"
+#include "coreservices/icommand.h"
+
+namespace debugger {
+
+class CmdLoadBin : public ICommand {
+ public:
+ explicit CmdLoadBin(ITap *tap, ISocInfo *info);
+
+ /** ICommand interface */
+ virtual bool isValid(AttributeType *args);
+ virtual void exec(AttributeType *args, AttributeType *res);
+
+ private:
+};
+
+} // namespace debugger
+
+#endif // __DEBUGGER_SERVICES_EXEC_CMD_LOADBIN_H__
exec/cmd/cmd_loadbin.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: exec/cmd/cmd_loadsrec.cpp
===================================================================
--- exec/cmd/cmd_loadsrec.cpp (nonexistent)
+++ exec/cmd/cmd_loadsrec.cpp (revision 5)
@@ -0,0 +1,252 @@
+/**
+ * @file
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief SREC-file loader command.
+ */
+
+#include "iservice.h"
+#include "cmd_loadsrec.h"
+#include
+
+namespace debugger {
+
+//#define SHOW_USAGE_INFO
+
+#ifdef SHOW_USAGE_INFO
+#define ADDR_SPACE (1 << 16)
+char mark_[ADDR_SPACE] = {0};
+
+void mark_addr(uint64_t addr, int len) {
+ for (int i = 0; i < len; i++) {
+ if ((addr + i) >= ADDR_SPACE) {
+ continue;
+ }
+ mark_[addr + i] = 1;
+ }
+}
+
+bool is_flash(unsigned addr) {
+ if (addr >= 0x0450 && addr < 0x0500) {
+ return true;
+ }
+ if (addr >= 0x0580 && addr < 0x0600) {
+ return true;
+ }
+ if (addr >= 0x0E00 && addr < 0xfe00) {
+ return true;
+ }
+ return false;
+}
+
+void print_flash_usage() {
+ unsigned start_addr = 0;
+ int cnt = 0;
+ int total_cnt = 0;
+
+ RISCV_printf(NULL, 0, "!!! Free Flash regions:", NULL);
+ for (unsigned i = 0; i < ADDR_SPACE; i++) {
+ if (!is_flash(i)) {
+ if (cnt != 0) {
+ RISCV_printf(NULL, 0, " [%04x..%04x], length %d B",
+ start_addr, (start_addr + cnt - 1), cnt);
+ total_cnt += cnt;
+ cnt = 0;
+ }
+ continue;
+ }
+
+ if (mark_[i]) {
+ if (cnt != 0) {
+ RISCV_printf(NULL, 0, " [%04x..%04x], length %d B",
+ start_addr, (start_addr + cnt - 1), cnt);
+ total_cnt += cnt;
+ cnt = 0;
+ }
+ continue;
+ }
+ if (cnt == 0) {
+ start_addr = i;
+ }
+ cnt++;
+ }
+
+ RISCV_printf(NULL, 0, " =========================", NULL);
+ RISCV_printf(NULL, 0, " Total: %d B", total_cnt);
+}
+#endif
+
+CmdLoadSrec::CmdLoadSrec(ITap *tap, ISocInfo *info)
+ : ICommand ("loadsrec", tap, info) {
+
+ briefDescr_.make_string("Load SREC-file");
+ detailedDescr_.make_string(
+ "Description:\n"
+ " Load SREC-file to SOC target memory.\n"
+ "Example:\n"
+ " loadsrec /home/hc08/image.s19\n");
+}
+
+bool CmdLoadSrec::isValid(AttributeType *args) {
+ if ((*args)[0u].is_equal("loadsrec")
+ && (args->size() == 2 || args->size() == 3)) {
+ return CMD_VALID;
+ }
+ return CMD_INVALID;
+}
+
+void CmdLoadSrec::exec(AttributeType *args, AttributeType *res) {
+ res->make_nil();
+ if (!isValid(args)) {
+ generateError(res, "Wrong argument list");
+ return;
+ }
+
+ const char *filename = (*args)[1].to_string();
+ FILE *fp = fopen(filename, "rb");
+ if (!fp) {
+ generateError(res, "File not found");
+ return;
+ }
+ fseek(fp, 0, SEEK_END);
+ int sz = ftell(fp);
+ rewind(fp);
+ uint8_t *image = new uint8_t[sz];
+ fread(image, 1, sz, fp);
+ fclose(fp);
+
+ int off = check_header(image);
+
+ DsuMapType *dsu = info_->getpDsu();
+ uint64_t soft_reset = 1;
+ uint64_t addr = reinterpret_cast(&dsu->ulocal.v.soft_reset);
+ tap_->write(addr, 8, reinterpret_cast(&soft_reset));
+
+ uint64_t sec_addr;
+ int sec_sz;
+ uint8_t sec_data[1024];
+ while ((off = readline(image, off, sec_addr, sec_sz, sec_data)) != 0) {
+ tap_->write(sec_addr, sec_sz, sec_data);
+#ifdef SHOW_USAGE_INFO
+ mark_addr(sec_addr, sec_sz);
+#endif
+ }
+
+// soft_reset = 0;
+// tap_->write(addr, 8, reinterpret_cast(&soft_reset));
+ delete [] image;
+
+#ifdef SHOW_USAGE_INFO
+ print_flash_usage();
+#endif
+}
+
+uint8_t CmdLoadSrec::str2byte(uint8_t *pair) {
+ uint8_t ret = 0;
+ for (int i = 0; i < 2; i++) {
+ ret <<= 4;
+ if (pair[i] >= '0' && pair[i] <= '9') {
+ ret |= pair[i] - '0';
+ } else if (pair[i] >= 'A' && pair[i] <= 'F') {
+ ret |= pair[i] - 'A' + 10;
+ } else if (pair[i] >= 'a' && pair[i] <= 'f') {
+ ret |= pair[i] - 'a' + 10;
+ }
+ }
+ return ret;
+}
+
+bool CmdLoadSrec::check_crc(uint8_t *str, int sz) {
+ uint8_t sum = 0;
+ uint8_t *cur = str;
+ for (int i = 0; i < sz; i++) {
+ sum += str2byte(cur);
+ cur += 2;
+ }
+ sum = ~sum;
+ uint8_t ctrl = str2byte(cur);
+ return ctrl == sum;
+}
+
+int CmdLoadSrec::check_header(uint8_t *img) {
+ int off = 2;
+ if (img[0] != 'S' || img[1] != '0') {
+ return 0;
+ }
+ uint8_t sz = str2byte(&img[off]);
+ if (!check_crc(&img[off], sz)) {
+ return 0;
+ }
+
+ off += 2;
+ uint16_t addr = str2byte(&img[off]);
+ off += 2;
+ addr = (addr << 8) + str2byte(&img[off]);
+ off += 2;
+ if (addr != 0) {
+ return 0;
+ }
+ for (int i = 0; i < sz - 3; i++) { // size (1) + addr (2) = 3
+ header_data_[i] = static_cast(str2byte(&img[off]));
+ header_data_[i + 1] = 0;
+ off += 2;
+ }
+ off += 2; // skip checksum
+ if (img[off] != '\r' || img[off + 1] != '\n') {
+ return 0;
+ }
+ return off + 2;
+}
+
+int CmdLoadSrec::readline(uint8_t *img, int off,
+ uint64_t &addr, int &sz, uint8_t *out) {
+ if (img[off++] != 'S') {
+ return 0;
+ }
+ int bytes4addr = 0;
+ switch (img[off++]) { // 16-bits address only
+ case '1':
+ bytes4addr = 2; // 16-bits address
+ break;
+ case '2':
+ bytes4addr = 3; // 24-bits address
+ break;
+ case '3':
+ bytes4addr = 4; // 32-bits address
+ break;
+ default:
+ return 0;
+ }
+ sz = str2byte(&img[off]);
+ if (!check_crc(&img[off], sz)) {
+ return 0;
+ }
+ sz -= 1;
+ off += 2;
+
+ addr = 0;
+ for (int i = 0; i < bytes4addr; i++) {
+ addr <<= 8;
+ addr += str2byte(&img[off]);
+ off += 2;
+ sz--;
+ }
+#if 1
+ // MCU specific endcoding:
+ if (bytes4addr == 3) {
+ uint64_t page = addr >> 16;
+ addr = (0x4000 * page) + (addr & 0x3FFF);
+ }
+#endif
+
+ for (int i = 0; i < sz; i++) {
+ out[i] = static_cast(str2byte(&img[off]));
+ off += 2;
+ }
+ off += 2; // skip checksum
+ if (img[off] != '\r' || img[off + 1] != '\n') {
+ return 0;
+ }
+ return off + 2;
+}
+
+} // namespace debugger
exec/cmd/cmd_loadsrec.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: exec/cmd/cmd_loadsrec.h
===================================================================
--- exec/cmd/cmd_loadsrec.h (nonexistent)
+++ exec/cmd/cmd_loadsrec.h (revision 5)
@@ -0,0 +1,38 @@
+/**
+ * @file
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief SREC-file loader command.
+ */
+
+#ifndef __DEBUGGER_CMD_LOADSREC_H__
+#define __DEBUGGER_CMD_LOADSREC_H__
+
+#include "api_core.h"
+#include "coreservices/itap.h"
+#include "coreservices/isocinfo.h"
+#include "coreservices/icommand.h"
+
+namespace debugger {
+
+class CmdLoadSrec : public ICommand {
+public:
+ explicit CmdLoadSrec(ITap *tap, ISocInfo *info);
+
+ /** ICommand interface */
+ virtual bool isValid(AttributeType *args);
+ virtual void exec(AttributeType *args, AttributeType *res);
+
+private:
+ uint8_t str2byte(uint8_t *pair);
+ bool check_crc(uint8_t *str, int sz);
+ int check_header(uint8_t *img);
+ int readline(uint8_t *img, int off,
+ uint64_t &addr, int &sz, uint8_t *out);
+
+private:
+ char header_data_[1024];
+};
+
+} // namespace debugger
+
+#endif // __DEBUGGER_CMD_LOADSREC_H__
exec/cmd/cmd_loadsrec.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: remote/tcpclient.cpp
===================================================================
--- remote/tcpclient.cpp (nonexistent)
+++ remote/tcpclient.cpp (revision 5)
@@ -0,0 +1,126 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief Remote access to debugger via TCP connection. Client thread.
+ */
+
+#include "tcpclient.h"
+
+namespace debugger {
+
+/** Class registration in the Core */
+REGISTER_CLASS(TcpClient)
+
+TcpClient::TcpClient(const char *name) : IService(name),
+ tcpcmd_(static_cast(this)) {
+ registerInterface(static_cast(this));
+ registerAttribute("Enable", &isEnable_);
+ RISCV_mutex_init(&mutexTx_);
+}
+
+TcpClient::~TcpClient() {
+ RISCV_mutex_destroy(&mutexTx_);
+}
+
+void TcpClient::postinitService() {
+ if (isEnable_.to_bool()) {
+ if (!run()) {
+ RISCV_error("Can't create thread.", NULL);
+ return;
+ }
+ }
+}
+
+void TcpClient::updateData(const char *buf, int buflen) {
+ AttributeType console;
+ console.make_list(2);
+ console[0u].make_string("Console");
+ console[1].make_string(buf);
+ console.to_config();
+
+ RISCV_mutex_lock(&mutexTx_);
+ memcpy(&txbuf_[txcnt_], console.to_string(), console.size() + 1);
+ txcnt_ += console.size() + 1;
+ RISCV_mutex_unlock(&mutexTx_);
+}
+
+void TcpClient::busyLoop() {
+ int rxbytes;
+ int sockerr;
+ addr_size_t sockerr_len = sizeof(sockerr);
+ RISCV_add_default_output(static_cast(this));
+
+ cmdcnt_ = 0;
+ txcnt_ = 0;
+ while (isEnabled()) {
+ rxbytes = recv(hsock_, rcvbuf, sizeof(rcvbuf), 0);
+ getsockopt(hsock_, SOL_SOCKET, SO_ERROR,
+ reinterpret_cast(&sockerr), &sockerr_len);
+
+ if (rxbytes == 0) {
+ RISCV_error("Socket error: rxbytes=%d, sockerr=%d",
+ rxbytes, sockerr);
+ loopEnable_.state = false;
+ } else if (rxbytes < 0) {
+ // Timeout:
+ } else if (rxbytes > 0) {
+ for (int i = 0; i < rxbytes; i++) {
+ cmdbuf_[cmdcnt_++] = rcvbuf[i];
+ if (rcvbuf[i] == '\0') {
+ processRxString();
+ cmdcnt_ = 0;
+ }
+ }
+ }
+ if (sendTxBuf() < 0) {
+ RISCV_error("Send error: txcnt=%d", txcnt_);
+ loopEnable_.state = false;
+ }
+ }
+ closeSocket();
+ RISCV_remove_default_output(static_cast(this));
+}
+
+void TcpClient::processRxString() {
+ tcpcmd_.updateData(cmdbuf_, cmdcnt_);
+ AttributeType *resp = tcpcmd_.response();
+ RISCV_mutex_lock(&mutexTx_);
+ memcpy(&txbuf_[txcnt_], resp->to_string(), resp->size() + 1);
+ txcnt_ += resp->size() + 1;
+ RISCV_mutex_unlock(&mutexTx_);
+}
+
+int TcpClient::sendTxBuf() {
+ int total = txcnt_;
+ char *ptx = txbuf_;
+ int txbytes;
+ while (total > 0) {
+ txbytes = send(hsock_, ptx, total, 0);
+ if (txbytes == 0) {
+ return -1;
+ }
+ total -= txbytes;
+ ptx += txbytes;
+ }
+ RISCV_mutex_lock(&mutexTx_);
+ txcnt_ = 0;
+ RISCV_mutex_unlock(&mutexTx_);
+ return 0;
+}
+
+void TcpClient::closeSocket() {
+ if (hsock_ < 0) {
+ return;
+ }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ closesocket(hsock_);
+#else
+ shutdown(hsock_, SHUT_RDWR);
+ close(hsock_);
+#endif
+ hsock_ = -1;
+}
+
+} // namespace debugger
remote/tcpclient.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: remote/tcpclient.h
===================================================================
--- remote/tcpclient.h (nonexistent)
+++ remote/tcpclient.h (revision 5)
@@ -0,0 +1,62 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief Remote access to debugger via TCP connection. Client thread.
+ */
+
+#ifndef __DEBUGGER_TCPCLIENT_H__
+#define __DEBUGGER_TCPCLIENT_H__
+
+#include
+#include
+#include "tcpcmd.h"
+#include "coreservices/ithread.h"
+#include "coreservices/irawlistener.h"
+
+namespace debugger {
+
+class TcpClient : public IService,
+ public IThread,
+ public IRawListener {
+ public:
+ explicit TcpClient(const char *name);
+ virtual ~TcpClient();
+
+ /** IService interface */
+ virtual void postinitService();
+ virtual void setExtArgument(void *args) {
+ hsock_ = *reinterpret_cast(args);
+ }
+
+ /** IRawListener interface */
+ virtual void updateData(const char *buf, int buflen);
+
+ protected:
+ /** IThread interface */
+ virtual void busyLoop();
+
+ protected:
+ void processRxString();
+ int sendTxBuf();
+ void closeSocket();
+
+ private:
+ AttributeType isEnable_;
+ AttributeType timeout_;
+ socket_def hsock_;
+ mutex_def mutexTx_;
+ char rcvbuf[4096];
+ char cmdbuf_[4096];
+ int cmdcnt_;
+ char txbuf_[1<<20];
+ int txcnt_;
+
+ TcpCommands tcpcmd_;
+};
+
+DECLARE_CLASS(TcpClient)
+
+} // namespace debugger
+
+#endif // __DEBUGGER_TCPCLIENT_H__
remote/tcpclient.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: remote/tcpcmd.cpp
===================================================================
--- remote/tcpcmd.cpp (nonexistent)
+++ remote/tcpcmd.cpp (revision 5)
@@ -0,0 +1,310 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief TCP commands parser/processor.
+ */
+
+#include "tcpcmd.h"
+
+namespace debugger {
+
+TcpCommands::TcpCommands(IService *parent) : IHap(HAP_All) {
+ parent_ = parent;
+ rxcnt_ = 0;
+
+ cpu_.make_string("core0");
+ executor_.make_string("cmdexec0");
+ source_.make_string("src0");
+
+ iexec_ = static_cast(
+ RISCV_get_service_iface(executor_.to_string(), IFACE_CMD_EXECUTOR));
+
+ iclk_ = static_cast(
+ RISCV_get_service_iface(cpu_.to_string(), IFACE_CLOCK));
+ IService *iservcpu = static_cast(
+ RISCV_get_service(cpu_.to_string()));
+ cpuLogLevel_ = static_cast(
+ iservcpu->getAttribute("LogLevel"));
+
+ iriscv_ = static_cast(
+ RISCV_get_service_iface(cpu_.to_string(), IFACE_CPU_RISCV));
+
+ isrc_ = static_cast(
+ RISCV_get_service_iface(source_.to_string(), IFACE_SOURCE_CODE));
+
+ char tstr[128];
+ RISCV_sprintf(tstr, sizeof(tstr), "%s_halt", parent_->getObjName());
+ RISCV_event_create(&eventHalt_, tstr);
+ RISCV_sprintf(tstr, sizeof(tstr), "%s_delay_ms", parent_->getObjName());
+ RISCV_event_create(&eventDelayMs_, tstr);
+ RISCV_sprintf(tstr, sizeof(tstr), "%s_pwr", parent_->getObjName());
+ RISCV_event_create(&eventPowerChanged_, tstr);
+
+ RISCV_register_hap(static_cast(this));
+}
+
+TcpCommands::~TcpCommands() {
+ RISCV_event_close(&eventHalt_);
+ RISCV_event_close(&eventDelayMs_);
+ RISCV_event_close(&eventPowerChanged_);
+}
+
+void TcpCommands::hapTriggered(IFace *isrc, EHapType type,
+ const char *descr) {
+ if (type == HAP_Halt) {
+ RISCV_event_set(&eventHalt_);
+ } else if (type == HAP_CpuTurnON || type == HAP_CpuTurnOFF) {
+ RISCV_event_set(&eventPowerChanged_);
+ }
+}
+
+void TcpCommands::stepCallback(uint64_t t) {
+ RISCV_event_set(&eventDelayMs_);
+}
+
+void TcpCommands::updateData(const char *buf, int buflen) {
+ for (int i = 0; i < buflen; i++) {
+ rxbuf_[rxcnt_++] = buf[i];
+ if (buf[i] == 0) {
+ processCommand();
+ rxcnt_ = 0;
+ }
+ }
+}
+
+void TcpCommands::processCommand() {
+ AttributeType cmd;
+ cmd.from_config(rxbuf_);
+ if (!cmd.is_list() || cmd.size() < 3) {
+ return;
+ }
+
+ uint64_t idx = cmd[0u].to_uint64();
+ resp_.make_list(2);
+ resp_[0u].make_uint64(idx);
+ resp_[1].make_string("OK");
+
+ AttributeType &requestType = cmd[1];
+ AttributeType &requestAction = cmd[2];
+ AttributeType *resp = &resp_[1];
+
+ if (requestType.is_equal("Command")) {
+ /** Redirect command to console directly */
+ iexec_->exec(requestAction.to_string(), resp, false);
+ } else if (requestType.is_equal("Breakpoint")) {
+ /** Breakpoints action */
+ if (requestAction[0u].is_equal("Add")) {
+ br_add(requestAction[1], resp);
+ } else if (requestAction[0u].is_equal("Remove")) {
+ br_rm(requestAction[1], resp);
+ } else {
+ resp->make_string("Wrong breakpoint command");
+ }
+ } else if (requestType.is_equal("Control")) {
+ /** Run Control action */
+ if (requestAction[0u].is_equal("GoUntil")) {
+ go_until(requestAction[1], resp);
+ } else if (requestAction[0u].is_equal("GoMsec")) {
+ go_msec(requestAction[1], resp);
+ } else if (requestAction[0u].is_equal("Step")) {
+ step(requestAction[1].to_int(), resp);
+ } else if (requestAction[0u].is_equal("PowerOn")) {
+ power_on(resp);
+ RISCV_debug("[%" RV_PRI64 "d] Command Power-On", idx);
+ } else if (requestAction[0u].is_equal("PowerOff")) {
+ power_off(resp);
+ RISCV_debug("[%" RV_PRI64 "d] Command Power-Off", idx);
+ } else {
+ resp->make_string("Wrong control command");
+ }
+ } else if (requestType.is_equal("Status")) {
+ /** Pump status */
+ if (requestAction.is_equal("IsON")) {
+ resp->make_boolean(true);
+ } else if (requestAction.is_equal("IsHalt")) {
+ //resp->make_boolean(iriscv_->isHalt());
+ } else if (requestAction.is_equal("Steps")) {
+ resp->make_uint64(iclk_->getStepCounter());
+ } else if (requestAction.is_equal("TimeSec")) {
+ double t1 = iclk_->getStepCounter() / iclk_->getFreqHz();
+ resp->make_floating(t1);
+ } else {
+ resp->make_string("Wrong status command");
+ }
+ } else if (requestType.is_equal("Symbol")) {
+ /** Symbols table conversion */
+ if (requestAction[0u].is_equal("ToAddr")) {
+ symb2addr(requestAction[1].to_string(), resp);
+ } else if (requestAction[0u].is_equal("FromAddr")) {
+ // todo:
+ } else {
+ resp->make_string("Wrong symbol command");
+ }
+ } else if (requestType.is_equal("Attribute")) {
+ IService *isrv = static_cast(
+ RISCV_get_service(requestAction[0u].to_string()));
+ if (isrv) {
+ AttributeType *iatr = static_cast(
+ isrv->getAttribute(requestAction[1].to_string()));
+ if (iatr) {
+ resp->clone(iatr);
+ } else {
+ resp->make_string("Attribute not found");
+ }
+ } else {
+ resp->make_string("Service not found");
+ }
+ } else {
+ resp->make_list(2);
+ (*resp)[0u].make_string("ERROR");
+ (*resp)[1].make_string("Wrong command format");
+ }
+ resp_.to_config();
+}
+
+AttributeType *TcpCommands::response() {
+ return &resp_;
+}
+
+void TcpCommands::br_add(const AttributeType &symb, AttributeType *res) {
+ uint64_t addr;
+ if (symb.is_string()) {
+ AttributeType t1;
+ symb2addr(symb.to_string(), &t1);
+ if (t1.is_nil()) {
+ res->make_string("br_add: Symbol not found");
+ return;
+ }
+ addr = t1.to_uint64();
+ } else if (symb.is_integer()) {
+ addr = symb.to_uint64();
+ } else {
+ res->make_string("br_add: Wrong format");
+ return;
+ }
+ char tstr[256];
+ RISCV_sprintf(tstr, sizeof(tstr), "br add 0x%x", addr);
+ iexec_->exec(tstr, res, false);
+}
+
+void TcpCommands::br_rm(const AttributeType &symb, AttributeType *res) {
+ uint64_t addr;
+ if (symb.is_string()) {
+ AttributeType t1;
+ symb2addr(symb.to_string(), &t1);
+ if (t1.is_nil()) {
+ res->make_string("br_rm: Symbol not found");
+ return;
+ }
+ addr = t1.to_uint64();
+ } else if (symb.is_integer()) {
+ addr = symb.to_uint64();
+ } else {
+ res->make_string("br_rm: Wrong format");
+ return;
+ }
+ char tstr[256];
+ RISCV_sprintf(tstr, sizeof(tstr), "br rm 0x%x", addr);
+ iexec_->exec(tstr, res, false);
+}
+
+void TcpCommands::step(int cnt, AttributeType *res) {
+ char tstr[16];
+ RISCV_sprintf(tstr, sizeof(tstr), "c %d", cnt);
+
+ int log_level_old = cpuLogLevel_->to_int();
+ cpuLogLevel_->make_int64(4);
+
+ RISCV_event_clear(&eventHalt_);
+ iexec_->exec(tstr, res, false);
+ RISCV_event_wait(&eventHalt_);
+ cpuLogLevel_->make_int64(log_level_old);
+}
+
+void TcpCommands::go_until(const AttributeType &symb, AttributeType *res) {
+ uint64_t addr;
+ if (symb.is_string()) {
+ AttributeType t1;
+ symb2addr(symb.to_string(), &t1);
+ if (t1.is_nil()) {
+ res->make_string("br_rm: Symbol not found");
+ return;
+ }
+ addr = t1.to_uint64();
+ } else if (symb.is_integer()) {
+ addr = symb.to_uint64();
+ } else {
+ res->make_string("br_rm: Wrong format");
+ return;
+ }
+ // Add breakpoint
+ char tstr[256];
+ RISCV_sprintf(tstr, sizeof(tstr), "br add 0x%x", addr);
+ iexec_->exec(tstr, res, false);
+
+ // Set CPU LogLevel=1 to hide all debugging messages
+ int log_level_old = cpuLogLevel_->to_int();
+ cpuLogLevel_->make_int64(1);
+
+ // Run simulation
+ RISCV_event_clear(&eventHalt_);
+ RISCV_sprintf(tstr, sizeof(tstr), "c", 0);
+ iexec_->exec(tstr, res, false);
+ RISCV_event_wait(&eventHalt_);
+ cpuLogLevel_->make_int64(log_level_old);
+
+ // Remove breakpoint:
+ RISCV_sprintf(tstr, sizeof(tstr), "br rm 0x%x", addr);
+ iexec_->exec(tstr, res, false);
+}
+
+void TcpCommands::symb2addr(const char *symbol, AttributeType *res) {
+ res->make_nil();
+ if (!isrc_) {
+ return;
+ }
+ // Letters capitalization:
+ char capital[256];
+ int i = 0;
+ while (symbol[i]) {
+ capital[i] = symbol[i];
+ if (symbol[i] >= 'a' && symbol[i] <= 'z') {
+ capital[i] += ('A' - 'a');
+ }
+ i++;
+ capital[i] = '\0';
+ }
+ uint64_t addr;
+ if (isrc_->symbol2Address(capital, &addr) == 0) {
+ res->make_uint64(addr);
+ return;
+ }
+}
+
+void TcpCommands::power_on(AttributeType *res) {
+}
+
+void TcpCommands::power_off(AttributeType *res) {
+}
+
+void TcpCommands::go_msec(const AttributeType &msec, AttributeType *res) {
+ RISCV_event_clear(&eventDelayMs_);
+ RISCV_event_clear(&eventHalt_);
+
+ uint64_t step = iclk_->getStepCounter();
+ double delta = 0.001 * iclk_->getFreqHz() * msec.to_float();
+ if (delta == 0) {
+ delta = 1;
+ }
+ iclk_->registerStepCallback(static_cast(this),
+ step + static_cast(delta));
+
+ iexec_->exec("c", res, false);
+ RISCV_event_wait(&eventDelayMs_);
+ iexec_->exec("s", res, false);
+ RISCV_event_wait(&eventHalt_);
+}
+
+
+} // namespace debugger
remote/tcpcmd.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: remote/tcpcmd.h
===================================================================
--- remote/tcpcmd.h (nonexistent)
+++ remote/tcpcmd.h (revision 5)
@@ -0,0 +1,85 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief TCP commands parser/processor.
+ */
+
+#ifndef __DEBUGGER_TCPCMD_H__
+#define __DEBUGGER_TCPCMD_H__
+
+#include
+#include
+#include
+#include
+#include "coreservices/ilink.h"
+#include "coreservices/ithread.h"
+#include "coreservices/icpugen.h"
+#include "coreservices/icpuriscv.h"
+#include "coreservices/icmdexec.h"
+#include "coreservices/isrccode.h"
+#include "coreservices/iclock.h"
+#include "coreservices/iwire.h"
+#include "coreservices/irawlistener.h"
+
+namespace debugger {
+
+class TcpCommands : public IRawListener,
+ public IHap,
+ public IClockListener {
+ public:
+ explicit TcpCommands(IService *parent);
+ ~TcpCommands();
+
+ /** IRawListener interface */
+ virtual void updateData(const char *buf, int buflen);
+
+ /** IHap */
+ virtual void hapTriggered(IFace *isrc, EHapType type, const char *descr);
+
+ /** IClockListener */
+ virtual void stepCallback(uint64_t t);
+
+ /** Common acccess methods */
+ AttributeType *response();
+
+ protected:
+ IFace *getInterface(const char *name) {
+ return parent_->getInterface(name);
+ }
+
+ private:
+ void processCommand();
+ void br_add(const AttributeType &symb, AttributeType *res);
+ void br_rm(const AttributeType &symb, AttributeType *res);
+ void go_msec(const AttributeType &symb, AttributeType *res);
+ void go_until(const AttributeType &symb, AttributeType *res);
+ void step(int cnt, AttributeType *res);
+ void symb2addr(const char *symbol, AttributeType *res);
+ void power_on(AttributeType *res);
+ void power_off(AttributeType *res);
+
+ private:
+ char rxbuf_[4096];
+ int rxcnt_;
+ AttributeType cpu_;
+ AttributeType executor_;
+ AttributeType source_;
+
+ AttributeType resp_;
+
+ IService *parent_;
+ ICmdExecutor *iexec_;
+ ISourceCode *isrc_;
+ ICpuRiscV *iriscv_;
+ IClock *iclk_;
+ AttributeType *cpuLogLevel_;
+
+ event_def eventHalt_;
+ event_def eventDelayMs_;
+ event_def eventPowerChanged_;
+};
+
+} // namespace debugger
+
+#endif // __DEBUGGER_TCPCMD_H__
remote/tcpcmd.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property
Index: remote/tcpserver.cpp
===================================================================
--- remote/tcpserver.cpp (nonexistent)
+++ remote/tcpserver.cpp (revision 5)
@@ -0,0 +1,229 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief Remote access to debugger via TCP connection. Server side.
+ */
+
+#include "tcpserver.h"
+
+namespace debugger {
+
+/** Class registration in the Core */
+REGISTER_CLASS(TcpServer)
+
+TcpServer::TcpServer(const char *name) : IService(name) {
+ registerInterface(static_cast(this));
+ registerAttribute("Enable", &isEnable_);
+ registerAttribute("Timeout", &timeout_);
+ registerAttribute("BlockingMode", &blockmode_);
+ registerAttribute("HostIP", &hostIP_);
+ registerAttribute("HostPort", &hostPort_);
+}
+
+void TcpServer::postinitService() {
+ createServerSocket();
+
+ if (listen(hsock_, 1) < 0) {
+ RISCV_error("listen() failed", 0);
+ return;
+ }
+
+ /** By default socket was created with Blocking mode */
+ if (!blockmode_.to_bool()) {
+ setBlockingMode(false);
+ }
+
+ if (isEnable_.to_bool()) {
+ if (!run()) {
+ RISCV_error("Can't create thread.", NULL);
+ return;
+ }
+ }
+}
+
+void TcpServer::busyLoop() {
+ socket_def client_sock;
+ int err;
+
+ fd_set readSet;
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 400000; // 400 ms
+
+ int idx = 0;
+ char tname[64];
+
+ IClass *icls;
+ IService *isrv;
+ while (isEnabled()) {
+ FD_ZERO(&readSet);
+ FD_SET(hsock_, &readSet);
+ err = select(hsock_ + 1, &readSet, NULL, NULL, &timeout);
+ if (err > 0) {
+ client_sock = accept(hsock_, 0, 0);
+ setRcvTimeout(client_sock, timeout_.to_int());
+ RISCV_sprintf(tname, sizeof(tname), "client%d", idx++);
+
+ icls = static_cast(RISCV_get_class("TcpClientClass"));
+ isrv = icls->createService(tname);
+ AttributeType lst, item;
+ lst.make_list(0);
+ item.make_list(2);
+ item[0u].make_string("LogLevel");
+ item[1].make_int64(4);
+ lst.add_to_list(&item);
+ item[0u].make_string("Enable");
+ item[1].make_boolean(true);
+ lst.add_to_list(&item);
+
+ isrv->initService(&lst);
+ IThread *ithrd =
+ static_cast(isrv->getInterface(IFACE_THREAD));
+ ithrd->setExtArgument(&client_sock);
+ isrv->postinitService();
+ RISCV_info("TCP %s %p started", isrv->getObjName(), client_sock);
+ } else if (err == 0) {
+ // timeout
+ } else {
+ RISCV_info("TCP server thread accept() failed", 0);
+ loopEnable_.state = false;
+ }
+ }
+ closeServerSocket();
+}
+
+int TcpServer::createServerSocket() {
+ char hostName[256];
+ if (gethostname(hostName, sizeof(hostName)) < 0) {
+ return -1;
+ }
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ /**
+ * Check availability of IPv4 address assigned via attribute 'hostIP'.
+ * If it woudn't be found use the last avaialble IP address.
+ */
+ int retval;
+ struct addrinfo *result = NULL;
+ struct addrinfo *ptr = NULL;
+ retval = getaddrinfo(hostName, "0", &hints, &result);
+ if (retval != 0) {
+ return -1;
+ }
+
+ if (hostIP_.size() == 0 || hostIP_.is_equal("127.0.0.1")) {
+ memset(&sockaddr_ipv4_, 0, sizeof(struct sockaddr_in));
+ sockaddr_ipv4_.sin_family = AF_INET;
+ sockaddr_ipv4_.sin_addr.s_addr = inet_addr("127.0.0.1");
+ } else {
+ for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
+ // Find only IPV4 address, ignore others.
+ if (ptr->ai_family != AF_INET) {
+ continue;
+ }
+ sockaddr_ipv4_ = *((struct sockaddr_in *)ptr->ai_addr);
+
+ if (hostIP_.is_equal(inet_ntoa(sockaddr_ipv4_.sin_addr))) {
+ break;
+ }
+ }
+ }
+ sockaddr_ipv4_.sin_port = htons(static_cast(hostPort_.to_int()));
+ RISCV_info("Selected Host IPv4 %s:%d",
+ inet_ntoa(sockaddr_ipv4_.sin_addr),
+ hostPort_.to_uint32());
+
+ hsock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (hsock_ < 0) {
+ RISCV_error("%s", "Error: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)");
+ return -1;
+ }
+
+ int res = bind(hsock_,
+ reinterpret_cast(&sockaddr_ipv4_),
+ sizeof(sockaddr_ipv4_));
+ if (res != 0) {
+ RISCV_error("Error: bind(hsock_, \"%s\", ...)", hostIP_.to_string());
+ return -1;
+ }
+
+ addr_size_t addr_sz = sizeof(sockaddr_ipv4_);
+ res = getsockname(hsock_,
+ reinterpret_cast(&sockaddr_ipv4_),
+ &addr_sz);
+
+ RISCV_info("IPv4 address %s:%d . . . opened",
+ inet_ntoa(sockaddr_ipv4_.sin_addr),
+ ntohs(sockaddr_ipv4_.sin_port));
+
+ return 0;
+}
+
+void TcpServer::setRcvTimeout(socket_def skt, int timeout_ms) {
+ if (!timeout_ms) {
+ return;
+ }
+ struct timeval tv;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ /** On windows timeout of the setsockopt() function is the DWORD
+ * size variable in msec, so we use only the first field in timeval
+ * struct and directly assgign argument.
+ */
+ tv.tv_sec = timeout_ms;
+ tv.tv_usec = 0;
+#else
+ tv.tv_usec = (timeout_ms % 1000) * 1000;
+ tv.tv_sec = timeout_ms / 1000;
+#endif
+ setsockopt(skt, SOL_SOCKET, SO_RCVTIMEO,
+ reinterpret_cast(&tv), sizeof(struct timeval));
+}
+
+bool TcpServer::setBlockingMode(bool mode) {
+ int ret;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ // 0 = disable non-blocking mode
+ // 1 = enable non-blocking mode
+ u_long arg = mode ? 0 : 1;
+ ret = ioctlsocket(hsock_, FIONBIO, &arg);
+ if (ret == SOCKET_ERROR) {
+ RISCV_error("Set non-blocking socket failed", 0);
+ }
+#else
+ int flags = fcntl(hsock_, F_GETFL, 0);
+ if (flags < 0) {
+ return false;
+ }
+ flags = mode ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
+ ret = fcntl(hsock_, F_SETFL, flags);
+#endif
+ if (ret == 0) {
+ // success
+ blockmode_.make_boolean(mode);
+ return true;
+ }
+ return false;
+}
+
+void TcpServer::closeServerSocket() {
+ if (hsock_ < 0) {
+ return;
+ }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ closesocket(hsock_);
+#else
+ shutdown(hsock_, SHUT_RDWR);
+ close(hsock_);
+#endif
+ hsock_ = -1;
+}
+
+
+} // namespace debugger
remote/tcpserver.cpp
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: remote/tcpserver.h
===================================================================
--- remote/tcpserver.h (nonexistent)
+++ remote/tcpserver.h (revision 5)
@@ -0,0 +1,52 @@
+/**
+ * @file
+ * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
+ * @author Sergey Khabarov - sergeykhbr@gmail.com
+ * @brief Remote access to debugger via TCP connection. Server side.
+ */
+
+#ifndef __DEBUGGER_TCPSERVER_H__
+#define __DEBUGGER_TCPSERVER_H__
+
+#include
+#include
+#include "coreservices/ithread.h"
+#include "tcpclient.h"
+
+namespace debugger {
+
+class TcpServer : public IService,
+ public IThread {
+ public:
+ explicit TcpServer(const char *name);
+
+ /** IService interface */
+ virtual void postinitService();
+
+ protected:
+ /** IThread interface */
+ virtual void busyLoop();
+
+ protected:
+ int createServerSocket();
+ void closeServerSocket();
+ void setRcvTimeout(socket_def skt, int timeout_ms);
+ bool setBlockingMode(bool mode);
+
+ private:
+ AttributeType isEnable_;
+ AttributeType timeout_;
+ AttributeType blockmode_;
+ AttributeType hostIP_;
+ AttributeType hostPort_;
+
+ struct sockaddr_in sockaddr_ipv4_;
+ socket_def hsock_;
+ char rcvbuf[4096];
+};
+
+DECLARE_CLASS(TcpServer)
+
+} // namespace debugger
+
+#endif // __DEBUGGER_TCPSERVER_H__
remote/tcpserver.h
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Rev URL
\ No newline at end of property