| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- /*
- en50221 encoder An implementation for libdvb
- an implementation for the en50221 transport layer
- Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
- This program 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 <stdio.h>
- #include <unistd.h>
- #include <limits.h>
- #include <string.h>
- #include <errno.h>
- #include <libdvbapi/dvbca.h>
- #include <libdvbmisc/dvbmisc.h>
- #include "en50221_app_rm.h"
- #include "en50221_app_datetime.h"
- #include "en50221_app_utils.h"
- #include "en50221_app_tags.h"
- #include "en50221_stdcam.h"
- #define LLCI_RESPONSE_TIMEOUT_MS 1000
- #define LLCI_POLL_DELAY_MS 100
- /* resource IDs we support */
- static uint32_t resource_ids[] =
- { EN50221_APP_RM_RESOURCEID,
- EN50221_APP_CA_RESOURCEID,
- EN50221_APP_AI_RESOURCEID,
- EN50221_APP_MMI_RESOURCEID,
- EN50221_APP_DATETIME_RESOURCEID,
- };
- #define RESOURCE_IDS_COUNT sizeof(resource_ids)/4
- struct llci_resource {
- struct en50221_app_public_resource_id resid;
- uint32_t binary_resource_id;
- en50221_sl_resource_callback callback;
- void *arg;
- };
- struct en50221_stdcam_llci {
- struct en50221_stdcam stdcam;
- int cafd;
- int slotnum;
- int state;
- struct llci_resource resources[RESOURCE_IDS_COUNT];
- struct en50221_transport_layer *tl;
- struct en50221_session_layer *sl;
- struct en50221_app_send_functions sendfuncs;
- int tl_slot_id;
- struct en50221_app_rm *rm_resource;
- struct en50221_app_datetime *datetime_resource;
- int datetime_session_number;
- uint8_t datetime_response_interval;
- time_t datetime_next_send;
- time_t datetime_dvbtime;
- };
- static enum en50221_stdcam_status en50221_stdcam_llci_poll(struct en50221_stdcam *stdcam);
- static void en50221_stdcam_llci_dvbtime(struct en50221_stdcam *stdcam, time_t dvbtime);
- static void en50221_stdcam_llci_destroy(struct en50221_stdcam *stdcam, int closefd);
- static void llci_cam_added(struct en50221_stdcam_llci *llci);
- static void llci_cam_in_reset(struct en50221_stdcam_llci *llci);
- static void llci_cam_removed(struct en50221_stdcam_llci *llci);
- static int llci_lookup_callback(void *arg, uint8_t _slot_id, uint32_t requested_resource_id,
- en50221_sl_resource_callback *callback_out, void **arg_out,
- uint32_t *connected_resource_id);
- static int llci_session_callback(void *arg, int reason, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id);
- static int llci_rm_enq_callback(void *arg, uint8_t _slot_id, uint16_t session_number);
- static int llci_rm_reply_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *_resource_ids);
- static int llci_rm_changed_callback(void *arg, uint8_t _slot_id, uint16_t session_number);
- static int llci_datetime_enquiry_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint8_t response_interval);
- struct en50221_stdcam *en50221_stdcam_llci_create(int cafd, int slotnum,
- struct en50221_transport_layer *tl,
- struct en50221_session_layer *sl)
- {
- // try and allocate space for the LLCI stdcam
- struct en50221_stdcam_llci *llci =
- malloc(sizeof(struct en50221_stdcam_llci));
- if (llci == NULL) {
- return NULL;
- }
- memset(llci, 0, sizeof(struct en50221_stdcam_llci));
- // create the sendfuncs
- llci->sendfuncs.arg = sl;
- llci->sendfuncs.send_data = (en50221_send_data) en50221_sl_send_data;
- llci->sendfuncs.send_datav = (en50221_send_datav) en50221_sl_send_datav;
- // create the resource manager resource
- int resource_idx = 0;
- llci->rm_resource = en50221_app_rm_create(&llci->sendfuncs);
- en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_RM_RESOURCEID);
- llci->resources[resource_idx].binary_resource_id = EN50221_APP_RM_RESOURCEID;
- llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_rm_message;
- llci->resources[resource_idx].arg = llci->rm_resource;
- en50221_app_rm_register_enq_callback(llci->rm_resource, llci_rm_enq_callback, llci);
- en50221_app_rm_register_reply_callback(llci->rm_resource, llci_rm_reply_callback, llci);
- en50221_app_rm_register_changed_callback(llci->rm_resource, llci_rm_changed_callback, llci);
- resource_idx++;
- // create the datetime resource
- llci->datetime_resource = en50221_app_datetime_create(&llci->sendfuncs);
- en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_DATETIME_RESOURCEID);
- llci->resources[resource_idx].binary_resource_id = EN50221_APP_DATETIME_RESOURCEID;
- llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_datetime_message;
- llci->resources[resource_idx].arg = llci->datetime_resource;
- en50221_app_datetime_register_enquiry_callback(llci->datetime_resource, llci_datetime_enquiry_callback, llci);
- resource_idx++;
- llci->datetime_session_number = -1;
- llci->datetime_response_interval = 0;
- llci->datetime_next_send = 0;
- llci->datetime_dvbtime = 0;
- // create the application information resource
- llci->stdcam.ai_resource = en50221_app_ai_create(&llci->sendfuncs);
- en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_AI_RESOURCEID);
- llci->resources[resource_idx].binary_resource_id = EN50221_APP_AI_RESOURCEID;
- llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_ai_message;
- llci->resources[resource_idx].arg = llci->stdcam.ai_resource;
- llci->stdcam.ai_session_number = -1;
- resource_idx++;
- // create the CA resource
- llci->stdcam.ca_resource = en50221_app_ca_create(&llci->sendfuncs);
- en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_CA_RESOURCEID);
- llci->resources[resource_idx].binary_resource_id = EN50221_APP_CA_RESOURCEID;
- llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_ca_message;
- llci->resources[resource_idx].arg = llci->stdcam.ca_resource;
- llci->stdcam.ca_session_number = -1;
- resource_idx++;
- // create the MMI resource
- llci->stdcam.mmi_resource = en50221_app_mmi_create(&llci->sendfuncs);
- en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_MMI_RESOURCEID);
- llci->resources[resource_idx].binary_resource_id = EN50221_APP_MMI_RESOURCEID;
- llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_mmi_message;
- llci->resources[resource_idx].arg = llci->stdcam.mmi_resource;
- llci->stdcam.mmi_session_number = -1;
- resource_idx++;
- // register session layer callbacks
- en50221_sl_register_lookup_callback(sl, llci_lookup_callback, llci);
- en50221_sl_register_session_callback(sl, llci_session_callback, llci);
- // done
- llci->stdcam.destroy = en50221_stdcam_llci_destroy;
- llci->stdcam.poll = en50221_stdcam_llci_poll;
- llci->stdcam.dvbtime = en50221_stdcam_llci_dvbtime;
- llci->cafd = cafd;
- llci->slotnum = slotnum;
- llci->tl = tl;
- llci->sl = sl;
- llci->tl_slot_id = -1;
- llci->state = EN50221_STDCAM_CAM_NONE;
- return &llci->stdcam;
- }
- static void en50221_stdcam_llci_dvbtime(struct en50221_stdcam *stdcam, time_t dvbtime)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam;
- llci->datetime_dvbtime = dvbtime;
- }
- static void en50221_stdcam_llci_destroy(struct en50221_stdcam *stdcam, int closefd)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam;
- // "remove" the cam
- llci_cam_removed(llci);
- // destroy resources
- if (llci->rm_resource)
- en50221_app_rm_destroy(llci->rm_resource);
- if (llci->datetime_resource)
- en50221_app_datetime_destroy(llci->datetime_resource);
- if (llci->stdcam.ai_resource)
- en50221_app_ai_destroy(llci->stdcam.ai_resource);
- if (llci->stdcam.ca_resource)
- en50221_app_ca_destroy(llci->stdcam.ca_resource);
- if (llci->stdcam.mmi_resource)
- en50221_app_mmi_destroy(llci->stdcam.mmi_resource);
- if (closefd)
- close(llci->cafd);
- free(llci);
- }
- static enum en50221_stdcam_status en50221_stdcam_llci_poll(struct en50221_stdcam *stdcam)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam;
- switch(dvbca_get_cam_state(llci->cafd, llci->slotnum)) {
- case DVBCA_CAMSTATE_MISSING:
- if (llci->state != EN50221_STDCAM_CAM_NONE)
- llci_cam_removed(llci);
- break;
- case DVBCA_CAMSTATE_READY:
- if (llci->state == EN50221_STDCAM_CAM_NONE)
- llci_cam_added(llci);
- else if (llci->state == EN50221_STDCAM_CAM_INRESET)
- llci_cam_in_reset(llci);
- break;
- }
- // poll the stack
- int error;
- if ((error = en50221_tl_poll(llci->tl)) != 0) {
- print(LOG_LEVEL, ERROR, 1, "Error reported by stack:%i\n", en50221_tl_get_error(llci->tl));
- }
- // send date/time response
- if (llci->datetime_session_number != -1) {
- time_t cur_time = time(NULL);
- if (llci->datetime_response_interval && (cur_time > llci->datetime_next_send)) {
- en50221_app_datetime_send(llci->datetime_resource,
- llci->datetime_session_number,
- llci->datetime_dvbtime, 0);
- llci->datetime_next_send = cur_time + llci->datetime_response_interval;
- }
- }
- return llci->state;
- }
- static void llci_cam_added(struct en50221_stdcam_llci *llci)
- {
- // clear down any old structures
- if (llci->tl_slot_id != -1) {
- llci_cam_removed(llci);
- }
- // reset the CAM
- dvbca_reset(llci->cafd, llci->slotnum);
- llci->state = EN50221_STDCAM_CAM_INRESET;
- }
- static void llci_cam_in_reset(struct en50221_stdcam_llci *llci)
- {
- if (dvbca_get_cam_state(llci->cafd, llci->slotnum) != DVBCA_CAMSTATE_READY) {
- return;
- }
- // register the slot
- if ((llci->tl_slot_id = en50221_tl_register_slot(llci->tl, llci->cafd, llci->slotnum,
- LLCI_RESPONSE_TIMEOUT_MS, LLCI_POLL_DELAY_MS)) < 0) {
- llci->state = EN50221_STDCAM_CAM_BAD;
- return;
- }
- // create a new connection on the slot
- if (en50221_tl_new_tc(llci->tl, llci->tl_slot_id) < 0) {
- llci->state = EN50221_STDCAM_CAM_BAD;
- llci->tl_slot_id = -1;
- en50221_tl_destroy_slot(llci->tl, llci->tl_slot_id);
- return;
- }
- llci->state = EN50221_STDCAM_CAM_OK;
- }
- static void llci_cam_removed(struct en50221_stdcam_llci *llci)
- {
- if (llci->tl_slot_id != -1) {
- en50221_tl_destroy_slot(llci->tl, llci->tl_slot_id);
- llci->tl_slot_id = -1;
- llci->datetime_session_number = -1;
- llci->stdcam.ai_session_number = -1;
- llci->stdcam.ca_session_number = -1;
- llci->stdcam.mmi_session_number = -1;
- }
- llci->state = EN50221_STDCAM_CAM_NONE;
- }
- static int llci_lookup_callback(void *arg, uint8_t _slot_id, uint32_t requested_resource_id,
- en50221_sl_resource_callback *callback_out, void **arg_out,
- uint32_t *connected_resource_id)
- {
- struct en50221_app_public_resource_id resid;
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
- (void) _slot_id;
- // decode the resource id
- if (!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) {
- return -1;
- }
- // try and find an instance of the resource
- uint32_t i;
- for(i=0; i<RESOURCE_IDS_COUNT; i++) {
- if ((resid.resource_class == llci->resources[i].resid.resource_class) &&
- (resid.resource_type == llci->resources[i].resid.resource_type)) {
- // limit sessions to certain resources
- switch(requested_resource_id) {
- case EN50221_APP_DATETIME_RESOURCEID:
- if (llci->datetime_session_number != -1)
- return -3;
- break;
- case EN50221_APP_AI_RESOURCEID:
- if (llci->stdcam.ai_session_number != -1)
- return -3;
- break;
- case EN50221_APP_CA_RESOURCEID:
- if (llci->stdcam.ca_session_number != -1)
- return -3;
- break;
- case EN50221_APP_MMI_RESOURCEID:
- if (llci->stdcam.mmi_session_number != -1)
- return -3;
- break;
- }
- // resource is ok.
- *callback_out = llci->resources[i].callback;
- *arg_out = llci->resources[i].arg;
- *connected_resource_id = llci->resources[i].binary_resource_id;
- return 0;
- }
- }
- return -1;
- }
- static int llci_session_callback(void *arg, int reason, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
- (void) _slot_id;
- switch(reason) {
- case S_SCALLBACK_REASON_CAMCONNECTED:
- if (resource_id == EN50221_APP_RM_RESOURCEID) {
- en50221_app_rm_enq(llci->rm_resource, session_number);
- } else if (resource_id == EN50221_APP_DATETIME_RESOURCEID) {
- llci->datetime_session_number = session_number;
- } else if (resource_id == EN50221_APP_AI_RESOURCEID) {
- en50221_app_ai_enquiry(llci->stdcam.ai_resource, session_number);
- llci->stdcam.ai_session_number = session_number;
- } else if (resource_id == EN50221_APP_CA_RESOURCEID) {
- en50221_app_ca_info_enq(llci->stdcam.ca_resource, session_number);
- llci->stdcam.ca_session_number = session_number;
- } else if (resource_id == EN50221_APP_MMI_RESOURCEID) {
- llci->stdcam.mmi_session_number = session_number;
- }
- break;
- case S_SCALLBACK_REASON_CLOSE:
- if (resource_id == EN50221_APP_MMI_RESOURCEID) {
- llci->stdcam.mmi_session_number = -1;
- } else if (resource_id == EN50221_APP_DATETIME_RESOURCEID) {
- llci->datetime_session_number = -1;
- } else if (resource_id == EN50221_APP_AI_RESOURCEID) {
- llci->stdcam.ai_session_number = -1;
- } else if (resource_id == EN50221_APP_CA_RESOURCEID) {
- llci->stdcam.ca_session_number = -1;
- } else if (resource_id == EN50221_APP_MMI_RESOURCEID) {
- llci->stdcam.mmi_session_number = -1;
- }
- break;
- }
- return 0;
- }
- static int llci_rm_enq_callback(void *arg, uint8_t _slot_id, uint16_t session_number)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
- (void) _slot_id;
- if (en50221_app_rm_reply(llci->rm_resource, session_number, RESOURCE_IDS_COUNT, resource_ids)) {
- print(LOG_LEVEL, ERROR, 1, "Failed to send RM ENQ on slot %02x\n", _slot_id);
- }
- return 0;
- }
- static int llci_rm_reply_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *_resource_ids)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
- (void) _slot_id;
- (void) resource_id_count;
- (void) _resource_ids;
- if (en50221_app_rm_changed(llci->rm_resource, session_number)) {
- print(LOG_LEVEL, ERROR, 1, "Failed to send RM REPLY on slot %02x\n", _slot_id);
- }
- return 0;
- }
- static int llci_rm_changed_callback(void *arg, uint8_t _slot_id, uint16_t session_number)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
- (void) _slot_id;
- if (en50221_app_rm_enq(llci->rm_resource, session_number)) {
- print(LOG_LEVEL, ERROR, 1, "Failed to send RM CHANGED on slot %02x\n", _slot_id);
- }
- return 0;
- }
- static int llci_datetime_enquiry_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint8_t response_interval)
- {
- struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
- (void) _slot_id;
- llci->datetime_response_interval = response_interval;
- llci->datetime_next_send = 0;
- if (response_interval) {
- llci->datetime_next_send = time(NULL) + response_interval;
- }
- en50221_app_datetime_send(llci->datetime_resource, session_number, llci->datetime_dvbtime, 0);
- return 0;
- }
|