// File: /workspace/github_cpp_makefile_star2_O2/ke6jjj[P]r-dat/AudioFrameReceiver.cc
// Function: AudioFrameReceiver::HandleDateTime(unsigned char const*, unsigned int)
void
AudioFrameReceiver::HandleDateTime(const uint8_t *item, uint32_t absoluteFrame)
{
  uint8_t dow, year, mon, day, hour, min, sec;
  int likelyYear;
  bool timeIsValid = false;
  bool droppedSync = false;
  uint64_t abs_seconds;

  if (item != NULL) {
    //
    // Date and time.
    //
    dow = item[0] & 0xf;
    year = BCDDecode(item[1]);
    mon = BCDDecode(item[2]);
    day = BCDDecode(item[3]);
    hour = BCDDecode(item[4]);
    min = BCDDecode(item[5]);
    sec = BCDDecode(item[6]);

    if (year < 80)
      likelyYear = year + 2000;
    else
      likelyYear = year + 1900;
    
    //
    // Check if anything seems funny (bad BCD decodes)
    //
    if (mon != 100 && day != 100 && hour != 100 && min != 100 && sec != 100) {
      //
      // Determine the absolute date time in seconds since 1900.
      //
      abs_seconds = SecondsSince1900(likelyYear, mon, day, hour, min, sec);
      timeIsValid = true;
    }
  } else {
    dow = year = mon = day = hour = min = sec = 0;
  }

  if (mHaveDateTimeSync) {
    //
    // Syncronization is in effect. Make sure that everything is still ok.
    //
    if (timeIsValid && absoluteFrame == mLastAbsoluteFrameNumber + 1) {
      //
      // Everything seems ok so far. We've got a new timestamp and there
      // hasn't been a discontiuity in the frame stream.
      //
      // Advance our current clock by 30ms.
      //
      mCurrentDateTimeMilliseconds += 30;
      if (mCurrentDateTimeMilliseconds >= 1000) {
        mCurrentDateTimeMilliseconds %= 1000;
        mCurrentDateTimeSeconds += 1;
      }

      //
      // Does the second hand of our clock still match the transmitted
      // clock?
      //
      if (mCurrentDateTimeSeconds != abs_seconds) {
        //
        // No. We're no longer in sync.
        //
        mHaveDateTimeSync = false;
        droppedSync = true;
      }
    } else {
      //
      // We lost date and time sub-code or there was a jump in absolute
      // time.
      //
      mHaveDateTimeSync = false;
      droppedSync = true;
    }
  }

  //
  // Regardless of the current sync state, keep the closest-to-the-second
  // engine running, possibly establishing sync when it detects a long
  // (34-frame) second.
  //
  if (mHaveLastDateTime && timeIsValid) {
    //
    // We have a previous date and time stamp. Has the time changed
    // since then?
    //
    if (mLastDateTimeSeconds != abs_seconds) {
      //
      // The time has changed. Is it a discontinuity or is it a simple
      // advancement?
      //
      if (abs_seconds == mLastDateTimeSeconds + 1) {
        //
        // Simple advancement. This is a chance to achive a frame
        // lock and/or confirm that the lock is still in place.
        // In order to do so, however, we have to observe two successive
        // increments. Do we have a previous increment observed?
        //           
        if (mHaveLastChangeFrame) {
          //
          // DAT provides 33 1/3 frames per second. Since timestamps
          // can only be placed at the begining of frames, timestamps
          // should advance in the following pattern:
          //
          // 1. 34 frames (No millisecond offset)
          // 2. 33 frames (20 millisecond offset)
          // 3. 33 frames (10 millisecond offset)
          //
          // The timestamp that started with the 34-frame sequence is the
          // one that is closest to the real start of the second.
          //
          uint32_t frames_per_second = absoluteFrame - mLastChangeFrame;
          if (frames_per_second == 34) {
            //
            // We've just received received the frame that ends pattern
            // 1 and starts pattern 2. This means this frame marks the
            // start of pattern 2.
            //
            // If we aren't time synchronized then we can be now.
            //
            if (!mHaveDateTimeSync) {
              //
              // We don't currently have a frame lock. Let's mark
              // that we do and that the last second change occured as
              // pattern 1.
              //
              mHaveDateTimeSync = true;
              mCurrentDateTimeMilliseconds = 20;
              mCurrentDateTimeSeconds = abs_seconds;
            }
          }
        }

        //
        // Mark that this is the new last change frame.
        //
        mHaveLastChangeFrame = true;
        mLastChangeFrame = absoluteFrame;
      } else {
        //
        // There's been a bad discontinuity. Mark that we no longer
        // have a good roll-over frame.
        //
        mHaveLastChangeFrame = false;
      }
    }
  }
    
  //
  // Record that we now have a date and time.
  //
  mHaveLastDateTime = timeIsValid;
  mLastDateTimeSeconds = abs_seconds;

  if (droppedSync && mHaveDateTimeSync)
    printf("Date     time: ------- SYNC DROPPED AND REESTABLISHED --------\n");
  else if (droppedSync)
    printf("Date     time: ------- SYNC DROPPED --------------------------\n");

  if (mHaveDateTimeSync) {
    printf("Date     time: %02d %04d-%02d-%02d %02d:%02d:%02d.%03d (SYNCED)\n",
      dow,
      likelyYear,
      mon,
      day,
      hour,
      min,
      sec,
      mCurrentDateTimeMilliseconds
    );
  } else if (timeIsValid) {
    printf("Date     time: %02d %04d-%02d-%02d %02d:%02d:%02d\n",
      dow,
      likelyYear,
      mon,
      day,
      hour,
      min,
      sec
    );
  }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movl %edx, %r8d
testq %rsi, %rsi
movq %rdi, 0x30(%rsp)
je 0x4369
movq %rsi, %r12
movl %r8d, 0x20(%rsp)
movb (%rsi), %al
andb $0xf, %al
movl %eax, 0x1c(%rsp)
movzbl 0x1(%rsi), %edi
callq 0x7710
movl %eax, %r14d
movzbl 0x2(%r12), %edi
callq 0x7710
movl %eax, %ebx
movzbl 0x3(%r12), %edi
callq 0x7710
movl %eax, %r13d
movzbl 0x4(%r12), %edi
callq 0x7710
movl %eax, %r15d
movzbl 0x5(%r12), %edi
callq 0x7710
movl %eax, %ebp
movzbl 0x6(%r12), %edi
callq 0x7710
movl %eax, %r11d
movzbl %r14b, %eax
leal 0x76c(%rax), %ecx
leal 0x7d0(%rax), %r12d
cmpb $0x50, %al
cmovael %ecx, %r12d
cmpb $0x64, %bl
sete %al
cmpb $0x64, %r13b
sete %cl
orb %al, %cl
cmpb $0x64, %r15b
sete %al
cmpb $0x64, %bpl
sete %dl
orb %al, %dl
orb %cl, %dl
cmpb $0x64, %r11b
sete %al
orb %dl, %al
jne 0x4383
movl %ebp, 0x10(%rsp)
movzbl %bpl, %esi
movl %r15d, 0x2c(%rsp)
movzbl %r15b, %edi
movzbl %r13b, %r8d
movzbl %bl, %r9d
testb $0x3, %r14b
jne 0x4248
movw $0x64, %cx
movl %r12d, %eax
xorl %edx, %edx
divw %cx
movl %edx, %ecx
movw $0x190, %r10w           # imm = 0x190
movl %r12d, %eax
xorl %edx, %edx
divw %r10w
leaq 0x4e42(%rip), %rax      # 0x9080
testw %cx, %cx
jne 0x424f
testw %dx, %dx
je 0x424f
leaq 0x4e01(%rip), %rax      # 0x9050
movl %r13d, 0x18(%rsp)
movl %ebx, 0x14(%rsp)
movl %r12d, %ecx
imulq $0x1e13380, %rcx, %r10  # imm = 0x1E13380
movl %r11d, 0xc(%rsp)
movzbl %r11b, %r11d
imulq $0x3c, %rsi, %r14
imulq $0xe10, %rdi, %r13      # imm = 0xE10
imulq $0x15180, %r8, %rsi     # imm = 0x15180
movslq -0x4(%rax,%r9,4), %rax
imulq $0x15180, %rax, %r8     # imm = 0x15180
leal -0x1(%r12), %ecx
movl %ecx, %r9d
shrl $0x2, %r9d
xorl %edi, %edi
movw $0x64, %bp
movl %ecx, %eax
xorl %edx, %edx
divw %bp
movzwl %ax, %eax
subl %eax, %r9d
movw $0x190, %bp             # imm = 0x190
movl %ecx, %eax
xorl %edx, %edx
divw %bp
movzwl %ax, %eax
addl %r9d, %eax
imull $0x15180, %eax, %eax    # imm = 0x15180
addl $0xfda18e00, %eax       # imm = 0xFDA18E00
addq %r13, %rsi
addq %r14, %rsi
addq %r11, %rsi
addq %r10, %rsi
addq %rax, %rsi
leaq (%r8,%rsi), %rcx
addq $-0x15180, %rcx         # imm = 0xFFFEAE80
movq 0x30(%rsp), %r14
leaq 0x2dd0(%r14), %r13
movb 0x2dd0(%r14), %sil
cmpb $0x1, %sil
jne 0x43cc
movl 0x2db4(%r14), %eax
incl %eax
movb $0x1, %dl
movl 0x20(%rsp), %r8d
cmpl %r8d, %eax
movl 0x2c(%rsp), %r15d
jne 0x4538
movl 0x2dd4(%r14), %edx
leal 0x1e(%rdx), %eax
movl %eax, 0x2dd4(%r14)
cmpl $0x3c9, %edx            # imm = 0x3C9
movl 0x14(%rsp), %ebx
movl 0x10(%rsp), %ebp
movl 0xc(%rsp), %r11d
jle 0x454a
movl $0x3e8, %edi            # imm = 0x3E8
xorl %edx, %edx
divl %edi
movl %edx, 0x2dd4(%r14)
movq 0x2dd8(%r14), %rax
incq %rax
movq %rax, 0x2dd8(%r14)
jmp 0x4551
movq %rdi, %r14
xorl %ebx, %ebx
xorl %r13d, %r13d
xorl %r15d, %r15d
xorl %ebp, %ebp
xorl %r11d, %r11d
movl $0x0, 0x1c(%rsp)
jmp 0x438d
movl 0x20(%rsp), %r8d
movq 0x30(%rsp), %r14
cmpb $0x0, 0x2dd0(%r14)
je 0x43b1
movl %r13d, 0x18(%rsp)
leaq 0x2dd0(%r14), %r13
xorl %edx, %edx
movb $0x0, (%r13)
movb $0x1, %dil
xorl %esi, %esi
jmp 0x43e5
movb $0x0, 0x2dbc(%r14)
cmpb $0x1, 0x2dd0(%r14)
je 0x44af
jmp 0x4529
movb $0x1, %dl
movl 0x14(%rsp), %ebx
movl 0x2c(%rsp), %r15d
movl 0x10(%rsp), %ebp
movl 0xc(%rsp), %r11d
movl 0x20(%rsp), %r8d
testb %dl, %dl
je 0x445b
cmpb $0x0, 0x2dbc(%r14)
je 0x445b
movq 0x2dc8(%r14), %rax
cmpq %rcx, %rax
je 0x445b
incq %rax
cmpq %rax, %rcx
jne 0x4453
cmpb $0x1, 0x2dbd(%r14)
jne 0x4442
movl %r8d, %eax
subl 0x2dc0(%r14), %eax
cmpl $0x22, %eax
jne 0x4442
testb %sil, %sil
jne 0x4442
movb $0x1, 0x2dd0(%r14)
movl $0x14, 0x2dd4(%r14)
movq %rcx, 0x2dd8(%r14)
movb $0x1, %sil
movb $0x1, 0x2dbd(%r14)
movl %r8d, 0x2dc0(%r14)
jmp 0x445b
movb $0x0, 0x2dbd(%r14)
movb %dl, 0x2dbc(%r14)
movq %rcx, 0x2dc8(%r14)
testb %dil, %dil
je 0x44a3
leaq 0x4b77(%rip), %rax      # 0x8fec
leaq 0x4b31(%rip), %rdi      # 0x8fad
testb %sil, %sil
cmovneq %rax, %rdi
movq %r12, 0x20(%rsp)
movl %r11d, %r14d
movl %edx, %r12d
callq 0x21c0
movl %r12d, %edx
movl %r14d, %r11d
movq 0x30(%rsp), %r14
movq 0x20(%rsp), %r12
cmpb $0x0, (%r13)
je 0x44ee
movl 0x18(%rsp), %r13d
movzbl 0x1c(%rsp), %esi
movzbl %bl, %ecx
movzbl %r13b, %r8d
movzbl %r15b, %r9d
movzbl %bpl, %r10d
movzbl %r11b, %r11d
movl 0x2dd4(%r14), %ebx
subq $0x8, %rsp
leaq 0x49e1(%rip), %rdi      # 0x8eba
movl %r12d, %edx
xorl %eax, %eax
pushq %rbx
pushq %r11
pushq %r10
callq 0x2040
addq $0x58, %rsp
jmp 0x452d
testb %dl, %dl
movl 0x18(%rsp), %eax
je 0x4529
movzbl 0x1c(%rsp), %esi
movzbl %bl, %ecx
movzbl %al, %r8d
movzbl %r15b, %r9d
movzbl %bpl, %r10d
movzbl %r11b, %r11d
leaq 0x49e6(%rip), %rdi      # 0x8efb
movl %r12d, %edx
xorl %eax, %eax
pushq %r11
pushq %r10
callq 0x2040
addq $0x48, %rsp
jmp 0x452d
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0x14(%rsp), %ebx
movl 0x10(%rsp), %ebp
movl 0xc(%rsp), %r11d
jmp 0x43a5
movq 0x2dd8(%r14), %rax
movb $0x1, %dl
cmpq %rcx, %rax
jne 0x43a5
xorl %edi, %edi
jmp 0x43e5
nop