OSDN Git Service

initial files
[iptd/iPTd_R3.git] / src / ry0 / device / PT1 / PT1Tuner.cpp
1 //\r
2 // PT1Tuner.cpp\r
3 //\r
4 \r
5 #include <io.h>\r
6 #include <new>\r
7 #include <share.h>\r
8 #include <winsock2.h>\r
9 \r
10 #define DBG_LEVEL 0\r
11 #include "Raym/Log.h"\r
12 #include "ry0/device/PT1/PT1Tuner.h"\r
13 #include "ry0/device/PT1/PT1Core.h"\r
14 \r
15 namespace ry0\r
16 {\r
17 namespace device\r
18 {\r
19 namespace PT1\r
20 {\r
21 \r
22 static HMODULE module_ = NULL; // for scan\r
23 \r
24 PT1Tuner::PT1Tuner(PT1Core *core, uint32_t tuner, HMODULE multi2_dll)\r
25 {\r
26     DebugLog2("PT1Tuner::PT1Tuner()\n");\r
27 \r
28     InitializeCriticalSection(&_cs);\r
29 \r
30     EnterCriticalSection(&_cs);\r
31 \r
32     _core = core;\r
33     _tuner = tuner;\r
34     _listener = NULL;\r
35     memset(_name, sizeof(_name), 0x00);\r
36     _channel = -1;\r
37     _recording = false;\r
38     _recfd = -1;\r
39     _locked = false;\r
40 \r
41     _b25 = NULL;\r
42     _bcas = NULL;\r
43 \r
44     while (multi2_dll != NULL)\r
45     {\r
46         // create "B25" & initialize\r
47         ARIB_STD_B25 *(*func_b25)();\r
48         func_b25 = reinterpret_cast<ARIB_STD_B25 *(*)()>(::GetProcAddress(multi2_dll, "create_arib_std_b25"));\r
49         if (func_b25 == NULL)\r
50         {\r
51             DebugLog0("b25 func address get ng.");\r
52             break;\r
53         }\r
54         _b25 = func_b25();\r
55         if (_b25 == NULL)\r
56         {\r
57             DebugLog0("b25 create ng.");\r
58             break;\r
59         }\r
60 \r
61         int ret = _b25->set_multi2_round(_b25, 4);\r
62         if (ret != 0)\r
63         {\r
64             _b25->release(_b25);\r
65             _b25 = NULL;\r
66             DebugLog0("b25 set multi2 round ng. %d", ret);\r
67             break;\r
68         }\r
69 \r
70         ret = _b25->set_strip(_b25, 0);\r
71         if (ret != 0)\r
72         {\r
73             _b25->release(_b25);\r
74             _b25 = NULL;\r
75             DebugLog0("b25 set strip ng. %d", ret);\r
76             break;\r
77         }\r
78 \r
79         ret = _b25->set_emm_proc(_b25, 0);\r
80         if (ret != 0)\r
81         {\r
82             _b25->release(_b25);\r
83             _b25 = NULL;\r
84             DebugLog0("b25 set emm proc ng. %d", ret);\r
85             break;\r
86         }\r
87 \r
88         // create "B-CAS" & initialize\r
89         B_CAS_CARD *(*func_bcas)();\r
90         func_bcas = reinterpret_cast<B_CAS_CARD *(*)()>(::GetProcAddress(multi2_dll, "create_b_cas_card"));\r
91         if (func_bcas == NULL)\r
92         {\r
93             // 関数アドレス取得NG\r
94             DebugLog0("bcas func address get ng.");\r
95             break;\r
96         }\r
97         _bcas = func_bcas();\r
98         if (_bcas == NULL)\r
99         {\r
100             _b25->release(_b25);\r
101             _b25 = NULL;\r
102             DebugLog0("bcas create ng.");\r
103             break;\r
104         }\r
105 \r
106         ret = _bcas->init(_bcas);\r
107         if (ret != 0)\r
108         {\r
109             _b25->release(_b25);\r
110             _b25 = NULL;\r
111             _bcas->release(_bcas);\r
112             _bcas = NULL;\r
113             DebugLog0("bcas init ng. %d", ret);\r
114             break;\r
115         }\r
116         ret = _b25->set_b_cas_card(_b25, _bcas);\r
117         if (ret != 0)\r
118         {\r
119             _b25->release(_b25);\r
120             _b25 = NULL;\r
121             _bcas->release(_bcas);\r
122             _bcas = NULL;\r
123             DebugLog0("b25 set bcas card ng. %d", ret);\r
124             break;\r
125         }\r
126 \r
127         DebugLog2("b25 & bcas initialize success.");\r
128         break;\r
129     }\r
130 \r
131 //    WSADATA wsaData;\r
132 //    WSAStartup(MAKEWORD(2,0), &wsaData);\r
133 \r
134     // temporary\r
135     if ((_udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)\r
136     {\r
137         DebugLog0("fatal error occured: socket(): 0x%08x", WSAGetLastError());\r
138         abort();\r
139     }\r
140     struct sockaddr_in own_addr;\r
141     own_addr.sin_family = AF_INET;\r
142     own_addr.sin_port = 0;\r
143     own_addr.sin_addr.s_addr = INADDR_ANY;\r
144     if (bind(_udp, (struct sockaddr *)&own_addr, sizeof(own_addr)) == SOCKET_ERROR)\r
145     {\r
146         DebugLog0("fatal error occured: bind()\n");\r
147         abort();\r
148     }\r
149     _dst_addr.sin_family = AF_UNSPEC;\r
150 \r
151     LeaveCriticalSection(&_cs);\r
152 }\r
153 \r
154 PT1Tuner::~PT1Tuner()\r
155 {\r
156     EnterCriticalSection(&_cs);\r
157     if (_bcas != NULL)\r
158     {\r
159         _bcas->release(_bcas);\r
160         _bcas = NULL;\r
161     }\r
162     if (_b25 != NULL)\r
163     {\r
164         _b25->release(_b25);\r
165         _b25 = NULL;\r
166     }\r
167     if (_recfd != -1)\r
168     {\r
169         _recfd = -1;\r
170     }\r
171     if (_dst_addr.sin_family == AF_INET)\r
172     {\r
173         _dst_addr.sin_family = AF_UNSPEC;\r
174     }\r
175     _listener = NULL;\r
176 \r
177     LeaveCriticalSection(&_cs);\r
178 \r
179     _core->release(this);\r
180 \r
181     closesocket(_udp);\r
182 \r
183     DeleteCriticalSection(&_cs);\r
184 \r
185     DebugLog2("PT1Tuner::~PT1Tuner()\n");\r
186 }\r
187 \r
188 void PT1Tuner::setListener(Listener *listener)\r
189 {\r
190     EnterCriticalSection(&_cs);\r
191     _listener = listener;\r
192     LeaveCriticalSection(&_cs);\r
193 }\r
194 \r
195 const char *PT1Tuner::name()\r
196 {\r
197     DebugLog2("PT1Tuner::name()\n");\r
198 \r
199     if (strlen(_name) == 0)\r
200     {\r
201         sprintf_s(_name, sizeof(_name), "%s-%02d", _core->name(), _tuner);\r
202     }\r
203 \r
204     return _name;\r
205 }\r
206 \r
207 Tuner::Type PT1Tuner::type()\r
208 {\r
209     DebugLog2("PT1Tuner::type()\n");\r
210 \r
211     switch (_tuner)\r
212     {\r
213     case 0:\r
214     case 2:\r
215         return ISDB_S;\r
216     case 1:\r
217     case 3:\r
218         return ISDB_T;\r
219     }\r
220     return TYPE_NA;\r
221 }\r
222 \r
223 Tuner::LnbPower PT1Tuner::lnbPower()\r
224 {\r
225     DebugLog2("PT1Tuner::lnbPower()\n");\r
226 \r
227     return LNB_POWER_OFF;\r
228 }\r
229 \r
230 bool PT1Tuner::getCnAgc(uint32_t *cn100, uint32_t *agc, uint32_t *maxAgc)\r
231 {\r
232     DebugLog2("PT1Tuner::getCnAgc()\n");\r
233     bool result = false;\r
234     if ((cn100 != NULL) && (agc != NULL) && (maxAgc != NULL))\r
235     {\r
236         result = _core->getCnAgc(_tuner, (EARTH::uint *)cn100, (EARTH::uint *)agc, (EARTH::uint *)maxAgc);\r
237     }\r
238     return result;\r
239 }\r
240 \r
241 int PT1Tuner::channel()\r
242 {\r
243     int result = -1;\r
244     EnterCriticalSection(&_cs);\r
245     result = _channel;\r
246     LeaveCriticalSection(&_cs);\r
247     return result;\r
248 }\r
249 \r
250 bool PT1Tuner::setChannel(int channel)\r
251 {\r
252     bool result = false;\r
253     EnterCriticalSection(&_cs);\r
254     if (_channel != channel)\r
255     {\r
256         if (!_recording)\r
257         {\r
258             result = _core->setChannel(_tuner, channel);\r
259             if (result)\r
260             {\r
261                 _channel = channel;\r
262             }\r
263             else\r
264             {\r
265                 _channel = -1;\r
266             }\r
267         }\r
268     }\r
269     else\r
270     {\r
271         result = true;\r
272     }\r
273     LeaveCriticalSection(&_cs);\r
274     return result;\r
275 }\r
276 \r
277 bool PT1Tuner::startRecording(int fd)\r
278 {\r
279     bool result = false;\r
280     EnterCriticalSection(&_cs);\r
281     if ((!_recording) && (!_locked) && (fd >= 0))\r
282     {\r
283         _recording = true;\r
284         _locked = true;\r
285         _recfd = fd;\r
286         result = true;\r
287     }\r
288     LeaveCriticalSection(&_cs);\r
289     return result;\r
290 }\r
291 \r
292 int PT1Tuner::stopRecording()\r
293 {\r
294     int result = -1;\r
295     EnterCriticalSection(&_cs);\r
296     if (_recording)\r
297     {\r
298         _recording = false;\r
299         if (_dst_addr.sin_family != AF_INET)\r
300         {\r
301             _locked = false;\r
302         }\r
303         result = _recfd;\r
304         _recfd = -1;\r
305     }\r
306     LeaveCriticalSection(&_cs);\r
307     return result;\r
308 }\r
309 \r
310 bool PT1Tuner::isRecording()\r
311 {\r
312     bool result = false;\r
313     EnterCriticalSection(&_cs);\r
314     result = _recording;\r
315     LeaveCriticalSection(&_cs);\r
316     return result;\r
317 }\r
318 \r
319 bool PT1Tuner::lock()\r
320 {\r
321     bool result = false;\r
322     EnterCriticalSection(&_cs);\r
323     if (!_locked)\r
324     {\r
325         _locked = true;\r
326         result = true;\r
327     }\r
328     LeaveCriticalSection(&_cs);\r
329     return result;\r
330 }\r
331 \r
332 void PT1Tuner::unlock()\r
333 {\r
334     EnterCriticalSection(&_cs);\r
335     if (_locked)\r
336     {\r
337         if (!_recording)\r
338         {\r
339             _locked = false;\r
340         }\r
341     }\r
342     LeaveCriticalSection(&_cs);\r
343 }\r
344 \r
345 bool PT1Tuner::isLocked()\r
346 {\r
347     bool result = false;\r
348     EnterCriticalSection(&_cs);\r
349     result = _locked;\r
350     LeaveCriticalSection(&_cs);\r
351     return result;\r
352 }\r
353 \r
354 bool PT1Tuner::startStreaming(struct sockaddr_in *addr)\r
355 {\r
356     bool result = false;\r
357     EnterCriticalSection(&_cs);\r
358     if (_dst_addr.sin_family == AF_UNSPEC)\r
359     {\r
360         if (addr->sin_family == AF_INET)\r
361         {\r
362             _dst_addr = *addr;\r
363             _locked = true;\r
364             result = true;\r
365         }\r
366     }\r
367     LeaveCriticalSection(&_cs);\r
368     return result;\r
369 }\r
370 \r
371 void PT1Tuner::stopStreaming()\r
372 {\r
373     EnterCriticalSection(&_cs);\r
374     if (_dst_addr.sin_family == AF_INET)\r
375     {\r
376         _dst_addr.sin_family = AF_UNSPEC;\r
377         if (!_recording)\r
378         {\r
379             _locked = false;\r
380         }\r
381     }\r
382     LeaveCriticalSection(&_cs);\r
383 }\r
384 \r
385 bool PT1Tuner::isStreaming()\r
386 {\r
387     bool result = false;\r
388     EnterCriticalSection(&_cs);\r
389     result = (_dst_addr.sin_family == AF_INET);\r
390     LeaveCriticalSection(&_cs);\r
391     return result;\r
392 }\r
393 \r
394 \r
395 void PT1Tuner::addPacket(uint32_t packet)\r
396 {\r
397 //    DebugLog3("%s\n", __FUNCTION__);\r
398 //    return;\r
399 \r
400     uint32_t packetCounter = BIT_SHIFT_MASK(packet, 26,  3);\r
401     uint32_t packetStart   = BIT_SHIFT_MASK(packet, 25,  1);\r
402     uint32_t packetData    = BIT_SHIFT_MASK(packet,  0, 24);\r
403 \r
404     // check counter\r
405     uint32_t count = BIT_SHIFT_MASK(_count, 0, 3);\r
406     _count++;\r
407 \r
408     if (packetCounter != count)\r
409     {\r
410 //        DebugLog3("counter value is invalid.\n");\r
411     }\r
412 \r
413     // check packet start offset flag\r
414     if (packetStart)\r
415     {\r
416         if (BIT_SHIFT_MASK(packetData, 15, 1))\r
417         {\r
418 //            DebugLog3("There is an error that could not be corrected by Reed-Solomon decoding\n");\r
419         }\r
420         else\r
421         {\r
422             // check sync byte\r
423             if (BIT_SHIFT_MASK(packetData, 16, 8) != 0x47)\r
424             {\r
425 //                DebugLog3("The first byte of the packet does not have an 0x47.\n");\r
426             }\r
427         }\r
428 \r
429         if (_packetOffset != 0)\r
430         {\r
431 //            DebugLog3("The previous packet was not completed.\n");\r
432         }\r
433         _packetOffset = 0;\r
434     }\r
435 \r
436     // copy\r
437     uint32_t i;\r
438     for (i = 0; i < 3; ++i)\r
439     {\r
440         if (_packetOffset < PT1Core::PACKET_SIZE)\r
441         {\r
442             _buffer[PT1Core::PACKET_SIZE * _packetCount + _packetOffset] = BIT_SHIFT_MASK(packetData, 8*(2-i), 8);\r
443             _packetOffset++;\r
444         }\r
445     }\r
446     if (PT1Core::PACKET_SIZE <= _packetOffset)\r
447     {\r
448         // One packet is complete\r
449         _packetOffset = 0;\r
450 \r
451         if (PT1Core::PAGE_SIZE * PT1Core::PAGE_COUNT / PT1Core::PACKET_SIZE <= ++_packetCount)\r
452         {\r
453             _packetCount = 0;\r
454 \r
455             uint8_t *ptr = _buffer;\r
456             int32_t size = (PT1Core::PAGE_SIZE * PT1Core::PAGE_COUNT);\r
457 \r
458             EnterCriticalSection(&_cs);\r
459 \r
460             if (_b25 != NULL)\r
461             {\r
462                 // MULTI2 Decode\r
463                 ARIB_STD_B25_BUFFER sBuffer, dBuffer;\r
464                 sBuffer.data = _buffer;\r
465                 sBuffer.size = (PT1Core::PAGE_SIZE * PT1Core::PAGE_COUNT);\r
466                 dBuffer.data = NULL;\r
467                 dBuffer.size = 0;\r
468 \r
469                 int ret = _b25->put(_b25, &sBuffer);\r
470                 if (ret >= 0)\r
471                 {\r
472                     ret = _b25->get(_b25, &dBuffer);\r
473                     if (ret >= 0)\r
474                     {\r
475                         ptr = dBuffer.data;\r
476                         size = dBuffer.size;\r
477                     }\r
478                     else\r
479                     {\r
480                         DebugLog3("_b25->get() NG. %d\n", ret);\r
481                         _b25->reset(_b25);\r
482                     }\r
483                 }\r
484                 else\r
485                 {\r
486                     DebugLog3("_b25->put() NG. %d\n", ret);\r
487                     _b25->reset(_b25);\r
488                 }\r
489             }\r
490 \r
491             // recording\r
492             if (_recfd >= 0)\r
493             {\r
494                 _write(_recfd, ptr, size);\r
495             }\r
496 \r
497             // streaming\r
498             if (_dst_addr.sin_family == AF_INET)\r
499             {\r
500 #if 1\r
501                 int32_t offset = 0;\r
502                 int32_t unit = 188 * 4;\r
503 //                int32_t unit = 188 * 8;\r
504                 int32_t remain = size;\r
505                 while (remain > 0)\r
506                 {\r
507                     if (remain < unit)\r
508                     {\r
509                         unit = remain;\r
510                     }\r
511                     int len = sendto(_udp, (const char *)&ptr[offset], unit, 0, (struct sockaddr *)&_dst_addr, sizeof(struct sockaddr_in));\r
512                     if (len > 0)\r
513                     {\r
514                         remain -= len;\r
515                         offset += len;\r
516                     }\r
517                     else\r
518                     {\r
519                         char tmp[1024];\r
520                         strerror_s(tmp, sizeof(tmp), errno);\r
521                         DebugLog3("len = %d, %s", len, tmp);\r
522                         break;\r
523                     }\r
524                 }\r
525 #else\r
526                 sendto(_udp, (const char *)ptr, size, 0,  (struct sockaddr *)&_dst_addr, sizeof(struct sockaddr_in));\r
527 #endif                \r
528             }\r
529         \r
530              // listener\r
531             if (_listener != NULL)\r
532             {\r
533                 _listener->put(ptr, size);\r
534             }\r
535 \r
536             LeaveCriticalSection(&_cs);\r
537 \r
538         }\r
539     }\r
540 }\r
541 \r
542 int PT1Tuner::scan(Tuner *tuners[], HMODULE multi2_dll)\r
543 {\r
544     DebugLog2("%s()\n", __FUNCTION__);\r
545 \r
546     if (module_ == NULL)\r
547     {\r
548         module_ = ::LoadLibrary(L"SDK_EARTHSOFT_PT1_PT2.dll");\r
549         if (module_ == NULL)\r
550         {\r
551             DebugLog0("Can't load library: ");\r
552             return -1;\r
553         }\r
554     }\r
555 \r
556     EARTH::PT::Bus::NewBusFunction function = reinterpret_cast<EARTH::PT::Bus::NewBusFunction>(::GetProcAddress(module_, "_"));\r
557     if (function == NULL)\r
558     {\r
559         DebugLog0("internal error.");\r
560         return -1;\r
561     }\r
562 \r
563     EARTH::PT::Bus *bus = NULL;\r
564     EARTH::status status = function(&bus);\r
565     if (status != EARTH::PT::STATUS_OK)\r
566     {\r
567         DebugLog3("error: NewBusFunction() 0x%08x", status);\r
568         return -1;\r
569     }\r
570 \r
571     EARTH::uint version;\r
572     bus->GetVersion(&version);\r
573     if ((version >> 8) != 2)\r
574     {\r
575         DebugLog3("no support version");\r
576         return -1;\r
577     }\r
578 \r
579     EARTH::PT::Bus::DeviceInfo deviceInfo[ry0::device::MAX_DEVICES];\r
580     EARTH::uint deviceInfoCount = sizeof(deviceInfo)/sizeof(*deviceInfo);\r
581     bus->Scan(deviceInfo, &deviceInfoCount, 3);\r
582 \r
583     DebugLog2("deviceInfoCount = %d", deviceInfoCount);\r
584 \r
585     int tunerCount = 0;\r
586 \r
587     for (EARTH::uint i = 0; i < deviceInfoCount; ++i)\r
588     {\r
589         const EARTH::PT::Bus::DeviceInfo *info = &deviceInfo[i];\r
590         if (info->BadBitCount == 0)\r
591         {\r
592             try\r
593             {\r
594                 PT1Core *core = new PT1Core(bus, info, &tuners[tunerCount], multi2_dll);\r
595                 tunerCount += PT1Core::MAX_TUNERS;\r
596             }\r
597             catch (int e)\r
598             {\r
599                 DebugLog0("throw %d", e);\r
600             }\r
601             catch (const std::bad_alloc& e)\r
602             {\r
603                 DebugLog0("throw bad_alloc %s", e);\r
604             }\r
605         }\r
606     }\r
607 \r
608     return tunerCount;\r
609 }\r
610 \r
611 } // PT1\r
612 } // device\r
613 } // ry0\r
614 \r
615 \r