diff --git a/libs/driver/libetherdream/etherdream.c b/libs/driver/libetherdream/etherdream.c index 90742a4..dacb93d 100755 --- a/libs/driver/libetherdream/etherdream.c +++ b/libs/driver/libetherdream/etherdream.c @@ -1,64 +1,50 @@ /* Ether Dream interface library - * - * Copyright 2011-2012 Jacob Potter - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or 3, or the GNU Lesser General Public License version 3, as published - * by the Free Software Foundation, at your option. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - +* +* Copyright 2011-2012 Jacob Potter +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of either the GNU General Public License version 2 +* or 3, or the GNU Lesser General Public License version 3, as published +* by the Free Software Foundation, at your option. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ #include "etherdream.h" - - -static FILE *trace_fp = NULL; -#if __MACH__ -static long long timer_start, timer_freq_numer, timer_freq_denom; -#else -static struct timespec start_time; -#endif -static pthread_mutex_t dac_list_lock; -static struct etherdream *dac_list = NULL; +static FILE* trace_fp = NULL; +static std::mutex dac_list_lock; +static struct etherdream* dac_list = NULL; +static std::chrono::high_resolution_clock::time_point startTime = std::chrono::high_resolution_clock::now(); +static std::thread watcherThread; /* microseconds() - * - * Return the number of microseconds since library initialization. - */ +* +* Return the number of microseconds since library initialization. +*/ static long long microseconds(void) { -#if __MACH__ - long long time_diff = mach_absolute_time() - timer_start; - return time_diff * timer_freq_numer / timer_freq_denom; -#else - struct timespec t; - clock_gettime(CLOCK_REALTIME, &t); - return (t.tv_sec - start_time.tv_sec) * 1000000 + - (t.tv_nsec - start_time.tv_nsec) / 1000; -#endif + const auto upTime = std::chrono::high_resolution_clock::now() - startTime; + return std::chrono::duration_cast(upTime).count(); } /* microsleep(us) - * - * Like usleep(). - */ +* +* Like usleep(). +*/ static void microsleep(long long us) { - nanosleep(&(struct timespec){ .tv_sec = us / 1000000, - .tv_nsec = (us % 1000000) * 1000 }, NULL); + std::this_thread::sleep_for(std::chrono::microseconds(us)); } /* trace(d, fmt, ...) - * - * Utility function for logging. - */ -static void trace(struct etherdream *d, char *fmt, ...) { +* +* Utility function for logging. +*/ +static void trace(struct etherdream* d, const char* fmt, ...) { if (!trace_fp) return; @@ -83,27 +69,29 @@ static void trace(struct etherdream *d, char *fmt, ...) { } /* log_socket_error(d, call) - * - * Log an error in a socket call. - */ -static void log_socket_error(struct etherdream *d, const char *call) { +* +* Log an error in a socket call. +*/ +static void log_socket_error(struct etherdream* d, const char* call) { trace(d, "!! socket error in %s: %d: %s\n", call, errno, strerror(errno)); } /* wait_for_fd_activity(d, usec, writable) - * - * Wait for activity (if writable is 0, then readable or error; if writable - * is 1, then writable or error) on d's socket. Time out after usec. Returns - * 1 if activity happened, 0 on timeout, -1 on error (will also log error). - */ -static int wait_for_fd_activity(struct etherdream *d, int usec, int writable) { +* +* Wait for activity (if writable is 0, then readable or error; if writable +* is 1, then writable or error) on d's socket. Time out after usec. Returns +* 1 if activity happened, 0 on timeout, -1 on error (will also log error). +*/ +static int wait_for_fd_activity(struct etherdream* d, int usec, int writable) { fd_set set; FD_ZERO(&set); FD_SET(d->conn.dc_sock, &set); + struct timeval t; + t.tv_sec = usec / 1000000; + t.tv_usec = usec % 1000000; int res = select(d->conn.dc_sock + 1, (writable ? NULL : &set), - (writable ? &set : NULL), &set, &(struct timeval){ - .tv_sec = usec / 1000000, .tv_usec = usec % 1000000 }); + (writable ? &set : NULL), &set, &t); if (res < 0) log_socket_error(d, "select"); @@ -111,11 +99,11 @@ static int wait_for_fd_activity(struct etherdream *d, int usec, int writable) { } /* read_bytes(d, buf, len) - * - * Read exactly len bytes from d's connection socket into buf. Returns 0 on - * success, -1 on error (will also log error). - */ -static int read_bytes(struct etherdream *d, char *buf, int len) { +* +* Read exactly len bytes from d's connection socket into buf. Returns 0 on +* success, -1 on error (will also log error). +*/ +static int read_bytes(struct etherdream* d, char* buf, int len) { while (d->conn.dc_read_buf_size < len) { int res = wait_for_fd_activity(d, DEFAULT_TIMEOUT, 0); if (res < 0) @@ -126,8 +114,8 @@ static int read_bytes(struct etherdream *d, char *buf, int len) { } res = recv(d->conn.dc_sock, - d->conn.dc_read_buf + d->conn.dc_read_buf_size, - len - d->conn.dc_read_buf_size, 0); + d->conn.dc_read_buf + d->conn.dc_read_buf_size, + len - d->conn.dc_read_buf_size, 0); if (res <= 0) { log_socket_error(d, "recv"); @@ -141,7 +129,7 @@ static int read_bytes(struct etherdream *d, char *buf, int len) { if (d->conn.dc_read_buf_size > len) { printf("moving %d up by %d\n", d->conn.dc_read_buf_size, len); memmove(d->conn.dc_read_buf, d->conn.dc_read_buf + len, - d->conn.dc_read_buf_size - len); + d->conn.dc_read_buf_size - len); } d->conn.dc_read_buf_size -= len; @@ -149,11 +137,11 @@ static int read_bytes(struct etherdream *d, char *buf, int len) { } /* send_all(d, data, len) - * - * Send all of data to d's socket. Returns 0 on success, -1 on error or if the - * send times out (will also log error). - */ -static int send_all(struct etherdream *d, const char *data, int len) { +* +* Send all of data to d's socket. Returns 0 on success, -1 on error or if the +* send times out (will also log error). +*/ +static int send_all(struct etherdream* d, const char* data, int len) { do { int res = wait_for_fd_activity(d, 100000, 1); if (res < 0) @@ -177,12 +165,12 @@ static int send_all(struct etherdream *d, const char *data, int len) { } /* read_resp(d) - * - * Read a response from the DAC into d's conn.resp buffer. Returns 0 on - * success, -1 on error (in which case the error will have been logged). - */ -static int read_resp(struct etherdream *d) { - int res = read_bytes(d, (char *)&d->conn.resp, sizeof(d->conn.resp)); +* +* Read a response from the DAC into d's conn.resp buffer. Returns 0 on +* success, -1 on error (in which case the error will have been logged). +*/ +static int read_resp(struct etherdream* d) { + int res = read_bytes(d, (char*)&d->conn.resp, sizeof(d->conn.resp)); if (res < 0) return res; @@ -191,12 +179,12 @@ static int read_resp(struct etherdream *d) { } /* dump_resp(d) - * - * Dump the last response received from d. - */ -static void dump_resp(struct etherdream *d) { - struct etherdream_conn *conn = &d->conn; - struct dac_status *st = &conn->resp.dac_status; +* +* Dump the last response received from d. +*/ +static void dump_resp(struct etherdream* d) { + struct etherdream_conn* conn = &d->conn; + struct dac_status* st = &conn->resp.dac_status; trace(d, "-- Protocol %d / LE %d / playback %d / source %d\n", 0 /* st->protocol */, st->light_engine_state, st->playback_state, st->source); @@ -208,86 +196,111 @@ static void dump_resp(struct etherdream *d) { } /* dac_connect(d, host, port) - * - * Initialize a dac's connection struct and open up a socket. On success, - * return 0; otherwise, return -1. - */ -static int dac_connect(struct etherdream *d) { - struct etherdream_conn *conn = &d->conn; - memset(conn, 0, sizeof *conn); +* +* Initialize a dac's connection struct and open up a socket. On success, +* return 0; otherwise, return -1. +*/ +static int dac_connect(struct etherdream* d) { + struct etherdream_conn* conn = &d->conn; + memset(conn, 0, sizeof * conn); // Open socket conn->dc_sock = socket(AF_INET, SOCK_STREAM, 0); + if (conn->dc_sock < 0) { log_socket_error(d, "socket"); return -1; } - unsigned long nonblocking = 1; - ioctl(conn->dc_sock, FIONBIO, &nonblocking); + u_long iMode = 1; +#ifdef _MSC_VER + ioctlsocket(conn->dc_sock, FIONBIO, &iMode); +#else + ioctl(conn->dc_sock, FIONBIO, &iMode); +#endif + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = d->addr.s_addr; + addr.sin_port = htons(7765); - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = d->addr.s_addr, .sin_port = htons(7765) - }; + connect(conn->dc_sock, (struct sockaddr*)&addr, (int)sizeof addr); +#ifdef _MSC_VER // Because the socket is nonblocking, this will always error... - connect(conn->dc_sock, (struct sockaddr *)&addr, (int)sizeof addr); + if (WSAGetLastError() != WSAEWOULDBLOCK) { +#else if (errno != EINPROGRESS) { +#endif log_socket_error(d, "connect"); goto bail; } + + // Wait for connection to go through - int res = wait_for_fd_activity(d, DEFAULT_TIMEOUT, 1); - if (res < 0) - goto bail; - if (res == 0) { - trace(d, "Connection to %s timed out.\n", inet_ntoa(d->addr)); - goto bail; + { + int res = wait_for_fd_activity(d, DEFAULT_TIMEOUT, 1); + if (res < 0) + goto bail; + if (res == 0) { + trace(d, "Connection to %s timed out.\n", inet_ntoa(d->addr)); + goto bail; + } } // See if we have *actually* connected - int error; - unsigned int len = sizeof error; - if (getsockopt(conn->dc_sock, SOL_SOCKET, SO_ERROR, (char *)&error, - &len) < 0) { - log_socket_error(d, "getsockopt"); - goto bail; - } + { + int error; +#ifdef _MSC_VER + int len = sizeof error; +#else + unsigned int len = sizeof error; +#endif + if (getsockopt(conn->dc_sock, SOL_SOCKET, SO_ERROR, (char*)&error, + &len) < 0) { + log_socket_error(d, "getsockopt"); + goto bail; + } - if (error) { - errno = error; - log_socket_error(d, "connect"); - goto bail; + if (error) { + errno = error; + log_socket_error(d, "connect"); + goto bail; + } } - int ndelay = 1; - if (setsockopt(conn->dc_sock, IPPROTO_TCP, TCP_NODELAY, - (char *)&ndelay, sizeof(ndelay)) < 0) { - log_socket_error(d, "setsockopt TCP_NODELAY"); - goto bail; + { + int ndelay = 1; + if (setsockopt(conn->dc_sock, IPPROTO_TCP, TCP_NODELAY, + (char*)&ndelay, sizeof(ndelay)) < 0) { + log_socket_error(d, "setsockopt TCP_NODELAY"); + goto bail; + } } // After we connect, the DAC will send an initial status response if (read_resp(d) < 0) goto bail; - char c = 'p'; - send_all(d, &c, 1); + { + char c = 'p'; + send_all(d, &c, 1); + } if (read_resp(d) < 0) goto bail; dump_resp(d); if (d->sw_revision >= 2) { - c = 'v'; + char c = 'v'; if (send_all(d, &c, 1) < 0) goto bail; - res = read_bytes(d, d->version, sizeof(d->version)); + int res = read_bytes(d, d->version, sizeof(d->version)); if (res < 0) return res; - } else { + } + else { strcpy(d->version, "[old]"); } @@ -295,17 +308,21 @@ static int dac_connect(struct etherdream *d) { return 0; bail: +#ifdef _MSC_VER + closesocket(d->conn.dc_sock); +#else close(d->conn.dc_sock); +#endif return -1; -} + } /* check_data_response(d) - * - * Handle a response from d: update our record of the number of sent-but-not- - * ACKed points, and error if the response was unexpected. - */ -static int check_data_response(struct etherdream *d) { - struct etherdream_conn *conn = &d->conn; +* +* Handle a response from d: update our record of the number of sent-but-not- +* ACKed points, and error if the response was unexpected. +*/ +static int check_data_response(struct etherdream* d) { + struct etherdream_conn* conn = &d->conn; if (conn->resp.dac_status.playback_state == 0) conn->dc_begin_sent = 0; @@ -316,7 +333,8 @@ static int check_data_response(struct etherdream *d) { } conn->unacked_points -= conn->ackbuf[conn->ackbuf_cons]; conn->ackbuf_cons = (conn->ackbuf_cons + 1) % MAX_LATE_ACKS; - } else { + } + else { conn->pending_meta_acks--; } @@ -331,12 +349,12 @@ static int check_data_response(struct etherdream *d) { } /* dac_get_acks(d, wait) - * - * Read any ACKs we are owed, waiting up to 'wait' microseconds. - */ -static int dac_get_acks(struct etherdream *d, int wait) { +* +* Read any ACKs we are owed, waiting up to 'wait' microseconds. +*/ +static int dac_get_acks(struct etherdream* d, int wait) { while (d->conn.pending_meta_acks - || (d->conn.ackbuf_prod != d->conn.ackbuf_cons)) { + || (d->conn.ackbuf_prod != d->conn.ackbuf_cons)) { int res = wait_for_fd_activity(d, wait, 0); if (res <= 0) return res; @@ -349,14 +367,14 @@ static int dac_get_acks(struct etherdream *d, int wait) { } /* dac_send_data(d, data, npoints, rate) - * - * Send points to the DAC, including prepare or begin commands and changing - * the point rate as necessary. - */ -static int dac_send_data(struct etherdream *d, struct dac_point *data, - int npoints, int rate) { +* +* Send points to the DAC, including prepare or begin commands and changing +* the point rate as necessary. +*/ +static int dac_send_data(struct etherdream* d, struct dac_point* data, + int npoints, int rate) { int res; - const struct dac_status *st = &d->conn.resp.dac_status; + const struct dac_status* st = &d->conn.resp.dac_status; if (st->playback_state == 0) { trace(d, "L: Sending prepare command...\n"); @@ -374,12 +392,15 @@ static int dac_send_data(struct etherdream *d, struct dac_point *data, } if (st->buffer_fullness > 1600 && st->playback_state == 1 \ - && !d->conn.dc_begin_sent) { + && !d->conn.dc_begin_sent) { trace(d, "L: Sending begin command...\n"); - struct begin_command b = { .command = 'b', .point_rate = rate, - .low_water_mark = 0 }; - if ((res = send_all(d, (const char *)&b, sizeof b)) < 0) + struct begin_command b = { + 'b', + 0, + (uint32_t)rate + }; + if ((res = send_all(d, (const char*)&b, sizeof b)) < 0) return res; d->conn.dc_begin_sent = 1; @@ -404,7 +425,7 @@ static int dac_send_data(struct etherdream *d, struct dac_point *data, d->conn.dc_local_buffer.data[0].control |= DAC_CTRL_RATE_CHANGE; /* Write the data */ - if ((res = send_all(d, (const char *)&d->conn.dc_local_buffer, + if ((res = send_all(d, (const char*)&d->conn.dc_local_buffer, 8 + npoints * sizeof(struct dac_point))) < 0) return res; @@ -421,29 +442,25 @@ static int dac_send_data(struct etherdream *d, struct dac_point *data, || d->conn.resp.dac_status.buffer_fullness < DEBUG_THRESHOLD_POINTS) /* dac_loop(dv) - * - * Main thread function for sending data to the DAC. - */ -static void *dac_loop(void *dv) { - struct etherdream *d = (struct etherdream *)dv; +* +* Main thread function for sending data to the DAC. +*/ +static void* dac_loop(etherdream * d) { int res = 0; - pthread_mutex_lock(&d->mutex); - while (1) { /* Wait for us to have data */ int state; while ((state = d->state) == ST_READY) { -// trace(d, "L: waiting\n"); // MEMO - pthread_cond_wait(&d->loop_cond, &d->mutex); + trace(d, "L: waiting\n"); + std::unique_lock lock(d->mutex); + d->loop_cond.wait(lock); } - pthread_mutex_unlock(&d->mutex); - if (state != ST_RUNNING) break; - struct buffer_item *b = &d->buffer[d->frame_buffer_read]; + struct buffer_item* b = &d->buffer[d->frame_buffer_read]; int cap; int expected_used, expected_fullness; @@ -451,9 +468,9 @@ static void *dac_loop(void *dv) { res = 0; /* Estimate how much data has been consumed since the - * last time we got an ACK. */ + * last time we got an ACK. */ long long time_diff = microseconds() - - d->conn.dc_last_ack_time; + - d->conn.dc_last_ack_time; expected_used = time_diff * b->pps / 1000000; @@ -461,7 +478,7 @@ static void *dac_loop(void *dv) { expected_used = 0; expected_fullness = - d->conn.resp.dac_status.buffer_fullness + d->conn.resp.dac_status.buffer_fullness + d->conn.unacked_points - expected_used; /* Now, see how much data we should write. */ @@ -517,48 +534,56 @@ static void *dac_loop(void *dv) { if (res < 0) break; - pthread_mutex_lock(&d->mutex); + { + std::unique_lock lock(d->mutex); - /* What next? */ - b->idx += cap; + /* What next? */ + b->idx += cap; - if (b->idx < b->points) { - /* There's more in this frame. */ - continue; - } + if (b->idx < b->points) { + /* There's more in this frame. */ + continue; + } + + b->idx = 0; - b->idx = 0; - - if (b->repeatcount > 1) { - /* Play this frame again? */ - b->repeatcount--; - } else if (d->frame_buffer_fullness > 1) { - /* Move to the next frame */ - d->frame_buffer_fullness--; - d->frame_buffer_read++; - if (d->frame_buffer_read >= BUFFER_NFRAMES) - d->frame_buffer_read = 0; - pthread_cond_broadcast(&d->loop_cond); - } else if (b->repeatcount >= 0) { - /* Stop playing until we get a new frame. */ -// trace(d, "L: returning to idle\n"); // MEMO - d->state = ST_READY; - } else { - /* repeatcount is negative and there's no new frame, - * so just play this one over again. */ + if (b->repeatcount > 1) { + /* Play this frame again? */ + b->repeatcount--; + } + else if (d->frame_buffer_fullness > 1) { + /* Move to the next frame */ + d->frame_buffer_fullness--; + d->frame_buffer_read++; + if (d->frame_buffer_read >= BUFFER_NFRAMES) + d->frame_buffer_read = 0; + d->loop_cond.notify_all(); + } + else if (b->repeatcount >= 0) { + /* Stop playing until we get a new frame. */ + trace(d, "L: returning to idle\n"); + d->state = ST_READY; + } + else { + /* repeatcount is negative and there's no new frame, + * so just play this one over again. */ + } } } trace(d, "L: Shutting down.\n"); d->state = ST_SHUTDOWN; + d->loop_cond.notify_all(); return 0; } -int etherdream_connect(struct etherdream *d) { +int etherdream_connect(struct etherdream* d) { + trace(d, "L: Connecting.\n"); + // Initialize buffer d->frame_buffer_read = 0; d->frame_buffer_fullness = 0; - memset(d->buffer, sizeof(d->buffer), 0); + memset(d->buffer, 0, sizeof(d->buffer)); // Connect to the DAC if (dac_connect(d) < 0) { @@ -568,42 +593,60 @@ int etherdream_connect(struct etherdream *d) { d->state = ST_READY; - int res = pthread_create(&d->workerthread, NULL, dac_loop, d); - if (res) { - trace(d, "!! Begin thread error: %s\n", strerror(res)); - return -1; - } + d->workerthread = std::thread([d]() { + dac_loop(d); + }); trace(d, "Ready.\n"); return 0; } -void etherdream_disconnect(struct etherdream *d) { - pthread_mutex_lock(&d->mutex); + +int etherdream_is_connected(struct etherdream* d) { + return d->state == ST_READY; +} + + +void etherdream_disconnect(struct etherdream* d) { + trace(d, "L: Disconnecting.\n"); + + d->mutex.lock(); if (d->state == ST_READY) - pthread_cond_broadcast(&d->loop_cond); + d->loop_cond.notify_all(); d->state = ST_SHUTDOWN; - pthread_mutex_unlock(&d->mutex); + d->mutex.unlock(); - pthread_join(d->workerthread, NULL); + d->workerthread.join(); +#ifdef _MSC_VER + closesocket(d->conn.dc_sock); +#else close(d->conn.dc_sock); +#endif } /* etherdream_get_id(d) - * - * Documented in etherdream.h. - */ -unsigned long etherdream_get_id(struct etherdream *d) { +* +* Documented in etherdream.h. +*/ +unsigned long etherdream_get_id(struct etherdream* d) { return d->dac_id; } +/* etherdream_get_in_addr(d) +* +* Documented in etherdream.h. +*/ +const struct in_addr* etherdream_get_in_addr(struct etherdream* d) { + return &d->addr; +} + /* etherdream_write(d, pts, npts, pps, reps) - * - * Documented in etherdream.h. - */ -int etherdream_write(struct etherdream *d, const struct etherdream_point *pts, - int npts, int pps, int reps) { +* +* Documented in etherdream.h. +*/ +int etherdream_write(struct etherdream* d, const struct etherdream_point* pts, + int npts, int pps, int reps) { /* Limit maximum frame size */ if (npts > BUFFER_POINTS_PER_FRAME) @@ -613,19 +656,19 @@ int etherdream_write(struct etherdream *d, const struct etherdream_point *pts, if (!reps) return 0; - pthread_mutex_lock(&d->mutex); + d->mutex.lock(); /* If not ready for a new frame, bail */ if (d->frame_buffer_fullness == BUFFER_NFRAMES) { - pthread_mutex_unlock(&d->mutex); + d->mutex.unlock(); trace(d, "M: NOT READY: %d points, %d reps\n", npts, reps); return -1; } - struct buffer_item *next = &d->buffer[(d->frame_buffer_read - + d->frame_buffer_fullness) % BUFFER_NFRAMES]; + struct buffer_item* next = &d->buffer[(d->frame_buffer_read + + d->frame_buffer_fullness) % BUFFER_NFRAMES]; - pthread_mutex_unlock(&d->mutex); + d->mutex.unlock(); // trace(d, "M: Writing: %d points, %d reps, %d pps\n", npts, reps, pps); @@ -639,7 +682,7 @@ int etherdream_write(struct etherdream *d, const struct etherdream_point *pts, next->data[i].g = pts[i].g; next->data[i].b = pts[i].b; next->data[i].i = pts[i].i; - next->data[i].u1 = pts[i].u1; + next->data[i].u1 = pts[i].u1; next->data[i].u2 = pts[i].u2; next->data[i].control = 0; } @@ -649,59 +692,65 @@ int etherdream_write(struct etherdream *d, const struct etherdream_point *pts, next->points = npts; /* Advance buffer and signal the writing thread if necessary */ - pthread_mutex_lock(&d->mutex); + d->mutex.lock(); d->frame_buffer_fullness++; if (d->state == ST_READY) - pthread_cond_signal(&d->loop_cond); + d->loop_cond.notify_one(); d->state = ST_RUNNING; - pthread_mutex_unlock(&d->mutex); + d->mutex.unlock(); return 0; } /* etherdream_is_ready(d) - * - * Documented in etherdream.h. - */ -int etherdream_is_ready(struct etherdream *d) { - pthread_mutex_lock(&d->mutex); +* +* Documented in etherdream.h. +*/ +int etherdream_is_ready(struct etherdream* d) { + d->mutex.lock(); int ready = (d->frame_buffer_fullness != BUFFER_NFRAMES); - pthread_mutex_unlock(&d->mutex); + d->mutex.unlock(); return ready; } /* etherdream_wait_for_ready(d) - * - * Documented in etherdream.h. - */ -int etherdream_wait_for_ready(struct etherdream *d) { - pthread_mutex_lock(&d->mutex); - while (d->frame_buffer_fullness == BUFFER_NFRAMES) - pthread_cond_wait(&d->loop_cond, &d->mutex); - pthread_mutex_unlock(&d->mutex); - return 0; +* +* Documented in etherdream.h. +*/ +int etherdream_wait_for_ready(struct etherdream* d) { + d->mutex.lock(); + while (d->frame_buffer_fullness == BUFFER_NFRAMES && d->state != ST_SHUTDOWN) { + std::unique_lock lock(d->mutex); d->loop_cond.wait(lock); + } + int is_shutdown = (d->state == ST_SHUTDOWN); + d->mutex.unlock(); + + if (is_shutdown) { + return -1; + } + else { + return 0; + } } /* etherdream_stop(d) - * - * Documented in etherdream.h. - */ -int etherdream_stop(struct etherdream *d) { - pthread_mutex_lock(&d->mutex); +* +* Documented in etherdream.h. +*/ +int etherdream_stop(struct etherdream* d) { + d->mutex.lock(); if (d->state == ST_RUNNING) d->buffer[d->frame_buffer_read].repeatcount = 0; - pthread_mutex_unlock(&d->mutex); + d->mutex.unlock(); return 0; } /* watch_for_dacs(arg) - * - * Thread function for the broadcast monitor thread. This listens for UDP - * broadcasts from Ether Dream boards on the network and adds them to our list. - */ -static void *watch_for_dacs(void *arg) { - (void)arg; - +* +* Thread function for the broadcast monitor thread. This listens for UDP +* broadcasts from Ether Dream boards on the network and adds them to our list. +*/ +static void* watch_for_dacs() { int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { log_socket_error(NULL, "socket"); @@ -709,17 +758,18 @@ static void *watch_for_dacs(void *arg) { } int opt = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, - sizeof opt) < 0) { + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, + sizeof opt) < 0) { log_socket_error(NULL, "setsockopt SO_REUSEADDR"); return NULL; } - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_ANY), .sin_port = htons(7654) - }; - if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(7654); + + if (bind(sock, (struct sockaddr*)&addr, sizeof addr) < 0) { log_socket_error(NULL, "bind"); return NULL; } @@ -729,17 +779,21 @@ static void *watch_for_dacs(void *arg) { while (1) { struct sockaddr_in src; struct dac_broadcast buf; +#ifdef _MSC_VER + int srclen = sizeof src; +#else unsigned int srclen = sizeof src; - int len = recvfrom(sock, (char *)&buf, sizeof buf, 0, - (struct sockaddr *)&src, &srclen); +#endif + int len = recvfrom(sock, (char*)&buf, sizeof buf, 0, + (struct sockaddr*)&src, &srclen); if (len < 0) { log_socket_error(NULL, "recvfrom"); return NULL; } /* See if this is a DAC we already knew about */ - pthread_mutex_lock(&dac_list_lock); - struct etherdream *p = dac_list; + dac_list_lock.lock(); + struct etherdream* p = dac_list; while (p) { if (p->addr.s_addr == src.sin_addr.s_addr) break; @@ -747,38 +801,30 @@ static void *watch_for_dacs(void *arg) { } if (p && (p->addr.s_addr == src.sin_addr.s_addr)) { - pthread_mutex_unlock(&dac_list_lock); + dac_list_lock.unlock(); continue; } - pthread_mutex_unlock(&dac_list_lock); + dac_list_lock.unlock(); /* Make a new DAC entry */ - struct etherdream *new_dac; - new_dac = (void *)malloc(sizeof (struct etherdream)); - if (!new_dac) { - trace(NULL, "!! malloc(struct etherdream) failed\n"); - continue; - } - - memset(new_dac, 0, sizeof *new_dac); - pthread_cond_init(&new_dac->loop_cond, NULL); - pthread_mutex_init(&new_dac->mutex, NULL); + struct etherdream* new_dac; + new_dac = new etherdream(); new_dac->addr = src.sin_addr; memcpy(new_dac->mac_address, buf.mac_address, 6); new_dac->dac_id = (buf.mac_address[3] << 16) - | (buf.mac_address[4] << 8) - | buf.mac_address[5]; + | (buf.mac_address[4] << 8) + | buf.mac_address[5]; new_dac->sw_revision = buf.sw_revision; new_dac->state = ST_DISCONNECTED; trace(NULL, "_: Found new DAC: %s\n", inet_ntoa(src.sin_addr)); - pthread_mutex_lock(&dac_list_lock); + dac_list_lock.lock(); new_dac->next = dac_list; dac_list = new_dac; - pthread_mutex_unlock(&dac_list_lock); + dac_list_lock.unlock(); } trace(NULL, "_: Exiting\n"); @@ -786,20 +832,10 @@ static void *watch_for_dacs(void *arg) { } /* etherdream_lib_start() - * - * Documented in etherdream.h. - */ +* +* Documented in etherdream.h. +*/ int etherdream_lib_start(void) { - // Get high-resolution timer info -#if __MACH__ - timer_start = mach_absolute_time(); - mach_timebase_info_data_t timebase_info; - mach_timebase_info(&timebase_info); - timer_freq_numer = timebase_info.numer; - timer_freq_denom = timebase_info.denom * 1000; -#else - clock_gettime(CLOCK_REALTIME, &start_time); -#endif // Set up the logging fd (just stderr for now) trace_fp = stderr; @@ -807,39 +843,50 @@ int etherdream_lib_start(void) { fflush(trace_fp); trace(NULL, "== libetherdream started ==\n"); - pthread_mutex_init(&dac_list_lock, NULL); - pthread_t watcher_thread; - pthread_create(&watcher_thread, NULL, watch_for_dacs, NULL); +#ifdef _MSC_VER + { + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2, 2); + auto err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + printf("WSAStartup failed with error: %d\n", err); + return err; + } + } +#endif + + watcherThread = std::thread(watch_for_dacs); return 0; } /* etherdream_dac_count() - * - * Documented in etherdream.h. - */ +* +* Documented in etherdream.h. +*/ int etherdream_dac_count(void) { - pthread_mutex_lock(&dac_list_lock); + dac_list_lock.lock(); int count = 0; - struct etherdream *d = dac_list; + struct etherdream* d = dac_list; while (d) { d = d->next; count++; } - pthread_mutex_unlock(&dac_list_lock); + dac_list_lock.unlock(); trace(NULL, "== etherdream_lib_get_dac_count(): %d\n", count); return count; } /* etherdream_get() - * - * Documented in etherdream.h. - */ -struct etherdream *etherdream_get(unsigned long idx) { - struct etherdream *d = dac_list; +* +* Documented in etherdream.h. +*/ +struct etherdream* etherdream_get(unsigned long idx) { + struct etherdream* d = dac_list; unsigned long i = 0; while (d) { @@ -851,4 +898,4 @@ struct etherdream *etherdream_get(unsigned long idx) { } return NULL; -} +} \ No newline at end of file diff --git a/libs/driver/libetherdream/etherdream.h b/libs/driver/libetherdream/etherdream.h index 5c7f5e4..29e531a 100755 --- a/libs/driver/libetherdream/etherdream.h +++ b/libs/driver/libetherdream/etherdream.h @@ -1,69 +1,71 @@ #ifndef ETHERDREAM_H #define ETHERDREAM_H -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - #define _POSIX_C_SOURCE 199309L #define _DARWIN_C_SOURCE 1 - + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#include +#else #include -#include #include #include -#include -#include -#include -#include -#include #include #include -#include +#endif + +#include +#include + +#include #include -#include - -#ifdef __MACH__ -#include -#include +#include + +#include "../common/protocol.h" + +#ifdef __cplusplus +extern "C" +{ #endif -struct etherdream_point { - int16_t x; - int16_t y; - uint16_t r; - uint16_t g; - uint16_t b; - uint16_t i; - uint16_t u1; - uint16_t u2; -}; - - +#include + #define BUFFER_POINTS_PER_FRAME 16000 -#define BUFFER_NFRAMES 2 -#define MAX_LATE_ACKS 64 -#define MIN_SEND_POINTS 40 -#define DEFAULT_TIMEOUT 2000000 -#define DEBUG_THRESHOLD_POINTS 800 - - - struct etherdream_conn { +#define BUFFER_NFRAMES 2 +#define MAX_LATE_ACKS 64 +#define MIN_SEND_POINTS 40 +#define DEFAULT_TIMEOUT 2000000 +#define DEBUG_THRESHOLD_POINTS 800 + + struct etherdream_point + { + int16_t x; + int16_t y; + uint16_t r; + uint16_t g; + uint16_t b; + uint16_t i; + uint16_t u1; + uint16_t u2; + }; + + struct etherdream_conn + { int dc_sock; char dc_read_buf[1024]; int dc_read_buf_size; - struct dac_response resp; + dac_response resp; long long dc_last_ack_time; - - struct { + + struct + { struct queue_command queue; struct data_command_header header; struct dac_point data[1000]; } __attribute__((packed)) dc_local_buffer; - + int dc_begin_sent; int ackbuf[MAX_LATE_ACKS]; int ackbuf_prod; @@ -71,131 +73,145 @@ struct etherdream_point { int unacked_points; int pending_meta_acks; }; - - struct buffer_item { + + struct buffer_item + { struct dac_point data[BUFFER_POINTS_PER_FRAME]; int points; int pps; int repeatcount; int idx; }; - - enum dac_state { + + enum dac_state + { ST_DISCONNECTED, ST_READY, ST_RUNNING, ST_BROKEN, ST_SHUTDOWN }; - - struct etherdream { - pthread_mutex_t mutex; - pthread_cond_t loop_cond; - + + struct etherdream + { + std::mutex mutex; + std::condition_variable loop_cond; + struct buffer_item buffer[BUFFER_NFRAMES]; int frame_buffer_read; int frame_buffer_fullness; int bounce_count; - - pthread_t workerthread; - + + std::thread workerthread; + struct in_addr addr; struct etherdream_conn conn; unsigned long dac_id; int sw_revision; char mac_address[6]; char version[32]; - + enum dac_state state; - - struct etherdream * next; + + etherdream *next; }; - -struct etherdream; - -/* etherdream_lib_start() - * - * Initialize the Ether Dream library and start a background thread to listen - * for DAC broadcasts. This should be called exactly once at program startup. - * - * Returns 0 on success, -1 on failure. - */ -int etherdream_lib_start(void); - -/* etherdream_dac_count() - * - * Return the number of detected DACs since etherdream_lib_start() was called. - * Ether Dream DACs broadcast once per second, so calling code should wait a - * little over a second after etherdream_lib_start() to ensure that all DACs - * on the network are seen. - */ -int etherdream_dac_count(void); - -/* etherdream_get(idx) - * - * Return the i'th detected DAC. This function accepts either an integer index - * (0-based) or an ID value as returned by etherdream_get_id(). Returns NULL - * if the requested DAC is not available. - */ -struct etherdream *etherdream_get(unsigned long idx); - -/* etherdream_get_id(d) - * - * Return the ID value (equal to the second half of the MAC address, when - * represented in hex) of the given Ether Dream. Does not require that a - * connection to d has been established. - */ -unsigned long etherdream_get_id(struct etherdream *d); - -/* etherdream_connect(d) - * - * Open a connection to d. This must be called before most other etherdream_ - * functions can be used. - */ -int etherdream_connect(struct etherdream *d); - -/* etherdream_is_ready(d) - * - * Return 1 if the local buffer for d can accept more frames, 0 if not, -1 on - * error (if the connection to d has not been opened or has failed). - */ -int etherdream_is_ready(struct etherdream *d); - -/* etherdream_wait_for_ready(d) - * - * Block the invoking thread until more data can be written to d. Returns 0 on - * success, -1 if the connection to d is not open or has failed. - */ -int etherdream_wait_for_ready(struct etherdream *d); - -/* etherdream_write(d, pts, npts, pps, repeatcount) - * - * Write a "frame" consisting of pts (length npts) to d. - * - * If repeatcount is -1, pts will be sent to the laser repeatedly until new - * data is received or until etherdream_stop is called. Otherwise, the points - * will be sent repeatedly at most npts times, and then the stream will - * automatically stop. pps specifies the output rate (30000 is a common value). - * repeatcount must not be 0. - * - * The Ether Dream uses a continuous streaming protocol, so if new frames are - * continuously sent, frame boundaries are not visible; however, to reduce - * overhead, frames should be reasonably large (at least 50-100 points). - */ -int etherdream_write(struct etherdream *d, const struct etherdream_point *pts, - int npts, int pps, int repeatcount); - -/* etherdream_stop(d) - * - * Stop output from d as soon as the current frame is finished. - */ -int etherdream_stop(struct etherdream *d); - -/* etherdream_disconnect(d) - * - * Close the TCP connection to d. - */ -void etherdream_disconnect(struct etherdream *d); + + /* etherdream_lib_start() + * + * Initialize the Ether Dream library and start a background thread to listen + * for DAC broadcasts. This should be called exactly once at program startup. + * + * Returns 0 on success, -1 on failure. + */ + int etherdream_lib_start(void); + + /* etherdream_dac_count() + * + * Return the number of detected DACs since etherdream_lib_start() was called. + * Ether Dream DACs broadcast once per second, so calling code should wait a + * little over a second after etherdream_lib_start() to ensure that all DACs + * on the network are seen. + */ + int etherdream_dac_count(void); + + /* etherdream_get(idx) + * + * Return the [i]'th detected DAC. This function accepts either an integer index + * (0-based) or an ID value as returned by etherdream_get_id(). Returns NULL + * if the requested DAC is not available. + */ + struct etherdream *etherdream_get(unsigned long idx); + + /* etherdream_get_id(d) + * + * Return the ID value (equal to the second half of the MAC address, when + * represented in hex) of the given Ether Dream. Does not require that a + * connection to d has been established. + */ + unsigned long etherdream_get_id(struct etherdream *d); + + /* etherdream_get_in_addr(d) + * + * Return the IP address of the given Ether Dream. Does not require that + * a connection to d has been established. + */ + const struct in_addr *etherdream_get_in_addr(struct etherdream *d); + + /* etherdream_connect(d) + * + * Open a connection to d. This must be called before most other etherdream_ + * functions can be used. + */ + int etherdream_connect(struct etherdream *d); + + /* etherdream_is_connected(d) + * + * Returns 1 if the network connection to d is connected, 0 if not. + */ + int etherdream_is_connected(struct etherdream *d); + + /* etherdream_is_ready(d) + * + * Return 1 if the local buffer for d can accept more frames, 0 if not, -1 on + * error (if the connection to d has not been opened or has failed). + */ + int etherdream_is_ready(struct etherdream *d); + + /* etherdream_wait_for_ready(d) + * + * Block the invoking thread until more data can be written to d. Returns 0 on + * success, -1 if the connection to d is not open or has failed. + */ + int etherdream_wait_for_ready(struct etherdream *d); + + /* etherdream_write(d, pts, npts, pps, repeatcount) + * + * Write a "frame" consisting of pts (length npts) to d. + * + * If repeatcount is -1, pts will be sent to the laser repeatedly until new + * data is received or until etherdream_stop is called. Otherwise, the points + * will be sent repeatedly at most npts times, and then the stream will + * automatically stop. pps specifies the output rate (30000 is a common value). + * repeatcount must not be 0. + * + * The Ether Dream uses a continuous streaming protocol, so if new frames are + * continuously sent, frame boundaries are not visible; however, to reduce + * overhead, frames should be reasonably large (at least 50-100 points). + */ + int etherdream_write(struct etherdream *d, const struct etherdream_point *pts, + int npts, int pps, int repeatcount); + + /* etherdream_stop(d) + * + * Stop output from d as soon as the current frame is finished. + */ + int etherdream_stop(struct etherdream *d); + + /* etherdream_disconnect(d) + * + * Close the TCP connection to d. + */ + void etherdream_disconnect(struct etherdream *d); #ifdef __cplusplus } // extern "c" diff --git a/libs/driver/libetherdream/test.c b/libs/driver/libetherdream/test.c index 5ffec41..60a8e18 100755 --- a/libs/driver/libetherdream/test.c +++ b/libs/driver/libetherdream/test.c @@ -2,7 +2,8 @@ #include #include -#include +//#include +#include #include "etherdream.h" @@ -21,25 +22,84 @@ uint16_t colorsin(float pos) { return res; } -void fill_circle(float phase) { +void fill_circle(float phase, int mode) { int i; for (i = 0; i < CIRCLE_POINTS; i++) { - struct etherdream_point *pt = &circle[i]; + struct etherdream_point* pt = &circle[i]; float ip = (float)i * 2.0 * M_PI / (float)CIRCLE_POINTS; - pt->x = sin(ip) * 20000; - pt->y = cos(ip) * 20000; - pt->r = colorsin(ip + phase); - pt->g = colorsin(ip + (2.0 * M_PI / 3.0) + phase); - pt->b = colorsin(ip + (4.0 * M_PI / 3.0) + phase); + float ipf = fmod(ip + phase, 2.0 * M_PI);; + + switch (mode) { + default: + case 0: { + float cmult = .05 * sin(30 * (ip - phase / 3)); + pt->x = sin(ip) * 20000 * (1 + cmult); + pt->y = cos(ip) * 20000 * (1 + cmult); + break; + } + case 1: { + float cmult = .10 * sin(10 * (ip - phase / 3)); + pt->x = sin(ip) * 20000 * (1 + cmult); + pt->y = cos(ip) * 20000 * (1 + cmult); + break; + /* XXX broken */ +/* + float R = 3; + float r = 5; + pt->x = 2000 * ((R-r)*cos(ip+phase) + r*cos((R-r)*ip/r)); + pt->y = 2000 * ((R-r)*sin(ip+phase) - r*sin((R-r)*ip/r)); + break; +*/ + } + case 2: { + ip *= 3; + float R = 5; + float r = 3; + float D = 5; + + pt->x = 2500 * ((R - r) * cos(ip + phase) + D * cos((R - r) * ip / r)); + pt->y = 2500 * ((R - r) * sin(ip + phase) - D * sin((R - r) * ip / r)); + break; + } + case 3: { + int n = 5; + float R = 5 * cos(M_PI / n) / cos(fmod(ip, (2 * M_PI / n)) - (M_PI / n)); + pt->x = 3500 * R * cos(ip + phase); + pt->y = 3500 * R * sin(ip + phase); + break; + } + case 4: { + float Xo = sin(ip); + pt->x = 20000 * Xo * cos(phase / 4); + pt->y = 20000 * Xo * -sin(phase / 4); + ipf = fmod(((Xo + 1) / 2.0) + phase / 3, 1.0) * 2 * M_PI; + } + } + + pt->r = colorsin(ipf); + pt->g = colorsin(ipf + (2.0 * M_PI / 3.0)); + pt->b = colorsin(ipf + (4.0 * M_PI / 3.0)); + /* + if (ipf < 2.0 * M_PI / 3.0) { + pt->r = 65535; + pt->g = pt->b = 0; + } else if (ipf < 4.0 * M_PI / 3.0) { + pt->g = 65535; + pt->r = pt->b = 0; + } else { + pt->b = 65535; + pt->r = pt->g = 0; + } + */ } } -int _main() { +int main(int argc, char** argv) { etherdream_lib_start(); /* Sleep for a bit over a second, to ensure that we see broadcasts * from all available DACs. */ - usleep(1200000); + //usleep(1200000); int cc = etherdream_dac_count(); if (!cc) { @@ -47,13 +107,19 @@ int _main() { return 0; } + int mode; + if (argc > 1) + mode = atoi(argv[1]); + else + mode = 0; + int i; for (i = 0; i < cc; i++) { printf("%d: Ether Dream %06lx\n", i, etherdream_get_id(etherdream_get(i))); } - struct etherdream *d = etherdream_get(0); + struct etherdream* d = etherdream_get(0); printf("Connecting...\n"); if (etherdream_connect(d) < 0) @@ -61,7 +127,7 @@ int _main() { i = 0; while (1) { - fill_circle((float)i / 50); + fill_circle((float)i / 50, mode); int res = etherdream_write(d, circle, CIRCLE_POINTS, 30000, 1); if (res != 0) { printf("write %d\n", res); diff --git a/src/ofxEtherdream.cpp b/src/ofxEtherdream.cpp index b8de96b..3cea9f8 100755 --- a/src/ofxEtherdream.cpp +++ b/src/ofxEtherdream.cpp @@ -1,173 +1,208 @@ #include "ofxEtherdream.h" //-------------------------------------------------------------- -void ofxEtherdream::setup(bool bStartThread, int idEtherdream) { +void ofxEtherdream::setup(bool bStartThread, int idEtherdream) +{ idEtherdreamConnection = idEtherdream; - + etherdream_lib_start(); - + setPPS(30000); setWaitBeforeSend(false); - - /* Sleep for a bit over a second, to ensure that we see broadcasts - * from all available DACs. */ - usleep(1000000); - + +/* Sleep for a bit over a second, to ensure that we see broadcasts + * from all available DACs. */ +#ifdef _MSC_VER + Sleep(1000); +#else + usleep(1000000); +#endif + init(); - - if(bStartThread) start(); -} + if (bStartThread) + start(); +} //-------------------------------------------------------------- -bool ofxEtherdream::stateIsFound() { +bool ofxEtherdream::stateIsFound() +{ return state == ETHERDREAM_FOUND; } //-------------------------------------------------------------- -bool ofxEtherdream::checkConnection(bool bForceReconnect) { - if(device->state == ST_SHUTDOWN || device->state == ST_BROKEN || device->state == ST_DISCONNECTED) { - - if(bForceReconnect) { +bool ofxEtherdream::checkConnection(bool bForceReconnect) +{ + if (device->state == ST_SHUTDOWN || device->state == ST_BROKEN || device->state == ST_DISCONNECTED) + { + + if (bForceReconnect) + { kill(); setup(true, idEtherdreamConnection); } - + return false; } return true; } //-------------------------------------------------------------- -void ofxEtherdream::init() { +void ofxEtherdream::init() +{ int device_num = etherdream_dac_count(); - if (!device_num || idEtherdreamConnection>device_num) { - ofLogWarning() << "ofxEtherdream::init - No DACs found"; - return; - } - - for (int i=0; i device_num) + { + ofLogWarning() << "ofxEtherdream::init - No DACs found"; + return; } - + + for (int i = 0; i < device_num; i++) + { + ofLogNotice() << "ofxEtherdream::init - " << i << " Ether Dream " << etherdream_get_id(etherdream_get(i)); + } + device = etherdream_get(idEtherdreamConnection); - + ofLogNotice() << "ofxEtherdream::init - Connecting..."; - if (etherdream_connect(device) < 0) return; + if (etherdream_connect(device) < 0) + return; ofLogNotice() << "ofxEtherdream::init - done"; - + state = ETHERDREAM_FOUND; } //-------------------------------------------------------------- -void ofxEtherdream::threadedFunction() { - while (isThreadRunning() != 0) { - - switch (state) { - case ETHERDREAM_NOTFOUND: - if(bAutoConnect) init(); - break; - - case ETHERDREAM_FOUND: - if(lock()) { - send(); - unlock(); - } - break; +void ofxEtherdream::threadedFunction() +{ + while (isThreadRunning() != 0) + { + + switch (state) + { + case ETHERDREAM_NOTFOUND: + if (bAutoConnect) + init(); + break; + + case ETHERDREAM_FOUND: + if (lock()) + { + send(); + unlock(); + } + break; } } } //-------------------------------------------------------------- -void ofxEtherdream::start() { - startThread(); // TODO: blocking or nonblocking? +void ofxEtherdream::start() +{ + startThread(); // TODO: blocking or nonblocking? } //-------------------------------------------------------------- -void ofxEtherdream::stop() { +void ofxEtherdream::stop() +{ stopThread(); } //-------------------------------------------------------------- -void ofxEtherdream::send() { - if(!stateIsFound() || points.empty()) return; - - if(bWaitBeforeSend) etherdream_wait_for_ready(device); - else if(!etherdream_is_ready(device)) return; - +void ofxEtherdream::send() +{ + if (!stateIsFound() || points.empty()) + return; + + if (bWaitBeforeSend) + etherdream_wait_for_ready(device); + else if (!etherdream_is_ready(device)) + return; + // DODGY HACK: casting ofxIlda::Point* to etherdream_point* - int res = etherdream_write(device, (etherdream_point*)points.data(), points.size(), pps, 1); - if (res != 0) { + int res = etherdream_write(device, (etherdream_point *)points.data(), points.size(), pps, 1); + if (res != 0) + { ofLogVerbose() << "ofxEtherdream::write " << res; } points.clear(); } - //-------------------------------------------------------------- -void ofxEtherdream::clear() { - if(lock()) { +void ofxEtherdream::clear() +{ + if (lock()) + { points.clear(); unlock(); } } //-------------------------------------------------------------- -void ofxEtherdream::addPoints(const vector& _points) { - if(lock()) { - if(!_points.empty()) { +void ofxEtherdream::addPoints(const vector &_points) +{ + if (lock()) + { + if (!_points.empty()) + { points.insert(points.end(), _points.begin(), _points.end()); } unlock(); } } - //-------------------------------------------------------------- -void ofxEtherdream::addPoints(const ofxIlda::Frame &ildaFrame) { +void ofxEtherdream::addPoints(const ofxIlda::Frame &ildaFrame) +{ addPoints(ildaFrame.getPoints()); } - //-------------------------------------------------------------- -void ofxEtherdream::setPoints(const vector& _points) { - if(lock()) { +void ofxEtherdream::setPoints(const vector &_points) +{ + if (lock()) + { points = _points; unlock(); } } - //-------------------------------------------------------------- -void ofxEtherdream::setPoints(const ofxIlda::Frame &ildaFrame) { +void ofxEtherdream::setPoints(const ofxIlda::Frame &ildaFrame) +{ setPoints(ildaFrame.getPoints()); } //-------------------------------------------------------------- -void ofxEtherdream::setWaitBeforeSend(bool b) { - if(lock()) { +void ofxEtherdream::setWaitBeforeSend(bool b) +{ + if (lock()) + { bWaitBeforeSend = b; unlock(); } } //-------------------------------------------------------------- -bool ofxEtherdream::getWaitBeforeSend() const { +bool ofxEtherdream::getWaitBeforeSend() const +{ return bWaitBeforeSend; } - //-------------------------------------------------------------- -void ofxEtherdream::setPPS(int i) { - if(lock()) { +void ofxEtherdream::setPPS(int i) +{ + if (lock()) + { pps = i; unlock(); } } //-------------------------------------------------------------- -int ofxEtherdream::getPPS() const { +int ofxEtherdream::getPPS() const +{ return pps; }