/* labcomm_encoder.c -- handling encoding of labcomm samples. Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> This file is part of LabComm. LabComm is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. LabComm 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 <http://www.gnu.org/licenses/>. */ #define CURRENT_VERSION "LabComm20141009" #include <errno.h> #include "labcomm.h" #include "labcomm_private.h" #include "labcomm_ioctl.h" #ifndef WITHOUT_PRAGMA #include "labcomm_dynamic_buffer_writer.h" #include "labcomm_bytearray_reader.h" #endif struct labcomm_encoder { struct labcomm_writer *writer; struct labcomm_error_handler *error; struct labcomm_memory *memory; struct labcomm_scheduler *scheduler; LABCOMM_SIGNATURE_ARRAY_DEF(registered, int); int context_type; //type tag for context. Currently only LABCOMM_PRAGMA void *context; // for, e.g. parent of pragma packet builder }; struct labcomm_encoder *labcomm_encoder_new( struct labcomm_writer *writer, struct labcomm_error_handler *error, struct labcomm_memory *memory, struct labcomm_scheduler *scheduler) { struct labcomm_encoder *result; result = labcomm_memory_alloc(memory, 0, sizeof(*result)); if (result) { int length; result->writer = writer; result->writer->encoder = result; result->writer->data = NULL; result->writer->data_size = 0; result->writer->count = 0; result->writer->pos = 0; result->writer->error = 0; result->error = error; result->memory = memory; result->scheduler = scheduler; LABCOMM_SIGNATURE_ARRAY_INIT(result->registered, int); labcomm_writer_alloc(result->writer, result->writer->action_context); labcomm_writer_start(result->writer, result->writer->action_context, LABCOMM_VERSION, NULL, CURRENT_VERSION); labcomm_write_packed32(result->writer, LABCOMM_VERSION); length = (labcomm_size_packed32(LABCOMM_VERSION) + labcomm_size_string(CURRENT_VERSION)); labcomm_write_packed32(result->writer, length); labcomm_write_string(result->writer, CURRENT_VERSION); labcomm_writer_end(result->writer, result->writer->action_context); } return result; } void labcomm_encoder_free(struct labcomm_encoder* e) { struct labcomm_memory *memory = e->memory; labcomm_writer_free(e->writer, e->writer->action_context); LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->registered, int); labcomm_memory_free(memory, 0, e); } #undef WITHOUT_PRAGMA #ifndef WITHOUT_PRAGMA struct pragma_packet_builder { char * pragma_type; struct labcomm_encoder* parent; }; struct labcomm_encoder *labcomm_pragma_builder_new( struct labcomm_encoder *e, char * pragma_type) { struct labcomm_writer *dyn_writer = labcomm_dynamic_buffer_writer_new( e->memory); struct labcomm_encoder *pb = labcomm_encoder_new(dyn_writer, e->error, e->memory, e->scheduler); size_t tlen = 1+strlen(pragma_type); char* ptype = labcomm_memory_alloc( e->memory, 1, tlen); if(ptype) { strncpy(ptype, pragma_type, tlen); } //XXX TODO: and else? struct pragma_packet_builder* ctxt = labcomm_memory_alloc( e->memory, 1, sizeof(struct pragma_packet_builder)); if(ctxt){ ctxt->pragma_type=ptype; ctxt->parent=e; } pb->context_type = LABCOMM_PRAGMA; pb->context = ctxt; return pb; } //HERE BE DRAGONS! Copied from decoder.c //Should this be moved to private_h? static int writer_ioctl(struct labcomm_writer *writer, uint32_t action, ...) { int result; va_list va; if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) { result = -EINVAL; goto out; } va_start(va, action); result = labcomm_writer_ioctl(writer, writer->action_context, 0, NULL, action, va); va_end(va); out: return result; } int labcomm_pragma_send(struct labcomm_encoder* e) { //HERE BE DRAGONS! //We assume that the writer is a dynamic_buffer_writer if(e->context_type != LABCOMM_PRAGMA) { printf("context type != PRAGMA, bailing out\n"); return 1; } if(!e->context) { printf("context == NULL, bailing out\n"); return 2; } struct pragma_packet_builder* ctx = e->context; struct labcomm_encoder *p = ctx->parent; char * pragma_type = ctx->pragma_type; char* pragma_data; int err,len; labcomm_writer_end(e->writer, e->writer->action_context); err = writer_ioctl(e->writer, LABCOMM_IOCTL_WRITER_GET_BYTES_WRITTEN, &len); if (err < 0) { // HERE BE DRAGONS! // What is the difference between error_handler (where is it defined?) // and error_handler_callback. And why is the latter only in // the decoder struct? // // e->on_error(LABCOMM_ERROR_BAD_WRITER, 2, // "Failed to get size: %s\n", strerror(-err)); fprintf(stderr, "BAD WRITER, Failed to get size> %s\n", strerror(-err)); err = -ENOENT; goto free_encoder; } err = writer_ioctl(e->writer, LABCOMM_IOCTL_WRITER_GET_BYTE_POINTER, &pragma_data); if (err < 0) { // e->on_error(LABCOMM_ERROR_BAD_WRITER, 2, // "Failed to get pointer: %s\n", strerror(-err)); fprintf(stderr, "BAD WRITER, Failed to get pointer> %s\n", strerror(-err)); err = -ENOENT; goto free_encoder; } { int data_len = labcomm_size_string(pragma_type) + len; int i; labcomm_write_packed32(p->writer, LABCOMM_PRAGMA); labcomm_write_packed32(p->writer, data_len); labcomm_write_string(p->writer, pragma_type); for(i=0; i<len;i++){ labcomm_write_byte(p->writer, pragma_data[i]); } labcomm_writer_end(p->writer, p->writer->action_context); err = p->writer->error; } free_encoder: //XXX are these needed, or is that done in encoder_free? labcomm_memory_free(e->memory, 1, ctx->pragma_type); labcomm_memory_free(e->memory, 1, ctx); labcomm_encoder_free(e); return err; } #endif int labcomm_internal_encoder_register( struct labcomm_encoder *e, struct labcomm_signature *signature, labcomm_encoder_function encode) { int result = -EINVAL; int index, *done, err, i, length; index = labcomm_get_local_index(signature); labcomm_scheduler_writer_lock(e->scheduler); if (index <= 0) { goto out; } done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->registered, int, index); if (*done) { goto out; } *done = 1; err = labcomm_writer_start(e->writer, e->writer->action_context, index, signature, NULL); if (err == -EALREADY) { result = 0; goto out; } if (err != 0) { result = err; goto out; } labcomm_write_packed32(e->writer, LABCOMM_SAMPLE_DEF); length = (labcomm_size_packed32(index) + labcomm_size_string(signature->name) + labcomm_size_packed32(signature->size) + signature->size); labcomm_write_packed32(e->writer, length); labcomm_write_packed32(e->writer, index); labcomm_write_string(e->writer, signature->name); labcomm_write_packed32(e->writer, signature->size); for (i = 0 ; i < signature->size ; i++) { if (e->writer->pos >= e->writer->count) { labcomm_writer_flush(e->writer, e->writer->action_context); } e->writer->data[e->writer->pos] = signature->signature[i]; e->writer->pos++; } labcomm_writer_end(e->writer, e->writer->action_context); result = e->writer->error; out: labcomm_scheduler_writer_unlock(e->scheduler); return result; } int labcomm_internal_encode( struct labcomm_encoder *e, struct labcomm_signature *signature, labcomm_encoder_function encode, void *value) { int result, index, length; index = labcomm_get_local_index(signature); length = (signature->encoded_size(value)); labcomm_scheduler_writer_lock(e->scheduler); result = labcomm_writer_start(e->writer, e->writer->action_context, index, signature, value); if (result == -EALREADY) { result = 0; goto no_end; } if (result != 0) { goto out; } result = labcomm_write_packed32(e->writer, index); result = labcomm_write_packed32(e->writer, length); if (result != 0) { goto out; } result = encode(e->writer, value); out: labcomm_writer_end(e->writer, e->writer->action_context); no_end: labcomm_scheduler_writer_unlock(e->scheduler); return result; } int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, uint32_t action, ...) { int result; va_list va; if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) { result = -EINVAL; goto out; } va_start(va, action); result = labcomm_writer_ioctl(encoder->writer, encoder->writer->action_context, 0, NULL, action, va); va_end(va); out: return result; } int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, struct labcomm_signature *signature, uint32_t action, va_list va) { int result = -ENOTSUP; int index; index = labcomm_get_local_index(signature); result = labcomm_writer_ioctl(encoder->writer, encoder->writer->action_context, index, signature, action, va); return result; }