FlashGBX 3.37__py3-none-any.whl → 4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
FlashGBX/Mapper.py CHANGED
@@ -18,7 +18,7 @@ class DMG_MBC:
18
18
  RAM_BANK_SIZE = 0x2000
19
19
  ROM_BANK_NUM = 0
20
20
  CURRENT_ROM_BANK = 0
21
- CURRENT_FLASH_BANK = 0
21
+ CURRENT_FLASH_BANK = -1
22
22
  START_BANK = 0
23
23
  RTC_BUFFER = None
24
24
 
@@ -195,6 +195,12 @@ class DMG_MBC:
195
195
  def WriteRTC(self, buffer, advance=False):
196
196
  pass
197
197
 
198
+ def GetRTCDict(self):
199
+ return {}
200
+
201
+ def WriteRTCDict(self, rtc_dict):
202
+ pass
203
+
198
204
  def GetRTCString(self):
199
205
  return "Not available"
200
206
 
@@ -294,12 +300,10 @@ class DMG_MBC3(DMG_MBC):
294
300
  dprint("Latching RTC")
295
301
  self.CLK_TOGGLE_FNCPTR(60)
296
302
  self.CartWrite([ [ 0x0000, 0x0A ] ])
297
- time.sleep(0.01)
298
303
  self.CLK_TOGGLE_FNCPTR(60)
299
304
  self.CartWrite([ [ 0x6000, 0x00 ] ])
300
305
  self.CLK_TOGGLE_FNCPTR(60)
301
306
  self.CartWrite([ [ 0x6000, 0x01 ] ])
302
- time.sleep(0.01)
303
307
 
304
308
  def ReadRTC(self):
305
309
  dprint("Reading RTC")
@@ -320,7 +324,53 @@ class DMG_MBC3(DMG_MBC):
320
324
  self.CartWrite([ [0x4000, 0] ])
321
325
  self.RTC_BUFFER = buffer
322
326
  return buffer
327
+
328
+ def WriteRTCDict(self, rtc_dict):
329
+ dprint("Writing RTC:", rtc_dict)
330
+ self.EnableRAM(enable=True)
331
+
332
+ buffer = bytearray(5)
333
+ buffer[0] = rtc_dict["rtc_s"] % 60
334
+ buffer[1] = rtc_dict["rtc_m"] % 60
335
+ buffer[2] = rtc_dict["rtc_h"] % 24
336
+ buffer[3] = rtc_dict["rtc_d"] & 0xFF
337
+ buffer[4] = rtc_dict["rtc_d"] >> 8 & 1
338
+
339
+ dprint("New values: RTC_S=0x{:02X}, RTC_M=0x{:02X}, RTC_H=0x{:02X}, RTC_DL=0x{:02X}, RTC_DH=0x{:02X}".format(buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]))
340
+
341
+ # Unlock and latch RTC
342
+ self.CLK_TOGGLE_FNCPTR(50)
343
+ self.CartWrite([ [ 0x0000, 0x0A ] ])
344
+ self.CLK_TOGGLE_FNCPTR(50)
345
+ self.CartWrite([ [ 0x6000, 0x00 ] ])
346
+ self.CLK_TOGGLE_FNCPTR(50)
347
+ self.CartWrite([ [ 0x6000, 0x01 ] ])
323
348
 
349
+ # Halt RTC
350
+ self.CLK_TOGGLE_FNCPTR(50)
351
+ self.CartWrite([ [ 0x4000, 0x0C ] ])
352
+ self.CLK_TOGGLE_FNCPTR(50)
353
+ self.CartWrite([ [ 0xA000, 0x40 ] ], sram=True)
354
+
355
+ # Write to registers
356
+ for i in range(0x08, 0x0D):
357
+ self.CLK_TOGGLE_FNCPTR(50)
358
+ self.CartWrite([ [ 0x4000, i ] ])
359
+ self.CLK_TOGGLE_FNCPTR(50)
360
+ data = buffer[i-8]
361
+ self.CartWrite([ [ 0xA000, data ] ], sram=True)
362
+
363
+ # Latch RTC
364
+ self.CLK_TOGGLE_FNCPTR(50)
365
+ self.CartWrite([ [ 0x6000, 0x00 ] ])
366
+ self.CLK_TOGGLE_FNCPTR(50)
367
+ self.CartWrite([ [ 0x6000, 0x01 ] ])
368
+
369
+ self.CartWrite([ [0x4000, 0] ])
370
+ self.EnableRAM(enable=False)
371
+
372
+ return True
373
+
324
374
  def WriteRTC(self, buffer, advance=False):
325
375
  dprint("Writing RTC:", buffer)
326
376
  self.EnableRAM(enable=True)
@@ -363,55 +413,26 @@ class DMG_MBC3(DMG_MBC):
363
413
  days = days % 512
364
414
  dprint(seconds, minutes, hours, days, carry)
365
415
 
366
- buffer[0x00] = seconds % 60
367
- buffer[0x04] = minutes % 60
368
- buffer[0x08] = hours % 24
369
- buffer[0x0C] = days & 0xFF
370
- buffer[0x10] = days >> 8 & 0x1
371
- if carry:
372
- buffer[0x10] |= 0x80
416
+ #buffer[0x00] = seconds % 60
417
+ #buffer[0x04] = minutes % 60
418
+ #buffer[0x08] = hours % 24
419
+ #buffer[0x0C] = days & 0xFF
420
+ #buffer[0x10] = days >> 8 & 0x1
421
+ #if carry:
422
+ # buffer[0x10] |= 0x80
373
423
  except Exception as e:
374
424
  print("Couldn’t update the RTC register values\n", e)
375
425
 
376
- dprint("New values: RTC_S=0x{:02X}, RTC_M=0x{:02X}, RTC_H=0x{:02X}, RTC_DL=0x{:02X}, RTC_DH=0x{:02X}".format(buffer[0x00], buffer[0x04], buffer[0x08], buffer[0x0C], buffer[0x10]))
377
-
378
- # Unlock and latch RTC
379
- self.CLK_TOGGLE_FNCPTR(50)
380
- self.CartWrite([ [ 0x0000, 0x0A ] ])
381
- self.CLK_TOGGLE_FNCPTR(50)
382
- self.CartWrite([ [ 0x6000, 0x00 ] ])
383
- self.CLK_TOGGLE_FNCPTR(50)
384
- self.CartWrite([ [ 0x6000, 0x01 ] ])
385
- time.sleep(0.01)
386
-
387
- # Halt RTC
388
- self.CLK_TOGGLE_FNCPTR(50)
389
- self.CartWrite([ [ 0x4000, 0x0C ] ])
390
- self.CLK_TOGGLE_FNCPTR(50)
391
- self.CartWrite([ [ 0xA000, 0x40 ] ], sram=True)
392
- time.sleep(0.1)
393
-
394
- # Write to registers
395
- for i in range(0x08, 0x0D):
396
- self.CLK_TOGGLE_FNCPTR(50)
397
- self.CartWrite([ [ 0x4000, i ] ])
398
- self.CLK_TOGGLE_FNCPTR(50)
399
- data = struct.unpack("<I", buffer[(i-8)*4:(i-8)*4+4])[0] & 0xFF
400
- self.CartWrite([ [ 0xA000, data ] ], sram=True)
401
- time.sleep(0.1)
402
-
403
- # Latch RTC
404
- self.CLK_TOGGLE_FNCPTR(50)
405
- self.CartWrite([ [ 0x6000, 0x00 ] ])
406
- self.CLK_TOGGLE_FNCPTR(50)
407
- self.CartWrite([ [ 0x6000, 0x01 ] ])
408
- time.sleep(0.1)
409
-
410
- self.CartWrite([ [0x4000, 0] ])
426
+ d = {
427
+ "rtc_s":seconds % 60,
428
+ "rtc_m":minutes % 60,
429
+ "rtc_h":hours % 24,
430
+ "rtc_d":days % 512,
431
+ }
432
+ self.WriteRTCDict(d)
411
433
  self.EnableRAM(enable=False)
412
434
 
413
- def GetRTCString(self):
414
- s = ""
435
+ def GetRTCDict(self):
415
436
  if self.RTC_BUFFER is None:
416
437
  self.ReadRTC()
417
438
  rtc_buffer = self.RTC_BUFFER
@@ -421,21 +442,37 @@ class DMG_MBC3(DMG_MBC):
421
442
  rtc_h = rtc_buffer[0x08]
422
443
  rtc_d = (rtc_buffer[0x0C] | rtc_buffer[0x10] << 8) & 0x1FF
423
444
  rtc_carry = ((rtc_buffer[0x10] & 0x80) != 0)
424
- if rtc_carry: rtc_d += 512
445
+ d = {
446
+ "rtc_d":rtc_d,
447
+ "rtc_h":rtc_h,
448
+ "rtc_m":rtc_m,
449
+ "rtc_s":rtc_s,
450
+ "rtc_carry":rtc_carry
451
+ }
452
+
453
+ #if rtc_carry: rtc_d += 256
425
454
  if rtc_h > 24 or rtc_m > 60 or rtc_s > 60:
426
455
  try:
427
456
  dprint("Invalid RTC state: {:d} days, {:02d}:{:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m, rtc_s))
428
457
  except:
429
458
  pass
430
459
  s = "Invalid state"
460
+ d["rtc_valid"] = False
431
461
  elif rtc_h == 0 and rtc_m == 0 and rtc_s == 0 and rtc_d == 0 and rtc_carry == 0:
432
462
  s = "Not available"
463
+ d["rtc_valid"] = False
433
464
  else:
434
465
  if rtc_d == 1:
435
466
  s = "{:d} day, {:02d}:{:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m, rtc_s)
436
467
  else:
437
468
  s = "{:d} days, {:02d}:{:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m, rtc_s)
438
- return s
469
+ d["rtc_valid"] = True
470
+
471
+ d["string"] = s
472
+ return d
473
+
474
+ def GetRTCString(self):
475
+ return self.GetRTCDict()["string"]
439
476
 
440
477
  def GetMaxROMSize(self):
441
478
  return 4*1024*1024
@@ -460,11 +497,13 @@ class DMG_MBC5(DMG_MBC):
460
497
 
461
498
  def SelectBankROM(self, index):
462
499
  dprint(self.GetName(), "|", index)
500
+
501
+ self.CURRENT_ROM_BANK = index
463
502
  commands = [
464
503
  [ 0x3000, ((index >> 8) & 0xFF) ],
465
504
  [ 0x2100, index & 0xFF ],
466
505
  ]
467
-
506
+
468
507
  start_address = 0 if index == 0 else 0x4000
469
508
 
470
509
  self.CartWrite(commands)
@@ -675,7 +714,7 @@ class DMG_GBD(DMG_MBC5):
675
714
  def SelectBankROM(self, index):
676
715
  dprint(self.GetName(), "|", index)
677
716
  commands = [
678
- [ 0x2100, index & 0xFF ],
717
+ [ 0x2000, index & 0xFF ],
679
718
  ]
680
719
 
681
720
  start_address = 0 if index == 0 else 0x4000
@@ -690,43 +729,78 @@ class DMG_GMMC1(DMG_MBC5):
690
729
  def GetName(self):
691
730
  return "G-MMC1"
692
731
 
693
- def EnableMapper(self):
694
- dprint(self.GetName())
732
+ def lk_dmg_mmsa_flash_command(self, addr, data):
695
733
  commands = [
696
- # Unlock
697
- [ 0x120, 0x09, 1 ],
698
- [ 0x121, 0xAA, 1 ],
699
- [ 0x122, 0x55, 1 ],
700
- [ 0x13F, 0xA5, 1 ],
701
-
702
- [ 0x120, 0x11, 1 ],
703
- [ 0x13F, 0xA5, 1 ],
704
-
705
- [ 0x2100, 0x01, 1 ],
734
+ [0x120, 0x0F],
735
+ [0x125, addr >> 8],
736
+ [0x126, addr & 0xFF],
737
+ [0x127, data],
738
+ [0x13F, 0xA5]
739
+ ]
740
+ return commands
741
+ def lk_dmg_mmsa_access_mapper(self):
742
+ commands = [
743
+ [0x120, 0x09],
744
+ [0x121, 0xAA],
745
+ [0x122, 0x55],
746
+ [0x13F, 0xA5]
747
+ ]
748
+ return commands
749
+ def lk_dmg_mmsa_access_rom(self):
750
+ commands = [
751
+ [0x120, 0x08],
752
+ [0x13F, 0xA5]
753
+ ]
754
+ return commands
755
+ def lk_dmg_mmsa_access_mbc(self, enable):
756
+ if enable:
757
+ commands = [
758
+ [0x120, 0x11],
759
+ [0x13F, 0xA5]
760
+ ]
761
+ else:
762
+ commands = [
763
+ [0x120, 0x10],
764
+ [0x13F, 0xA5]
765
+ ]
766
+ return commands
767
+ def lk_dmg_mmsa_disable_flash_write_protect(self):
768
+ commands = [
769
+ [0x120, 0x0A],
770
+ [0x125, 0x62],
771
+ [0x126, 0x04],
772
+ [0x13F, 0xA5],
706
773
 
707
- [ 0x2100, 0x01 ],
708
- [ 0x120, 0x02 ],
709
-
710
- # Reset
711
- [ 0x120, 0x0F ],
712
- [ 0x125, 0x40 ],
713
- [ 0x126, 0x80 ],
714
- [ 0x127, 0xF0 ],
715
- [ 0x13F, 0xA5 ],
716
-
717
- [ 0x120, 0x04 ],
718
- [ 0x13F, 0xA5 ],
719
-
720
- [ 0x120, 0x08 ],
721
- [ 0x13F, 0xA5 ]
774
+ [0x120, 0x02],
775
+ [0x13F, 0xA5]
722
776
  ]
723
- self.CartWrite(commands)
777
+ return commands
778
+ def lk_dmg_mmsa_map_full(self):
779
+ commands = [
780
+ [0x120, 0x04],
781
+ [0x13F, 0xA5]
782
+ ]
783
+ return commands
784
+ def lk_dmg_mmsa_map_menu(self):
785
+ commands = [
786
+ [0x120, 0x05],
787
+ [0x13F, 0xA5]
788
+ ]
789
+ return commands
790
+
791
+ def EnableMapper(self):
792
+ dprint(self.GetName())
793
+ self.CartWrite(self.lk_dmg_mmsa_access_mapper())
794
+ self.CartWrite(self.lk_dmg_mmsa_access_mbc(enable=True))
795
+ self.CartWrite(self.lk_dmg_mmsa_map_full())
796
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x0, 0xF0))
797
+ self.CartWrite(self.lk_dmg_mmsa_access_rom())
724
798
  return True
725
799
 
726
800
  def SelectBankROM(self, index):
727
801
  dprint(self.GetName(), "|", index)
728
802
  commands = [
729
- [ 0x2100, index & 0xFF ],
803
+ [ 0x2000, index & 0xFF ],
730
804
  ]
731
805
 
732
806
  start_address = 0 if index == 0 else 0x4000
@@ -738,63 +812,30 @@ class DMG_GMMC1(DMG_MBC5):
738
812
  return True
739
813
 
740
814
  def ReadHiddenSector(self):
741
- self.EnableMapper()
742
- commands = [
743
- # Unlock
744
- [ 0x120, 0x09, 1 ],
745
- [ 0x121, 0xAA, 1 ],
746
- [ 0x122, 0x55, 1 ],
747
- [ 0x13F, 0xA5, 1 ],
748
-
749
- [ 0x120, 0x11, 1 ],
750
- [ 0x13F, 0xA5, 1 ],
751
-
752
- [ 0x2100, 0x01, 1 ],
753
-
754
- [ 0x2100, 0x01 ],
755
- [ 0x120, 0x02 ],
756
-
757
- # Request hidden sector
758
- [ 0x2100, 0x01 ],
759
-
760
- [ 0x120, 0x0F ],
761
- [ 0x125, 0x55 ],
762
- [ 0x126, 0x55 ],
763
- [ 0x127, 0xAA ],
764
- [ 0x13F, 0xA5 ],
765
-
766
- [ 0x120, 0x0F ],
767
- [ 0x125, 0x2A ],
768
- [ 0x126, 0xAA ],
769
- [ 0x127, 0x55 ],
770
- [ 0x13F, 0xA5 ],
771
-
772
- [ 0x120, 0x0F ],
773
- [ 0x125, 0x55 ],
774
- [ 0x126, 0x55 ],
775
- [ 0x127, 0x77 ],
776
- [ 0x13F, 0xA5 ],
777
-
778
- [ 0x120, 0x0F ],
779
- [ 0x125, 0x55 ],
780
- [ 0x126, 0x55 ],
781
- [ 0x127, 0xAA ],
782
- [ 0x13F, 0xA5 ],
783
-
784
- [ 0x120, 0x0F ],
785
- [ 0x125, 0x2A ],
786
- [ 0x126, 0xAA ],
787
- [ 0x127, 0x55 ],
788
- [ 0x13F, 0xA5 ],
789
-
790
- [ 0x120, 0x0F ],
791
- [ 0x125, 0x55 ],
792
- [ 0x126, 0x55 ],
793
- [ 0x127, 0x77 ],
794
- [ 0x13F, 0xA5 ]
795
- ]
796
- self.CartWrite(commands)
797
- return self.CartRead(0, 128)
815
+ hp = 5
816
+ while hp > 0:
817
+ self.EnableMapper()
818
+ rom = self.CartRead(0, 128)
819
+ self.CartWrite(self.lk_dmg_mmsa_access_mapper())
820
+ self.CartWrite(self.lk_dmg_mmsa_access_mbc(enable=True))
821
+ self.CartWrite([[0x2100, 0x1]])
822
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x5555, 0xAA))
823
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x2AAA, 0x55))
824
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x5555, 0x77))
825
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x5555, 0xAA))
826
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x2AAA, 0x55))
827
+ self.CartWrite(self.lk_dmg_mmsa_flash_command(0x5555, 0x77))
828
+ self.CartWrite([[0x2100, 0x0]])
829
+ hs = self.CartRead(0, 128)
830
+ self.CartWrite(self.lk_dmg_mmsa_access_rom())
831
+ if hs != rom: break
832
+ hp -= 1
833
+ dprint("HP:", hp, hs)
834
+
835
+ if hp > 0:
836
+ return hs
837
+ else:
838
+ return False
798
839
 
799
840
  def CalcChecksum(self, buffer):
800
841
  header = RomFileDMG(buffer[:0x180]).GetHeader()
@@ -927,52 +968,20 @@ class DMG_HuC3(DMG_MBC):
927
968
  ts = int(time.time())
928
969
  buffer.extend(struct.pack("<Q", ts))
929
970
 
930
- #dstr = ' '.join(format(x, '02X') for x in buffer)
931
- #dprint("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
971
+ dstr = ' '.join(format(x, '02X') for x in buffer)
972
+ dprint("RTC: [{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
932
973
 
933
974
  self.RTC_BUFFER = buffer
934
975
  return buffer
935
976
 
936
- def WriteRTC(self, buffer, advance=False):
937
- if advance:
938
- try:
939
- dt_now = datetime.datetime.fromtimestamp(time.time())
940
- dprint(buffer)
941
- if buffer == bytearray([0x00] * len(buffer)): # Reset
942
- hours = 0
943
- minutes = 0
944
- days = 0
945
- else:
946
- data = struct.unpack("<I", buffer[0:4])[0]
947
- hours = math.floor((data & 0xFFF) / 60)
948
- minutes = (data & 0xFFF) % 60
949
- days = (data >> 12) & 0xFFF
950
-
951
- timestamp_then = struct.unpack("<Q", buffer[-8:])[0]
952
- timestamp_now = int(time.time())
953
- dprint(hours, minutes, days)
954
- if timestamp_then < timestamp_now:
955
- dt_then = datetime.datetime.fromtimestamp(timestamp_then)
956
- dt_buffer1 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, 1, 1, 0, 0, 0), "%Y-%m-%d %H:%M:%S")
957
- dt_buffer2 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, 1, 1, hours, minutes, 0), "%Y-%m-%d %H:%M:%S")
958
- dt_buffer2 += datetime.timedelta(days=days)
959
- rd = relativedelta(dt_now, dt_then)
960
- dt_new = dt_buffer2 + rd
961
- dprint(dt_then, dt_now, dt_buffer1, dt_buffer2, dt_new, sep="\n")
962
- minutes = dt_new.minute
963
- hours = dt_new.hour
964
- #temp = dt_new - dt_buffer1
965
- #days = temp.days
966
- temp = datetime.date.fromtimestamp(timestamp_now) - datetime.date.fromtimestamp(timestamp_then)
967
- days = temp.days + days
968
- dprint(minutes, hours, days)
969
-
970
- total_minutes = 60 * hours + minutes
971
- data = (total_minutes & 0xFFF) | ((days & 0xFFF) << 12)
972
- buffer[0:4] = struct.pack("<I", data)
973
-
974
- except Exception as e:
975
- print("Couldn’t update the RTC register values\n", e)
977
+ def WriteRTCDict(self, rtc_dict):
978
+ dprint("Writing RTC:", rtc_dict)
979
+ self.EnableRAM(enable=True)
980
+
981
+ total_minutes = 60 * rtc_dict["rtc_h"] + rtc_dict["rtc_m"]
982
+ data = (total_minutes & 0xFFF) | ((rtc_dict["rtc_d"] & 0xFFF) << 12)
983
+ buffer = bytearray(4)
984
+ buffer[0:4] = struct.pack("<I", data)
976
985
 
977
986
  commands = [
978
987
  [ 0x0000, 0x0B ],
@@ -1026,18 +1035,79 @@ class DMG_HuC3(DMG_MBC):
1026
1035
  self.CartWrite(commands, delay=0.03)
1027
1036
  dstr = ' '.join(format(x, '02X') for x in buffer)
1028
1037
  dprint("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
1038
+ return True
1039
+
1040
+ def WriteRTC(self, buffer, advance=False):
1041
+ if advance:
1042
+ try:
1043
+ dt_now = datetime.datetime.fromtimestamp(time.time())
1044
+ dprint(buffer)
1045
+ if buffer == bytearray([0x00] * len(buffer)): # Reset
1046
+ hours = 0
1047
+ minutes = 0
1048
+ days = 0
1049
+ else:
1050
+ data = struct.unpack("<I", buffer[0:4])[0]
1051
+ hours = math.floor((data & 0xFFF) / 60)
1052
+ minutes = (data & 0xFFF) % 60
1053
+ days = (data >> 12) & 0xFFF
1054
+
1055
+ timestamp_then = struct.unpack("<Q", buffer[-8:])[0]
1056
+ timestamp_now = int(time.time())
1057
+ dprint(hours, minutes, days)
1058
+ if timestamp_then < timestamp_now:
1059
+ dt_then = datetime.datetime.fromtimestamp(timestamp_then)
1060
+ dt_buffer1 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, 1, 1, 0, 0, 0), "%Y-%m-%d %H:%M:%S")
1061
+ dt_buffer2 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, 1, 1, hours, minutes, 0), "%Y-%m-%d %H:%M:%S")
1062
+ dt_buffer2 += datetime.timedelta(days=days)
1063
+ rd = relativedelta(dt_now, dt_then)
1064
+ dt_new = dt_buffer2 + rd
1065
+ dprint(dt_then, dt_now, dt_buffer1, dt_buffer2, dt_new, sep="\n")
1066
+ minutes = dt_new.minute
1067
+ hours = dt_new.hour
1068
+ #temp = dt_new - dt_buffer1
1069
+ #days = temp.days
1070
+ temp = datetime.date.fromtimestamp(timestamp_now) - datetime.date.fromtimestamp(timestamp_then)
1071
+ days = temp.days + days
1072
+ dprint(minutes, hours, days)
1073
+
1074
+ #total_minutes = 60 * hours + minutes
1075
+ #data = (total_minutes & 0xFFF) | ((days & 0xFFF) << 12)
1076
+ #buffer[0:4] = struct.pack("<I", data)
1077
+ d = {
1078
+ "rtc_h":hours,
1079
+ "rtc_m":minutes,
1080
+ "rtc_d":days
1081
+ }
1082
+ self.WriteRTCDict(d)
1083
+
1084
+ except Exception as e:
1085
+ print("Couldn’t update the RTC register values\n", e)
1029
1086
 
1030
- def GetRTCString(self):
1087
+ def GetRTCDict(self):
1031
1088
  if self.RTC_BUFFER is None:
1032
1089
  self.ReadRTC()
1033
1090
  rtc_buffer = struct.unpack("<I", self.RTC_BUFFER[0:4])[0]
1034
1091
  rtc_h = math.floor((rtc_buffer & 0xFFF) / 60)
1035
1092
  rtc_m = (rtc_buffer & 0xFFF) % 60
1036
1093
  rtc_d = (rtc_buffer >> 12) & 0xFFF
1094
+
1095
+ d = {
1096
+ "rtc_h":rtc_h,
1097
+ "rtc_m":rtc_m,
1098
+ "rtc_d":rtc_d,
1099
+ "rtc_valid":True
1100
+ }
1101
+
1037
1102
  if rtc_d == 1:
1038
- return "{:d} day, {:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m)
1103
+ d["string"] = "{:d} day, {:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m)
1039
1104
  else:
1040
- return "{:d} days, {:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m)
1105
+ d["string"] = "{:d} days, {:02d}:{:02d}".format(rtc_d, rtc_h, rtc_m)
1106
+
1107
+ return d
1108
+
1109
+ def GetRTCString(self):
1110
+ return self.GetRTCDict()["string"]
1041
1111
 
1042
1112
  def GetMaxROMSize(self):
1043
1113
  return 2*1024*1024
@@ -1127,6 +1197,73 @@ class DMG_TAMA5(DMG_MBC):
1127
1197
  self.RTC_BUFFER = buffer
1128
1198
  return buffer
1129
1199
 
1200
+ def WriteRTCDict(self, rtc_dict):
1201
+ buffer = rtc_dict["rtc_buffer"]
1202
+ buffer[0x00] = Util.EncodeBCD(rtc_dict["rtc_s"])
1203
+ buffer[0x01] = Util.EncodeBCD(rtc_dict["rtc_i"])
1204
+ buffer[0x02] = Util.EncodeBCD(rtc_dict["rtc_h"])
1205
+ buffer[0x03] = ((Util.EncodeBCD(rtc_dict["rtc_d"]) & 0xF) << 4) | 6 #weekday?
1206
+ buffer[0x04] = (Util.EncodeBCD(rtc_dict["rtc_d"]) >> 4) | ((Util.EncodeBCD(rtc_dict["rtc_m"]) & 0xF) << 4)
1207
+ buffer[0x05] = (Util.EncodeBCD(rtc_dict["rtc_m"]) >> 4) | ((Util.EncodeBCD(rtc_dict["rtc_y"]) & 0xF) << 4)
1208
+ buffer[0x06] = (Util.EncodeBCD(rtc_dict["rtc_y"]) >> 4)
1209
+ buffer[0x0D] = rtc_dict["rtc_leap_year_state"] << 4 | 1 #24h flag
1210
+
1211
+ for page in range(0, 5):
1212
+ if page == 0:
1213
+ commands = [
1214
+ # Select TAMA6
1215
+ [ 0xA001, 0x06 ],
1216
+ [ 0xA000, 0x04 ],
1217
+ # Stop timer
1218
+ [ 0xA001, 0x06 ],
1219
+ [ 0xA000, 0x04 ],
1220
+ [ 0xA001, 0x07 ],
1221
+ [ 0xA000, 0x00 ],
1222
+ ]
1223
+ commands = [
1224
+ # Select TAMA6
1225
+ [ 0xA001, 0x06 ],
1226
+ [ 0xA000, 0x04 ],
1227
+ # Reset timer
1228
+ [ 0xA001, 0x06 ],
1229
+ [ 0xA000, 0x04 ],
1230
+ [ 0xA001, 0x07 ],
1231
+ [ 0xA000, 0x01 ],
1232
+ ]
1233
+ self.CartWrite(commands, sram=True)
1234
+
1235
+ page_buffer = buffer[page*8:page*8+8]
1236
+ for reg in range(0, 0x0D):
1237
+ commands = [
1238
+ # Select RTC
1239
+ [ 0xA001, 0x06 ],
1240
+ [ 0xA000, 0x08 ],
1241
+ # Select RTC register
1242
+ [ 0xA001, 0x04 ],
1243
+ [ 0xA000, reg ],
1244
+ # Set data
1245
+ [ 0xA001, 0x05 ]
1246
+ ]
1247
+ self.CartWrite(commands, sram=True)
1248
+ if reg % 2 == 0:
1249
+ self.CartWrite([[ 0xA000, page_buffer[reg>>1] & 0xF ]], sram=True)
1250
+ else:
1251
+ self.CartWrite([[ 0xA000, page_buffer[reg>>1] >> 4 ]], sram=True)
1252
+ commands = [
1253
+ # Select RTC operation
1254
+ [ 0xA001, 0x07 ],
1255
+ [ 0xA000, (page << 1) ],
1256
+ # Read data
1257
+ [ 0xA001, 0x0C ]
1258
+ ]
1259
+ self.CartWrite(commands, sram=True)
1260
+ value1, value2 = None, None
1261
+ while value1 is None or value1 != value2:
1262
+ value2 = value1
1263
+ value1 = self.CartRead(0xA000)
1264
+
1265
+ return True
1266
+
1130
1267
  def WriteRTC(self, buffer, advance=False):
1131
1268
  if advance:
1132
1269
  try:
@@ -1140,7 +1277,7 @@ class DMG_TAMA5(DMG_MBC):
1140
1277
  months = 1
1141
1278
  years = 0
1142
1279
  leap_year_state = 0
1143
- z24h_flag = 1
1280
+ #z24h_flag = 1
1144
1281
  else:
1145
1282
  #dstr = ' '.join(format(x, '02X') for x in buffer)
1146
1283
  #print("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
@@ -1153,7 +1290,7 @@ class DMG_TAMA5(DMG_MBC):
1153
1290
  months = Util.DecodeBCD(buffer[0x04] >> 4 | (buffer[0x05] & 0xF) << 4)
1154
1291
  years = Util.DecodeBCD(buffer[0x05] >> 4 | (buffer[0x06] & 0xF) << 4)
1155
1292
  leap_year_state = Util.DecodeBCD(buffer[0x0D] >> 4)
1156
- z24h_flag = Util.DecodeBCD(buffer[0x0D] & 0xF)
1293
+ #z24h_flag = Util.DecodeBCD(buffer[0x0D] & 0xF)
1157
1294
  #print("Old:", seconds, minutes, hours, day_of_week, days, months, years, leap_year_state, z24h_flag)
1158
1295
 
1159
1296
  timestamp_then = struct.unpack("<Q", buffer[-8:])[0]
@@ -1190,14 +1327,14 @@ class DMG_TAMA5(DMG_MBC):
1190
1327
  #print("leap_year_state#2", leap_year_state)
1191
1328
  #print("New:", seconds, minutes, hours, day_of_week, days, months, years, leap_year_state, z24h_flag)
1192
1329
 
1193
- buffer[0x00] = Util.EncodeBCD(seconds)
1194
- buffer[0x01] = Util.EncodeBCD(minutes)
1195
- buffer[0x02] = Util.EncodeBCD(hours)
1196
- buffer[0x03] = (weekday & 0xF) | ((Util.EncodeBCD(days) & 0xF) << 4)
1197
- buffer[0x04] = (Util.EncodeBCD(days) >> 4) | ((Util.EncodeBCD(months) & 0xF) << 4)
1198
- buffer[0x05] = (Util.EncodeBCD(months) >> 4) | ((Util.EncodeBCD(years) & 0xF) << 4)
1199
- buffer[0x06] = (Util.EncodeBCD(years) >> 4)
1200
- buffer[0x0D] = leap_year_state << 4 | z24h_flag
1330
+ # buffer[0x00] = Util.EncodeBCD(seconds)
1331
+ # buffer[0x01] = Util.EncodeBCD(minutes)
1332
+ # buffer[0x02] = Util.EncodeBCD(hours)
1333
+ # buffer[0x03] = (weekday & 0xF) | ((Util.EncodeBCD(days) & 0xF) << 4)
1334
+ # buffer[0x04] = (Util.EncodeBCD(days) >> 4) | ((Util.EncodeBCD(months) & 0xF) << 4)
1335
+ # buffer[0x05] = (Util.EncodeBCD(months) >> 4) | ((Util.EncodeBCD(years) & 0xF) << 4)
1336
+ # buffer[0x06] = (Util.EncodeBCD(years) >> 4)
1337
+ # buffer[0x0D] = leap_year_state << 4 | z24h_flag
1201
1338
 
1202
1339
  #dstr = ' '.join(format(x, '02X') for x in buffer)
1203
1340
  #print("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
@@ -1205,61 +1342,20 @@ class DMG_TAMA5(DMG_MBC):
1205
1342
  except Exception as e:
1206
1343
  print("Couldn’t update the RTC register values\n", e)
1207
1344
 
1208
- for page in range(0, 4):
1209
- if page == 0:
1210
- commands = [
1211
- # Select TAMA6
1212
- [ 0xA001, 0x06 ],
1213
- [ 0xA000, 0x04 ],
1214
- # Stop timer
1215
- [ 0xA001, 0x06 ],
1216
- [ 0xA000, 0x04 ],
1217
- [ 0xA001, 0x07 ],
1218
- [ 0xA000, 0x00 ],
1219
- ]
1220
- commands = [
1221
- # Select TAMA6
1222
- [ 0xA001, 0x06 ],
1223
- [ 0xA000, 0x04 ],
1224
- # Reset timer
1225
- [ 0xA001, 0x06 ],
1226
- [ 0xA000, 0x04 ],
1227
- [ 0xA001, 0x07 ],
1228
- [ 0xA000, 0x01 ],
1229
- ]
1230
- self.CartWrite(commands, sram=True)
1231
-
1232
- page_buffer = buffer[page*8:page*8+8]
1233
- for reg in range(0, 0x0D):
1234
- commands = [
1235
- # Select RTC
1236
- [ 0xA001, 0x06 ],
1237
- [ 0xA000, 0x08 ],
1238
- # Select RTC register
1239
- [ 0xA001, 0x04 ],
1240
- [ 0xA000, reg ],
1241
- # Set data
1242
- [ 0xA001, 0x05 ]
1243
- ]
1244
- self.CartWrite(commands, sram=True)
1245
- if reg % 2 == 0:
1246
- self.CartWrite([[ 0xA000, page_buffer[reg>>1] & 0xF ]], sram=True)
1247
- else:
1248
- self.CartWrite([[ 0xA000, page_buffer[reg>>1] >> 4 ]], sram=True)
1249
- commands = [
1250
- # Select RTC operation
1251
- [ 0xA001, 0x07 ],
1252
- [ 0xA000, (page << 1) ],
1253
- # Read data
1254
- [ 0xA001, 0x0C ]
1255
- ]
1256
- self.CartWrite(commands, sram=True)
1257
- value1, value2 = None, None
1258
- while value1 is None or value1 != value2:
1259
- value2 = value1
1260
- value1 = self.CartRead(0xA000)
1261
-
1262
- def GetRTCString(self):
1345
+ d = {
1346
+ "rtc_y":years,
1347
+ "rtc_m":months,
1348
+ "rtc_d":days,
1349
+ "rtc_h":hours,
1350
+ "rtc_i":minutes,
1351
+ "rtc_s":seconds,
1352
+ "rtc_leap_year_state":leap_year_state,
1353
+ "rtc_buffer":buffer,
1354
+ "rtc_valid":True
1355
+ }
1356
+ self.WriteRTCDict(d)
1357
+
1358
+ def GetRTCDict(self):
1263
1359
  if self.RTC_BUFFER is None:
1264
1360
  self.ReadRTC()
1265
1361
  rtc_buffer = self.RTC_BUFFER
@@ -1271,11 +1367,28 @@ class DMG_TAMA5(DMG_MBC):
1271
1367
  months = Util.DecodeBCD(rtc_buffer[0x04] >> 4 | (rtc_buffer[0x05] & 0xF) << 4)
1272
1368
  years = Util.DecodeBCD(rtc_buffer[0x05] >> 4 | (rtc_buffer[0x06] & 0xF) << 4)
1273
1369
  leap_year_state = Util.DecodeBCD(rtc_buffer[0x0D] >> 4)
1370
+
1371
+ d = {
1372
+ "rtc_y":years,
1373
+ "rtc_m":months,
1374
+ "rtc_d":days,
1375
+ #"rtc_w":weekday,
1376
+ "rtc_h":hours,
1377
+ "rtc_i":minutes,
1378
+ "rtc_s":seconds,
1379
+ "rtc_leap_year_state":leap_year_state,
1380
+ "rtc_buffer":rtc_buffer,
1381
+ "rtc_valid":True
1382
+ }
1383
+
1274
1384
  if leap_year_state == 0:
1275
- return "Year {:d}*, {:d}-{:d}, {:02d}:{:02d}:{:02d}".format(years, months, days, hours, minutes, seconds)
1385
+ d["string"] = "{:d} year(s)ᴸ, {:d}-{:d}, {:02d}:{:02d}:{:02d}".format(years - 19, months, days, hours, minutes, seconds)
1276
1386
  else:
1277
- return "Year {:d}, {:d}-{:d}, {:02d}:{:02d}:{:02d}".format(years, months, days, hours, minutes, seconds)
1278
-
1387
+ d["string"] = "{:d} year(s), {:d}-{:d}, {:02d}:{:02d}:{:02d}".format(years - 19, months, days, hours, minutes, seconds)
1388
+ return d
1389
+
1390
+ def GetRTCString(self):
1391
+ return self.GetRTCDict()["string"]
1279
1392
 
1280
1393
  def ReadWithCSPulse(self):
1281
1394
  return False
@@ -1297,7 +1410,10 @@ class DMG_Unlicensed_256M(DMG_MBC5):
1297
1410
  flash_bank = math.floor(index / 512)
1298
1411
  dprint(self.GetName(), "|SelectBankFlash()|", index, "->", flash_bank)
1299
1412
 
1300
- self.CART_POWERCYCLE_FNCPTR()
1413
+ if self.CURRENT_FLASH_BANK != flash_bank:
1414
+ dprint("Power cycling now")
1415
+ self.CART_POWERCYCLE_FNCPTR()
1416
+ self.CURRENT_FLASH_BANK = flash_bank
1301
1417
 
1302
1418
  commands = [
1303
1419
  [ 0x7000, 0x00 ],
@@ -1308,7 +1424,7 @@ class DMG_Unlicensed_256M(DMG_MBC5):
1308
1424
  self.CartWrite(commands, delay=0.1)
1309
1425
 
1310
1426
  def SelectBankROM(self, index):
1311
- dprint(self.GetName(), "|SelectBankROM()|", index)
1427
+ dprint(self.GetName(), index)
1312
1428
 
1313
1429
  if (index % 512 == 0) or (self.CURRENT_FLASH_BANK != math.floor(index / 512)):
1314
1430
  self.SelectBankFlash(index)
@@ -1333,6 +1449,8 @@ class DMG_Unlicensed_256M(DMG_MBC5):
1333
1449
  if index % 4 == 0:
1334
1450
  self.EnableRAM(enable=False)
1335
1451
  self.CART_POWERCYCLE_FNCPTR()
1452
+ self.CURRENT_FLASH_BANK = flash_bank
1453
+
1336
1454
  commands = [
1337
1455
  [ 0x7000, (0x40 * math.floor(index / 4)) & 0xFF ],
1338
1456
  [ 0x7001, 0xC0 ],
@@ -1385,15 +1503,18 @@ class DMG_Unlicensed_XploderGB(DMG_MBC):
1385
1503
  def SelectBankROM(self, index):
1386
1504
  dprint(self.GetName(), "|", index)
1387
1505
  if index == 0:
1506
+ self.CartRead(0x0102, 1)
1388
1507
  self.CART_POWERCYCLE_FNCPTR()
1389
1508
  self.CartRead(0x0102, 1)
1390
1509
  self.CartWrite([[ 0x0006, index & 0xFF ]])
1510
+ self.CURRENT_ROM_BANK = index
1391
1511
  start_address = 0x4000
1392
1512
  return (start_address, self.ROM_BANK_SIZE)
1393
1513
 
1394
1514
  def SelectBankRAM(self, index):
1395
1515
  dprint(self.GetName(), "|", index)
1396
1516
  if index == 0:
1517
+ self.CartRead(0x0102, 1)
1397
1518
  self.CART_POWERCYCLE_FNCPTR()
1398
1519
  self.CartRead(0x0102, 1)
1399
1520
  return self.SelectBankROM(index + 8)
@@ -1479,8 +1600,8 @@ class AGB_GPIO:
1479
1600
 
1480
1601
  # Commands
1481
1602
  RTC_RESET = 0x60
1482
- RTC_WRITE_STATS = 0x62
1483
- RTC_READ_STATS = 0x63
1603
+ RTC_WRITE_STATUS = 0x62
1604
+ RTC_READ_STATUS = 0x63
1484
1605
  RTC_WRITE_DATE = 0x64
1485
1606
  RTC_READ_DATE = 0x65
1486
1607
  RTC_WRITE_TIME = 0x66
@@ -1502,10 +1623,10 @@ class AGB_GPIO:
1502
1623
  data = self.CART_READ_FNCPTR(address)
1503
1624
  data = struct.pack(">H", data)
1504
1625
  data = struct.unpack("<H", data)[0]
1505
- dprint("0x{:X} is 0x{:X}".format(address, data))
1626
+ #dprint("0x{:X} is 0x{:X}".format(address, data))
1506
1627
  else:
1507
1628
  data = self.CART_READ_FNCPTR(address, length)
1508
- dprint("0x{:X} is".format(address), data)
1629
+ #dprint("0x{:X} is".format(address), data)
1509
1630
 
1510
1631
  return data
1511
1632
 
@@ -1513,7 +1634,7 @@ class AGB_GPIO:
1513
1634
  for command in commands:
1514
1635
  address = command[0]
1515
1636
  value = command[1]
1516
- dprint("0x{:X} = 0x{:X}".format(address, value))
1637
+ # dprint("0x{:X} = 0x{:X}".format(address, value))
1517
1638
  self.CART_WRITE_FNCPTR(address, value)
1518
1639
  if delay is not False: time.sleep(delay)
1519
1640
 
@@ -1538,9 +1659,10 @@ class AGB_GPIO:
1538
1659
  [ self.GPIO_REG_DAT, 4 ],
1539
1660
  [ self.GPIO_REG_DAT, 5 ]
1540
1661
  ])
1541
- bit = (self.CartRead(self.GPIO_REG_DAT) & 2) >> 1
1662
+ temp = self.CartRead(self.GPIO_REG_DAT) & 0xFF
1663
+ bit = (temp & 2) >> 1
1542
1664
  data = (data >> 1) | (bit << 7)
1543
- dprint(bit, data)
1665
+ # print("RTCReadData(): i={:d}/temp={:X}/bit={:x}/data={:x}".format(i, temp, bit, data))
1544
1666
  return data
1545
1667
 
1546
1668
  def RTCWriteData(self, data):
@@ -1560,7 +1682,7 @@ class AGB_GPIO:
1560
1682
  [ self.GPIO_REG_DAT, 5 ],
1561
1683
  [ self.GPIO_REG_CNT, 7 ], # Write Enable
1562
1684
  ])
1563
- self.RTCCommand(self.RTC_READ_STATS)
1685
+ self.RTCCommand(self.RTC_READ_STATUS)
1564
1686
  self.CartWrite([
1565
1687
  [ self.GPIO_REG_CNT, 5 ], # Read Enable
1566
1688
  ])
@@ -1579,7 +1701,7 @@ class AGB_GPIO:
1579
1701
  [ self.GPIO_REG_DAT, 5 ],
1580
1702
  [ self.GPIO_REG_CNT, 7 ], # Write Enable
1581
1703
  ])
1582
- self.RTCCommand(self.RTC_WRITE_STATS)
1704
+ self.RTCCommand(self.RTC_WRITE_STATUS)
1583
1705
  self.RTCWriteData(value)
1584
1706
 
1585
1707
  self.CartWrite([
@@ -1588,11 +1710,15 @@ class AGB_GPIO:
1588
1710
  [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1589
1711
  ])
1590
1712
 
1591
- def HasRTC(self):
1713
+ def HasRTC(self, buffer=None):
1592
1714
  if not self.RTC: return False
1715
+ if buffer is not None: self.RTC_BUFFER = buffer[1:]
1593
1716
 
1594
- status = self.RTCReadStatus()
1595
- dprint(status)
1717
+ if buffer is None:
1718
+ status = self.RTCReadStatus()
1719
+ else:
1720
+ status = buffer[0]
1721
+
1596
1722
  if (status >> 7) == 1:
1597
1723
  dprint("No RTC because of set RTC Status Register Power Flag:", status >> 7 & 1)
1598
1724
  return 1
@@ -1601,41 +1727,46 @@ class AGB_GPIO:
1601
1727
  #return 2
1602
1728
 
1603
1729
  rom1 = self.CartRead(self.GPIO_REG_DAT, 6)
1604
- self.CartWrite([
1605
- [ self.GPIO_REG_RE, 1 ], # Enable RTC Mapping
1606
- ])
1607
- rom2 = self.CartRead(self.GPIO_REG_DAT, 6)
1608
- self.CartWrite([
1609
- [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1610
- ])
1611
- #dprint(rom1, rom2)
1730
+ if buffer is None:
1731
+ self.CartWrite([
1732
+ [ self.GPIO_REG_RE, 1 ], # Enable RTC Mapping
1733
+ ])
1734
+ rom2 = self.CartRead(self.GPIO_REG_DAT, 6)
1735
+ self.CartWrite([
1736
+ [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1737
+ ])
1738
+ else:
1739
+ rom2 = buffer[1:7]
1740
+
1741
+ dprint(' '.join(format(x, '02X') for x in rom1), "/", ' '.join(format(x, '02X') for x in rom2))
1612
1742
  if (rom1 == rom2):
1613
1743
  dprint("No RTC because ROM data didn’t change:", rom1, rom2)
1614
1744
  return 3
1615
-
1745
+
1616
1746
  return True
1617
1747
 
1618
- def ReadRTC(self):
1748
+ def ReadRTC(self, buffer=None):
1619
1749
  if not self.RTC: return False
1620
- self.CartWrite([
1621
- [ self.GPIO_REG_RE, 1 ], # Enable RTC Mapping
1622
- [ self.GPIO_REG_DAT, 1 ],
1623
- [ self.GPIO_REG_DAT, 5 ],
1624
- [ self.GPIO_REG_CNT, 7 ], # Write Enable
1625
- ])
1626
- self.RTCCommand(self.RTC_READ_DATE)
1627
- self.CartWrite([
1628
- [ self.GPIO_REG_CNT, 5 ], # Read Enable
1629
- ])
1630
- buffer = bytearray()
1631
- for _ in range(0, 7):
1632
- buffer.append(self.RTCReadData())
1633
-
1634
- self.CartWrite([
1635
- [ self.GPIO_REG_DAT, 1 ],
1636
- [ self.GPIO_REG_DAT, 1 ],
1637
- [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1638
- ])
1750
+ if buffer is None:
1751
+ self.CartWrite([
1752
+ [ self.GPIO_REG_RE, 1 ], # Enable RTC Mapping
1753
+ [ self.GPIO_REG_DAT, 1 ],
1754
+ [ self.GPIO_REG_DAT, 5 ],
1755
+ [ self.GPIO_REG_CNT, 7 ], # Write Enable
1756
+ ])
1757
+ self.RTCCommand(self.RTC_READ_DATE)
1758
+ self.CartWrite([
1759
+ [ self.GPIO_REG_CNT, 5 ], # Read Enable
1760
+ ])
1761
+ buffer = bytearray()
1762
+ for _ in range(0, 7):
1763
+ buffer.append(self.RTCReadData())
1764
+
1765
+ self.CartWrite([
1766
+ [ self.GPIO_REG_DAT, 1 ],
1767
+ [ self.GPIO_REG_DAT, 1 ],
1768
+ [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1769
+ ])
1639
1770
 
1640
1771
  # Add timestamp of backup time
1641
1772
  ts = int(time.time())
@@ -1653,48 +1784,80 @@ class AGB_GPIO:
1653
1784
  self.RTC_BUFFER = buffer
1654
1785
  return buffer
1655
1786
 
1787
+ def WriteRTCDict(self, rtc_dict):
1788
+ buffer = bytearray(7)
1789
+ try:
1790
+ buffer[0] = Util.EncodeBCD(rtc_dict["rtc_y"])
1791
+ buffer[1] = Util.EncodeBCD(rtc_dict["rtc_m"])
1792
+ buffer[2] = Util.EncodeBCD(rtc_dict["rtc_d"])
1793
+ buffer[3] = Util.EncodeBCD(rtc_dict["rtc_w"])
1794
+ buffer[4] = Util.EncodeBCD(rtc_dict["rtc_h"])
1795
+ if buffer[4] >= 12: buffer[4] |= 0x80
1796
+ buffer[5] = Util.EncodeBCD(rtc_dict["rtc_i"])
1797
+ buffer[6] = Util.EncodeBCD(rtc_dict["rtc_s"])
1798
+ dprint("New values: RTC_Y=0x{:02X}, RTC_M=0x{:02X}, RTC_D=0x{:02X}, RTC_W=0x{:02X}, RTC_H=0x{:02X}, RTC_I=0x{:02X}, RTC_S=0x{:02X}".format(buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6]))
1799
+ except ValueError as e:
1800
+ print("Couldn’t update the RTC register values\n", e)
1801
+
1802
+ self.CartWrite([
1803
+ [ self.GPIO_REG_RE, 1 ], # Enable RTC Mapping
1804
+ [ self.GPIO_REG_DAT, 1 ],
1805
+ [ self.GPIO_REG_DAT, 5 ],
1806
+ [ self.GPIO_REG_CNT, 7 ], # Write Enable
1807
+ ])
1808
+ self.RTCCommand(self.RTC_WRITE_DATE)
1809
+ for i in range(0, 7):
1810
+ self.RTCWriteData(buffer[i])
1811
+
1812
+ self.CartWrite([
1813
+ [ self.GPIO_REG_DAT, 1 ],
1814
+ [ self.GPIO_REG_DAT, 1 ],
1815
+ [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1816
+ ])
1817
+ return True
1818
+
1656
1819
  def WriteRTC(self, buffer, advance=False):
1657
1820
  rtc_status = None
1821
+ if buffer == bytearray([0xFF] * len(buffer)): # Reset
1822
+ years = 0
1823
+ months = 1
1824
+ days = 1
1825
+ weekday = 0
1826
+ hours = 0
1827
+ minutes = 0
1828
+ seconds = 0
1829
+ rtc_status = 0x40 | 0x80
1830
+ else:
1831
+ years = Util.DecodeBCD(buffer[0x00])
1832
+ months = Util.DecodeBCD(buffer[0x01])
1833
+ days = Util.DecodeBCD(buffer[0x02])
1834
+ weekday = Util.DecodeBCD(buffer[0x03])
1835
+ hours = Util.DecodeBCD(buffer[0x04] & 0x7F)
1836
+ minutes = Util.DecodeBCD(buffer[0x05])
1837
+ seconds = Util.DecodeBCD(buffer[0x06])
1838
+ rtc_status = buffer[0x07]
1839
+ if rtc_status == 0x01: rtc_status = 0x40 # old dumps had this value
1840
+
1658
1841
  if advance:
1659
1842
  try:
1660
1843
  dt_now = datetime.datetime.fromtimestamp(time.time())
1661
- if buffer == bytearray([0xFF] * len(buffer)): # Reset
1662
- years = 0
1663
- months = 1
1664
- days = 1
1665
- weekday = 0
1666
- hours = 0
1667
- minutes = 0
1668
- seconds = 0
1669
- rtc_status = 0x40 | 0x80
1670
- else:
1671
- years = Util.DecodeBCD(buffer[0x00])
1672
- months = Util.DecodeBCD(buffer[0x01])
1673
- days = Util.DecodeBCD(buffer[0x02])
1674
- weekday = Util.DecodeBCD(buffer[0x03])
1675
- hours = Util.DecodeBCD(buffer[0x04] & 0x7F)
1676
- minutes = Util.DecodeBCD(buffer[0x05])
1677
- seconds = Util.DecodeBCD(buffer[0x06])
1678
- rtc_status = buffer[0x07]
1679
- if rtc_status == 0x01: rtc_status = 0x40 # old dumps had this value
1680
-
1681
- timestamp_then = struct.unpack("<Q", buffer[-8:])[0]
1682
- timestamp_now = int(time.time())
1683
- if timestamp_then < timestamp_now:
1684
- dt_then = datetime.datetime.fromtimestamp(timestamp_then)
1685
- dt_buffer = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(years + 2000, months % 13, days % 32, hours % 60, minutes % 60, seconds % 60), "%Y-%m-%d %H:%M:%S")
1686
- rd = relativedelta(dt_now, dt_then)
1687
- dt_new = dt_buffer + rd
1688
- years = dt_new.year - 2000
1689
- months = dt_new.month
1690
- days = dt_new.day
1691
- dt_buffer_notime = dt_buffer.replace(hour=0, minute=0, second=0)
1692
- dt_new_notime = dt_new.replace(hour=0, minute=0, second=0)
1693
- days_passed = int((dt_new_notime.timestamp() - dt_buffer_notime.timestamp()) / 60 / 60 / 24)
1694
- weekday += days_passed % 7
1695
- hours = dt_new.hour
1696
- minutes = dt_new.minute
1697
- seconds = dt_new.second
1844
+ timestamp_then = struct.unpack("<Q", buffer[-8:])[0]
1845
+ timestamp_now = int(time.time())
1846
+ if timestamp_then < timestamp_now:
1847
+ dt_then = datetime.datetime.fromtimestamp(timestamp_then)
1848
+ dt_buffer = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(years + 2000, months % 13, days % 32, hours % 60, minutes % 60, seconds % 60), "%Y-%m-%d %H:%M:%S")
1849
+ rd = relativedelta(dt_now, dt_then)
1850
+ dt_new = dt_buffer + rd
1851
+ years = dt_new.year - 2000
1852
+ months = dt_new.month
1853
+ days = dt_new.day
1854
+ dt_buffer_notime = dt_buffer.replace(hour=0, minute=0, second=0)
1855
+ dt_new_notime = dt_new.replace(hour=0, minute=0, second=0)
1856
+ days_passed = int((dt_new_notime.timestamp() - dt_buffer_notime.timestamp()) / 60 / 60 / 24)
1857
+ weekday += days_passed % 7
1858
+ hours = dt_new.hour
1859
+ minutes = dt_new.minute
1860
+ seconds = dt_new.second
1698
1861
 
1699
1862
  #dprint(years, months, days, weekday, hours, minutes, seconds)
1700
1863
  buffer[0x00] = Util.EncodeBCD(years)
@@ -1712,48 +1875,63 @@ class AGB_GPIO:
1712
1875
  except Exception as e:
1713
1876
  print("Couldn’t update the RTC register values\n", e)
1714
1877
 
1715
- self.CartWrite([
1716
- [ self.GPIO_REG_RE, 1 ], # Enable RTC Mapping
1717
- [ self.GPIO_REG_DAT, 1 ],
1718
- [ self.GPIO_REG_DAT, 5 ],
1719
- [ self.GPIO_REG_CNT, 7 ], # Write Enable
1720
- ])
1721
- self.RTCCommand(self.RTC_WRITE_DATE)
1722
- for i in range(0, 7):
1723
- self.RTCWriteData(buffer[i])
1724
-
1725
- self.CartWrite([
1726
- [ self.GPIO_REG_DAT, 1 ],
1727
- [ self.GPIO_REG_DAT, 1 ],
1728
- [ self.GPIO_REG_RE, 0 ], # Disable RTC Mapping
1729
- ])
1878
+ d = {
1879
+ "rtc_y":years,
1880
+ "rtc_m":months,
1881
+ "rtc_d":days,
1882
+ "rtc_w":weekday,
1883
+ "rtc_h":hours,
1884
+ "rtc_i":minutes,
1885
+ "rtc_s":seconds,
1886
+ }
1887
+ dprint(d)
1888
+ self.WriteRTCDict(d)
1730
1889
 
1731
1890
  if rtc_status is not None:
1732
1891
  self.RTCWriteStatus(rtc_status)
1733
1892
 
1734
- def GetRTCString(self):
1735
- has_rtc = self.HasRTC()
1893
+ def GetRTCDict(self, has_rtc=None):
1894
+ if has_rtc is None:
1895
+ has_rtc = self.HasRTC()
1736
1896
  if has_rtc is not True:
1737
- if has_rtc is False:
1738
- return "Not available"
1897
+ if has_rtc is False or has_rtc in (2, 3):
1898
+ return {"string":"Not available"}
1739
1899
  elif has_rtc == 1:
1740
- return "Not available / Battery dry"
1741
- elif has_rtc == 3:
1742
- return "Not available"
1743
-
1900
+ return {"string":"Not available / Battery dry"}
1901
+
1744
1902
  if self.RTC_BUFFER is None:
1745
1903
  self.ReadRTC()
1746
1904
  rtc_buffer = self.RTC_BUFFER
1905
+
1747
1906
  #weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
1748
1907
  rtc_y = (rtc_buffer[0] & 0x0F) + ((rtc_buffer[0] >> 4) * 10)
1749
1908
  rtc_m = (rtc_buffer[1] & 0x0F) + ((rtc_buffer[1] >> 4) * 10)
1750
1909
  rtc_d = (rtc_buffer[2] & 0x0F) + ((rtc_buffer[2] >> 4) * 10)
1751
- #rtc_w = (rtc_buffer[3] & 0x0F) + ((rtc_buffer[3] >> 4) * 10)
1910
+ rtc_w = (rtc_buffer[3] & 0x0F) + ((rtc_buffer[3] >> 4) * 10)
1752
1911
  rtc_h = ((rtc_buffer[4] & 0x0F) + (((rtc_buffer[4] >> 4) & 0x7) * 10))
1753
1912
  rtc_i = (rtc_buffer[5] & 0x0F) + ((rtc_buffer[5] >> 4) * 10)
1754
1913
  rtc_s = (rtc_buffer[6] & 0x0F) + ((rtc_buffer[6] >> 4) * 10)
1755
1914
 
1915
+ d = {
1916
+ "rtc_y":rtc_y,
1917
+ "rtc_m":rtc_m,
1918
+ "rtc_d":rtc_d,
1919
+ "rtc_w":rtc_w,
1920
+ "rtc_h":rtc_h,
1921
+ "rtc_i":rtc_i,
1922
+ "rtc_s":rtc_s,
1923
+ "rtc_24h":rtc_buffer[0] >> 6 & 1
1924
+ }
1925
+
1756
1926
  if rtc_y == 0 and rtc_m == 0 and rtc_d == 0 and rtc_h == 0 and rtc_i == 0 and rtc_s == 0:
1757
- raise Exception("Invalid RTC data")
1927
+ #raise ValueError("Invalid RTC data")
1928
+ d["string"] = "Invalid RTC data"
1929
+ d["rtc_valid"] = False
1758
1930
  else:
1759
- return "20{:02d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(rtc_y, rtc_m, rtc_d, rtc_h, rtc_i, rtc_s)
1931
+ d["string"] = "20{:02d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(rtc_y, rtc_m, rtc_d, rtc_h, rtc_i, rtc_s)
1932
+ d["rtc_valid"] = True
1933
+
1934
+ return d
1935
+
1936
+ def GetRTCString(self, has_rtc=None):
1937
+ return self.GetRTCDict(has_rtc=has_rtc)["string"]