Le jeudi 4 décembre 2008 23:58:31 Morgan Tørvolt, vous avez écrit : > Hi all. > > This might be a stupid question, please feel free to call me a moron > and tell me how to solve this little problem I am having. I have tried > getting in touch with someone on the irc channel to help me sort this > out without much luck. Hopefully someone here has some knowledge of > the libdvben50221 library. I would imagine that very many use this > library with their dvb cards, so there should be someone out there. > > The camthread in gnutv, which continuously polls the stdcam, calls the > stdcam's poll function (obviously). The poll function is in my > pointing to the en50221_stdcam_llci_poll function. This function in > turn calls en50221_tl_poll, but without passing the return value of > this on to the camthread function of gnutv. What happened in my case > was that the transport layer crashed in some obscure way (this has > only happened once actually), and the en50221_tl_poll function > returned -1 all the time, and set the error state to be -3, which is > EN50221ERR_TIMEOUT. It did not recover in over an hour of waiting. > This message was spamming my console window: > en50221_stdcam_llci_poll: Error reported by stack:-3 > > After looking high and low for a way to be able to detect this state, > I have come up with nothing. I cannot read the error value directly > out of the stuct as it is a forward declaration in the header file and > actually declared in the .c file. I can access the error data using > the en50221_tl_get_error() function, but that only tells me that at > some point there was an error with the given error value. > > At least on my cam I get this message often when I start a program: > "en50221_stdcam_llci_poll: Error reported by stack:-7", which is a > message I can test with. My testing suggest that the error is set to > -7 and is left there until a new error occurs. In other words, it is > not possible to detect if the error -7 occurs every second, every > minute, or just once at the start and no errors since then. The same > problem exists with the timeout error I had. gnutv could have detected > that there had been a timeout error, but could in no way I can see, > find out if it had resolved itself or not. > > The error I saw was a timeout error that happened after more than 24 > hours from starting the program, and the transport layer was returning > -3 continuously. > > I can think of a few ways to solve this problem. > * One would be a callback function on transport layer error in the stdcam > * Have an error counter in the transport layer struct, and a function > to read the counter. Must be reflected in the session layer as well it > seems. > * Return the transport layer poll's return value in some way from the > stdcam poll function. Possibly by setting adding to the stdcam_status > enum a value like "EN50221_STDCAM_TL_ERROR". Maybe a bitshifted value > as well? It should then be easy to check the error using the > en50221_tl_get_error function. > * This is already solved trough some other solution, and I have been > to blind to see it all along. > > I prefer the options from bottom to top. > Any takers? Look at en50221_stdcam_llci_poll(..) in the joined file. This is how i solved that. -- Christophe Thommeret
/* en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer Copyright (C) 2006 Andrew de Quincey (adq_dvb@xxxxxxxxxxxxx) 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 adapter; int cafd; int slotnum; int state; int error_counter; 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 anum, 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->adapter = anum; llci->error_counter = 0; llci->cafd = cafd; llci->slotnum = slotnum; llci->tl = tl; llci->sl = sl; llci->tl_slot_id = -1; llci->state = EN50221_STDCAM_CAM_INRESET; 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, "ca%d: Error reported by stack:%i", llci->adapter, en50221_tl_get_error(llci->tl)); ++llci->error_counter; if ( llci->error_counter>30 ) { // cam probably crashed, reset. llci_cam_removed(llci); llci->error_counter = 0; } } else llci->error_counter = 0; // 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; } 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, "ca%d: Failed to send RM ENQ on slot %02x\n", llci->adapter, _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, "ca%d: Failed to send RM REPLY on slot %02x\n", llci->adapter, _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, "ca%d: Failed to send RM CHANGED on slot %02x\n", llci->adapter, _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; }
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb