-
Notifications
You must be signed in to change notification settings - Fork 806
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OpenOCD connects, and sends some data that we receive.
- Loading branch information
Showing
6 changed files
with
300 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
#include <arpa/inet.h> | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#include <algorithm> | ||
#include <cassert> | ||
#include <cstdio> | ||
|
||
#include "remote_bitbang.h" | ||
|
||
#define DEBUG | ||
#ifdef DEBUG | ||
# define D(x) x | ||
#else | ||
# define D(x) | ||
#endif // DEBUG | ||
|
||
/////////// Circular buffer | ||
|
||
template <typename T> | ||
unsigned int circular_buffer_t<T>::size() const | ||
{ | ||
if (end >= start) | ||
return end - start; | ||
else | ||
return end + capacity - start; | ||
} | ||
|
||
template <typename T> | ||
void circular_buffer_t<T>::consume(unsigned int bytes) | ||
{ | ||
start = (start + bytes) % capacity; | ||
} | ||
|
||
template <typename T> | ||
unsigned int circular_buffer_t<T>::contiguous_empty_size() const | ||
{ | ||
if (end >= start) | ||
if (start == 0) | ||
return capacity - end - 1; | ||
else | ||
return capacity - end; | ||
else | ||
return start - end - 1; | ||
} | ||
|
||
template <typename T> | ||
unsigned int circular_buffer_t<T>::contiguous_data_size() const | ||
{ | ||
if (end >= start) | ||
return end - start; | ||
else | ||
return capacity - start; | ||
} | ||
|
||
template <typename T> | ||
void circular_buffer_t<T>::data_added(unsigned int bytes) | ||
{ | ||
end += bytes; | ||
assert(end <= capacity); | ||
if (end == capacity) | ||
end = 0; | ||
} | ||
|
||
template <typename T> | ||
void circular_buffer_t<T>::reset() | ||
{ | ||
start = 0; | ||
end = 0; | ||
} | ||
|
||
template <typename T> | ||
void circular_buffer_t<T>::append(const T *src, unsigned int count) | ||
{ | ||
unsigned int copy = std::min(count, contiguous_empty_size()); | ||
memcpy(contiguous_empty(), src, copy * sizeof(T)); | ||
data_added(copy); | ||
count -= copy; | ||
if (count > 0) { | ||
assert(count < contiguous_empty_size()); | ||
memcpy(contiguous_empty(), src+copy, count * sizeof(T)); | ||
data_added(count); | ||
} | ||
} | ||
|
||
/////////// remote_bitbang_t | ||
|
||
remote_bitbang_t::remote_bitbang_t(uint16_t port, sim_t *sim) : | ||
socket_fd(0), | ||
client_fd(0), | ||
recv_buf(64 * 1024), | ||
send_buf(64 * 1024) | ||
{ | ||
socket_fd = socket(AF_INET, SOCK_STREAM, 0); | ||
if (socket_fd == -1) { | ||
fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n", | ||
strerror(errno), errno); | ||
abort(); | ||
} | ||
|
||
fcntl(socket_fd, F_SETFL, O_NONBLOCK); | ||
int reuseaddr = 1; | ||
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, | ||
sizeof(int)) == -1) { | ||
fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n", | ||
strerror(errno), errno); | ||
abort(); | ||
} | ||
|
||
struct sockaddr_in addr; | ||
memset(&addr, 0, sizeof(addr)); | ||
addr.sin_family = AF_INET; | ||
addr.sin_addr.s_addr = INADDR_ANY; | ||
addr.sin_port = htons(port); | ||
|
||
if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) { | ||
fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n", | ||
strerror(errno), errno); | ||
abort(); | ||
} | ||
|
||
if (listen(socket_fd, 1) == -1) { | ||
fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n", | ||
strerror(errno), errno); | ||
abort(); | ||
} | ||
} | ||
|
||
void remote_bitbang_t::accept() | ||
{ | ||
client_fd = ::accept(socket_fd, NULL, NULL); | ||
if (client_fd == -1) { | ||
if (errno == EAGAIN) { | ||
// No client waiting to connect right now. | ||
} else { | ||
fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno), | ||
errno); | ||
abort(); | ||
} | ||
} else { | ||
fcntl(client_fd, F_SETFL, O_NONBLOCK); | ||
} | ||
} | ||
|
||
void remote_bitbang_t::read() | ||
{ | ||
// Reading from a non-blocking socket still blocks if there is no data | ||
// available. | ||
|
||
size_t count = recv_buf.contiguous_empty_size(); | ||
ssize_t bytes = ::read(client_fd, recv_buf.contiguous_empty(), count); | ||
if (bytes == -1) { | ||
if (errno == EAGAIN) { | ||
// We'll try again the next call. | ||
} else { | ||
fprintf(stderr, "failed to read on socket: %s (%d)\n", strerror(errno), errno); | ||
abort(); | ||
} | ||
} else if (bytes == 0) { | ||
// The remote disconnected. | ||
client_fd = 0; | ||
recv_buf.reset(); | ||
send_buf.reset(); | ||
} else { | ||
recv_buf.data_added(bytes); | ||
D(fprintf(stderr, "receive buffer: ")); | ||
for (unsigned i = 0; i < recv_buf.size(); i++) { | ||
D(fprintf(stderr, "%c", recv_buf[i])); | ||
} | ||
D(fprintf(stderr, "\n")); | ||
} | ||
} | ||
|
||
void remote_bitbang_t::write() | ||
{ | ||
if (send_buf.empty()) | ||
return; | ||
|
||
while (!send_buf.empty()) { | ||
unsigned int count = send_buf.contiguous_data_size(); | ||
assert(count > 0); | ||
ssize_t bytes = ::write(client_fd, send_buf.contiguous_data(), count); | ||
if (bytes == -1) { | ||
fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno); | ||
abort(); | ||
} else if (bytes == 0) { | ||
// Client can't take any more data right now. | ||
break; | ||
} else { | ||
D(fprintf(stderr, "wrote %zd bytes: ", bytes)); | ||
for (int i = 0; i < bytes; i++) { | ||
D(fprintf(stderr, "%c", send_buf[i])); | ||
} | ||
D(fprintf(stderr, "\n")); | ||
send_buf.consume(bytes); | ||
} | ||
} | ||
} | ||
|
||
void remote_bitbang_t::tick() | ||
{ | ||
if (client_fd > 0) { | ||
this->read(); | ||
this->write(); | ||
} else { | ||
this->accept(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#ifndef REMOTE_BITBANG_H | ||
#define REMOTE_BITBANG_H | ||
|
||
#include <stdint.h> | ||
|
||
class sim_t; | ||
|
||
template <typename T> | ||
class circular_buffer_t | ||
{ | ||
public: | ||
// The buffer can store capacity-1 data elements. | ||
circular_buffer_t(unsigned int capacity) : data(new T[capacity]), | ||
start(0), end(0), capacity(capacity) {} | ||
circular_buffer_t() : start(0), end(0), capacity(0) {} | ||
~circular_buffer_t() { delete[] data; } | ||
|
||
T *data; | ||
unsigned int start; // Data start, inclusive. | ||
unsigned int end; // Data end, exclusive. | ||
unsigned int capacity; // Size of the buffer. | ||
unsigned int size() const; | ||
bool empty() const { return start == end; } | ||
bool full() const { return ((end+1) % capacity) == start; } | ||
T entry(unsigned index) { return data[(start + index) % capacity]; } | ||
|
||
// Return size and address of the block of RAM where more data can be copied | ||
// to be added to the buffer. | ||
unsigned int contiguous_empty_size() const; | ||
T *contiguous_empty() { return data + end; } | ||
void data_added(unsigned int bytes); | ||
|
||
unsigned int contiguous_data_size() const; | ||
T *contiguous_data() { return data + start; } | ||
// Tell the buffer that some bytes were consumed from the start of the | ||
// buffer. | ||
void consume(unsigned int bytes); | ||
|
||
void reset(); | ||
|
||
T operator[](unsigned int i) const { return data[(start + i) % capacity]; } | ||
|
||
void append(const T *src, unsigned int count); | ||
}; | ||
|
||
class remote_bitbang_t | ||
{ | ||
public: | ||
// Create a new server, listening for connections from localhost on the given | ||
// port. | ||
remote_bitbang_t(uint16_t port, sim_t *sim); | ||
|
||
// Do a bit of work. | ||
void tick(); | ||
|
||
private: | ||
int socket_fd; | ||
int client_fd; | ||
circular_buffer_t<uint8_t> recv_buf; | ||
circular_buffer_t<uint8_t> send_buf; | ||
|
||
// Check for a client connecting, and accept if there is one. | ||
void accept(); | ||
// Read as much into recv_buf as possible. | ||
void read(); | ||
// Write as much of send_buf as possible. | ||
void write(); | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.