test-app.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. /*
  2. en50221 encoder An implementation for libdvb
  3. an implementation for the en50221 transport layer
  4. Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
  5. Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
  6. Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
  7. This library is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU Lesser General Public License as
  9. published by the Free Software Foundation; either version 2.1 of
  10. the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <unistd.h>
  22. #include <libdvben50221/en50221_session.h>
  23. #include <libdvben50221/en50221_app_utils.h>
  24. #include <libdvben50221/en50221_app_ai.h>
  25. #include <libdvben50221/en50221_app_auth.h>
  26. #include <libdvben50221/en50221_app_ca.h>
  27. #include <libdvben50221/en50221_app_datetime.h>
  28. #include <libdvben50221/en50221_app_dvb.h>
  29. #include <libdvben50221/en50221_app_epg.h>
  30. #include <libdvben50221/en50221_app_lowspeed.h>
  31. #include <libdvben50221/en50221_app_mmi.h>
  32. #include <libdvben50221/en50221_app_rm.h>
  33. #include <libdvben50221/en50221_app_smartcard.h>
  34. #include <libdvben50221/en50221_app_teletext.h>
  35. #include <libdvbapi/dvbca.h>
  36. #include <pthread.h>
  37. #include <libdvbcfg/dvbcfg_zapchannel.h>
  38. #include <libdvbapi/dvbdemux.h>
  39. #include <libucsi/section.h>
  40. #include <libucsi/mpeg/section.h>
  41. #define DEFAULT_SLOT 0
  42. #define MAX_SESSIONS 256
  43. #define MAX_TC 32
  44. void *stackthread_func(void* arg);
  45. void *pmtthread_func(void* arg);
  46. int test_lookup_callback(void *arg, uint8_t slot_id, uint32_t requested_resource_id,
  47. en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id);
  48. int test_session_callback(void *arg, int reason, uint8_t slot_id, uint16_t session_number, uint32_t resource_id);
  49. int test_datetime_enquiry_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t response_interval);
  50. int test_rm_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number);
  51. int test_rm_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *resource_ids);
  52. int test_rm_changed_callback(void *arg, uint8_t slot_id, uint16_t session_number);
  53. int test_ai_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  54. uint8_t application_type, uint16_t application_manufacturer,
  55. uint16_t manufacturer_code, uint8_t menu_string_length,
  56. uint8_t *menu_string);
  57. int test_ca_info_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids);
  58. int test_ca_pmt_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  59. struct en50221_app_pmt_reply *reply, uint32_t reply_size);
  60. int test_mmi_close_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay);
  61. int test_mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  62. uint8_t cmd_id, uint8_t mmi_mode);
  63. int test_mmi_keypad_control_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  64. uint8_t cmd_id, uint8_t *key_codes, uint32_t key_codes_count);
  65. int test_mmi_subtitle_segment_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  66. uint8_t *segment, uint32_t segment_size);
  67. int test_mmi_scene_end_mark_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  68. uint8_t decoder_continue_flag, uint8_t scene_reveal_flag,
  69. uint8_t send_scene_done, uint8_t scene_tag);
  70. int test_mmi_scene_control_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  71. uint8_t decoder_continue_flag, uint8_t scene_reveal_flag,
  72. uint8_t scene_tag);
  73. int test_mmi_subtitle_download_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  74. uint8_t *segment, uint32_t segment_size);
  75. int test_mmi_flush_download_callback(void *arg, uint8_t slot_id, uint16_t session_number);
  76. int test_mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  77. uint8_t blind_answer, uint8_t expected_answer_length,
  78. uint8_t *text, uint32_t text_size);
  79. int test_mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  80. struct en50221_app_mmi_text *title,
  81. struct en50221_app_mmi_text *sub_title,
  82. struct en50221_app_mmi_text *bottom,
  83. uint32_t item_count, struct en50221_app_mmi_text *items,
  84. uint32_t item_raw_length, uint8_t *items_raw);
  85. int test_app_mmi_list_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  86. struct en50221_app_mmi_text *title,
  87. struct en50221_app_mmi_text *sub_title,
  88. struct en50221_app_mmi_text *bottom,
  89. uint32_t item_count, struct en50221_app_mmi_text *items,
  90. uint32_t item_raw_length, uint8_t *items_raw);
  91. struct section_ext *read_section_ext(char *buf, int buflen, int adapter, int demux, int pid, int table_id);
  92. int adapterid;
  93. int shutdown_stackthread = 0;
  94. int shutdown_pmtthread = 0;
  95. int in_menu = 0;
  96. int in_enq = 0;
  97. int ca_connected = 0;
  98. int pmt_pid = -1;
  99. int ca_session_number = 0;
  100. // instances of resources we actually implement here
  101. struct en50221_app_rm *rm_resource;
  102. struct en50221_app_datetime *datetime_resource;
  103. struct en50221_app_ai *ai_resource;
  104. struct en50221_app_ca *ca_resource;
  105. struct en50221_app_mmi *mmi_resource;
  106. // lookup table used in resource manager implementation
  107. struct resource {
  108. struct en50221_app_public_resource_id resid;
  109. uint32_t binary_resource_id;
  110. en50221_sl_resource_callback callback;
  111. void *arg;
  112. };
  113. struct resource resources[20];
  114. int resources_count = 0;
  115. // this contains all known resource ids so we can see if the cam asks for something exotic
  116. uint32_t resource_ids[] = { EN50221_APP_TELETEXT_RESOURCEID,
  117. EN50221_APP_SMARTCARD_RESOURCEID(1),
  118. EN50221_APP_RM_RESOURCEID,
  119. EN50221_APP_MMI_RESOURCEID,
  120. EN50221_APP_LOWSPEED_RESOURCEID(1,1),
  121. EN50221_APP_EPG_RESOURCEID(1),
  122. EN50221_APP_DVB_RESOURCEID,
  123. EN50221_APP_CA_RESOURCEID,
  124. EN50221_APP_DATETIME_RESOURCEID,
  125. EN50221_APP_AUTH_RESOURCEID,
  126. EN50221_APP_AI_RESOURCEID, };
  127. int resource_ids_count = sizeof(resource_ids)/4;
  128. uint16_t ai_session_numbers[5];
  129. uint16_t mmi_session_number;
  130. int main(int argc, char * argv[])
  131. {
  132. pthread_t stackthread;
  133. pthread_t pmtthread;
  134. struct en50221_app_send_functions sendfuncs;
  135. if ((argc < 2) || (argc > 3)) {
  136. fprintf(stderr, "Syntax: test-app <adapterid> [<pmtpid>]\n");
  137. exit(1);
  138. }
  139. adapterid = atoi(argv[1]);
  140. if (argc == 3) {
  141. if (sscanf(argv[2], "%i", &pmt_pid) != 1) {
  142. fprintf(stderr, "Unable to parse PMT PID\n");
  143. exit(1);
  144. }
  145. }
  146. // create transport layer
  147. struct en50221_transport_layer *tl = en50221_tl_create(5, 32);
  148. if (tl == NULL) {
  149. fprintf(stderr, "Failed to create transport layer\n");
  150. exit(1);
  151. }
  152. // find CAMs
  153. int cafd;
  154. if (((cafd = dvbca_open(adapterid, 0)) < 0) || (dvbca_get_cam_state(cafd, DEFAULT_SLOT) == DVBCA_CAMSTATE_MISSING)) {
  155. fprintf(stderr, "Unable to open CAM on adapter %i\n", adapterid);
  156. exit(1);
  157. }
  158. // reset it and wait
  159. dvbca_reset(cafd, DEFAULT_SLOT);
  160. printf("Found a CAM on adapter%i... waiting...\n", adapterid);
  161. while(dvbca_get_cam_state(cafd, DEFAULT_SLOT) != DVBCA_CAMSTATE_READY) {
  162. usleep(1000);
  163. }
  164. // register it with the CA stack
  165. int slot_id = 0;
  166. if ((slot_id = en50221_tl_register_slot(tl, cafd, DEFAULT_SLOT, 1000, 100)) < 0) {
  167. fprintf(stderr, "Slot registration failed\n");
  168. exit(1);
  169. }
  170. printf("slotid: %i\n", slot_id);
  171. // create session layer
  172. struct en50221_session_layer *sl = en50221_sl_create(tl, 256);
  173. if (sl == NULL) {
  174. fprintf(stderr, "Failed to create session layer\n");
  175. exit(1);
  176. }
  177. // create the sendfuncs
  178. sendfuncs.arg = sl;
  179. sendfuncs.send_data = (en50221_send_data) en50221_sl_send_data;
  180. sendfuncs.send_datav = (en50221_send_datav) en50221_sl_send_datav;
  181. // create the resource manager resource
  182. rm_resource = en50221_app_rm_create(&sendfuncs);
  183. en50221_app_decode_public_resource_id(&resources[resources_count].resid, EN50221_APP_RM_RESOURCEID);
  184. resources[resources_count].binary_resource_id = EN50221_APP_RM_RESOURCEID;
  185. resources[resources_count].callback = (en50221_sl_resource_callback) en50221_app_rm_message;
  186. resources[resources_count].arg = rm_resource;
  187. en50221_app_rm_register_enq_callback(rm_resource, test_rm_enq_callback, NULL);
  188. en50221_app_rm_register_reply_callback(rm_resource, test_rm_reply_callback, NULL);
  189. en50221_app_rm_register_changed_callback(rm_resource, test_rm_changed_callback, NULL);
  190. resources_count++;
  191. // create the datetime resource
  192. datetime_resource = en50221_app_datetime_create(&sendfuncs);
  193. en50221_app_decode_public_resource_id(&resources[resources_count].resid, EN50221_APP_DATETIME_RESOURCEID);
  194. resources[resources_count].binary_resource_id = EN50221_APP_DATETIME_RESOURCEID;
  195. resources[resources_count].callback = (en50221_sl_resource_callback) en50221_app_datetime_message;
  196. resources[resources_count].arg = datetime_resource;
  197. en50221_app_datetime_register_enquiry_callback(datetime_resource, test_datetime_enquiry_callback, NULL);
  198. resources_count++;
  199. // create the application information resource
  200. ai_resource = en50221_app_ai_create(&sendfuncs);
  201. en50221_app_decode_public_resource_id(&resources[resources_count].resid, EN50221_APP_AI_RESOURCEID);
  202. resources[resources_count].binary_resource_id = EN50221_APP_AI_RESOURCEID;
  203. resources[resources_count].callback = (en50221_sl_resource_callback) en50221_app_ai_message;
  204. resources[resources_count].arg = ai_resource;
  205. en50221_app_ai_register_callback(ai_resource, test_ai_callback, NULL);
  206. resources_count++;
  207. // create the CA resource
  208. ca_resource = en50221_app_ca_create(&sendfuncs);
  209. en50221_app_decode_public_resource_id(&resources[resources_count].resid, EN50221_APP_CA_RESOURCEID);
  210. resources[resources_count].binary_resource_id = EN50221_APP_CA_RESOURCEID;
  211. resources[resources_count].callback = (en50221_sl_resource_callback) en50221_app_ca_message;
  212. resources[resources_count].arg = ca_resource;
  213. en50221_app_ca_register_info_callback(ca_resource, test_ca_info_callback, NULL);
  214. en50221_app_ca_register_pmt_reply_callback(ca_resource, test_ca_pmt_reply_callback, NULL);
  215. resources_count++;
  216. // create the MMI resource
  217. mmi_resource = en50221_app_mmi_create(&sendfuncs);
  218. en50221_app_decode_public_resource_id(&resources[resources_count].resid, EN50221_APP_MMI_RESOURCEID);
  219. resources[resources_count].binary_resource_id = EN50221_APP_MMI_RESOURCEID;
  220. resources[resources_count].callback = (en50221_sl_resource_callback) en50221_app_mmi_message;
  221. resources[resources_count].arg = mmi_resource;
  222. en50221_app_mmi_register_close_callback(mmi_resource, test_mmi_close_callback, NULL);
  223. en50221_app_mmi_register_display_control_callback(mmi_resource, test_mmi_display_control_callback, NULL);
  224. en50221_app_mmi_register_keypad_control_callback(mmi_resource, test_mmi_keypad_control_callback, NULL);
  225. en50221_app_mmi_register_subtitle_segment_callback(mmi_resource, test_mmi_subtitle_segment_callback, NULL);
  226. en50221_app_mmi_register_scene_end_mark_callback(mmi_resource, test_mmi_scene_end_mark_callback, NULL);
  227. en50221_app_mmi_register_scene_control_callback(mmi_resource, test_mmi_scene_control_callback, NULL);
  228. en50221_app_mmi_register_subtitle_download_callback(mmi_resource, test_mmi_subtitle_download_callback, NULL);
  229. en50221_app_mmi_register_flush_download_callback(mmi_resource, test_mmi_flush_download_callback, NULL);
  230. en50221_app_mmi_register_enq_callback(mmi_resource, test_mmi_enq_callback, NULL);
  231. en50221_app_mmi_register_menu_callback(mmi_resource, test_mmi_menu_callback, NULL);
  232. en50221_app_mmi_register_list_callback(mmi_resource, test_app_mmi_list_callback, NULL);
  233. resources_count++;
  234. // start another thread running the stack
  235. pthread_create(&stackthread, NULL, stackthread_func, tl);
  236. // start another thread parsing PMT
  237. if (pmt_pid != -1) {
  238. pthread_create(&pmtthread, NULL, pmtthread_func, tl);
  239. }
  240. // register callbacks
  241. en50221_sl_register_lookup_callback(sl, test_lookup_callback, sl);
  242. en50221_sl_register_session_callback(sl, test_session_callback, sl);
  243. // create a new connection on each slot
  244. int tc = en50221_tl_new_tc(tl, slot_id);
  245. printf("tcid: %i\n", tc);
  246. printf("Press a key to enter menu\n");
  247. getchar();
  248. en50221_app_ai_entermenu(ai_resource, ai_session_numbers[slot_id]);
  249. // wait
  250. char tmp[256];
  251. while(1) {
  252. fgets(tmp, sizeof(tmp), stdin);
  253. int choice = atoi(tmp);
  254. if (in_menu) {
  255. en50221_app_mmi_menu_answ(mmi_resource, mmi_session_number, choice);
  256. in_menu = 0;
  257. }
  258. if (in_enq) {
  259. uint32_t i;
  260. uint32_t len = strlen(tmp);
  261. for(i=0; i< len; i++) {
  262. if (!isdigit(tmp[i])) {
  263. len = i;
  264. break;
  265. }
  266. }
  267. en50221_app_mmi_answ(mmi_resource, mmi_session_number, MMI_ANSW_ID_ANSWER, (uint8_t*) tmp, len);
  268. in_enq = 0;
  269. }
  270. }
  271. printf("Press a key to exit\n");
  272. getchar();
  273. // destroy slots
  274. en50221_tl_destroy_slot(tl, slot_id);
  275. shutdown_stackthread = 1;
  276. shutdown_pmtthread = 1;
  277. pthread_join(stackthread, NULL);
  278. if (pmt_pid != -1) {
  279. pthread_join(pmtthread, NULL);
  280. }
  281. // destroy session layer
  282. en50221_sl_destroy(sl);
  283. // destroy transport layer
  284. en50221_tl_destroy(tl);
  285. return 0;
  286. }
  287. int test_lookup_callback(void *arg, uint8_t slot_id, uint32_t requested_resource_id,
  288. en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id)
  289. {
  290. struct en50221_app_public_resource_id resid;
  291. (void)arg;
  292. // decode the resource id
  293. if (en50221_app_decode_public_resource_id(&resid, requested_resource_id)) {
  294. printf("%02x:Public resource lookup callback %i %i %i\n", slot_id,
  295. resid.resource_class, resid.resource_type, resid.resource_version);
  296. } else {
  297. printf("%02x:Private resource lookup callback %08x\n", slot_id, requested_resource_id);
  298. return -1;
  299. }
  300. // FIXME: need better comparison
  301. // FIXME: return resourceid we actually connected to
  302. // try and find an instance of the resource
  303. int i;
  304. for(i=0; i<resources_count; i++) {
  305. if ((resid.resource_class == resources[i].resid.resource_class) &&
  306. (resid.resource_type == resources[i].resid.resource_type)) {
  307. *callback_out = resources[i].callback;
  308. *arg_out = resources[i].arg;
  309. *connected_resource_id = resources[i].binary_resource_id;
  310. return 0;
  311. }
  312. }
  313. return -1;
  314. }
  315. int test_session_callback(void *arg, int reason, uint8_t slot_id, uint16_t session_number, uint32_t resource_id)
  316. {
  317. (void)arg;
  318. switch(reason) {
  319. case S_SCALLBACK_REASON_CAMCONNECTING:
  320. printf("%02x:CAM connecting to resource %08x, session_number %i\n",
  321. slot_id, resource_id, session_number);
  322. break;
  323. case S_SCALLBACK_REASON_CAMCONNECTED:
  324. printf("%02x:CAM successfully connected to resource %08x, session_number %i\n",
  325. slot_id, resource_id, session_number);
  326. if (resource_id == EN50221_APP_RM_RESOURCEID) {
  327. en50221_app_rm_enq(rm_resource, session_number);
  328. } else if (resource_id == EN50221_APP_AI_RESOURCEID) {
  329. en50221_app_ai_enquiry(ai_resource, session_number);
  330. } else if (resource_id == EN50221_APP_CA_RESOURCEID) {
  331. en50221_app_ca_info_enq(ca_resource, session_number);
  332. ca_session_number = session_number;
  333. }
  334. break;
  335. case S_SCALLBACK_REASON_CAMCONNECTFAIL:
  336. printf("%02x:CAM on failed to connect to resource %08x\n", slot_id, resource_id);
  337. break;
  338. case S_SCALLBACK_REASON_CONNECTED:
  339. printf("%02x:Host connection to resource %08x connected successfully, session_number %i\n",
  340. slot_id, resource_id, session_number);
  341. break;
  342. case S_SCALLBACK_REASON_CONNECTFAIL:
  343. printf("%02x:Host connection to resource %08x failed, session_number %i\n",
  344. slot_id, resource_id, session_number);
  345. break;
  346. case S_SCALLBACK_REASON_CLOSE:
  347. printf("%02x:Connection to resource %08x, session_number %i closed\n",
  348. slot_id, resource_id, session_number);
  349. break;
  350. case S_SCALLBACK_REASON_TC_CONNECT:
  351. printf("%02x:Host originated transport connection %i connected\n", slot_id, session_number);
  352. break;
  353. case S_SCALLBACK_REASON_TC_CAMCONNECT:
  354. printf("%02x:CAM originated transport connection %i connected\n", slot_id, session_number);
  355. break;
  356. }
  357. return 0;
  358. }
  359. int test_rm_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number)
  360. {
  361. (void)arg;
  362. printf("%02x:%s\n", slot_id, __func__);
  363. if (en50221_app_rm_reply(rm_resource, session_number, resource_ids_count, resource_ids)) {
  364. printf("%02x:Failed to send reply to ENQ\n", slot_id);
  365. }
  366. return 0;
  367. }
  368. int test_rm_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *_resource_ids)
  369. {
  370. (void)arg;
  371. printf("%02x:%s\n", slot_id, __func__);
  372. uint32_t i;
  373. for(i=0; i< resource_id_count; i++) {
  374. printf(" CAM provided resource id: %08x\n", _resource_ids[i]);
  375. }
  376. if (en50221_app_rm_changed(rm_resource, session_number)) {
  377. printf("%02x:Failed to send REPLY\n", slot_id);
  378. }
  379. return 0;
  380. }
  381. int test_rm_changed_callback(void *arg, uint8_t slot_id, uint16_t session_number)
  382. {
  383. (void)arg;
  384. printf("%02x:%s\n", slot_id, __func__);
  385. if (en50221_app_rm_enq(rm_resource, session_number)) {
  386. printf("%02x:Failed to send ENQ\n", slot_id);
  387. }
  388. return 0;
  389. }
  390. int test_datetime_enquiry_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t response_interval)
  391. {
  392. (void)arg;
  393. printf("%02x:%s\n", slot_id, __func__);
  394. printf(" response_interval:%i\n", response_interval);
  395. if (en50221_app_datetime_send(datetime_resource, session_number, time(NULL), -1)) {
  396. printf("%02x:Failed to send datetime\n", slot_id);
  397. }
  398. return 0;
  399. }
  400. int test_ai_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  401. uint8_t application_type, uint16_t application_manufacturer,
  402. uint16_t manufacturer_code, uint8_t menu_string_length,
  403. uint8_t *menu_string)
  404. {
  405. (void)arg;
  406. printf("%02x:%s\n", slot_id, __func__);
  407. printf(" Application type: %02x\n", application_type);
  408. printf(" Application manufacturer: %04x\n", application_manufacturer);
  409. printf(" Manufacturer code: %04x\n", manufacturer_code);
  410. printf(" Menu string: %.*s\n", menu_string_length, menu_string);
  411. ai_session_numbers[slot_id] = session_number;
  412. return 0;
  413. }
  414. int test_ca_info_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids)
  415. {
  416. (void)arg;
  417. (void)session_number;
  418. printf("%02x:%s\n", slot_id, __func__);
  419. uint32_t i;
  420. for(i=0; i< ca_id_count; i++) {
  421. printf(" Supported CA ID: %04x\n", ca_ids[i]);
  422. }
  423. ca_connected = 1;
  424. return 0;
  425. }
  426. int test_ca_pmt_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  427. struct en50221_app_pmt_reply *reply, uint32_t reply_size)
  428. {
  429. (void)arg;
  430. (void)session_number;
  431. (void)reply;
  432. (void)reply_size;
  433. printf("%02x:%s\n", slot_id, __func__);
  434. return 0;
  435. }
  436. int test_mmi_close_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay)
  437. {
  438. (void)arg;
  439. (void)session_number;
  440. printf("%02x:%s\n", slot_id, __func__);
  441. printf(" cmd_id: %02x\n", cmd_id);
  442. printf(" delay: %02x\n", delay);
  443. return 0;
  444. }
  445. int test_mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  446. uint8_t cmd_id, uint8_t mmi_mode)
  447. {
  448. (void)arg;
  449. (void)session_number;
  450. printf("%02x:%s\n", slot_id, __func__);
  451. printf(" cmd_id: %02x\n", cmd_id);
  452. printf(" mode: %02x\n", mmi_mode);
  453. if (cmd_id == MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) {
  454. struct en50221_app_mmi_display_reply_details details;
  455. details.u.mode_ack.mmi_mode = mmi_mode;
  456. if (en50221_app_mmi_display_reply(mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK, &details)) {
  457. printf("%02x:Failed to send mode ack\n", slot_id);
  458. }
  459. }
  460. return 0;
  461. }
  462. int test_mmi_keypad_control_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  463. uint8_t cmd_id, uint8_t *key_codes, uint32_t key_codes_count)
  464. {
  465. (void)arg;
  466. (void)session_number;
  467. (void)cmd_id;
  468. (void)key_codes;
  469. (void)key_codes_count;
  470. printf("%02x:%s\n", slot_id, __func__);
  471. return 0;
  472. }
  473. int test_mmi_subtitle_segment_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  474. uint8_t *segment, uint32_t segment_size)
  475. {
  476. (void)arg;
  477. (void)session_number;
  478. (void)segment;
  479. (void)segment_size;
  480. printf("%02x:%s\n", slot_id, __func__);
  481. return 0;
  482. }
  483. int test_mmi_scene_end_mark_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  484. uint8_t decoder_continue_flag, uint8_t scene_reveal_flag,
  485. uint8_t send_scene_done, uint8_t scene_tag)
  486. {
  487. (void)arg;
  488. (void)session_number;
  489. (void)decoder_continue_flag;
  490. (void)scene_reveal_flag;
  491. (void)send_scene_done;
  492. (void)scene_tag;
  493. printf("%02x:%s\n", slot_id, __func__);
  494. return 0;
  495. }
  496. int test_mmi_scene_control_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  497. uint8_t decoder_continue_flag, uint8_t scene_reveal_flag,
  498. uint8_t scene_tag)
  499. {
  500. (void)arg;
  501. (void)session_number;
  502. (void)decoder_continue_flag;
  503. (void)scene_reveal_flag;
  504. (void)scene_tag;
  505. printf("%02x:%s\n", slot_id, __func__);
  506. return 0;
  507. }
  508. int test_mmi_subtitle_download_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  509. uint8_t *segment, uint32_t segment_size)
  510. {
  511. (void)arg;
  512. (void)session_number;
  513. (void)segment;
  514. (void)segment_size;
  515. printf("%02x:%s\n", slot_id, __func__);
  516. return 0;
  517. }
  518. int test_mmi_flush_download_callback(void *arg, uint8_t slot_id, uint16_t session_number)
  519. {
  520. (void)arg;
  521. (void)session_number;
  522. printf("%02x:%s\n", slot_id, __func__);
  523. return 0;
  524. }
  525. int test_mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  526. uint8_t blind_answer, uint8_t expected_answer_length,
  527. uint8_t *text, uint32_t text_size)
  528. {
  529. (void)arg;
  530. (void)text;
  531. (void)text_size;
  532. printf("%02x:%s\n", slot_id, __func__);
  533. printf(" blind: %i\n", blind_answer);
  534. printf(" expected_answer_length: %i\n", expected_answer_length);
  535. mmi_session_number = session_number;
  536. in_enq = 1;
  537. return 0;
  538. }
  539. int test_mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  540. struct en50221_app_mmi_text *title,
  541. struct en50221_app_mmi_text *sub_title,
  542. struct en50221_app_mmi_text *bottom,
  543. uint32_t item_count, struct en50221_app_mmi_text *items,
  544. uint32_t item_raw_length, uint8_t *items_raw)
  545. {
  546. (void)arg;
  547. (void)items_raw;
  548. printf("%02x:%s\n", slot_id, __func__);
  549. printf(" title: %.*s\n", title->text_length, title->text);
  550. printf(" sub_title: %.*s\n", sub_title->text_length, sub_title->text);
  551. printf(" bottom: %.*s\n", bottom->text_length, bottom->text);
  552. uint32_t i;
  553. for(i=0; i< item_count; i++) {
  554. printf(" item %i: %.*s\n", i+1, items[i].text_length, items[i].text);
  555. }
  556. printf(" raw_length: %i\n", item_raw_length);
  557. mmi_session_number = session_number;
  558. in_menu = 1;
  559. return 0;
  560. }
  561. int test_app_mmi_list_callback(void *arg, uint8_t slot_id, uint16_t session_number,
  562. struct en50221_app_mmi_text *title,
  563. struct en50221_app_mmi_text *sub_title,
  564. struct en50221_app_mmi_text *bottom,
  565. uint32_t item_count, struct en50221_app_mmi_text *items,
  566. uint32_t item_raw_length, uint8_t *items_raw)
  567. {
  568. (void)arg;
  569. (void)items_raw;
  570. (void)arg;
  571. printf("%02x:%s\n", slot_id, __func__);
  572. printf(" title: %.*s\n", title->text_length, title->text);
  573. printf(" sub_title: %.*s\n", sub_title->text_length, sub_title->text);
  574. printf(" bottom: %.*s\n", bottom->text_length, bottom->text);
  575. uint32_t i;
  576. for(i=0; i< item_count; i++) {
  577. printf(" item %i: %.*s\n", i+1, items[i].text_length, items[i].text);
  578. }
  579. printf(" raw_length: %i\n", item_raw_length);
  580. mmi_session_number = session_number;
  581. in_menu = 1;
  582. return 0;
  583. }
  584. void *stackthread_func(void* arg) {
  585. struct en50221_transport_layer *tl = arg;
  586. int lasterror = 0;
  587. while(!shutdown_stackthread) {
  588. int error;
  589. if ((error = en50221_tl_poll(tl)) != 0) {
  590. if (error != lasterror) {
  591. fprintf(stderr, "Error reported by stack slot:%i error:%i\n",
  592. en50221_tl_get_error_slot(tl),
  593. en50221_tl_get_error(tl));
  594. }
  595. lasterror = error;
  596. }
  597. }
  598. shutdown_stackthread = 0;
  599. return 0;
  600. }
  601. void *pmtthread_func(void* arg) {
  602. (void)arg;
  603. char buf[4096];
  604. uint8_t capmt[4096];
  605. int pmtversion = -1;
  606. while(!shutdown_pmtthread) {
  607. if (!ca_connected) {
  608. sleep(1);
  609. continue;
  610. }
  611. // read the PMT
  612. struct section_ext *section_ext = read_section_ext(buf, sizeof(buf), adapterid, 0, pmt_pid, stag_mpeg_program_map);
  613. if (section_ext == NULL) {
  614. fprintf(stderr, "Failed to read PMT\n");
  615. exit(1);
  616. }
  617. struct mpeg_pmt_section *pmt = mpeg_pmt_section_codec(section_ext);
  618. if (pmt == NULL) {
  619. fprintf(stderr, "Bad PMT received\n");
  620. exit(1);
  621. }
  622. if (pmt->head.version_number == pmtversion) {
  623. continue;
  624. }
  625. // translate it into a CA PMT
  626. int listmgmt = CA_LIST_MANAGEMENT_ONLY;
  627. if (pmtversion != -1) {
  628. listmgmt = CA_LIST_MANAGEMENT_UPDATE;
  629. }
  630. int size;
  631. if ((size = en50221_ca_format_pmt(pmt,
  632. capmt,
  633. sizeof(capmt),
  634. listmgmt,
  635. 0,
  636. CA_PMT_CMD_ID_OK_DESCRAMBLING)) < 0) {
  637. fprintf(stderr, "Failed to format CA PMT object\n");
  638. exit(1);
  639. }
  640. // set it
  641. if (en50221_app_ca_pmt(ca_resource, ca_session_number, capmt, size)) {
  642. fprintf(stderr, "Failed to send CA PMT object\n");
  643. exit(1);
  644. }
  645. pmtversion = pmt->head.version_number;
  646. }
  647. shutdown_pmtthread = 0;
  648. return 0;
  649. }
  650. struct section_ext *read_section_ext(char *buf, int buflen, int adapter, int demux, int pid, int table_id)
  651. {
  652. int demux_fd = -1;
  653. uint8_t filter[18];
  654. uint8_t mask[18];
  655. int size;
  656. struct section *section;
  657. struct section_ext *result = NULL;
  658. // open the demuxer
  659. if ((demux_fd = dvbdemux_open_demux(adapter, demux, 0)) < 0) {
  660. goto exit;
  661. }
  662. // create a section filter
  663. memset(filter, 0, sizeof(filter));
  664. memset(mask, 0, sizeof(mask));
  665. filter[0] = table_id;
  666. mask[0] = 0xFF;
  667. if (dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) {
  668. goto exit;
  669. }
  670. // read the section
  671. if ((size = read(demux_fd, buf, buflen)) < 0) {
  672. goto exit;
  673. }
  674. // parse it as a section
  675. section = section_codec((uint8_t*) buf, size);
  676. if (section == NULL) {
  677. goto exit;
  678. }
  679. // parse it as a section_ext
  680. result = section_ext_decode(section, 0);
  681. exit:
  682. if (demux_fd != -1)
  683. close(demux_fd);
  684. return result;
  685. }