int buffer_gethdr(int server, mxArray *plhs[], const mxArray *prhs[]) { int verbose = 0; int result = 0; message_t *request = NULL; message_t *response = NULL; /* this is for the Matlab specific output */ const char *field_names[NUMBER_OF_FIELDS] = {"nchans", "nsamples", "nevents", "fsample", "data_type", "bufsize"}; /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->command = GET_HDR; request->def->bufsize = 0; if (verbose) print_request(request->def); result = clientrequest(server, request, &response); if (result == 0) { if (verbose) print_response(response->def); if (response->def->command==GET_OK) { headerdef_t *headerdef = (headerdef_t *) response->buf; if (verbose) print_headerdef(headerdef); plhs[0] = mxCreateStructMatrix(1, 1, NUMBER_OF_FIELDS, field_names); mxSetFieldByNumber(plhs[0], 0, 0, mxCreateDoubleScalar((double)(headerdef->nchans))); mxSetFieldByNumber(plhs[0], 0, 1, mxCreateDoubleScalar((double)(headerdef->nsamples))); mxSetFieldByNumber(plhs[0], 0, 2, mxCreateDoubleScalar((double)(headerdef->nevents))); mxSetFieldByNumber(plhs[0], 0, 3, mxCreateDoubleScalar((double)(headerdef->fsample))); mxSetFieldByNumber(plhs[0], 0, 4, mxCreateDoubleScalar((double)(headerdef->data_type))); mxSetFieldByNumber(plhs[0], 0, 5, mxCreateDoubleScalar((double)(headerdef->bufsize))); addChunksToMatrix(plhs[0], (const char *) response->buf + sizeof(headerdef_t), headerdef->bufsize, headerdef->nchans); } else { result = response->def->command; } } if (response) { FREE(response->def); FREE(response->buf); FREE(response); } if (request) { FREE(request->def); FREE(request->buf); FREE(request); } return result; }
void buffer_flushdat(char *hostname, int port, mxArray *plhs[], const mxArray *prhs[]) { int server; int verbose = 0; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->command = FLUSH_DAT; request->def->bufsize = 0; /* open the TCP socket */ if ((server = open_connection(hostname, port)) < 0) { mexErrMsgTxt("ERROR: failed to create socket\n"); } if (verbose) print_request(request->def); clientrequest(server, request, &response); if (verbose) print_response(response->def); close_connection(server); if (response->def->command!=FLUSH_OK) { mexErrMsgTxt("ERROR: the buffer returned an error\n"); } if (request) { FREE(request->def); FREE(request->buf); FREE(request); } if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return; }
int buffer_flushevt(int server, mxArray *plhs[], const mxArray *prhs[]) { int verbose = 0; int result; message_t *request = NULL; message_t *response = NULL; /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->command = FLUSH_EVT; request->def->bufsize = 0; if (verbose) print_request(request->def); result = clientrequest(server, request, &response); if (verbose) print_response(response->def); if (result == 0) { if (response->def->command!=FLUSH_OK) { result = response->def->command; } } if (request) { FREE(request->def); FREE(request->buf); FREE(request); } if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return result; }
/** Wait for new samples/events in the FieldTrip buffer @param ft_buffer FieldTrip connection @param current Previous (already handled!) number of samples/events (must not be NULL!) @param result Current number of samples/events (must not be NULL!) @param ms Timeout in milliseconds @return 0 on success, -1 on error */ int rda_aux_wait_dat(int ft_buffer, const samples_events_t *previous, samples_events_t *result, int ms) { int r; message_t req, *resp = NULL; messagedef_t msg_def; waitdef_t wait_def; wait_def.threshold = *previous; wait_def.milliseconds = ms; req.def = &msg_def; req.buf = &wait_def; msg_def.version = VERSION; msg_def.command = WAIT_DAT; msg_def.bufsize = sizeof(waitdef_t); r = clientrequest(ft_buffer, &req, &resp); if (r<0) { *result = *previous; return r; } if (resp == NULL || resp->def == NULL || resp->buf == NULL || resp->def->command != WAIT_OK || resp->def->bufsize != sizeof(samples_events_t)) { printf("Bad response from WAIT_DAT call\n"); r = -1; *result = *previous; goto cleanup; } memcpy(result, resp->buf, sizeof(samples_events_t)); cleanup: if (resp) { if (resp->buf) free(resp->buf); if (resp->def) free(resp->def); free(resp); } return r; }
int send_header_to_FT() { int c, namelen = 0, status = 0; char *namevec = NULL, *name; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; ft_chunk_t *chunk = NULL; // collect the channel names /* for (c = 0; c < nchan; c++) { name = ch_info[c]->ch_name; printf("Found channel name '%s'\n", name); namevec = realloc(namevec, namelen + strlen(name) + 1); strcpy(namevec + namelen, name); namelen = namelen + strlen(name) + 1; } chunk = malloc(sizeof(ft_chunk_t)); chunk->def.type = FT_CHUNK_CHANNEL_NAMES; chunk->def.size = namelen; memcpy(chunk->data, namevec, namelen); */ // allocate the elements that will be used in the communication request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->buf = NULL; dacq_log("Creating a header for %d channels and sampling rate of %g Hz\n", nchan, sfreq); header->def->nchans = nchan; header->def->nsamples = 0; header->def->nevents = 0; header->def->fsample = sfreq; header->def->data_type = DATATYPE_FLOAT32; header->def->bufsize = 0; FREE(header->buf); // initialization phase, send the header request->def->command = PUT_HDR; request->def->bufsize = append(&request->buf, request->def->bufsize, header->def, sizeof(headerdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, header->buf, header->def->bufsize); status = clientrequest(fieldtrip_sock, request, &response); if (status) { dacq_log("Something wrong with FieldTrip buffer during initialization, status %d. Quiting.\n", status); clean_up(); exit(1); } // How to send the channel name "chunk"? dacq_log("Header sent\n"); // FIXME do someting with the response, i.e. check that it is OK FREE(request); FREE(response); FREE(namevec); FREE(chunk); return(0); }
int send_header_to_FT() { int c, namelen = 0, status = 0; char *namevec = NULL, *name; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; ft_chunk_t *chunk = NULL; dacq_log("Creating a header: %d channels, sampling rate %g Hz\n", nchan, sfreq); // Construct the channel name chunk for (c = 0; c < nchan; c++) { name = ch_info[c]->ch_name; namevec = realloc(namevec, namelen + strlen(name) + 1); strcpy(namevec + namelen, name); namelen = namelen + strlen(name) + 1; } chunk = malloc(sizeof(ft_chunkdef_t) + namelen * sizeof(char)); chunk->def.type = FT_CHUNK_CHANNEL_NAMES; chunk->def.size = namelen; memcpy(chunk->data, namevec, namelen); // I don't like this kind of assumptions on how structures are laid out in memory FREE(namevec); // Construct the header with the channel name chunk header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->def->nchans = nchan; header->def->nsamples = 0; header->def->nevents = 0; header->def->fsample = sfreq; header->def->data_type = DATATYPE_FLOAT32; header->def->bufsize = sizeof(ft_chunkdef_t) + namelen * sizeof(char); header->buf = chunk; // Construct the message with the header request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; request->def->command = PUT_HDR; request->def->bufsize = append(&request->buf, request->def->bufsize, header->def, sizeof(headerdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, header->buf, header->def->bufsize); // Send the message to the buffer status = clientrequest(fieldtrip_sock, request, &response); if (status) { dacq_log("Something wrong with FieldTrip buffer during initialization, status %d. Exiting.\n", status); clean_up(); exit(1); } dacq_log("Header sent to the FieldTrip buffer\n"); // FIXME: Do someting with the response, i.e. check that it is OK FREE(request->def); FREE(request); FREE(header->def); FREE(header); FREE(chunk); FREE(response->def); FREE(response); return(0); }
void handleStartPacket(int ftSocket, int size, void *buf) { rda_msg_start_t *header = (rda_msg_start_t *) buf; double *dRes = (double *) ((char *) buf + sizeof(rda_msg_start_t)); char *nameStart; int sizeNames; printf("\nRDA start packet (%i bytes) -- %i channels, Ts=%.1fus\n\n", size, header->nChannels, header->dSamplingInterval); numChannels = header->nChannels; goodToSend = 0; if (numChannels > 0) { int i; char *name = (char *) buf + sizeof(rda_msg_start_t) + numChannels*sizeof(double); nameStart = name; printf("Channel Resolution Name\n"); for (i=0;i<numChannels;i++) { int maxLen = size - (name - (char *) buf); int len = strnlen(name, maxLen); if (len>=maxLen) { fprintf(stderr, "Invalid START packet received (unterminated channel names) -- ignoring.\n"); return; } if (i<MAX_PRINT_CHN) { printf("%5i %10.3f '%s'\n", i, dRes[i], name); } name+=len+1; } sizeNames = name - nameStart; if (numChannels > MAX_PRINT_CHN) { printf("Suppressed output of further %i channels\n", numChannels - MAX_PRINT_CHN); } } else { fprintf(stderr, "Invalid START packet received -- channel number = %i\n", numChannels); return; } if (ftSocket != -1) { message_t request, *response; messagedef_t msgdef; char *msgbuf; headerdef_t *hdr; ft_chunk_t *chunk; int res; int sizeChunks = 2*sizeof(ft_chunkdef_t) + sizeNames + numChannels*sizeof(double); int sizeAll = sizeof(headerdef_t) + sizeChunks; msgbuf = (char *) malloc(sizeAll); hdr = (headerdef_t *) msgbuf; if (hdr == NULL) { fprintf(stderr, "Out of memory -- not sending header\n"); return; } request.def = &msgdef; request.buf = msgbuf; msgdef.version = VERSION; msgdef.command = PUT_HDR; msgdef.bufsize = sizeAll; hdr->nchans = numChannels; hdr->nsamples = 0; hdr->nevents = 0; hdr->fsample = 1.0e6/header->dSamplingInterval; hdr->data_type = DATATYPE_FLOAT32; hdr->bufsize = sizeChunks; chunk = (ft_chunk_t *) (msgbuf + sizeof(headerdef_t)); chunk->def.type = FT_CHUNK_CHANNEL_NAMES; chunk->def.size = sizeNames; memcpy(chunk->data, nameStart, sizeNames); chunk = (ft_chunk_t *) (msgbuf + sizeof(headerdef_t) + sizeof(ft_chunkdef_t) + sizeNames); chunk->def.type = FT_CHUNK_RESOLUTIONS; chunk->def.size = numChannels*sizeof(double); memcpy(chunk->data, (char *) buf + sizeof(rda_msg_start_t), numChannels*sizeof(double)); res = clientrequest(ftSocket, &request, &response); if (res == 0) { if (response->def->command == PUT_OK) { goodToSend = 1; samplesWritten = 0; } free(response->def); if (response->buf) free(response->buf); free(response); } } }
void handleDataPacket(int ftSocket, int size, void *buf) { rda_msg_data_t *header = (rda_msg_data_t *) buf; int isInt, sizeData; message_t request, *response; messagedef_t reqdef; request.def = &reqdef; isInt = (header->hdr.nType == RDA_INT_MSG) ? 1 : 0; sizeData = (isInt ? sizeof(INT16_T) : sizeof(float)) * header->nPoints * numChannels; printf("RDA data block %4i (%i bytes): %4i samples, %2i markers\n", header->nBlock, header->hdr.nSize, header->nPoints, header->nMarkers); if (header->nMarkers > 0) { char *evbuf; /* offset of markers into RDA packet */ int offset = sizeof(rda_msg_data_t) + sizeData; /* maximum length of all the "type" strings combined (actually a bit more because of trailing zeros) */ int maxSizeTypes = size - offset - sizeof(rda_marker_t)*header->nMarkers; /* offset + size of events in evbuf */ int evsiz = 0; evbuf = (char *) malloc(header->nMarkers*(sizeof(eventdef_t) + sizeof(INT32_T)) + maxSizeTypes); if (evbuf == NULL) { fprintf(stderr, "Out of memory\n"); return; } while (offset + sizeof(rda_marker_t) <= size) { rda_marker_t *marker = (rda_marker_t *) ((char *) buf + offset); char *markerType = (char *) buf + offset + sizeof(rda_marker_t); int maxLen = size - (markerType - (char *) buf); int typeLen = strnlen(markerType, maxLen); eventdef_t *evdef; printf("Marker: Pos=%i Length=%i Channel=%i Type=%.*s\n", marker->nPosition, marker->nPoints, marker->nChannel, maxLen, markerType); offset+=marker->nSize; evdef = (eventdef_t *) evbuf + evsiz; evdef->type_type = DATATYPE_CHAR; evdef->type_numel = typeLen; evdef->value_type = DATATYPE_INT32; evdef->value_numel = 1; evdef->sample = samplesWritten + marker->nPosition; evdef->offset = 0; evdef->duration = marker->nPoints; evdef->bufsize = typeLen + sizeof(INT32_T); memcpy(evbuf + evsiz + sizeof(eventdef_t), markerType, typeLen); *((INT32_T *) (evbuf + evsiz + sizeof(eventdef_t) + typeLen)) = marker->nChannel; evsiz += evdef->bufsize + sizeof(eventdef_t); } reqdef.version = VERSION; reqdef.command = PUT_EVT; reqdef.bufsize = evsiz; request.buf = evbuf; if (clientrequest(ftSocket, &request, &response)) { fprintf(stderr, "Error when writing events to buffer.\n"); } else { if (response->def->command != PUT_OK) { fprintf(stderr, "Buffer server returned an error (writing events).\n"); } free(response->def); if (response->buf) free(response->buf); free(response); } free(evbuf); } if (goodToSend && header->nPoints > 0) { /* Write samples to FieldTrip buffer */ datadef_t *ddef = (datadef_t *) malloc(sizeof(datadef_t) + sizeData); if (ddef == NULL) { fprintf(stderr, "Out of memory!\n"); return; } ddef->nsamples = header->nPoints; ddef->nchans = numChannels; ddef->data_type = isInt ? DATATYPE_INT16 : DATATYPE_FLOAT32; ddef->bufsize = sizeData; /* ddef+1 points at first byte after datadef, header+1 points at first byte after RDA header */ memcpy(ddef + 1, header + 1, sizeData); reqdef.version = VERSION; reqdef.command = PUT_DAT; reqdef.bufsize = sizeof(datadef_t) + sizeData; request.buf = ddef; if (clientrequest(ftSocket, &request, &response)) { fprintf(stderr, "Error when writing samples to buffer.\n"); } else { if (response->def->command != PUT_OK) { fprintf(stderr, "Buffer server returned an error (writing samples).\n"); } else { samplesWritten += header->nPoints; } free(response->def); if (response->buf) free(response->buf); free(response); } free(ddef); } }
void buffer_putevt(char *hostname, int port, mxArray * plhs[], const mxArray * prhs[]) { size_t n; int server, fieldnumber; mxArray *field; char msg[512]; message_t *request = NULL; message_t *response = NULL; event_t *event = NULL; /* allocate the event */ event = malloc(sizeof(event_t)); event->def = malloc(sizeof(eventdef_t)); event->buf = NULL; event->def->bufsize = 0; /* allocate the request message */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->command = PUT_EVT; request->def->bufsize = 0; /* define the event, it has the fields type_type type_numel value_type value_numel sample offset duration */ /* FIXME loop over mutiple events in case of an event-array */ fieldnumber = mxGetFieldNumber(prhs[0], "type_type"); if (fieldnumber<0) { mexErrMsgTxt("field 'type_type' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'type_type'"); goto cleanup; } else event->def->type_type = (UINT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "type_numel"); if (fieldnumber<0) { mexErrMsgTxt("field 'type_numel' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'type_numel'"); goto cleanup; } else event->def->type_numel = (UINT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "value_type"); if (fieldnumber<0) { mexErrMsgTxt("field 'value_type' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'value_type'"); goto cleanup; } else event->def->value_type = (UINT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "value_numel"); if (fieldnumber<0) { mexErrMsgTxt("field 'value_numel' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'value_numel'"); goto cleanup; } else event->def->value_numel = (UINT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "sample"); if (fieldnumber<0) { mexErrMsgTxt("field 'sample' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'sample'"); goto cleanup; } else event->def->sample = (INT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "offset"); if (fieldnumber<0) { mexErrMsgTxt("field 'offset' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'offset'"); goto cleanup; } else event->def->offset = (INT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "duration"); if (fieldnumber<0) { mexErrMsgTxt("field 'duration' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'duration'"); goto cleanup; } else event->def->duration = (INT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "bufsize"); if (fieldnumber<0) { mexErrMsgTxt("field 'bufsize' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) { mexErrMsgTxt("invalid data type for 'bufsize'"); goto cleanup; } else event->def->bufsize = (INT32_T)mxGetScalar(field) ; } fieldnumber = mxGetFieldNumber(prhs[0], "buf"); if (fieldnumber<0) { mexErrMsgTxt("field 'buf' is missing"); goto cleanup; } else { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsUint8(field)) { mexErrMsgTxt("invalid data type for 'buf'"); goto cleanup; } else if (mxGetNumberOfElements(field) != event->def->bufsize ) { mexErrMsgTxt("invalid number of elements (buf)"); goto cleanup; } else { /* FIXME check the allocation */ event->buf = malloc(event->def->bufsize); memcpy(event->buf, mxGetPr(field), event->def->bufsize); } } /* construct a PUT_EVT request */ request->def->bufsize = append(&request->buf, request->def->bufsize, event->def, sizeof(eventdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, event->buf, event->def->bufsize); /* the event structure is not needed any more */ FREE(event->def); FREE(event->buf); FREE(event); /* open the TCP socket */ if ((server = open_connection(hostname, port)) < 0) { sprintf(msg, "ERROR: failed to create socket (%d)\n", server); mexErrMsgTxt(msg); } /* write the request, read the response */ clientrequest(server, request, &response); close_connection(server); /* the request structure is not needed any more */ if (request) { FREE(request->def); FREE(request->buf); FREE(request); } /* check that the response is PUT_OK */ if (!response) mexErrMsgTxt("unknown error in response\n"); else if (!response->def) mexErrMsgTxt("unknown error in response\n"); else if (response->def->command!=PUT_OK) { sprintf(msg, "ERROR: the buffer returned an error (%d)\n", response->def->command); mexErrMsgTxt(msg); } /* the response structure is not needed any more */ if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return; cleanup: FREE(event->def); FREE(event->buf); FREE(event); if (request) { FREE(request->def); FREE(request->buf); FREE(request); } if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return; }
int main(int argc, char *argv[]) { struct sockaddr_in si_me, si_other; socklen_t slen = sizeof(struct sockaddr_in); int udpsocket, n; char buf[BUFLEN]; struct { uint16_t version; uint16_t nchans; uint16_t nbit; uint16_t fsample; uint16_t sec; uint16_t smp; } packet_v0; struct { uint8_t version; uint8_t nchans; uint16_t diagnostic_word; uint16_t mode_word; uint16_t fsample; uint32_t smp; } packet_v3; /* this is the common denominator of packet format v0 and v3 */ struct { uint16_t version; uint16_t nchans; uint16_t nbit; uint16_t fsample; uint32_t smp; } packet; int sample = 0, status = 0, verbose = 0; host_t host; /* these represent the acquisition system properties */ int nchans = 16; /* will be updated later on */ int fsample = 1000; /* will be updated later on */ int nbit = 16; int blocksize = 43; /* these are used in the communication with the FT buffer and represent statefull information */ int ftSocket = -1; ft_buffer_server_t *ftServer; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; data_t *data = NULL; printf(usage); if (argc>1) strcpy(host.name, argv[1]); else { strcpy(host.name, FTHOST); } if (argc>2) host.port = atoi(argv[2]); else { host.port = FTPORT; } fprintf(stderr, "jaga2ft: hostname = %s\n", host.name); fprintf(stderr, "jaga2ft: port = %d\n", host.port); /* Spawn tcpserver or connect to remote buffer */ if (strcmp(host.name, "-") == 0) { ftServer = ft_start_buffer_server(host.port, NULL, NULL, NULL); if (ftServer==NULL) { fprintf(stderr, "jaga2ft: could not start up a local buffer serving at port %i\n", host.port); return 1; } ftSocket = 0; printf("jaga2ft: streaming to local buffer on port %i\n", host.port); } else { ftSocket = open_connection(host.name, host.port); if (ftSocket < 0) { fprintf(stderr, "jaga2ft: could not connect to remote buffer at %s:%i\n", host.name, host.port); return 1; } printf("jaga2ft: streaming to remote buffer at %s:%i\n", host.name, host.port); } /* open the UDP server */ if ((udpsocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) diep("socket udp"); int enable = 1; if (setsockopt(udpsocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) diep("setsockopt"); memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(JAGAPORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(udpsocket, &si_me, sizeof(si_me))==-1) diep("bind udp"); /* allocate the elements that will be used in the communication to the FT buffer */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->buf = NULL; data = malloc(sizeof(data_t)); data->def = malloc(sizeof(datadef_t)); data->buf = NULL; /* read the first packet to get some information */ if ((n=recvfrom(udpsocket, buf, BUFLEN, 0, &si_other, &slen))==-1) diep("recvfrom()"); if (verbose>0) printf("jaga2ft: received %d byte packet from %s:%d\n", n, inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port)); /* parse the UDP package */ if (buf[0]==0) { packet_v0.version = *(uint16_t *)(buf+0); packet_v0.nchans = *(uint16_t *)(buf+2); packet_v0.nbit = *(uint16_t *)(buf+4); packet_v0.fsample = *(uint16_t *)(buf+6); packet_v0.sec = *(uint16_t *)(buf+8); packet_v0.smp = *(uint16_t *)(buf+10); /* the packets are quite similar, the data starts at the same location */ packet.version = packet_v0.version; packet.nchans = packet_v0.nchans; packet.nbit = packet_v0.nbit; packet.fsample = packet_v0.fsample; packet.smp = packet_v0.smp; } else if (buf[0]==3) { packet_v3.version = *(uint8_t *)(buf+0); packet_v3.nchans = *(uint8_t *)(buf+1); packet_v3.diagnostic_word = *(uint16_t *)(buf+2); packet_v3.mode_word = *(uint16_t *)(buf+4); packet_v3.fsample = *(uint16_t *)(buf+6); packet_v3.smp = *(uint32_t *)(buf+8); /* the packets are quite similar, the data starts at the same location */ packet.version = packet_v3.version; packet.nchans = packet_v3.nchans; packet.nbit = 16; packet.fsample = packet_v3.fsample; packet.smp = packet_v3.smp; } else { fprintf(stderr, "invalid packet version"); exit(1); } /* update the defaults */ nchans = packet.nchans; fsample = packet.fsample; /* define the header */ header->def->nchans = nchans; header->def->nsamples = 0; header->def->nevents = 0; header->def->fsample = fsample; header->def->data_type = DATATYPE_UINT16; header->def->bufsize = 0; /* define the constant part of the data and allocate space for the variable part */ data->def->nchans = nchans; data->def->nsamples = blocksize; data->def->data_type = DATATYPE_UINT16; data->def->bufsize = WORDSIZE_UINT16*nchans*blocksize; /* initialization phase, send the header */ request->def->command = PUT_HDR; request->def->bufsize = append(&request->buf, request->def->bufsize, header->def, sizeof(headerdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, header->buf, header->def->bufsize); /* this is not needed any more */ cleanup_header(&header); status = clientrequest(ftSocket, request, &response); if (verbose>0) fprintf(stderr, "jaga2ft: clientrequest returned %d\n", status); if (status) { fprintf(stderr, "jaga2ft: could not send request to buffer\n"); exit(1); } if (status || response==NULL || response->def == NULL) { fprintf(stderr, "jaga2ft: err2\n"); exit(1); } cleanup_message(&request); if (response->def->command != PUT_OK) { fprintf(stderr, "jaga2ft: error in 'put header' request.\n"); exit(1); } cleanup_message(&response); /* register CTRL-C handler */ signal(SIGINT, abortHandler); printf("Starting to listen - press CTRL-C to quit\n"); /* add a small pause between writing header + first data block */ usleep(200000); while (keepRunning) { if (verbose>1) for (n=0; n<12; n++) printf("buf[%2u] = %hhu\n", n, buf[n]); /* parse the UDP package */ if (buf[0]==0) { packet_v0.version = *(uint16_t *)(buf+0); packet_v0.nchans = *(uint16_t *)(buf+2); packet_v0.nbit = *(uint16_t *)(buf+4); packet_v0.fsample = *(uint16_t *)(buf+6); packet_v0.sec = *(uint16_t *)(buf+8); packet_v0.smp = *(uint16_t *)(buf+10); /* the packets are quite similar, the data starts at the same location */ packet.version = packet_v0.version; packet.nchans = packet_v0.nchans; packet.nbit = packet_v0.nbit; packet.fsample = packet_v0.fsample; packet.smp = packet_v0.smp; } else if (buf[0]==3) { packet_v3.version = *(uint8_t *)(buf+0); packet_v3.nchans = *(uint8_t *)(buf+1); packet_v3.diagnostic_word = *(uint16_t *)(buf+2); packet_v3.mode_word = *(uint16_t *)(buf+4); packet_v3.fsample = *(uint16_t *)(buf+6); packet_v3.smp = *(uint32_t *)(buf+8); /* the packets are quite similar, the data starts at the same location */ packet.version = packet_v3.version; packet.nchans = packet_v3.nchans; packet.nbit = 16; packet.fsample = packet_v3.fsample; packet.smp = packet_v3.smp; } else { fprintf(stderr, "invalid packet version"); exit(1); } /* point to the data */ data->buf = (buf+12); /* do some sanity checks */ if (packet.nchans!=nchans) { fprintf(stderr, "jaga2ft: inconsistent number of channels %hu\n", packet.nchans); exit(1); } if (packet.nbit!=nbit) { fprintf(stderr, "jaga2ft: inconsistent number of bits %hu\n", packet.nbit); exit(1); } if (packet.fsample!=fsample) { fprintf(stderr, "jaga2ft: inconsistent sampling rate %hu\n", packet.fsample); exit(1); } /* create the request */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; request->def->command = PUT_DAT; request->def->bufsize = append(&request->buf, request->def->bufsize, data->def, sizeof(datadef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, data->buf, data->def->bufsize); status = clientrequest(ftSocket, request, &response); if (verbose>0) fprintf(stderr, "jaga2ft: clientrequest returned %d\n", status); if (status) { fprintf(stderr, "jaga2ft: err3\n"); exit(1); } if (status) { fprintf(stderr, "jaga2ft: err4\n"); exit(1); } sample += blocksize; printf("jaga2ft: sample count = %i\n", sample); /* FIXME do someting with the response, i.e. check that it is OK */ cleanup_message(&request); if (response == NULL || response->def == NULL || response->def->command!=PUT_OK) { fprintf(stderr, "Error when writing samples.\n"); } cleanup_message(&response); /* read the next packet */ if ((n=recvfrom(udpsocket, buf, BUFLEN, 0, &si_other, &slen))==-1) diep("recvfrom()"); if (verbose>0) printf("jaga2ft: received %d byte packet from %s:%d\n", n, inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port)); } /* while(1) */ data->buf = NULL; /* this is not allocated on the heap but pointing to somewhere on the stack */ cleanup_data(&data); close(udpsocket); if (ftSocket > 0) { close_connection(ftSocket); } else { ft_stop_buffer_server(ftServer); } return 0; }
void buffer_getdat(char *hostname, int port, mxArray *plhs[], const mxArray *prhs[]) { int server; int verbose = 0; size_t n; double *val; char msg[512]; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; data_t *data = NULL; datasel_t datasel; /* this is for the Matlab specific output */ const char *field_names[NUMBER_OF_FIELDS] = {"nchans", "nsamples", "data_type", "bufsize", "buf"}; mxArray *datp; /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->command = GET_DAT; request->def->bufsize = 0; if ((prhs[0]!=NULL) && (mxGetNumberOfElements(prhs[0])==2) && (mxIsDouble(prhs[0])) && (!mxIsComplex(prhs[0]))) { /* fprintf(stderr, "args OK\n"); */ val = (double *)mxGetData(prhs[0]); datasel.begsample = (UINT32_T)(val[0]); datasel.endsample = (UINT32_T)(val[1]); if (verbose) print_datasel(&datasel); request->def->bufsize = append(&request->buf, request->def->bufsize, &datasel, sizeof(datasel_t)); } /* open the TCP socket */ if ((server = open_connection(hostname, port)) < 0) { sprintf(msg, "ERROR: failed to create socket (%d)\n", server); mexErrMsgTxt(msg); } if (verbose) print_request(request->def); clientrequest(server, request, &response); if (verbose) print_response(response->def); close_connection(server); if (response->def->command==GET_OK) { data = malloc(sizeof(data_t)); data->def = response->buf; data->buf = (char *)response->buf + sizeof(datadef_t); if (verbose) print_datadef(data->def); switch (data->def->data_type) { case DATATYPE_INT8: datp = mxCreateNumericMatrix(data->def->nchans, data->def->nsamples, mxINT8_CLASS, mxREAL); memcpy(mxGetPr(datp), data->buf, data->def->nchans*data->def->nsamples*WORDSIZE_INT8); break; case DATATYPE_INT16: datp = mxCreateNumericMatrix(data->def->nchans, data->def->nsamples, mxINT16_CLASS, mxREAL); memcpy(mxGetPr(datp), data->buf, data->def->nchans*data->def->nsamples*WORDSIZE_INT16); break; case DATATYPE_INT32: datp = mxCreateNumericMatrix(data->def->nchans, data->def->nsamples, mxINT32_CLASS, mxREAL); memcpy(mxGetPr(datp), data->buf, data->def->nchans*data->def->nsamples*WORDSIZE_INT32); break; case DATATYPE_INT64: datp = mxCreateNumericMatrix(data->def->nchans, data->def->nsamples, mxINT64_CLASS, mxREAL); memcpy(mxGetPr(datp), data->buf, data->def->nchans*data->def->nsamples*WORDSIZE_INT64); break; case DATATYPE_FLOAT32: datp = mxCreateNumericMatrix(data->def->nchans, data->def->nsamples, mxSINGLE_CLASS, mxREAL); memcpy(mxGetPr(datp), data->buf, data->def->nchans*data->def->nsamples*WORDSIZE_FLOAT32); break; case DATATYPE_FLOAT64: datp = mxCreateNumericMatrix(data->def->nchans, data->def->nsamples, mxDOUBLE_CLASS, mxREAL); memcpy(mxGetPr(datp), data->buf, data->def->nchans*data->def->nsamples*WORDSIZE_FLOAT64); break; default: mexErrMsgTxt("ERROR; unsupported data type\n"); } plhs[0] = mxCreateStructMatrix(1, 1, NUMBER_OF_FIELDS, field_names); mxSetFieldByNumber(plhs[0], 0, 0, mxCreateDoubleScalar((double)data->def->nchans)); mxSetFieldByNumber(plhs[0], 0, 1, mxCreateDoubleScalar((double)(data->def->nsamples))); mxSetFieldByNumber(plhs[0], 0, 2, mxCreateDoubleScalar((double)(data->def->data_type))); mxSetFieldByNumber(plhs[0], 0, 3, mxCreateDoubleScalar((double)(data->def->bufsize))); mxSetFieldByNumber(plhs[0], 0, 4, datp); FREE(data); } else { sprintf(msg, "ERROR: the buffer returned an error (%d)\n", response->def->command); mexErrMsgTxt(msg); } if (request) { FREE(request->def); FREE(request->buf); FREE(request); } if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return; }
/** Prepares "start" RDA packet with channel names determined from the corresponding chunk (or empty) Also converts to little-endian if this machine is big endian @param hdr Points to headerdef_t structure, will be filled, may not be NULL @return created start item, or NULL on error (connection / out of memory) */ rda_buffer_item_t *rda_aux_get_hdr_prep_start(int ft_buffer, headerdef_t *hdr) { rda_buffer_item_t *item = NULL; const ft_chunk_t *chunk; rda_msg_start_t *R; char *str; double *dRes; const void *dResSource; size_t bytesTotal; int i,r,numExtraZeros,sizeOrgNames; message_t req, *resp = NULL; messagedef_t msg_def; req.def = &msg_def; req.buf = NULL; msg_def.version = VERSION; msg_def.command = GET_HDR; msg_def.bufsize = 0; r = clientrequest(ft_buffer, &req, &resp); if (r<0 || resp == NULL || resp->def == NULL) { goto cleanup; } if (resp->def->command != GET_OK || resp->def->bufsize < sizeof(headerdef_t) || resp->buf == NULL) { goto cleanup; } memcpy(hdr, resp->buf, sizeof(headerdef_t)); /* Ok, we have the basic header, now look for proper FT_CHUNK_RESOLUTIONS */ chunk = find_chunk(resp->buf, sizeof(headerdef_t), resp->def->bufsize, FT_CHUNK_RESOLUTIONS); if (chunk != NULL && chunk->def.size == hdr->nchans*sizeof(double)) { dResSource = chunk->data; /* fine - we just need a memcpy later on */ } else { dResSource = NULL; /* no suitable chunk found - set defaults later on */ } /* Now see if we can find channel names */ chunk = find_chunk(resp->buf, sizeof(headerdef_t), resp->def->bufsize, FT_CHUNK_CHANNEL_NAMES); if (chunk != NULL && chunk->def.size >= hdr->nchans) { /* The chunk seems ok - check whether we really have N (0-terminated) strings */ int k,nz = 0; for (k = 0; k<chunk->def.size && nz<=hdr->nchans; k++) { if (chunk->data[k] == 0) nz++; } /* Okay, either k is at the end and we have nz<=N, or we have reached N=nz before the end of the chunk. In both cases, it's safe to transmit the first 'k' bytes and add (N-nz) trailing zeros */ numExtraZeros = hdr->nchans - nz; sizeOrgNames = k; } else { sizeOrgNames = 0; numExtraZeros = hdr->nchans; } bytesTotal = sizeof(rda_msg_start_t) + hdr->nchans*(sizeof(double)) + sizeOrgNames + numExtraZeros; item = rda_aux_alloc_item(bytesTotal); if (item == NULL) goto cleanup; R = (rda_msg_start_t *) item->data; memcpy(R->hdr.guid, _rda_guid, sizeof(_rda_guid)); R->hdr.nSize = bytesTotal; R->hdr.nType = RDA_START_MSG; R->nChannels = hdr->nchans; R->dSamplingInterval = 1.0e6/(double) hdr->fsample; /* should be in microseconds */ if (_i_am_big_endian_) { /* take care of hdr.nSize, hdr.nType, nChannels */ ft_swap32(3, &(R->hdr.nSize)); ft_swap64(1, &(R->dSamplingInterval)); } /* R+1 points to first byte after header info */ dRes = (double *) ((void *)(R+1)); if (dResSource == NULL) { /* Fill with resolution = 1.0 -- we have nothing better */ for (i=0;i<hdr->nchans;i++) dRes[i]=1.0; } else { memcpy(dRes, dResSource, hdr->nchans * sizeof(double)); } /* swap byte order if necessary */ if (_i_am_big_endian_) { ft_swap64(hdr->nchans, dRes); } /* Let 'str' point to first byte after the resolution values */ str = (char *) ((void *)(dRes + hdr->nchans)); if (sizeOrgNames > 0) { memcpy(str, chunk->data, sizeOrgNames); } for (i=0;i<numExtraZeros;i++) str[sizeOrgNames + i] = 0; /* done */ cleanup: if (resp) { if (resp->def) free(resp->def); if (resp->buf) free(resp->buf); free(resp); } return item; }
/** Retrieves samples and markers and returns them in as a new 'item', or NULL on errors. */ rda_buffer_item_t *rda_aux_get_samples_and_markers(int ft_buffer, const samples_events_t *last, const samples_events_t *cur, int numBlock, int use16bit) { rda_buffer_item_t *item = NULL; int numEvt = 0,numChans = 0,numSmp = 0; message_t req, *respSmp = NULL, *respEvt = NULL; messagedef_t msg_def; datadef_t *ddef; size_t bytesSamples = 0, bytesMarkers = 0; /* First, try to grab the samples */ if (cur->nsamples > last->nsamples) { datasel_t dat_sel; msg_def.version = VERSION; msg_def.command = GET_DAT; msg_def.bufsize = sizeof(dat_sel); dat_sel.begsample = last->nsamples; dat_sel.endsample = cur->nsamples-1; req.def = &msg_def; req.buf = &dat_sel; if (clientrequest(ft_buffer, &req, &respSmp)<0) { goto cleanup; } numSmp = cur->nsamples - last->nsamples; if (respSmp == NULL || respSmp->def == NULL || respSmp->buf == NULL || respSmp->def->command != GET_OK) { goto cleanup; } else { ddef = (datadef_t *) respSmp->buf; if (ddef->nsamples != numSmp) goto cleanup; numChans = ddef->nchans; bytesSamples = (use16bit ? sizeof(INT16_T) : sizeof(float)) * numSmp * numChans; } } /* Now, try to grab the markers */ if (cur->nevents > last->nevents) { eventsel_t evt_sel; int offset = 0; msg_def.version = VERSION; msg_def.command = GET_EVT; msg_def.bufsize = sizeof(evt_sel); evt_sel.begevent = last->nevents; evt_sel.endevent = cur->nevents-1; req.def = &msg_def; req.buf = &evt_sel; if (clientrequest(ft_buffer, &req, &respEvt) < 0) { goto cleanup; } if (respEvt == NULL || respEvt->def == NULL || respEvt->buf == NULL || respEvt->def->command != GET_OK) { goto cleanup; } /* count the number of events, increase bytesTotal as required */ while (offset + sizeof(eventdef_t) <= respEvt->def->bufsize) { eventdef_t *evdef = (eventdef_t *) ((char *)respEvt->buf + offset); offset += sizeof(eventdef_t) + evdef->bufsize; if (evdef->bufsize < evdef->type_numel*wordsize_from_type(evdef->type_type) + evdef->value_numel*wordsize_from_type(evdef->value_type)) { fprintf(stderr,"Invalid event received: Buffer to small for given value/type description\n"); continue; /* Skip to next event */ } bytesMarkers += sizeof(rda_marker_t); if (evdef->type_type == DATATYPE_CHAR) { if (evdef->value_type == DATATYPE_CHAR) { /* Transform into TYPE:VALUE\0 */ bytesMarkers += evdef->type_numel + evdef->value_numel + 2; } else { /* Transform into TYPE:-\0 */ bytesMarkers += evdef->type_numel + 3; } } else { if (evdef->value_type == DATATYPE_CHAR) { /* Transform into FT:VALUE\0 */ bytesMarkers += evdef->value_numel + 4; } else { /* Transform into FT:-\0 */ bytesMarkers += 5; } } numEvt++; } } /* Now, allocate an item with enough space for both samples and markers */ item = rda_aux_alloc_item(sizeof(rda_msg_data_t) + bytesSamples + bytesMarkers); if (item == NULL) { fprintf(stderr, "Out of memory\n"); goto cleanup; } item->blockNumber = numBlock; /* Okay, we've got the samples in respSmp, events in respEvt, and a big enough 'item'. First fill in the header. */ { rda_msg_data_t *R = (rda_msg_data_t *) item->data; memcpy(R->hdr.guid, _rda_guid, sizeof(_rda_guid)); R->hdr.nType = use16bit ? RDA_INT_MSG : RDA_FLOAT_MSG; R->hdr.nSize = item->size; R->nBlock = numBlock; R->nPoints = numSmp; R->nMarkers = numEvt; if (_i_am_big_endian_) { /* take care of hdr.nSize, hdr.nType, nBlocks, nPoints, nMarkers */ ft_swap32(5, &(R->hdr.nSize)); } } /* Now, fill in the samples, possibly using conversion */ if (numSmp > 0) { char *dataDest = ((char *) item->data + sizeof(rda_msg_data_t)); char *dataSrc = ((char *) respSmp->buf + sizeof(datadef_t)); int numTotal = numSmp * numChans; if (use16bit) { if (_i_am_big_endian_) { /* copy + swap the 16 bit samples */ int i; for (i=0;i<numTotal;i++) { dataDest[0] = dataSrc[1]; dataDest[1] = dataSrc[0]; dataDest+=2; dataSrc+=2; } } else { /* just copy the samples */ memcpy(dataDest, dataSrc, bytesSamples); } } else { rda_aux_convert_to_float(numTotal, dataDest, ddef->data_type, dataSrc); if (_i_am_big_endian_) ft_swap32(numTotal, dataDest); } } /* Finally, fill in the events */ if (numEvt>0) { char *ptr = (char *) item->data + sizeof(rda_msg_data_t) + bytesSamples; int offset = 0; /* count the number of events, increase bytesTotal as required */ while (offset + sizeof(eventdef_t) <= respEvt->def->bufsize) { eventdef_t *evdef = (eventdef_t *) ((char *)respEvt->buf + offset); char *evbuf = (char *)respEvt->buf + offset + sizeof(eventdef_t); rda_marker_t *marker = (rda_marker_t *) ptr; int i, markerPos; offset += sizeof(eventdef_t) + evdef->bufsize; if (evdef->bufsize < evdef->type_numel*wordsize_from_type(evdef->type_type) + evdef->value_numel*wordsize_from_type(evdef->value_type)) { continue; /* skip to next event */ } markerPos = evdef->sample - (last->nsamples +1); /* relative to first sample in this block */ marker->nPosition = (markerPos > 0) ? markerPos : 0; /* needs to be unsigned! */ marker->nChannel = -1; /* All channels, FieldTrip doesn't have this*/ marker->nPoints = evdef->duration; ptr += sizeof(rda_marker_t); if (evdef->type_type == DATATYPE_CHAR) { /* copy type */ for (i=0;i<evdef->type_numel;i++) { *ptr++ = *evbuf++; } } else { *ptr++ = 'F'; *ptr++ = 'T'; /* Skip bytes in event->buffer */ evbuf += evdef->type_numel; } *ptr++ = ':'; if (evdef->value_type == DATATYPE_CHAR) { /* copy value */ for (i=0;i<evdef->value_numel;i++) { *ptr++ = *evbuf++; } } else { *ptr++ = '-'; } /* add trailing 0, see how big the complete marker got */ *ptr++ = 0; marker->nSize = (ptr - (char *) marker); if (_i_am_big_endian_) { /* convert the 4 int32's in the marker definition */ ft_swap32(4, (void *) marker); } } } /* Done */ cleanup: if (respSmp) { FREE(respSmp->buf); FREE(respSmp->def); free(respSmp); } if (respEvt) { FREE(respEvt->buf); FREE(respEvt->def); free(respEvt); } return item; }
void *event_thread(void *arg) { long tdif; host_t *host = (host_t *)arg; /* these will be sent as event */ int sample = 0; int value = 0; char *type = "trigger"; /* these are used in the communication and represent statefull information */ int server = -1; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; data_t *data = NULL; event_t *event = NULL; /* these represent the acquisition system properties */ int fsample = 250; int blocksize = 125; /* this is to prevent closing the thread at an unwanted moment and memory from leaking */ int oldcancelstate, oldcanceltype; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldcancelstate); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldcanceltype); pthread_cleanup_push(cleanup_message, request); pthread_cleanup_push(cleanup_message, response); pthread_cleanup_push(cleanup_header, header); pthread_cleanup_push(cleanup_data, data); pthread_cleanup_push(cleanup_event, event); pthread_cleanup_push(cleanup_socket, &server); /* this determines the hostname and port on which the client will write */ if (!arg) exit(1); fprintf(stderr, "event: host.name = %s\n", host->name); fprintf(stderr, "event: host.port = %d\n", host->port); /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->buf = NULL; data = malloc(sizeof(data_t)); data->def = malloc(sizeof(datadef_t)); data->buf = NULL; event = malloc(sizeof(event_t)); event->def = malloc(sizeof(eventdef_t)); event->buf = NULL; while (1) { /* increment the trigger value on each iteration */ value++; sample += blocksize; /* construct the event definition */ event->def->type_type = DATATYPE_CHAR; event->def->type_numel = strlen(type); event->def->value_type = DATATYPE_INT32; event->def->value_numel = 1; event->def->sample = sample; event->def->offset = 0; event->def->duration = 0; event->def->bufsize = 0; /* see below */ event->buf = NULL; /* add the variable information to the event buffer */ event->def->bufsize = append(&event->buf, event->def->bufsize, type, event->def->type_numel); /* type is a char-array */ event->def->bufsize = append(&event->buf, event->def->bufsize, &value, WORDSIZE_INT32); /* value is an integer */ /* construct the request */ request->def->command = PUT_EVT; request->def->bufsize = append(&request->buf, request->def->bufsize, event->def, sizeof(eventdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, event->buf, event->def->bufsize); server = open_connection(host->name, host->port); clientrequest(server, request, &response); if (server>=0) closesocket(server); /* FIXME do someting with the response, i.e. check that it is OK */ request->def->bufsize = 0; FREE(request->buf); event->def->bufsize = 0; FREE(event->buf); if (response) { FREE(response->def); FREE(response->buf); FREE(response); } /* approximate delay in microseconds */ tdif = (long)(blocksize * 1000000 / fsample); usleep(tdif); } /* while(1) */ cleanup: /* from now on it is save to cancel the thread */ pthread_setcancelstate(oldcancelstate, NULL); pthread_setcanceltype(oldcanceltype, NULL); pthread_cleanup_pop(1); /* server */ pthread_cleanup_pop(1); /* event */ pthread_cleanup_pop(1); /* data */ pthread_cleanup_pop(1); /* header */ pthread_cleanup_pop(1); /* response */ pthread_cleanup_pop(1); /* request */ pthread_exit(NULL); return NULL; }
int main(int argc, char *argv[]) { host_t host; /* these variables are for the threading */ int rc; pthread_t tid; /* these variables are for writing the data */ int i, j, k, status = 0, verbose = 0, samplecount = 0; time_t tic, toc; time_t elapsed; /* these represent the acquisition system properties */ int fsample = 512; /* this is just for the header */ int nchans = 32; int nsamples = 64; int stateless = 0; /* boolean */ /* these are used in the communication and represent statefull information */ int server = -1; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; data_t *data = NULL; event_t *event = NULL; /* start with defaults */ sprintf(host.name, DEFAULT_HOSTNAME); host.port = DEFAULT_PORT; if (argc>1) sprintf(host.name, argv[1]); if (argc>2) host.port = atoi(argv[2]); if (argc>3) nchans = atoi(argv[3]); if (argc>4) nsamples = atoi(argv[4]); if (argc>5) stateless = atoi(argv[5]); check_datatypes(); if (verbose>0) fprintf(stderr, "test_benchmark: host.name = %s\n", host.name); if (verbose>0) fprintf(stderr, "test_benchmark: host.port = %d\n", host.port); /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->buf = NULL; data = malloc(sizeof(data_t)); data->def = malloc(sizeof(datadef_t)); data->buf = NULL; event = malloc(sizeof(event_t)); event->def = malloc(sizeof(eventdef_t)); event->buf = NULL; /* define the header */ header->def->nchans = nchans; header->def->nsamples = 0; header->def->nevents = 0; header->def->fsample = fsample; header->def->data_type = DATATYPE_FLOAT32; header->def->bufsize = 0; FREE(header->buf); /* define the constant part of the data and allocate space for the variable part */ data->def->nchans = nchans; data->def->nsamples = nsamples; data->def->data_type = DATATYPE_FLOAT32; data->def->bufsize = WORDSIZE_FLOAT32*nchans*nsamples; FREE(data->buf); data->buf = malloc(WORDSIZE_FLOAT32*nchans*nsamples); /* create the random data */ for (j=0; j<nsamples; j++) for (i=0; i<nchans; i++) ((FLOAT32_T *)(data->buf))[j*nchans+i] = 2.0*((FLOAT32_T)rand())/RAND_MAX - 1.0; /* initialization phase, send the header */ request->def->command = PUT_HDR; request->def->bufsize = append(&request->buf, request->def->bufsize, header->def, sizeof(headerdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, header->buf, header->def->bufsize); server = open_connection(host.name, host.port); status = clientrequest(server, request, &response); if (verbose>0) fprintf(stderr, "test_benchmark: clientrequest returned %d\n", status); if (status) { fprintf(stderr, "random: err1\n"); goto cleanup; } if (stateless) { status = close_connection(server); if (status) { fprintf(stderr, "random: err2\n"); goto cleanup; } } cleanup_message(&request); cleanup_message(&response); request = NULL; response = NULL; tic = time(NULL); while (1) { /* create the request */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; request->def->command = PUT_DAT; request->def->bufsize = append(&request->buf, request->def->bufsize, data->def, sizeof(datadef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, data->buf, data->def->bufsize); if (stateless) server = open_connection(host.name, host.port); status = clientrequest(server, request, &response); if (verbose>0) fprintf(stderr, "random: clientrequest returned %d\n", status); if (status) { fprintf(stderr, "random: err3\n"); goto cleanup; } if (stateless) { status = close_connection(server); if (status) { fprintf(stderr, "random: err4\n"); goto cleanup; } } cleanup_message(&request); cleanup_message(&response); request = NULL; response = NULL; samplecount += nsamples*nchans; toc = time(NULL); elapsed = toc-tic; fprintf(stderr, "samplecount = %d, elapsed = %d, samples/sec = %f\n", samplecount, elapsed, ((float)(samplecount))/((float)elapsed)); } /* while(1) */ cleanup: cleanup_event(&event); cleanup_data(&data); cleanup_header(&header); cleanup_message(&request); cleanup_message(&response); pthread_exit(0); return 0; }
/** Background thread for grabbing setup and data packets from the internal, overallocated ringbuffer. This thread stops automatically if the socket pair is closed in the main thread. */ void *dataToFieldTripThread(void *arg) { ACQ_OverAllocType *pack; EventChain EC; int slot, res, i,j; int numChannels = 0, numSamples; int warningGiven = 0; messagedef_t reqdef; message_t request, *response; EC.evs = NULL; EC.sizeAlloc = 0; request.def = &reqdef; while (1) { res = read(mySockets[1], &slot, sizeof(int)); if (res == 0) break; /* socket pair was closed - exit */ if (res != sizeof(int)) { fprintf(stderr, "Error when reading from socket pair\n"); break; } if (slot<0 || slot>=INT_RB_SIZE) { fprintf(stderr, "Got errorneous slot number from socket pair\n"); break; } pack = &intPackets[slot]; if (pack->message_type == ACQ_MSGQ_SETUP_COLLECTION) { UINT32_T size; headerdef_t *hdef; /* contains header information + chunks !!! */ hdef = handleRes4((const char *) pack->data, &size); /* clear internal ringbuffer slot */ pack->message_type = ACQ_MSGQ_INVALID; if (hdef == NULL) continue; /* problem while picking up header -- ignore this packet */ /* prepare PUT_HDR request here, but only send it along with first data block */ reqdef.version = VERSION; reqdef.command = PUT_HDR; reqdef.bufsize = size; request.buf = hdef; res = clientrequest(ftSocket, &request, &response); if (res < 0) { fprintf(stderr, "Error in FieldTrip connection\n"); } else if (response) { if (response->def->command != PUT_OK) { fprintf(stderr, "Error in PUT_HDR\n"); } else { /* printf("FT: Transmitted header\n"); */ /* set numChannels variable to the value we picked up this also enables transmitting data in following packets */ numChannels = hdef->nchans; warningGiven = 0; } cleanup_message((void **) &response); } free(hdef); } else if (pack->message_type == ACQ_MSGQ_DATA) { datadef_t *ddef; int sampleNumber; if (numChannels == 0) { fprintf(stderr, "No header written yet -- ignoring data packet\n"); pack->message_type = ACQ_MSGQ_INVALID; continue; } if (!warningGiven && pack->numChannels != numChannels) { printf("\nWARNING: Channel count in first data packet does not equal header information from .res4 file (%i channels)\n\n", numChannels); warningGiven = 1; } sampleNumber = pack->sampleNumber; numSamples = pack->numSamples; /* Put the FT datadef at the location of the current ACQ packet definition. This just fits, no memcpy'ing of the samples again... */ ddef = (datadef_t *) &pack->messageId; ddef->nsamples = numSamples; ddef->nchans = numChannels; ddef->data_type = DATATYPE_INT32; ddef->bufsize = sizeof(int) * numSamples * numChannels; reqdef.version = VERSION; reqdef.command = PUT_DAT; reqdef.bufsize = ddef->bufsize + sizeof(datadef_t); request.buf = ddef; /* data is still behind that */ res = clientrequest(ftSocket, &request, &response); if (res < 0) { fprintf(stderr, "Error in FieldTrip connection (writing data)\n"); } else if (response) { if (response->def->command != PUT_OK) { fprintf(stderr, "Error in PUT_DAT\n"); } else { /* printf("FT: Transmitted samples\n"); */ } cleanup_message((void **) &response); } /* look at trigger channels and add events to chain, clear this first */ EC.size = EC.num = 0; for (j=0;j<numSamples;j++) { int *sj = pack->data + j*numChannels; for (i=0;i<numTriggerChannels;i++) { int sji = sj[triggerChannel[i]]; if (sji != lastValue[i] && sji > 0) addTriggerEvent(&EC, i, sampleNumber + j, sji); lastValue[i] = sji; } } if (EC.size > 0) { reqdef.version = VERSION; reqdef.command = PUT_EVT; reqdef.bufsize = EC.size; request.buf = EC.evs; res = clientrequest(ftSocket, &request, &response); if (res < 0) { fprintf(stderr, "Error in FieldTrip connection (writing events)\n"); } else if (response) { if (response->def->command != PUT_OK) { fprintf(stderr, "Error in PUT_EVT\n"); } else { printf("Wrote %i events (%i bytes)\n", EC.num, reqdef.bufsize); /* printf("FT: Transmitted samples\n"); */ } } cleanup_message((void **) &response); } } else { fprintf(stderr,"Converter thread: Packet contains neither SETUP nor DATA (%i)...\n", pack->message_type); } pack->message_type = ACQ_MSGQ_INVALID; } printf("Leaving converter thread...\n"); close(mySockets[1]); if (EC.sizeAlloc > 0) free(EC.evs); return NULL; }
int main(int argc, char *argv[]) { int n, i, c, count = 0, sample = 0, chan = 0, status = 0, verbose = 0, labelSize; unsigned char buf[OPENBCI_BUFLEN], byte; char *labelString; SerialPort SP; host_t host; struct timespec tic, toc; /* these represent the general acquisition system properties */ int nchans = OPENBCI_NCHANS; float fsample = OPENBCI_FSAMPLE; /* these are used in the communication with the FT buffer and represent statefull information */ int ftSocket = -1; ft_buffer_server_t *ftServer; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; data_t *data = NULL; ft_chunkdef_t *label = NULL; /* this contains the configuration details */ configuration config; /* configure the default settings */ config.blocksize = 10; config.port = 1972; config.hostname = strdup("-"); config.serial = strdup("/dev/tty.usbserial-DN0094FY"); config.reset = strdup("on"); config.datalog = strdup("off"); config.testsignal = strdup("off"); config.timestamp = strdup("on"); config.timeref = strdup("start"); config.enable_chan1 = strdup("on"); config.enable_chan2 = strdup("on"); config.enable_chan3 = strdup("on"); config.enable_chan4 = strdup("on"); config.enable_chan5 = strdup("on"); config.enable_chan6 = strdup("on"); config.enable_chan7 = strdup("on"); config.enable_chan8 = strdup("on"); config.enable_chan9 = strdup("on"); config.enable_chan10 = strdup("on"); config.enable_chan11 = strdup("on"); config.label_chan1 = strdup("ADC1"); config.label_chan2 = strdup("ADC2"); config.label_chan3 = strdup("ADC3"); config.label_chan4 = strdup("ADC4"); config.label_chan5 = strdup("ADC5"); config.label_chan6 = strdup("ADC6"); config.label_chan7 = strdup("ADC7"); config.label_chan8 = strdup("ADC8"); config.label_chan9 = strdup("AccelerationX"); config.label_chan10 = strdup("AccelerationY"); config.label_chan11 = strdup("AccelerationZ"); config.label_chan12 = strdup("TimeStamp"); config.setting_chan1 = strdup("x1060110X"); config.setting_chan2 = strdup("x2060110X"); config.setting_chan3 = strdup("x3060110X"); config.setting_chan4 = strdup("x4060110X"); config.setting_chan5 = strdup("x5060110X"); config.setting_chan6 = strdup("x6060110X"); config.setting_chan7 = strdup("x7060110X"); config.setting_chan8 = strdup("x8060110X"); config.impedance_chan1 = strdup("z100Z"); config.impedance_chan2 = strdup("z200Z"); config.impedance_chan3 = strdup("z300Z"); config.impedance_chan4 = strdup("z400Z"); config.impedance_chan5 = strdup("z500Z"); config.impedance_chan6 = strdup("z600Z"); config.impedance_chan7 = strdup("z700Z"); config.impedance_chan8 = strdup("z800Z"); if (argc<2) { printf(usage); exit(0); } if (argc==2) { if (strncmp(argv[1], "/dev", 4)==0 || strncasecmp(argv[1], "COM", 3)==0) /* the second argument is the serial port */ config.serial = strdup(argv[1]); else { /* the second argument is the configuration file */ fprintf(stderr, "openbci2ft: loading configuration from '%s'\n", argv[1]); if (ini_parse(argv[1], iniHandler, &config) < 0) { fprintf(stderr, "Can't load '%s'\n", argv[1]); return 1; } } } if (argc>2) strcpy(host.name, argv[2]); else { strcpy(host.name, config.hostname); } if (argc>3) host.port = atoi(argv[3]); else { host.port = config.port; } #define ISTRUE(s) strcasecmp(s, "on")==0 nchans = 0; if (ISTRUE(config.enable_chan1)) nchans++; if (ISTRUE(config.enable_chan2)) nchans++; if (ISTRUE(config.enable_chan3)) nchans++; if (ISTRUE(config.enable_chan4)) nchans++; if (ISTRUE(config.enable_chan5)) nchans++; if (ISTRUE(config.enable_chan6)) nchans++; if (ISTRUE(config.enable_chan7)) nchans++; if (ISTRUE(config.enable_chan8)) nchans++; if (ISTRUE(config.enable_chan9)) nchans++; if (ISTRUE(config.enable_chan10)) nchans++; if (ISTRUE(config.enable_chan11)) nchans++; if (ISTRUE(config.timestamp)) nchans++; fprintf(stderr, "openbci2ft: serial = %s\n", config.serial); fprintf(stderr, "openbci2ft: hostname = %s\n", host.name); fprintf(stderr, "openbci2ft: port = %d\n", host.port); fprintf(stderr, "openbci2ft: blocksize = %d\n", config.blocksize); fprintf(stderr, "openbci2ft: reset = %s\n", config.reset); fprintf(stderr, "openbci2ft: datalog = %s\n", config.datalog); fprintf(stderr, "openbci2ft: timestamp = %s\n", config.timestamp); fprintf(stderr, "openbci2ft: testsignal = %s\n", config.testsignal); /* Spawn tcpserver or connect to remote buffer */ if (strcmp(host.name, "-") == 0) { ftServer = ft_start_buffer_server(host.port, NULL, NULL, NULL); if (ftServer==NULL) { fprintf(stderr, "openbci2ft: could not start up a local buffer serving at port %i\n", host.port); return 1; } ftSocket = 0; printf("openbci2ft: streaming to local buffer on port %i\n", host.port); } else { ftSocket = open_connection(host.name, host.port); if (ftSocket < 0) { fprintf(stderr, "openbci2ft: could not connect to remote buffer at %s:%i\n", host.name, host.port); return 1; } printf("openbci2ft: streaming to remote buffer at %s:%i\n", host.name, host.port); } /* allocate the elements that will be used in the communication to the FT buffer */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->buf = NULL; data = malloc(sizeof(data_t)); data->def = malloc(sizeof(datadef_t)); data->buf = NULL; /* define the header */ header->def->nchans = nchans; header->def->fsample = fsample; header->def->nsamples = 0; header->def->nevents = 0; header->def->data_type = DATATYPE_FLOAT32; header->def->bufsize = 0; /* FIXME add the channel names */ labelSize = 0; /* count the number of bytes required */ if (ISTRUE (config.enable_chan1)) labelSize += strlen (config.label_chan1) + 1; if (ISTRUE (config.enable_chan2)) labelSize += strlen (config.label_chan2) + 1; if (ISTRUE (config.enable_chan3)) labelSize += strlen (config.label_chan3) + 1; if (ISTRUE (config.enable_chan4)) labelSize += strlen (config.label_chan4) + 1; if (ISTRUE (config.enable_chan5)) labelSize += strlen (config.label_chan5) + 1; if (ISTRUE (config.enable_chan6)) labelSize += strlen (config.label_chan6) + 1; if (ISTRUE (config.enable_chan7)) labelSize += strlen (config.label_chan7) + 1; if (ISTRUE (config.enable_chan8)) labelSize += strlen (config.label_chan8) + 1; if (ISTRUE (config.enable_chan9)) labelSize += strlen (config.label_chan9) + 1; if (ISTRUE (config.enable_chan10)) labelSize += strlen (config.label_chan10) + 1; if (ISTRUE (config.enable_chan11)) labelSize += strlen (config.label_chan11) + 1; if (ISTRUE (config.timestamp)) labelSize += strlen (config.label_chan12) + 1; if (verbose > 0) fprintf (stderr, "openbci2ft: labelSize = %d\n", labelSize); /* go over all channels for a 2nd time, now copying the strings to the destination */ labelString = (char *) malloc (labelSize * sizeof(char)); labelSize = 0; if (ISTRUE (config.enable_chan1)) { strcpy (labelString+labelSize, config.label_chan1); labelSize += strlen (config.label_chan1) + 1; } if (ISTRUE (config.enable_chan2)) { strcpy (labelString+labelSize, config.label_chan2); labelSize += strlen (config.label_chan2) + 1; } if (ISTRUE (config.enable_chan3)) { strcpy (labelString+labelSize, config.label_chan3); labelSize += strlen (config.label_chan3) + 1; } if (ISTRUE (config.enable_chan4)) { strcpy (labelString+labelSize, config.label_chan4); labelSize += strlen (config.label_chan4) + 1; } if (ISTRUE (config.enable_chan5)) { strcpy (labelString+labelSize, config.label_chan5); labelSize += strlen (config.label_chan5) + 1; } if (ISTRUE (config.enable_chan6)) { strcpy (labelString+labelSize, config.label_chan6); labelSize += strlen (config.label_chan6) + 1; } if (ISTRUE (config.enable_chan7)) { strcpy (labelString+labelSize, config.label_chan7); labelSize += strlen (config.label_chan7) + 1; } if (ISTRUE (config.enable_chan8)) { strcpy (labelString+labelSize, config.label_chan8); labelSize += strlen (config.label_chan8) + 1; } if (ISTRUE (config.enable_chan9)) { strcpy (labelString+labelSize, config.label_chan9); labelSize += strlen (config.label_chan9) + 1; } if (ISTRUE (config.enable_chan10)) { strcpy (labelString+labelSize, config.label_chan10); labelSize += strlen (config.label_chan10) + 1; } if (ISTRUE (config.enable_chan11)) { strcpy (labelString+labelSize, config.label_chan11); labelSize += strlen (config.label_chan11) + 1; } if (ISTRUE (config.timestamp)) { strcpy (labelString+labelSize, config.label_chan12); labelSize += strlen (config.label_chan12) + 1; } /* add the channel label chunk to the header */ label = (ft_chunkdef_t *) malloc (sizeof (ft_chunkdef_t)); label->type = FT_CHUNK_CHANNEL_NAMES; label->size = labelSize; header->def->bufsize = append (&header->buf, header->def->bufsize, label, sizeof (ft_chunkdef_t)); header->def->bufsize = append (&header->buf, header->def->bufsize, labelString, labelSize); FREE (label); FREE (labelString); /* define the constant part of the data and allocate space for the variable part */ data->def->nchans = nchans; data->def->nsamples = config.blocksize; data->def->data_type = DATATYPE_FLOAT32; data->def->bufsize = WORDSIZE_FLOAT32 * nchans * config.blocksize; data->buf = malloc (data->def->bufsize); /* initialization phase, send the header */ request->def->command = PUT_HDR; request->def->bufsize = append (&request->buf, request->def->bufsize, header->def, sizeof (headerdef_t)); request->def->bufsize = append (&request->buf, request->def->bufsize, header->buf, header->def->bufsize); /* this is not needed any more */ cleanup_header (&header); status = clientrequest (ftSocket, request, &response); if (verbose > 0) fprintf (stderr, "openbci2ft: clientrequest returned %d\n", status); if (status) { fprintf (stderr, "openbci2ft: could not send request to buffer\n"); exit (1); } if (status || response == NULL || response->def == NULL) { fprintf (stderr, "openbci2ft: error in %s on line %d\n", __FILE__, __LINE__); exit (1); } cleanup_message (&request); if (response->def->command != PUT_OK) { fprintf (stderr, "openbci2ft: error in 'put header' request.\n"); exit (1); } cleanup_message (&response); /* open the serial port */ fprintf (stderr, "openbci2ft: opening serial port ...\n"); if (!serialOpenByName (&SP, config.serial)) { fprintf (stderr, "Could not open serial port %s\n", config.serial); return 1; } if (!serialSetParameters (&SP, 115200, 8, 0, 0, 0)) { fprintf (stderr, "Could not modify serial port parameters\n"); return 1; } fprintf (stderr, "openbci2ft: opening serial port ... ok\n"); /* 8-bit board will always be initialized upon opening serial port, 32-bit board needs explicit initialization */ fprintf (stderr, "openbci2ft: initializing ...\n"); fprintf (stderr, "openbci2ft: press reset on the OpenBCI board if this takes too long\n"); if (ISTRUE (config.reset)) serialWrite (&SP, 1, "v"); /* soft reset, this will return $$$ */ else serialWrite (&SP, 1, "D"); /* query default channel settings, this will also return $$$ */ /* wait for '$$$' which indicates that the OpenBCI has been initialized */ c = 0; while (c != 3) { usleep (1000); n = serialRead (&SP, 1, &byte); if (n == 1) { if (byte == '$') c++; else c = 0; } } /* while waiting for '$$$' */ if (strcasecmp (config.datalog, "14s") == 0) serialWrite (&SP, 1, "a"); else if (strcasecmp (config.datalog, "5min") == 0) serialWrite (&SP, 1, "A"); else if (strcasecmp (config.datalog, "15min") == 0) serialWrite (&SP, 1, "S"); else if (strcasecmp (config.datalog, "30min") == 0) serialWrite (&SP, 1, "F"); else if (strcasecmp (config.datalog, "1hr") == 0) serialWrite (&SP, 1, "G"); else if (strcasecmp (config.datalog, "2hr") == 0) serialWrite (&SP, 1, "H"); else if (strcasecmp (config.datalog, "4hr") == 0) serialWrite (&SP, 1, "J"); else if (strcasecmp (config.datalog, "12hr") == 0) serialWrite (&SP, 1, "K"); else if (strcasecmp (config.datalog, "24hr") == 0) serialWrite (&SP, 1, "L"); else if (strcasecmp (config.datalog, "off") != 0) { fprintf (stderr, "Incorrect specification of datalog\n"); return 1; } serialWriteSlow (&SP, strlen (config.setting_chan1), config.setting_chan1); serialWriteSlow (&SP, strlen (config.setting_chan2), config.setting_chan2); serialWriteSlow (&SP, strlen (config.setting_chan3), config.setting_chan3); serialWriteSlow (&SP, strlen (config.setting_chan4), config.setting_chan4); serialWriteSlow (&SP, strlen (config.setting_chan5), config.setting_chan5); serialWriteSlow (&SP, strlen (config.setting_chan6), config.setting_chan6); serialWriteSlow (&SP, strlen (config.setting_chan7), config.setting_chan7); serialWriteSlow (&SP, strlen (config.setting_chan8), config.setting_chan8); if (strcasecmp (config.testsignal, "gnd") == 0) serialWrite (&SP, 1, "0"); else if (strcasecmp (config.testsignal, "dc") == 0) serialWrite (&SP, 1, "-"); else if (strcasecmp (config.testsignal, "1xSlow") == 0) serialWrite (&SP, 1, "="); else if (strcasecmp (config.testsignal, "1xFast") == 0) serialWrite (&SP, 1, "p"); else if (strcasecmp (config.testsignal, "2xSlow") == 0) serialWrite (&SP, 1, "["); else if (strcasecmp (config.testsignal, "2xFast") == 0) serialWrite (&SP, 1, "]"); else if (strcasecmp (config.testsignal, "off") != 0) { fprintf (stderr, "Incorrect specification of testsignal\n"); return 1; } fprintf (stderr, "openbci2ft: initializing ... ok\n"); printf ("Starting to listen - press CTRL-C to quit\n"); /* register CTRL-C handler */ signal (SIGINT, abortHandler); /* start streaming data */ serialWrite (&SP, 1, "b"); /* determine the reference time for the timestamps */ if (strcasecmp (config.timeref, "start") == 0) { /* since the start of the acquisition */ get_monotonic_time (&tic, TIMESTAMP_REF_BOOT); } else if (strcasecmp (config.timeref, "boot") == 0) { /* since the start of the day */ tic.tv_sec = 0; tic.tv_nsec = 0; } else if (strcasecmp (config.timeref, "epoch") == 0) { /* since the start of the epoch, i.e. 1-1-1970 */ tic.tv_sec = 0; tic.tv_nsec = 0; } else { fprintf (stderr, "Incorrect specification of timeref, should be 'start', 'day' or 'epoch'\n"); return 1; } while (keepRunning) { sample = 0; while (sample < config.blocksize) { /* wait for the first byte of the following packet */ buf[0] = 0; while (buf[0] != 0xA0) { if (serialInputPending (&SP)) n = serialRead (&SP, 1, buf); else usleep (1000); } /* while */ /* * Header * Byte 1: 0xA0 * Byte 2: Sample Number * * EEG Data * Note: values are 24-bit signed, MSB first * Bytes 3-5: Data value for EEG channel 1 * Bytes 6-8: Data value for EEG channel 2 * Bytes 9-11: Data value for EEG channel 3 * Bytes 12-14: Data value for EEG channel 4 * Bytes 15-17: Data value for EEG channel 5 * Bytes 18-20: Data value for EEG channel 6 * Bytes 21-23: Data value for EEG channel 6 * Bytes 24-26: Data value for EEG channel 8 * * Accelerometer Data * Note: values are 16-bit signed, MSB first * Bytes 27-28: Data value for accelerometer channel X * Bytes 29-30: Data value for accelerometer channel Y * Bytes 31-32: Data value for accelerometer channel Z * * Footer * Byte 33: 0xC0 */ /* read the remaining 32 bytes of the packet */ while (n < OPENBCI_BUFLEN) if (serialInputPending (&SP)) n += serialRead (&SP, (OPENBCI_BUFLEN - n), buf + n); else usleep (1000); if (verbose > 1) { for (i = 0; i < OPENBCI_BUFLEN; i++) printf ("%02x ", buf[i]); printf ("\n"); } chan = 0; if (ISTRUE (config.enable_chan1)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[2] << 24 | buf[3] << 16 | buf[4] << 8) / 255; if (ISTRUE (config.enable_chan2)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[5] << 24 | buf[6] << 16 | buf[7] << 8) / 255; if (ISTRUE (config.enable_chan3)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[8] << 24 | buf[9] << 16 | buf[10] << 8) / 255; if (ISTRUE (config.enable_chan4)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[11] << 24 | buf[12] << 16 | buf[13] << 8) / 255; if (ISTRUE (config.enable_chan5)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[14] << 24 | buf[15] << 16 | buf[16] << 8) / 255; if (ISTRUE (config.enable_chan6)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[17] << 24 | buf[18] << 16 | buf[19] << 8) / 255; if (ISTRUE (config.enable_chan7)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[20] << 24 | buf[21] << 16 | buf[22] << 8) / 255; if (ISTRUE (config.enable_chan8)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB1 * (buf[23] << 24 | buf[24] << 16 | buf[25] << 8) / 255; if (ISTRUE (config.enable_chan9)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB2 * (buf[26] << 24 | buf[27] << 16) / 32767; if (ISTRUE (config.enable_chan10)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB2 * (buf[28] << 24 | buf[29] << 16) / 32767; if (ISTRUE (config.enable_chan11)) ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = OPENBCI_CALIB2 * (buf[28] << 24 | buf[31] << 16) / 32767; if (ISTRUE (config.timestamp)) { if (strcasecmp (config.timeref, "start") == 0) get_monotonic_time (&toc, TIMESTAMP_REF_BOOT); else if (strcasecmp (config.timeref, "boot") == 0) get_monotonic_time (&toc, TIMESTAMP_REF_BOOT); else if (strcasecmp (config.timeref, "epoch") == 0) get_monotonic_time (&toc, TIMESTAMP_REF_EPOCH); ((FLOAT32_T *) (data->buf))[nchans * sample + (chan++)] = get_elapsed_time (&tic, &toc); } sample++; } /* while c<config.blocksize */ count += sample; printf ("openbci2ft: sample count = %i\n", count); /* create the request */ request = malloc (sizeof (message_t)); request->def = malloc (sizeof (messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; request->def->command = PUT_DAT; request->def->bufsize = append (&request->buf, request->def->bufsize, data->def, sizeof (datadef_t)); request->def->bufsize = append (&request->buf, request->def->bufsize, data->buf, data->def->bufsize); status = clientrequest (ftSocket, request, &response); if (verbose > 0) fprintf (stderr, "openbci2ft: clientrequest returned %d\n", status); if (status) { fprintf (stderr, "openbci2ft: error in %s on line %d\n", __FILE__, __LINE__); exit (1); } if (status) { fprintf (stderr, "openbci2ft: error in %s on line %d\n", __FILE__, __LINE__); exit (1); } /* FIXME do someting with the response, i.e. check that it is OK */ cleanup_message (&request); if (response == NULL || response->def == NULL || response->def->command != PUT_OK) { fprintf (stderr, "Error when writing samples.\n"); } cleanup_message (&response); } /* while keepRunning */ /* stop streaming data */ serialWrite (&SP, 1, "s"); cleanup_data (&data); if (ftSocket > 0) { close_connection (ftSocket); } else { ft_stop_buffer_server (ftServer); } return 0; } /* main */
int main(int argc, char *argv[]) { int n, i, c, sample = 0, status = 0, verbose = 0; unsigned char buf[BUFLEN], byte; SerialPort SP; host_t host; /* these represent the acquisition system properties */ int nchans = OPENBCI_NCHANS; int blocksize = BLOCKSIZE; float fsample = OPENBCI_FSAMPLE; /* these are used in the communication with the FT buffer and represent statefull information */ int ftSocket = -1; ft_buffer_server_t *ftServer; message_t *request = NULL; message_t *response = NULL; header_t *header = NULL; data_t *data = NULL; if (argc<2) { printf(usage); exit(0); } if (argc>2) strcpy(host.name, argv[2]); else { strcpy(host.name, FTHOST); } if (argc>3) host.port = atoi(argv[3]); else { host.port = FTPORT; } fprintf(stderr, "openbci2ft: device = %s\n", argv[1]); fprintf(stderr, "openbci2ft: hostname = %s\n", host.name); fprintf(stderr, "openbci2ft: port = %d\n", host.port); /* Spawn tcpserver or connect to remote buffer */ if (strcmp(host.name, "-") == 0) { ftServer = ft_start_buffer_server(host.port, NULL, NULL, NULL); if (ftServer==NULL) { fprintf(stderr, "openbci2ft: could not start up a local buffer serving at port %i\n", host.port); return 1; } ftSocket = 0; printf("openbci2ft: streaming to local buffer on port %i\n", host.port); } else { ftSocket = open_connection(host.name, host.port); if (ftSocket < 0) { fprintf(stderr, "openbci2ft: could not connect to remote buffer at %s:%i\n", host.name, host.port); return 1; } printf("openbci2ft: streaming to remote buffer at %s:%i\n", host.name, host.port); } /* allocate the elements that will be used in the communication to the FT buffer */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; header = malloc(sizeof(header_t)); header->def = malloc(sizeof(headerdef_t)); header->buf = NULL; data = malloc(sizeof(data_t)); data->def = malloc(sizeof(datadef_t)); data->buf = NULL; /* define the header */ header->def->nchans = nchans; header->def->fsample = fsample; header->def->nsamples = 0; header->def->nevents = 0; header->def->data_type = DATATYPE_FLOAT32; header->def->bufsize = 0; /* define the constant part of the data and allocate space for the variable part */ data->def->nchans = nchans; data->def->nsamples = blocksize; data->def->data_type = DATATYPE_FLOAT32; data->def->bufsize = WORDSIZE_FLOAT32*nchans*blocksize; data->buf = malloc(data->def->bufsize); /* initialization phase, send the header */ request->def->command = PUT_HDR; request->def->bufsize = append(&request->buf, request->def->bufsize, header->def, sizeof(headerdef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, header->buf, header->def->bufsize); /* this is not needed any more */ cleanup_header(&header); status = clientrequest(ftSocket, request, &response); if (verbose>0) fprintf(stderr, "openbci2ft: clientrequest returned %d\n", status); if (status) { fprintf(stderr, "openbci2ft: could not send request to buffer\n"); exit(1); } if (status || response==NULL || response->def == NULL) { fprintf(stderr, "openbci2ft: error in %s on line %d\n", __FILE__, __LINE__); exit(1); } cleanup_message(&request); if (response->def->command != PUT_OK) { fprintf(stderr, "openbci2ft: error in 'put header' request.\n"); exit(1); } cleanup_message(&response); /* open the serial port */ fprintf(stderr, "openbci2ft: opening serial port ...\n"); if (!serialOpenByName(&SP, argv[1])) { fprintf(stderr, "Could not open serial port %s\n", argv[1]); return 1; } if (!serialSetParameters(&SP, 115200, 8, 0, 0, 0)) { fprintf(stderr, "Could not modify serial port parameters\n"); return 1; } fprintf(stderr, "openbci2ft: opening serial port ... ok\n"); /* 8-bit board will always be initialized upon opening serial port, 32-bit board needs explicit initialization */ fprintf(stderr, "openbci2ft: initializing ...\n"); serialWrite(&SP, 1, "v"); fprintf(stderr, "openbci2ft: press reset on the OpenBCI board if this takes too long\n"); usleep(1000); /* wait for '$$$' which indicates that the OpenBCI has been initialized */ c = 0; while (c!=3) { n = serialRead(&SP, 1, &byte); if (n==1) { if (byte=='$') c++; else c = 0; } } /* while waiting for '$$$' */ fprintf(stderr, "openbci2ft: initializing ... ok\n"); printf("Starting to listen - press CTRL-C to quit\n"); /* register CTRL-C handler */ signal(SIGINT, abortHandler); /* start streaming data */ serialWrite(&SP, 1, "b"); while (keepRunning) { c = 0; while (c<blocksize) { /* wait for the first byte of the packet */ buf[0]=0; while (buf[0]!=0xA0) { if (serialInputPending(&SP)) n = serialRead(&SP, 1, buf); else usleep(1000); } /* while */ /* read the remaining 32 bytes of the packet */ while (n<BUFLEN) if (serialInputPending(&SP)) n += serialRead(&SP, (BUFLEN-n), buf+n); else usleep(100000); if (verbose>1) { for (i=0; i<BUFLEN; i++) printf("%02x ", buf[i]); printf("\n"); } ((FLOAT32_T *)(data->buf))[nchans*c + 0] = OPENBCI_CALIB1 * (buf[ 2]<<24 | buf[ 3]<<16 | buf[ 4]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 1] = OPENBCI_CALIB1 * (buf[ 5]<<24 | buf[ 6]<<16 | buf[ 7]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 2] = OPENBCI_CALIB1 * (buf[ 8]<<24 | buf[ 9]<<16 | buf[10]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 3] = OPENBCI_CALIB1 * (buf[11]<<24 | buf[12]<<16 | buf[13]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 4] = OPENBCI_CALIB1 * (buf[14]<<24 | buf[15]<<16 | buf[16]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 5] = OPENBCI_CALIB1 * (buf[17]<<24 | buf[18]<<16 | buf[19]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 6] = OPENBCI_CALIB1 * (buf[20]<<24 | buf[21]<<16 | buf[22]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 7] = OPENBCI_CALIB1 * (buf[23]<<24 | buf[24]<<16 | buf[25]<<8)/255; ((FLOAT32_T *)(data->buf))[nchans*c + 8] = OPENBCI_CALIB2 * (buf[26]<<24 | buf[27]<<16)/32767; ((FLOAT32_T *)(data->buf))[nchans*c + 9] = OPENBCI_CALIB2 * (buf[28]<<24 | buf[29]<<16)/32767; ((FLOAT32_T *)(data->buf))[nchans*c +10] = OPENBCI_CALIB2 * (buf[28]<<24 | buf[31]<<16)/32767; c++; } /* while c<blocksize */ sample += blocksize; printf("openbci2ft: sample count = %i\n", sample); /* * Header * Byte 1: 0xA0 * Byte 2: Sample Number * * EEG Data * Note: values are 24-bit signed, MSB first * Bytes 3-5: Data value for EEG channel 1 * Bytes 6-8: Data value for EEG channel 2 * Bytes 9-11: Data value for EEG channel 3 * Bytes 12-14: Data value for EEG channel 4 * Bytes 15-17: Data value for EEG channel 5 * Bytes 18-20: Data value for EEG channel 6 * Bytes 21-23: Data value for EEG channel 6 * Bytes 24-26: Data value for EEG channel 8 * * Accelerometer Data * Note: values are 16-bit signed, MSB first * Bytes 27-28: Data value for accelerometer channel X * Bytes 29-30: Data value for accelerometer channel Y * Bytes 31-32: Data value for accelerometer channel Z * * Footer * Byte 33: 0xC0 */ /* create the request */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->bufsize = 0; request->def->command = PUT_DAT; request->def->bufsize = append(&request->buf, request->def->bufsize, data->def, sizeof(datadef_t)); request->def->bufsize = append(&request->buf, request->def->bufsize, data->buf, data->def->bufsize); status = clientrequest(ftSocket, request, &response); if (verbose>0) fprintf(stderr, "openbci2ft: clientrequest returned %d\n", status); if (status) { fprintf(stderr, "openbci2ft: error in %s on line %d\n", __FILE__, __LINE__); exit(1); } if (status) { fprintf(stderr, "openbci2ft: error in %s on line %d\n", __FILE__, __LINE__); exit(1); } /* FIXME do someting with the response, i.e. check that it is OK */ cleanup_message(&request); if (response == NULL || response->def == NULL || response->def->command!=PUT_OK) { fprintf(stderr, "Error when writing samples.\n"); } cleanup_message(&response); } /* while keepRunning */ /* stop streaming data */ serialWrite(&SP, 1, "s"); cleanup_data(&data); if (ftSocket > 0) { close_connection(ftSocket); } else { ft_stop_buffer_server(ftServer); } return 0; } /* main */
int buffer_puthdr(int server, mxArray * plhs[], const mxArray * prhs[]) { int fieldnumber; mxArray *field; int result; message_t request; messagedef_t request_def; message_t *response = NULL; headerdef_t header_def; ft_chunkdef_t chunk_def; /* allocate the request message */ request.def = &request_def; request.buf = NULL; request_def.version = VERSION; request_def.command = PUT_HDR; request_def.bufsize = 0; /* define the header, it has the fields "nchans", "nsamples", "nevents", "fsample", "data_type" */ if (mxGetNumberOfElements(prhs[0])!=1) mexErrMsgTxt("Only one header can be put into the buffer at a time."); fieldnumber = mxGetFieldNumber(prhs[0], "nchans"); if (fieldnumber<0) mexErrMsgTxt("field 'nchans' is missing"); field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) mexErrMsgTxt("invalid data type for 'nchans'"); header_def.nchans = (UINT32_T)mxGetScalar(field) ; fieldnumber = mxGetFieldNumber(prhs[0], "nsamples"); if (fieldnumber<0) mexErrMsgTxt("field 'nsamples' is missing"); field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) mexErrMsgTxt("invalid data type for 'nsamples'"); header_def.nsamples = (UINT32_T)mxGetScalar(field) ; fieldnumber = mxGetFieldNumber(prhs[0], "nevents"); if (fieldnumber<0) mexErrMsgTxt("field is missing 'nevents'"); field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) mexErrMsgTxt("invalid data type for 'nevents'"); header_def.nevents = (UINT32_T)mxGetScalar(field) ; fieldnumber = mxGetFieldNumber(prhs[0], "fsample"); if (fieldnumber<0) mexErrMsgTxt("field is missing 'fsample'"); field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) mexErrMsgTxt("invalid data type for 'fsample'"); header_def.fsample = (float)mxGetScalar(field) ; fieldnumber = mxGetFieldNumber(prhs[0], "data_type"); if (fieldnumber<0) mexErrMsgTxt("field 'data_type' is missing"); field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsNumeric(field) || mxIsEmpty(field)) mexErrMsgTxt("invalid data type for 'data_type'"); header_def.data_type = (UINT32_T)mxGetScalar(field) ; /* construct a PUT_HDR request */ request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, &header_def, sizeof(headerdef_t)); /* append existing chunks to request.buf, set correct header_def.bufsize at the end */ fieldnumber = mxGetFieldNumber(prhs[0], "nifti_1"); if (fieldnumber>=0) { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsUint8(field) || mxGetNumberOfElements(field)!=SIZE_NIFTI_1) { mexWarnMsgTxt("invalid data type for field 'nifti_1' -- ignoring"); } else { chunk_def.size = SIZE_NIFTI_1; chunk_def.type = FT_CHUNK_NIFTI1; request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, &chunk_def, sizeof(chunk_def)); request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, mxGetData(field), chunk_def.size); } } fieldnumber = mxGetFieldNumber(prhs[0], "siemensap"); if (fieldnumber>=0) { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsUint8(field)) { mexWarnMsgTxt("invalid data type for field 'siemensap' -- ignoring"); } else { chunk_def.size = mxGetNumberOfElements(field); chunk_def.type = FT_CHUNK_SIEMENS_AP; request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, &chunk_def, sizeof(chunk_def)); request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, mxGetData(field), chunk_def.size); } } fieldnumber = mxGetFieldNumber(prhs[0], "ctf_res4"); if (fieldnumber>=0) { field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); if (!mxIsUint8(field)) { mexWarnMsgTxt("invalid data type for field 'ctf_res4' -- ignoring"); } else { chunk_def.size = mxGetNumberOfElements(field); chunk_def.type = FT_CHUNK_CTF_RES4; request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, &chunk_def, sizeof(chunk_def)); request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, mxGetData(field), chunk_def.size); } } fieldnumber = mxGetFieldNumber(prhs[0], "channel_names"); if (fieldnumber>=0) { ft_chunk_t *chunk = NULL; field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); chunk = encodeChannelNames(field, header_def.nchans); if (chunk == NULL) { mexWarnMsgTxt("invalid data type for field 'channel_names' -- ignoring."); } else { request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, chunk, sizeof(ft_chunkdef_t) + chunk->def.size); mxFree(chunk); } } fieldnumber = mxGetFieldNumber(prhs[0], "resolutions"); if (fieldnumber>=0) { ft_chunk_t *chunk = NULL; field = mxGetFieldByNumber(prhs[0], 0, fieldnumber); chunk = encodeResolutions(field, header_def.nchans); if (chunk == NULL) { mexWarnMsgTxt("invalid data type for field 'resolutions' -- ignoring."); } else { request_def.bufsize = ft_mx_append(&request.buf, request_def.bufsize, chunk, sizeof(ft_chunkdef_t) + chunk->def.size); mxFree(chunk); } } /* header->def->bufsize is the request->def->bufsize - sizeof(header->def) */ ((headerdef_t *) request.buf)->bufsize = request_def.bufsize - sizeof(headerdef_t); /* write the request, read the response */ result = clientrequest(server, &request, &response); /* the request structure is not needed any more, but only .buf needs to be free'd */ if (request.buf != NULL) mxFree(request.buf); if (result == 0) { /* check that the response is PUT_OK */ if (!response) mexErrMsgTxt("unknown error in response\n"); if (!response->def) { FREE(response->buf); FREE(response); mexErrMsgTxt("unknown error in response\n"); } if (response->def->command!=PUT_OK) { result = response->def->command; } } /* the response structure is not needed any more */ if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return result; }
int buffer_getevt(int server, mxArray *plhs[], const mxArray *prhs[]) { int verbose = 0; int i, nevents; int offset; double *val; int result; mxArray *bufptr; message_t *request = NULL; message_t *response = NULL; eventsel_t eventsel; /* this is for the Matlab specific output */ const char *field_names[] = { "type", "value", "sample", "offset", "duration" }; /* allocate the elements that will be used in the communication */ request = malloc(sizeof(message_t)); request->def = malloc(sizeof(messagedef_t)); request->buf = NULL; request->def->version = VERSION; request->def->command = GET_EVT; request->def->bufsize = 0; if ((prhs[0]!=NULL) && (mxGetNumberOfElements(prhs[0])==2) && (mxIsDouble(prhs[0])) && (!mxIsComplex(prhs[0]))) { /* fprintf(stderr, "args OK\n"); */ val = (double *)mxGetData(prhs[0]); eventsel.begevent = (UINT32_T)(val[0]); eventsel.endevent = (UINT32_T)(val[1]); if (verbose) print_eventsel(&eventsel); request->def->bufsize = append(&request->buf, request->def->bufsize, &eventsel, sizeof(eventsel_t)); } if (verbose) print_request(request->def); result = clientrequest(server, request, &response); if (verbose) print_response(response->def); if (result == 0) { if (response->def->command==GET_OK) { eventdef_t *event_def; /* first count the number of events */ nevents = 0; offset = 0; while (offset<response->def->bufsize) { event_def = (eventdef_t *)((char *)response->buf + offset); /* event_buf = (char *)response->buf + offset + sizeof(eventdef_t); */ if (verbose) print_eventdef(event_def); offset += sizeof(eventdef_t) + event_def->bufsize; nevents++; } /* create a structure array that can hold all events */ plhs[0] = mxCreateStructMatrix(1, nevents, NUMBER_OF_FIELDS, field_names); offset = 0; for (i=0; i<nevents; i++) { char *buf_type,*buf_value; event_def = (eventdef_t *) ((char *)response->buf + offset); buf_type = (char *) response->buf + offset + sizeof(eventdef_t); buf_value = buf_type + event_def->type_numel * wordsize_from_type(event_def->type_type); mxSetFieldByNumber(plhs[0], i, 0, matrix_from_ft_type_data(event_def->type_type, 1, event_def->type_numel, buf_type)); mxSetFieldByNumber(plhs[0], i, 1, matrix_from_ft_type_data(event_def->value_type, 1, event_def->value_numel, buf_value)); mxSetFieldByNumber(plhs[0], i, 2, mxCreateDoubleScalar((double)event_def->sample+1)); /* 1-based in Matlab, 0-based in protocol */ mxSetFieldByNumber(plhs[0], i, 3, mxCreateDoubleScalar((double)event_def->offset)); mxSetFieldByNumber(plhs[0], i, 4, mxCreateDoubleScalar((double)event_def->duration)); offset += sizeof(eventdef_t) + event_def->bufsize; } } else { result = response->def->command; } } if (request) { FREE(request->def); FREE(request->buf); FREE(request); } if (response) { FREE(response->def); FREE(response->buf); FREE(response); } return result; }