1#!/usr/bin/env python3
2
3"""Implementation of TransferFrame class components common to all S-Band and X-Band definitions."""
4
5import sys
6import logging
7from enum import Enum
8from collections import defaultdict
9from binascii import hexlify
10
11from chart.common.binary import unpack_uint8
12from chart.common.binary import unpack_uint16_be
13from chart.common.binary import unpack_uint24_be
14from chart.common.binary import unpack_uint32_be
15from chart.common.binary import unpack_int32_be
16from chart.products.pus.ccsds import CCSDSTM
17from chart.products.pus.ccsds_displayer import INDENTATION
18from chart.products.pus.ccsds import CCSDSBadHeader
19from chart.products.utils import Segment
20
21class TFException(Exception):
22 pass
23
24
25class TFBadSize(TFException):
26 pass
27
28
29class TFUnrecognisedType(TFException):
30 pass
31
32
33class TFNoTimestamp(TFException):
34 pass
35
36
37class TF_ASM(Segment):
38 """Representation of Attached Sync Marker."""
39
40 # Attached Sync Marker length, Bytes
41 LENGTH = 4
42
43 @property
44 def attached_sync_marker(self):
45 """Get Attached Sync Marker."""
46 return unpack_uint32_be(self, 0)
47
48 def show(self, target=sys.stdout, indent=''):
49 """Display basic ASM information to stdout. Write to `csv_writer` if not None."""
50 target.write("""
51{indent}CADU Synchronisation Marker: {len} - {data}
52""".format(
53 indent=indent,
54 len=len(self.buff),
55 data=self.hex_dump()))
56
57
58class TF_trailer(Segment):
59 """Representation of a TF_trailer."""
60
61 # Transfer Frame Trailer length, Bytes
62 LENGTH = 4
63
64 # @property
65 # def TF_trailer(self):
66 # return self.buff
67
68 def show(self, target=sys.stdout, indent=''):
69 """Display basic TF_trailer HEX Dump information to stdout. Write to `csv_writer` if not None."""
70 target.write("""
71{indent}TF_trailer: {len} - {data}
72""".format(
73 indent=indent,
74 len=len(self.buff),
75 data=self.hex_dump()))
76
77
78class PEC(Segment):
79 """Representation of Packet Error Correction codes used in CCSDS packets."""
80 LENGTH = 2
81 def show(self, target=sys.stdout, indent=''):
82 target.write('{i}PEC: {pec}\n'.format(i=indent, pec=self.hex_dump()))
83
84
85class TF_error_control(Segment):
86 """Representation of a TF_error_control Check, Reed Solomon Code."""
87 # Frame Error Control Field Length, Reed Solomon Code
88 LENGTH = 160
89
90 # Reed Solomon Check
91 @property
92 def reed_solomon(self):
93 """Get Reed Solomon checksum codes."""
94 # print(ord(self.buff[0]))
95 return self.buff
96
97 def show(self, target=sys.stdout, indent=''):
98 """Display basic TF_error_control HEX Dump information to stdout. Write to `csv_writer` if not None."""
99 target.write("""
100{indent}TF_error_control: {len} - {data}
101""".format(
102 indent=indent,
103 len=len(self.buff),
104 data=self.hex_dump()))
105
106
107class MMDS_TF(Segment):
108 """Representation of an S3 X-Band Transfer Frame.
109
110 Holder of one, or mamy, or a partial, or one or many + a partial CCSDS packet.
111 """
112 # Display name for the frame displayer
113 classname = 'MMDS TF'
114
115 # M_PDU Packet Zone length, Bytes
116 PACKET_ZONE_LENGTH = 1902
117
118 # Transfer Frame Length, Bytes
119 # MMDS_TF_PRIMARY_HEADER_LENGTH (8) + M_PDU_HEADER_LENGTH (2) + PACKET_ZONE_LENGTH (1902)
120 LENGTH = 1912
121
122 def __init__(self, buff, file_pos):
123 super(MMDS_TF, self).__init__(buff, file_pos)
124 # Our XBAND_TF_header class is identical to CHART-S3 project's
125 # TransferFrame class.
126 # It's unclear what the old MMDS_TF_HEader is
127 self.mmds_tf_header = XBAND_TF_header(buff[0 : XBAND_TF_header.LENGTH])
128 self.tf_packet_data = buff[XBAND_TF_header.LENGTH :
129 XBAND_TF_header.LENGTH + MMDS_TF.PACKET_ZONE_LENGTH]
130 # self.ccsds = CCSDSTM(buff[MMDS_TF_header.LENGTH:])
131
132 def __str__(self):
133 return 'TF({ver} / {sid} / {chan_id} - {chan_fr})'.format(
134 ver=self.mmds_tf_header.transfer_frame_ver,
135 sid=self.mmds_tf_header.space_craft_id,
136 chan_id=self.mmds_tf_header.channel_id,
137 chan_fr=self.mmds_tf_header.oper_control_flag)
138
139 def show(self, target=sys.stdout, indent=''):
140 """Display ourselves."""
141 self.mmds_tf_header.show(target, indent)
142
143 # Transfer Frame Primary Header ...
144 @property
145 def length(self):
146 return self.LENGTH
147
148 @property
149 def channel_id(self):
150 return self.mmds_tf_header.channel_id
151
152 @property
153 def oper_control_flag(self):
154 return self.mmds_tf_header.oper_control_flag
155
156 @property
157 def first_header_ptr(self):
158 return self.mmds_tf_header.first_header_ptr
159
160 @property
161 def packet_data(self):
162 return self.tf_packet_data
163
164
165class MMDS_TF_error_control(Segment):
166 """Representation of a MMDS TF_error_control Check, Reed Solomon Code."""
167
168 # TBD Not yet decoded
169
170 # MMDS Frame Error Control Field Length, Reed Solomon Code
171 LENGTH = 128
172
173 # Reed Solomon Check
174 @property
175 def reed_solomon(self):
176 """Get Reed Solomon Check."""
177 # print(ord(self.buff[0]))
178 return self.buff
179
180 def show(self, target=sys.stdout, indent=''):
181 """Display basic MMDS TF_error_control HEX Dump information to stdout. Write to `csv_writer` if not None."""
182 target.write("""
183{indent}TF_error_control: {len} - {data}
184""".format(
185 indent=indent,
186 len=len(self.buff),
187 data=self.hex_dump()))
188
189
190class XBAND_TF_header(Segment):
191 """Representation of XBand Transfer Frame Primary Header.
192
193 See Jason-CS Packet Utilisation Standard, JC.ID.ASG.SY.00001
194 """
195
196 # Transfer Frame Primary Header (8) + M_PDU Header length (2), Bytes
197 LENGTH = 10
198
199 # Transfer Frame Primary Header Fields...
200 @property
201 def transfer_frame_ver(self):
202 """Get Transfer Frame Version Number."""
203 return self.buff[0] >> 6 # ^ Byte 0, bits 1 - 2
204
205 @property
206 def space_craft_id(self):
207 """Get Space Craft ID."""
208 return (unpack_uint16_be(self.buff, 0) >> 6) & 0x3ff # ^ Byte 0, bits 3 - 10
209
210 @property
211 def channel_id(self):
212 """Get Channel ID."""
213 return unpack_uint16_be(self.buff, 0) & 0x3f # ^ Byte 0, bits 11 - 16
214
215 @property
216 def channel_frame_cnt(self):
217 """Get Channel Frame Counter."""
218 return unpack_uint24_be(self.buff, 2) # ^ Byte 2, bits 1 - 24
219
220 @property
221 def replay_flag(self):
222 """Get Signal Field Replay Flag."""
223 return self.buff[5] >> 7 # ^ Byte 5, bit 1
224
225 @property
226 def reserve_spare(self):
227 """Get Signal Field Reserved Spare."""
228 return unpack_uint8(self.buff, 5) & 0x80 # ^ Byte 5, bits 2 - 8
229
230 @property
231 def header_error_con(self):
232 """Get Header Error Control."""
233 return unpack_uint16_be(self.buff, 6) # ^ Byte 6, bits 1 - 16
234
235
236 # Transfer Frame M_PDU Header Fields...
237 @property
238 def header_reserved(self):
239 """Get Transfer Frame M_PDU Header Reserved."""
240 return self.buff[8] >> 3 # ^ Byte 8, bits 1 - 5
241
242 @property
243 def first_header_ptr(self):
244 """Get Transfer Frame M_PDU Header First header pointer."""
245 return unpack_uint16_be(self.buff, 8) & 0x07ff # ^ Byte 8, bits 6 - 16
246
247
248 def show(self, target=sys.stdout, indent=''):
249 """Display the Transfer Frame Primary Header format."""
250 target.write("""{i}Transfer Frame:
251{i}{ii}Transfer Frame Version Number: {ver}
252{i}{ii}Spacecraft ID: {sid}
253{i}{ii}Virtual Channel ID: {cid}
254{i}{ii}Virtual Channel Frame Count: {cfc}
255{i}{ii}Signalling Field - Replay Flag: {rf}
256{i}{ii}Signalling Field - Reserved Spare: {rs}
257{i}{ii}Frame Header Error Control: {hec}
258{i}{ii}TF M_PDU Header - Reserved: {hr}
259{i}{ii}TF M_PDU Header - First header pointer: {fhp}
260""".format(
261 i=indent,
262 ii=INDENTATION,
263 ver=self.transfer_frame_ver,
264 sid=self.space_craft_id,
265 cid=self.channel_id,
266 cfc=self.channel_frame_cnt,
267 rf=self.replay_flag,
268 rs=self.reserve_spare,
269 hec=self.header_error_con,
270 hr=self.header_reserved,
271 fhp=self.first_header_ptr))
272
273
274class XBand_TF(Segment):
275 """Representation of a single S3 X-Band Transfer Frame.
276
277 Holder of one, or many, or a partial, or one or many + a partial CCSDS packet.
278 """
279 # XBAND_TF_header(10b) + TF_packet_data(1105b)
280 LENGTH = 1115
281
282 # Payload
283 PACKET_ZONE_LENGTH = 1105
284
285 # For frame displayer
286 classname = 'XBand TF'
287
288 def __init__(self, buff, file_pos=None):
289 super(XBand_TF, self).__init__(buff, file_pos)
290 # self.tdev_tc_header = None # do we need this?
291 self.tf_header = XBAND_TF_header(buff[0: XBAND_TF_header.LENGTH])
292 self.tf_packet_data = buff[
293 XBAND_TF_header.LENGTH: XBAND_TF_header.LENGTH + XBand_TF.PACKET_ZONE_LENGTH]
294 # self.ccsds = CCSDSTM(
295 # buff[XBAND_TF_header.LENGTH : XBAND_TF_header.LENGTH + XBand_TF.PACKET_ZONE_LENGTH])
296
297 def __str__(self):
298 return 'TF({ver} / {sid} / {chan_id} - {frame_cnt})'.format(
299 ver=self.tf_header.transfer_frame_ver,
300 sid=self.tf_header.space_craft_id,
301 chan_id=self.tf_header.channel_id,
302 frame_cnt=self.tf_header.channel_frame_cnt)
303
304 def show(self, target=sys.stdout, indent=''):
305 """Display ourselves."""
306 self.tf_header.show(target, indent)
307
308 @property
309 def length(self):
310 return self.LENGTH
311
312 @property
313 def channel_id(self):
314 return self.tf_header.channel_id
315
316 @property
317 def channel_frame_cnt(self):
318 return self.tf_header.channel_frame_cnt
319
320 @property
321 def first_header_ptr(self):
322 return self.tf_header.first_header_ptr
323
324 @property
325 def packet_data(self):
326 return self.tf_packet_data
327
328
329class CORTEXHeader(Segment):
330 """Representation of a CORTEX Header.
331
332 Implementation of S-Band TransferFrame class.
333 See Packet Utilisation Standard,
334 Represents S3 S-Band NDIU Cortex Frame containing Transfer Frame.
335 The Cortex .tlm files contain the full NDIU Cortex Frame records.
336 """
337
338 # CORTEX Header Size, Bytes this is a fixed length header block
339 LENGTH = 64
340
341 # @property
342 # def CORTEX_header(self):
343 # return self.buff
344
345 @property
346 def message_length(self):
347 """Read our message length field and convert to bytes."""
348 # print('cortex header message length', unpack_uint24_be(self.buff, 0))
349 # for a in range(12):
350 # print(a, self.buff[a])
351 # 1/0
352 # This does not really match the spec in the document above
353 return unpack_uint32_be(self.buff, 4)
354
355 def show(self, target=sys.stdout, indent=''):
356 """Display basic cortex header HEX Dump information to stdout. Write to `csv_writer` if not None."""
357 target.write("""
358{indent}CORTEXHeader : {len} - {data}
359""".format(
360 indent=indent,
361 len=len(self.buff),
362 data=self.hex_dump()))
363
364
365class SBAND_TF_header(Segment):
366 """Representation of AOS Transfer Trame (VDCU) Primary Header.
367
368 See above for ASM Class
369 """
370
371 # this is a fixed length header block
372 LENGTH = 6
373
374 # Transfer Frame Primary Header ...
375 @property
376 def transfer_frame_ver(self):
377 """Get Transfer Frame Version Number."""
378 return self.buff[0] >> 6
379
380 @property
381 def space_craft_id(self):
382 """Get Space Craft ID."""
383 return (unpack_uint16_be(self.buff, 0) >> 4) & 0x3ff
384
385 @property
386 def channel_id(self):
387 """Get Channel ID."""
388 return (unpack_uint16_be(self.buff, 0) & 0x0f) >> 1
389
390 @property
391 def oper_control_flag(self):
392 """Get Operation Control Flag."""
393 return unpack_uint16_be(self.buff, 0) & 0x1
394
395 @property
396 def master_channel_frame_cnt(self):
397 """Get Master Channel Frame Counter."""
398 return self.buff[2]
399
400 @property
401 def virtual_channel_frame_cnt(self):
402 """Get Master Channel Frame Counter."""
403 return self.buff[3]
404
405 @property
406 def sec_header_flag(self):
407 """Get Secondary Header Flag."""
408
409 # ^ Byte 4, bit 1, move right 15, & 0b1
410 return (unpack_uint16_be(self.buff, 4) >> 15) & 0b1
411
412 @property
413 def data_field_sync_flag(self):
414 """Get Transfer Frame data fields synchronise flag."""
415 # ^ Byte 4 bit 2, move right 14 & 0b1
416 return (unpack_uint16_be(self.buff, 4) >> 14) & 0b1
417
418 @property
419 def packet_order_flag(self):
420 """Get Transfer Frame packet order flag."""
421 # ^ Byte 4, bit 3, move right 13 & 0b1
422 return (unpack_uint16_be(self.buff, 4) >> 13) & 0b1
423
424 @property
425 def seg_length_id(self):
426 """Get Transfer Frame segment length ID."""
427 # ^ Byte 4, bits 4 - 5, move right 11 & 0b11
428 return (unpack_uint16_be(self.buff, 4) >> 11) & 0b11
429
430 @property
431 def first_header_ptr(self):
432 """Get Transfer Frame CCSDS First header pointer."""
433 # ^ Byte 4, bits 6 - 16
434 return unpack_uint16_be(self.buff, 4) & 0b11111111111
435
436 def show(self, target=sys.stdout, indent=''):
437 """Display the Transfer Frame Primary Header format."""
438 target.write("""{i}Transfer Frame:
439{i}{ii}Transfer Frame Version Number: {ver}
440{i}{ii}Space Craft ID: {sid}
441{i}{ii}Virtual Channel ID: {chan_id}
442{i}{ii}Operational Control Field Flag: {op_flag}
443{i}{ii}Master Channel Frame Counter: {master}
444{i}{ii}Virtual Channel Frame Counter: {virtual}
445{i}{ii}{ii}TF Secondary Header Flag: {h_sec}
446{i}{ii}{ii}TF Data Field Sync Flag: {h_syn}
447{i}{ii}{ii}TF Packet Order Flag: {h_po}
448{i}{ii}{ii}TF Segment Length ID: {h_seg}
449{i}{ii}{ii}TF CCSDS - First header pointer: {h_ptr}
450""".format(i=indent,
451 ii=INDENTATION,
452 indentation=INDENTATION,
453 ver=self.transfer_frame_ver,
454 sid=self.space_craft_id,
455 chan_id=self.channel_id,
456 op_flag=self.oper_control_flag,
457 master=self.master_channel_frame_cnt,
458 virtual=self.virtual_channel_frame_cnt,
459 h_sec=self.sec_header_flag,
460 h_syn=self.data_field_sync_flag,
461 h_po=self.packet_order_flag,
462 h_seg=self.seg_length_id,
463 h_ptr=self.first_header_ptr))
464
465 def write(self, handle):
466 """Store the (possibly modified) CCSDS packet to `handle` as a raw packet, no header."""
467 # print('writing {len} bytes'.format(len=self.length))
468 length = self.length
469 handle.write(self.buff[:length])
470 return length
471
472
473class CORTEX_trailer(Segment):
474 """Representation of a CORTEX_Trailer."""
475
476 # length of this block depends on GS, see settings.CORTEXt_GS_ATTRIBUTES
477 # LENGTH_MIN = 4
478 # LENGTH_MAX = 5
479
480 # @property
481 # def CORTEX_trailer(self):
482 # return self.buff
483
484 @property
485 def postamble(self):
486 return unpack_int32_be(self.buff, 0)
487
488 def show(self, target=sys.stdout, indent=''):
489 """Display basic CORTEX_trailer HEX Dump information to stdout. Write to `csv_writer` if not None."""
490 target.write("""
491{indent}CORTEX_trailer: {len} - {data}
492""".format(
493 indent=indent,
494 len=len(self.buff),
495 data=self.hex_dump()))
496
497
498class SBandTMTF(Segment):
499 """S-band Telemetry Transfer Frame."""
500
501 # 6 + 1103 + 4 + 2
502 VCDU_LENGTH = 1103
503 PACKET_LENGTH = VCDU_LENGTH + PEC.LENGTH
504
505 LENGTH = SBAND_TF_header.LENGTH + PACKET_LENGTH + TF_trailer.LENGTH
506
507 def __init__(self, buff, file_pos=None):
508 super(SBandTMTF, self).__init__(buff, file_pos)
509 self.tf_header = SBAND_TF_header(buff[0:SBAND_TF_header.LENGTH])
510 self.payload = TF_packet_data(
511 buff[SBAND_TF_header.LENGTH:
512 SBAND_TF_header.LENGTH + SBandTMTF.VCDU_LENGTH + PEC.LENGTH])
513 self.ccsds = CCSDSTM(buff[SBAND_TF_header.LENGTH:
514 SBAND_TF_header.LENGTH + SBandTMTF.VCDU_LENGTH + PEC.LENGTH])
515 self.pec = PEC(buff[SBAND_TF_header.LENGTH + SBandTMTF.VCDU_LENGTH:
516 SBAND_TF_header.LENGTH + SBandTMTF.VCDU_LENGTH + PEC.LENGTH])
517
518 def show(self, target=sys.stdout, indent=''):
519 """Display basic ASM information to stdout. Write to `csv_writer` if not None."""
520 self.tf_header.show(target, indent)
521 self.pec.show(target, indent)
522
523 @property
524 def channel_id(self):
525 return self.tf_header.channel_id
526
527 @property
528 def first_header_ptr(self):
529 return self.tf_header.first_header_ptr
530
531 @property
532 def packet_data(self):
533 return self.payload
534
535
536class CADU(Segment):
537 """Represent an S-BAND CADU frame."""
538
539 # Frame, Channel Access Data Unit (CADU) length, Bytes
540 # ASM (4) + TF_LENGTH (1115) + EC-RS (160)
541
542 # 4 + 1115 + 160
543 VCDU_LENGTH = 1103
544 RS_LENGTH = 160
545 LENGTH = TF_ASM.LENGTH + SBAND_TF_header.LENGTH + VCDU_LENGTH + TF_trailer.LENGTH + PEC.LENGTH + RS_LENGTH
546
547 def __init__(self, buff, file_pos=None):
548 super(CADU, self).__init__(buff, file_pos)
549 self.sync_marker = TF_ASM(buff[0:TF_ASM.LENGTH])
550 self.packet_data = TF_packet_data(buff[SBAND_TF_header.LENGTH:
551 SBAND_TF_header.LENGTH + CADU.VCDU_LENGTH + PEC.LENGTH])
552 self.reed_solomon = TF_error_control(buff[SBAND_TF_header.LENGTH + CADU.VCDU_LENGTH + PEC.LENGTH:
553 SBAND_TF_header.LENGTH + CADU.VCDU_LENGTH + PEC.LENGTH + CADU.RS_LENGTH])
554
555 def show(self, target=sys.stdout, indent=''):
556 """Display basic ASM information to stdout. Write to `csv_writer` if not None."""
557 self.sync_marker.show(target, indent)
558 self.packet_data.show(target, indent)
559 self.reed_solomon.show(target, indent)
560
561
562class CORTEXFrame(Segment):
563 """Representation of a single Cortex record holding a Transfer Frame.
564
565 For Cortex definition see
566 COMMAND RANGING & TELEMETRY UNIT CORTEX Series TCP-IP ETHERNET INTERFACE
567 https://dmtool.eumetsat.int/cs/idcplg?IdcService=EUM_GET_FILE&dRevLabel=2&dDocName=371846&allowInterrupt=1
568 (ยง2.4.5, p100).
569 """
570 label = 'Cortex frame'
571
572 # CORTEX_TF (multiples of 4 bytes)
573 # CORTEX_header (64 byte)
574 # TF_ASM sync marker (4 byte)
575 # SBAND_TF_header VCDU header (6 byte)
576 # bytes VCDU payload (1103 byte)
577 # TF_trailer (4 byte)
578 # TF_error_control (160 byte)
579 # CORTEX_trailer (variable, 4 or 5 byte)
580
581 # CORTEX_TF_LENGTH_MIN = CORTEX_header.LENGTH + CADU.LENGTH + CORTEX_trailer.LENGTH_MIN
582 # CORTEX_TF_LENGTH_MAX = CORTEX_header.LENGTH + CADU.LENGTH + CORTEX_trailer.LENGTH_MAX
583
584 def __init__(self, buff, file_pos, product_id=None): # buff, cortex_trailer_len=CORTEX_trailer.LENGTH_MAX):
585 super().__init__(buff, file_pos, product_id)
586 start = 0
587
588 self.cortex_header = CORTEXHeader(buff[start : start + CORTEXHeader.LENGTH])
589 end = self.cortex_header.message_length
590 # print('end starts at', end)
591 start += CORTEXHeader.LENGTH
592
593 self.tf_asm = TF_ASM(buff[start : start + TF_ASM.LENGTH])
594 start += TF_ASM.LENGTH
595
596 self.tf_header = SBAND_TF_header(buff[start : start + SBAND_TF_header.LENGTH])
597 start += self.tf_header.LENGTH
598
599 # Jump to the end and read the CORTEX postamble
600 self.cortex_trailer = CORTEX_trailer(buff[end - 4:end])
601 # print('cortex trailer int', unpack_int32_be(self.cortex_trailer.buff,0))
602 end -= 4
603
604 # Reed solomon bytes which we don't check
605 self.tf_error_control = TF_error_control(buff[end - TF_error_control.LENGTH: end])
606 end -= TF_error_control.LENGTH
607
608 # ?
609 end -= 7
610
611 # self.tf_trailer = TF_trailer(buff[end - TF_trailer.LENGTH: end])
612 # print('cortex tf trailer', self.tf_trailer.buff[0], self.tf_trailer.buff[1], self.tf_trailer.buff[2], self.tf_trailer.buff[3])
613 # end -= TF_trailer.LENGTH
614
615 self.tf_packet_data = buff[start : end]
616 # print('tf packet data', start, end, len(self.tf_packet_data))
617
618 def __str__(self):
619 return 'Cortex_TF({ver} / {sid} / {chan_id} - {chan_fr})'.format(
620 ver=self.tf_header.transfer_frame_ver,
621 sid=self.tf_header.space_craft_id,
622 chan_id=self.tf_header.channel_id,
623 chan_fr=self.tf_header.oper_control_flag)
624
625 @property
626 def length(self):
627 """Compute length of packet based on CORTEX header."""
628 # return CORTEXHeader.LENGTH + TF_ASM.LENGTH + SBAND_TF_header.LENGTH +\
629 # len(self.tf_packet_data) + TF_trailer.LENGTH + TF_error_control.length +\
630 # CORTEX_trailer.LENGTH
631 return self.cortex_header.message_length
632
633 @property
634 def channel_id(self):
635 # print('cortex tf retrieving channel id')
636 res = self.tf_header.channel_id
637 # print('cortex tf got channel id', res)
638 return res
639
640 @property
641 def first_header_ptr(self):
642 return self.tf_header.first_header_ptr
643
644 @property
645 def packet_data(self):
646 return self.tf_packet_data # .packet_data
647
648 def show(self, target=sys.stdout, indent=''):
649 """Display basic cortex header HEX Dump information to stdout. Write to `csv_writer` if not None."""
650 from chart.products.pus.ccsds_io import gen_ccsds_from_frames
651 from chart.products.pus.ccsds_io import CCSDS_FIXED_HEADER
652 from chart.products.pus.ccsds_io import RawCCSDS
653 from chart.products.pus.exceptions import CCSDSBadHeader
654 from chart.products.pus.ccsds import IDLE_PACKET_APID
655 target.write("""{i}TF Header:
656{i}{ii}Sync marker: 0x{sync:x}
657""".format(
658 i=indent,
659 ii=INDENTATION,
660 sync=self.tf_asm.attached_sync_marker))
661 self.tf_header.show(target, indent)
662
663 target.write('{i}Headers in payload:\n'.format(i=indent))
664 hp = self.tf_header.first_header_ptr
665 buff = self.tf_packet_data.buff
666 if hp > 0:
667 target.write('{i}{ii}Not processing {cc} initial bytes\n'.format(
668 i=indent,
669 ii=INDENTATION,
670 cc=hp))
671
672 while hp < len(self.tf_packet_data):# - CCSDS_FIXED_HEADER):
673 ccsds = RawCCSDS(self.tf_packet_data[hp:])
674 try:
675 apid = ccsds.ccsds.apid
676 except (ValueError, IndexError):
677 apid = '?'
678
679 packet_def = None
680 filler = ''
681 if apid == IDLE_PACKET_APID:
682 filler = ' (idle)'
683
684 else:
685 try:
686 packet_def = ccsds.packet_def
687 except CCSDSBadHeader: # too small
688 break
689 except (ValueError, IndexError):
690 pass
691
692 ident = ''
693 if packet_def is not None:
694 ident = ' SPID {spid} ({name})'.format(spid=packet_def.spid,
695 name=packet_def.name)
696
697 criteria = ''
698 try:
699 service = ccsds.ccsds.service
700 except CCSDSBadHeader: # too small
701 break
702 except IndexError:
703 service = '?'
704
705 try:
706 subservice = ccsds.ccsds.subservice
707 except CCSDSBadHeader: # too small
708 break
709 except IndexError:
710 subservice = '?'
711
712 try:
713 param1 = ccsds.ccsds.param1
714 except CCSDSBadHeader: # too small
715 break
716 except (IndexError, ValueError):
717 param1 = '?'
718
719 try:
720 param2 = ccsds.ccsds.param2
721 except IndexError:
722 param2 = '?'
723
724 # First attempt to show full criteria - needs 9 bytes of packet
725 criteria = '{service}/{subservice}/{apid}/{param1}/{param2}'.format(
726 service=service,
727 subservice=subservice,
728 apid=apid,
729 param1=param1,
730 param2=param2)
731
732 partial = ''
733 try:
734 length = ccsds.length
735 except CCSDSBadHeader:
736 length = '?'
737 parial = ' partial header'
738
739 if length != '?':
740 if length > len(ccsds.ccsds.buff):
741 partial = ' partial payload (missing {m} bytes)'.format(
742 m=length - len(ccsds.ccsds.buff))
743
744 target.write(
745 '{i}{ii}Pos {pos} Len {length} '\
746 'Crit {criteria}{ident}{partial}{filler}\n'.format(
747 i=indent,
748 ii=INDENTATION,
749 pos=hp,
750 length=length,
751 criteria=criteria,
752 ident=ident,
753 partial=partial,
754 filler=filler))
755
756 if length == '?':
757 break
758
759 hp += ccsds.length
760
761 remain = len(self.tf_packet_data) - hp
762 if remain > 0:
763 target.write('{i}{ii}Not processing {cc} trailing bytes\n'.format(
764 i=indent,
765 ii=INDENTATION,
766 cc=remain))
767
768 target.write("{i}CORTEX postamble: {pa}\n\n".format(
769 i=indent, pa=self.cortex_trailer.postamble))
770
771
772# class CortexFrame(Segment):
773# """Representation of a variable length Cortex Xband frame.
774
775# Main frame format from:
776# https://dmtool.eumetsat.int/cs/idcplg?IdcService=EUM_GET_FILE&dRevLabel=2&dDocName=371846&allowInterrupt=1
777# Section 2.4.5 TELEMETRY MESSAGE
778
779# Payload section of is a raw VCDU.
780# """
781# pass