/* en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer Copyright (C) 2004, 2005 Manu Abraham Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "en50221_app_lowspeed.h" #include "en50221_app_tags.h" #include "asn_1.h" struct en50221_app_lowspeed_session { uint16_t session_number; uint8_t *block_chain; uint32_t block_length; struct en50221_app_lowspeed_session *next; }; struct en50221_app_lowspeed { struct en50221_app_send_functions *funcs; en50221_app_lowspeed_command_callback command_callback; void *command_callback_arg; en50221_app_lowspeed_send_callback send_callback; void *send_callback_arg; struct en50221_app_lowspeed_session *sessions; pthread_mutex_t lock; }; static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command, uint8_t *data, int data_length); static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed *lowspeed, uint8_t slot_id, uint16_t session_number, uint8_t *data, uint32_t data_length); static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed *lowspeed, uint8_t slot_id, uint16_t session_number, int more_last, uint8_t *data, uint32_t data_length); struct en50221_app_lowspeed *en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs) { struct en50221_app_lowspeed *lowspeed = NULL; // create structure and set it up lowspeed = malloc(sizeof(struct en50221_app_lowspeed)); if (lowspeed == NULL) { return NULL; } lowspeed->funcs = funcs; lowspeed->command_callback = NULL; lowspeed->send_callback = NULL; lowspeed->sessions = NULL; pthread_mutex_init(&lowspeed->lock, NULL); // done return lowspeed; } void en50221_app_lowspeed_destroy(struct en50221_app_lowspeed *lowspeed) { struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions; while (cur_s) { struct en50221_app_lowspeed_session *next = cur_s->next; if (cur_s->block_chain) free(cur_s->block_chain); free(cur_s); cur_s = next; } pthread_mutex_destroy(&lowspeed->lock); free(lowspeed); } void en50221_app_lowspeed_clear_session(struct en50221_app_lowspeed *lowspeed, uint16_t session_number) { pthread_mutex_lock(&lowspeed->lock); struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions; struct en50221_app_lowspeed_session *prev_s = NULL; while (cur_s) { if (cur_s->session_number == session_number) { if (cur_s->block_chain) free(cur_s->block_chain); if (prev_s) { prev_s->next = cur_s->next; } else { lowspeed->sessions = cur_s->next; } free(cur_s); return; } prev_s = cur_s; cur_s = cur_s->next; } pthread_mutex_unlock(&lowspeed->lock); } void en50221_app_lowspeed_register_command_callback(struct en50221_app_lowspeed *lowspeed, en50221_app_lowspeed_command_callback callback, void *arg) { pthread_mutex_lock(&lowspeed->lock); lowspeed->command_callback = callback; lowspeed->command_callback_arg = arg; pthread_mutex_unlock(&lowspeed->lock); } void en50221_app_lowspeed_register_send_callback(struct en50221_app_lowspeed *lowspeed, en50221_app_lowspeed_send_callback callback, void *arg) { pthread_mutex_lock(&lowspeed->lock); lowspeed->send_callback = callback; lowspeed->send_callback_arg = arg; pthread_mutex_unlock(&lowspeed->lock); } int en50221_app_lowspeed_send_comms_reply(struct en50221_app_lowspeed *lowspeed, uint16_t session_number, uint8_t comms_reply_id, uint8_t return_value) { uint8_t data[6]; data[0] = (TAG_COMMS_REPLY >> 16) & 0xFF; data[1] = (TAG_COMMS_REPLY >> 8) & 0xFF; data[2] = TAG_COMMS_REPLY & 0xFF; data[3] = 2; data[4] = comms_reply_id; data[5] = return_value; return lowspeed->funcs->send_data(lowspeed->funcs->arg, session_number, data, 6); } int en50221_app_lowspeed_send_comms_data(struct en50221_app_lowspeed *lowspeed, uint16_t session_number, uint8_t phase_id, uint32_t tx_data_length, uint8_t * tx_data) { uint8_t buf[10]; // the spec defines this limit if (tx_data_length > 254) { return -1; } // set up the tag buf[0] = (TAG_COMMS_RECV_LAST >> 16) & 0xFF; buf[1] = (TAG_COMMS_RECV_LAST >> 8) & 0xFF; buf[2] = TAG_COMMS_RECV_LAST & 0xFF; // encode the length field int length_field_len; if ((length_field_len = asn_1_encode(tx_data_length + 1, buf + 3, 3)) < 0) { return -1; } // the phase_id buf[3 + length_field_len] = phase_id; // build the iovecs struct iovec iov[2]; iov[0].iov_base = buf; iov[0].iov_len
# Channel table for Jequitibá - MG - Brazil
# Source: http://www.portalbsd.com.br/terrestres_channels.php?channels=3602

# Physical channel 28
[Record TV Minas]
	DELIVERY_SYSTEM = ISDBT
	BANDWIDTH_HZ = 6000000
	FREQUENCY = 557142857
	INVERSION = AUTO
	GUARD_INTERVAL = AUTO
	TRANSMISSION_MODE = AUTO
	INVERSION = AUTO
	GUARD_INTERVAL = AUTO
	TRANSMISSION_MODE = AUTO
	ISDBT_LAYER_ENABLED = 7
	ISDBT_SOUND_BROADCASTING = 0
	ISDBT_SB_SUBCHANNEL_ID = 0
	ISDBT_SB_SEGMENT_IDX = 0
	ISDBT_SB_SEGMENT_COUNT = 0
	ISDBT_LAYERA_FEC = AUTO
	ISDBT_LAYERA_MODULATION = QAM/AUTO
	ISDBT_LAYERA_SEGMENT_COUNT = 0
	ISDBT_LAYERA_TIME_INTERLEAVING = 0
	ISDBT_LAYERB_FEC = AUTO
	ISDBT_LAYERB_MODULATION = QAM/AUTO
	ISDBT_LAYERB_SEGMENT_COUNT = 0
	ISDBT_LAYERB_TIME_INTERLEAVING = 0
	ISDBT_LAYERC_FEC = AUTO
	ISDBT_LAYERC_MODULATION = QAM/AUTO
	ISDBT_LAYERC_SEGMENT_COUNT = 0
	ISDBT_LAYERC_TIME_INTERLEAVING = 0

# Physical channel 33
[Globo Minas]
	DELIVERY_SYSTEM = ISDBT
	BANDWIDTH_HZ = 6000000
	FREQUENCY = 587142857
	INVERSION = AUTO
	GUARD_INTERVAL = AUTO
	TRANSMISSION_MODE = AUTO
	INVERSION = AUTO
	GUARD_INTERVAL = AUTO
	TRANSMISSION_MODE = AUTO
	ISDBT_LAYER_ENABLED = 7
	ISDBT_SOUND_BROADCASTING = 0
	ISDBT_SB_SUBCHANNEL_ID = 0
	ISDBT_SB_SEGMENT_IDX = 0
	ISDBT_SB_SEGMENT_COUNT = 0
	ISDBT_LAYERA_FEC = AUTO
	ISDBT_LAYERA_MODULATION = QAM/AUTO
	ISDBT_LAYERA_SEGMENT_COUNT = 0
	ISDBT_LAYERA_TIME_INTERLEAVING = 0
	ISDBT_LAYERB_FEC = AUTO
	ISDBT_LAYERB_MODULATION = QAM/AUTO
	ISDBT_LAYERB_SEGMENT_COUNT = 0
	ISDBT_LAYERB_TIME_INTERLEAVING = 0
	ISDBT_LAYERC_FEC = AUTO
	ISDBT_LAYERC_MODULATION = QAM/AUTO
	ISDBT_LAYERC_SEGMENT_COUNT = 0
	ISDBT_LAYERC_TIME_INTERLEAVING = 0
print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); pthread_mutex_unlock(&lowspeed->lock); return -1; } cur_s->session_number = session_number; cur_s->block_chain = NULL; cur_s->block_length = 0; cur_s->next = lowspeed->sessions; lowspeed->sessions = cur_s; } // append the data uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length); if (new_data == NULL) { print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); pthread_mutex_unlock(&lowspeed->lock); return -1; } memcpy(new_data + cur_s->block_length, data, asn_data_length); cur_s->block_chain = new_data; cur_s->block_length += asn_data_length; // done pthread_mutex_unlock(&lowspeed->lock); return 0; } // we hit the last of a possible chain of fragments int do_free = 0; if (cur_s != NULL) { // we have a preceding fragment - need to append uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length); if (new_data == NULL) { print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); pthread_mutex_unlock(&lowspeed->lock); return -1; } memcpy(new_data + cur_s->block_length, data, asn_data_length); asn_data_length = cur_s->block_length + asn_data_length; data = new_data; cur_s->block_chain = NULL; cur_s->block_length = 0; do_free = 1; } // check the reassembled data length if (asn_data_length < 1) { pthread_mutex_unlock(&lowspeed->lock); print(LOG_LEVEL, ERROR, 1, "Received short data\n"); if (do_free) free(data); return -1; } // now, parse the data uint8_t phase_id = data[0]; // tell the app en50221_app_lowspeed_send_callback cb = lowspeed->send_callback; void *cb_arg = lowspeed->send_callback_arg; pthread_mutex_unlock(&lowspeed->lock); int cbstatus = 0; if (cb) { cbstatus = cb(cb_arg, slot_id, session_number, phase_id, data + 1, asn_data_length - 1); } // done if (do_free) free(data); return cbstatus; }