en50221_stdcam_llci.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*
  2. en50221 encoder An implementation for libdvb
  3. an implementation for the en50221 transport layer
  4. Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as
  7. published by the Free Software Foundation; either version 2.1 of
  8. the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <limits.h>
  20. #include <string.h>
  21. #include <errno.h>
  22. #include <libdvbapi/dvbca.h>
  23. #include <libdvbmisc/dvbmisc.h>
  24. #include "en50221_app_rm.h"
  25. #include "en50221_app_datetime.h"
  26. #include "en50221_app_utils.h"
  27. #include "en50221_app_tags.h"
  28. #include "en50221_stdcam.h"
  29. #define LLCI_RESPONSE_TIMEOUT_MS 1000
  30. #define LLCI_POLL_DELAY_MS 100
  31. /* resource IDs we support */
  32. static uint32_t resource_ids[] =
  33. { EN50221_APP_RM_RESOURCEID,
  34. EN50221_APP_CA_RESOURCEID,
  35. EN50221_APP_AI_RESOURCEID,
  36. EN50221_APP_MMI_RESOURCEID,
  37. EN50221_APP_DATETIME_RESOURCEID,
  38. };
  39. #define RESOURCE_IDS_COUNT sizeof(resource_ids)/4
  40. struct llci_resource {
  41. struct en50221_app_public_resource_id resid;
  42. uint32_t binary_resource_id;
  43. en50221_sl_resource_callback callback;
  44. void *arg;
  45. };
  46. struct en50221_stdcam_llci {
  47. struct en50221_stdcam stdcam;
  48. int cafd;
  49. int slotnum;
  50. int state;
  51. struct llci_resource resources[RESOURCE_IDS_COUNT];
  52. struct en50221_transport_layer *tl;
  53. struct en50221_session_layer *sl;
  54. struct en50221_app_send_functions sendfuncs;
  55. int tl_slot_id;
  56. struct en50221_app_rm *rm_resource;
  57. struct en50221_app_datetime *datetime_resource;
  58. int datetime_session_number;
  59. uint8_t datetime_response_interval;
  60. time_t datetime_next_send;
  61. time_t datetime_dvbtime;
  62. };
  63. static enum en50221_stdcam_status en50221_stdcam_llci_poll(struct en50221_stdcam *stdcam);
  64. static void en50221_stdcam_llci_dvbtime(struct en50221_stdcam *stdcam, time_t dvbtime);
  65. static void en50221_stdcam_llci_destroy(struct en50221_stdcam *stdcam, int closefd);
  66. static void llci_cam_added(struct en50221_stdcam_llci *llci);
  67. static void llci_cam_in_reset(struct en50221_stdcam_llci *llci);
  68. static void llci_cam_removed(struct en50221_stdcam_llci *llci);
  69. static int llci_lookup_callback(void *arg, uint8_t _slot_id, uint32_t requested_resource_id,
  70. en50221_sl_resource_callback *callback_out, void **arg_out,
  71. uint32_t *connected_resource_id);
  72. static int llci_session_callback(void *arg, int reason, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id);
  73. static int llci_rm_enq_callback(void *arg, uint8_t _slot_id, uint16_t session_number);
  74. 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);
  75. static int llci_rm_changed_callback(void *arg, uint8_t _slot_id, uint16_t session_number);
  76. static int llci_datetime_enquiry_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint8_t response_interval);
  77. struct en50221_stdcam *en50221_stdcam_llci_create(int cafd, int slotnum,
  78. struct en50221_transport_layer *tl,
  79. struct en50221_session_layer *sl)
  80. {
  81. // try and allocate space for the LLCI stdcam
  82. struct en50221_stdcam_llci *llci =
  83. malloc(sizeof(struct en50221_stdcam_llci));
  84. if (llci == NULL) {
  85. return NULL;
  86. }
  87. memset(llci, 0, sizeof(struct en50221_stdcam_llci));
  88. // create the sendfuncs
  89. llci->sendfuncs.arg = sl;
  90. llci->sendfuncs.send_data = (en50221_send_data) en50221_sl_send_data;
  91. llci->sendfuncs.send_datav = (en50221_send_datav) en50221_sl_send_datav;
  92. // create the resource manager resource
  93. int resource_idx = 0;
  94. llci->rm_resource = en50221_app_rm_create(&llci->sendfuncs);
  95. en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_RM_RESOURCEID);
  96. llci->resources[resource_idx].binary_resource_id = EN50221_APP_RM_RESOURCEID;
  97. llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_rm_message;
  98. llci->resources[resource_idx].arg = llci->rm_resource;
  99. en50221_app_rm_register_enq_callback(llci->rm_resource, llci_rm_enq_callback, llci);
  100. en50221_app_rm_register_reply_callback(llci->rm_resource, llci_rm_reply_callback, llci);
  101. en50221_app_rm_register_changed_callback(llci->rm_resource, llci_rm_changed_callback, llci);
  102. resource_idx++;
  103. // create the datetime resource
  104. llci->datetime_resource = en50221_app_datetime_create(&llci->sendfuncs);
  105. en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_DATETIME_RESOURCEID);
  106. llci->resources[resource_idx].binary_resource_id = EN50221_APP_DATETIME_RESOURCEID;
  107. llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_datetime_message;
  108. llci->resources[resource_idx].arg = llci->datetime_resource;
  109. en50221_app_datetime_register_enquiry_callback(llci->datetime_resource, llci_datetime_enquiry_callback, llci);
  110. resource_idx++;
  111. llci->datetime_session_number = -1;
  112. llci->datetime_response_interval = 0;
  113. llci->datetime_next_send = 0;
  114. llci->datetime_dvbtime = 0;
  115. // create the application information resource
  116. llci->stdcam.ai_resource = en50221_app_ai_create(&llci->sendfuncs);
  117. en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_AI_RESOURCEID);
  118. llci->resources[resource_idx].binary_resource_id = EN50221_APP_AI_RESOURCEID;
  119. llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_ai_message;
  120. llci->resources[resource_idx].arg = llci->stdcam.ai_resource;
  121. llci->stdcam.ai_session_number = -1;
  122. resource_idx++;
  123. // create the CA resource
  124. llci->stdcam.ca_resource = en50221_app_ca_create(&llci->sendfuncs);
  125. en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_CA_RESOURCEID);
  126. llci->resources[resource_idx].binary_resource_id = EN50221_APP_CA_RESOURCEID;
  127. llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_ca_message;
  128. llci->resources[resource_idx].arg = llci->stdcam.ca_resource;
  129. llci->stdcam.ca_session_number = -1;
  130. resource_idx++;
  131. // create the MMI resource
  132. llci->stdcam.mmi_resource = en50221_app_mmi_create(&llci->sendfuncs);
  133. en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_MMI_RESOURCEID);
  134. llci->resources[resource_idx].binary_resource_id = EN50221_APP_MMI_RESOURCEID;
  135. llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_mmi_message;
  136. llci->resources[resource_idx].arg = llci->stdcam.mmi_resource;
  137. llci->stdcam.mmi_session_number = -1;
  138. resource_idx++;
  139. // register session layer callbacks
  140. en50221_sl_register_lookup_callback(sl, llci_lookup_callback, llci);
  141. en50221_sl_register_session_callback(sl, llci_session_callback, llci);
  142. // done
  143. llci->stdcam.destroy = en50221_stdcam_llci_destroy;
  144. llci->stdcam.poll = en50221_stdcam_llci_poll;
  145. llci->stdcam.dvbtime = en50221_stdcam_llci_dvbtime;
  146. llci->cafd = cafd;
  147. llci->slotnum = slotnum;
  148. llci->tl = tl;
  149. llci->sl = sl;
  150. llci->tl_slot_id = -1;
  151. llci->state = EN50221_STDCAM_CAM_NONE;
  152. return &llci->stdcam;
  153. }
  154. static void en50221_stdcam_llci_dvbtime(struct en50221_stdcam *stdcam, time_t dvbtime)
  155. {
  156. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam;
  157. llci->datetime_dvbtime = dvbtime;
  158. }
  159. static void en50221_stdcam_llci_destroy(struct en50221_stdcam *stdcam, int closefd)
  160. {
  161. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam;
  162. // "remove" the cam
  163. llci_cam_removed(llci);
  164. // destroy resources
  165. if (llci->rm_resource)
  166. en50221_app_rm_destroy(llci->rm_resource);
  167. if (llci->datetime_resource)
  168. en50221_app_datetime_destroy(llci->datetime_resource);
  169. if (llci->stdcam.ai_resource)
  170. en50221_app_ai_destroy(llci->stdcam.ai_resource);
  171. if (llci->stdcam.ca_resource)
  172. en50221_app_ca_destroy(llci->stdcam.ca_resource);
  173. if (llci->stdcam.mmi_resource)
  174. en50221_app_mmi_destroy(llci->stdcam.mmi_resource);
  175. if (closefd)
  176. close(llci->cafd);
  177. free(llci);
  178. }
  179. static enum en50221_stdcam_status en50221_stdcam_llci_poll(struct en50221_stdcam *stdcam)
  180. {
  181. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam;
  182. switch(dvbca_get_cam_state(llci->cafd, llci->slotnum)) {
  183. case DVBCA_CAMSTATE_MISSING:
  184. if (llci->state != EN50221_STDCAM_CAM_NONE)
  185. llci_cam_removed(llci);
  186. break;
  187. case DVBCA_CAMSTATE_READY:
  188. if (llci->state == EN50221_STDCAM_CAM_NONE)
  189. llci_cam_added(llci);
  190. else if (llci->state == EN50221_STDCAM_CAM_INRESET)
  191. llci_cam_in_reset(llci);
  192. break;
  193. }
  194. // poll the stack
  195. int error;
  196. if ((error = en50221_tl_poll(llci->tl)) != 0) {
  197. print(LOG_LEVEL, ERROR, 1, "Error reported by stack:%i\n", en50221_tl_get_error(llci->tl));
  198. }
  199. // send date/time response
  200. if (llci->datetime_session_number != -1) {
  201. time_t cur_time = time(NULL);
  202. if (llci->datetime_response_interval && (cur_time > llci->datetime_next_send)) {
  203. en50221_app_datetime_send(llci->datetime_resource,
  204. llci->datetime_session_number,
  205. llci->datetime_dvbtime, 0);
  206. llci->datetime_next_send = cur_time + llci->datetime_response_interval;
  207. }
  208. }
  209. return llci->state;
  210. }
  211. static void llci_cam_added(struct en50221_stdcam_llci *llci)
  212. {
  213. // clear down any old structures
  214. if (llci->tl_slot_id != -1) {
  215. llci_cam_removed(llci);
  216. }
  217. // reset the CAM
  218. dvbca_reset(llci->cafd, llci->slotnum);
  219. llci->state = EN50221_STDCAM_CAM_INRESET;
  220. }
  221. static void llci_cam_in_reset(struct en50221_stdcam_llci *llci)
  222. {
  223. if (dvbca_get_cam_state(llci->cafd, llci->slotnum) != DVBCA_CAMSTATE_READY) {
  224. return;
  225. }
  226. // register the slot
  227. if ((llci->tl_slot_id = en50221_tl_register_slot(llci->tl, llci->cafd, llci->slotnum,
  228. LLCI_RESPONSE_TIMEOUT_MS, LLCI_POLL_DELAY_MS)) < 0) {
  229. llci->state = EN50221_STDCAM_CAM_BAD;
  230. return;
  231. }
  232. // create a new connection on the slot
  233. if (en50221_tl_new_tc(llci->tl, llci->tl_slot_id) < 0) {
  234. llci->state = EN50221_STDCAM_CAM_BAD;
  235. llci->tl_slot_id = -1;
  236. en50221_tl_destroy_slot(llci->tl, llci->tl_slot_id);
  237. return;
  238. }
  239. llci->state = EN50221_STDCAM_CAM_OK;
  240. }
  241. static void llci_cam_removed(struct en50221_stdcam_llci *llci)
  242. {
  243. if (llci->tl_slot_id != -1) {
  244. en50221_tl_destroy_slot(llci->tl, llci->tl_slot_id);
  245. llci->tl_slot_id = -1;
  246. llci->datetime_session_number = -1;
  247. llci->stdcam.ai_session_number = -1;
  248. llci->stdcam.ca_session_number = -1;
  249. llci->stdcam.mmi_session_number = -1;
  250. }
  251. llci->state = EN50221_STDCAM_CAM_NONE;
  252. }
  253. static int llci_lookup_callback(void *arg, uint8_t _slot_id, uint32_t requested_resource_id,
  254. en50221_sl_resource_callback *callback_out, void **arg_out,
  255. uint32_t *connected_resource_id)
  256. {
  257. struct en50221_app_public_resource_id resid;
  258. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
  259. (void) _slot_id;
  260. // decode the resource id
  261. if (!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) {
  262. return -1;
  263. }
  264. // try and find an instance of the resource
  265. uint32_t i;
  266. for(i=0; i<RESOURCE_IDS_COUNT; i++) {
  267. if ((resid.resource_class == llci->resources[i].resid.resource_class) &&
  268. (resid.resource_type == llci->resources[i].resid.resource_type)) {
  269. // limit sessions to certain resources
  270. switch(requested_resource_id) {
  271. case EN50221_APP_DATETIME_RESOURCEID:
  272. if (llci->datetime_session_number != -1)
  273. return -3;
  274. break;
  275. case EN50221_APP_AI_RESOURCEID:
  276. if (llci->stdcam.ai_session_number != -1)
  277. return -3;
  278. break;
  279. case EN50221_APP_CA_RESOURCEID:
  280. if (llci->stdcam.ca_session_number != -1)
  281. return -3;
  282. break;
  283. case EN50221_APP_MMI_RESOURCEID:
  284. if (llci->stdcam.mmi_session_number != -1)
  285. return -3;
  286. break;
  287. }
  288. // resource is ok.
  289. *callback_out = llci->resources[i].callback;
  290. *arg_out = llci->resources[i].arg;
  291. *connected_resource_id = llci->resources[i].binary_resource_id;
  292. return 0;
  293. }
  294. }
  295. return -1;
  296. }
  297. static int llci_session_callback(void *arg, int reason, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id)
  298. {
  299. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
  300. (void) _slot_id;
  301. switch(reason) {
  302. case S_SCALLBACK_REASON_CAMCONNECTED:
  303. if (resource_id == EN50221_APP_RM_RESOURCEID) {
  304. en50221_app_rm_enq(llci->rm_resource, session_number);
  305. } else if (resource_id == EN50221_APP_DATETIME_RESOURCEID) {
  306. llci->datetime_session_number = session_number;
  307. } else if (resource_id == EN50221_APP_AI_RESOURCEID) {
  308. en50221_app_ai_enquiry(llci->stdcam.ai_resource, session_number);
  309. llci->stdcam.ai_session_number = session_number;
  310. } else if (resource_id == EN50221_APP_CA_RESOURCEID) {
  311. en50221_app_ca_info_enq(llci->stdcam.ca_resource, session_number);
  312. llci->stdcam.ca_session_number = session_number;
  313. } else if (resource_id == EN50221_APP_MMI_RESOURCEID) {
  314. llci->stdcam.mmi_session_number = session_number;
  315. }
  316. break;
  317. case S_SCALLBACK_REASON_CLOSE:
  318. if (resource_id == EN50221_APP_MMI_RESOURCEID) {
  319. llci->stdcam.mmi_session_number = -1;
  320. } else if (resource_id == EN50221_APP_DATETIME_RESOURCEID) {
  321. llci->datetime_session_number = -1;
  322. } else if (resource_id == EN50221_APP_AI_RESOURCEID) {
  323. llci->stdcam.ai_session_number = -1;
  324. } else if (resource_id == EN50221_APP_CA_RESOURCEID) {
  325. llci->stdcam.ca_session_number = -1;
  326. } else if (resource_id == EN50221_APP_MMI_RESOURCEID) {
  327. llci->stdcam.mmi_session_number = -1;
  328. }
  329. break;
  330. }
  331. return 0;
  332. }
  333. static int llci_rm_enq_callback(void *arg, uint8_t _slot_id, uint16_t session_number)
  334. {
  335. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
  336. (void) _slot_id;
  337. if (en50221_app_rm_reply(llci->rm_resource, session_number, RESOURCE_IDS_COUNT, resource_ids)) {
  338. print(LOG_LEVEL, ERROR, 1, "Failed to send RM ENQ on slot %02x\n", _slot_id);
  339. }
  340. return 0;
  341. }
  342. 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)
  343. {
  344. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
  345. (void) _slot_id;
  346. (void) resource_id_count;
  347. (void) _resource_ids;
  348. if (en50221_app_rm_changed(llci->rm_resource, session_number)) {
  349. print(LOG_LEVEL, ERROR, 1, "Failed to send RM REPLY on slot %02x\n", _slot_id);
  350. }
  351. return 0;
  352. }
  353. static int llci_rm_changed_callback(void *arg, uint8_t _slot_id, uint16_t session_number)
  354. {
  355. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
  356. (void) _slot_id;
  357. if (en50221_app_rm_enq(llci->rm_resource, session_number)) {
  358. print(LOG_LEVEL, ERROR, 1, "Failed to send RM CHANGED on slot %02x\n", _slot_id);
  359. }
  360. return 0;
  361. }
  362. static int llci_datetime_enquiry_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint8_t response_interval)
  363. {
  364. struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg;
  365. (void) _slot_id;
  366. llci->datetime_response_interval = response_interval;
  367. llci->datetime_next_send = 0;
  368. if (response_interval) {
  369. llci->datetime_next_send = time(NULL) + response_interval;
  370. }
  371. en50221_app_datetime_send(llci->datetime_resource, session_number, llci->datetime_dvbtime, 0);
  372. return 0;
  373. }