ac6502 1.3.0 → 1.4.1

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.
Files changed (141) hide show
  1. package/README.md +139 -32
  2. package/dist/components/IO/ACIA.d.ts +76 -0
  3. package/dist/components/IO/ACIA.js +282 -0
  4. package/dist/components/IO/ACIA.js.map +1 -0
  5. package/dist/components/IO/Attachments/Attachment.d.ts +112 -0
  6. package/dist/components/IO/Attachments/Attachment.js +71 -0
  7. package/dist/components/IO/Attachments/Attachment.js.map +1 -0
  8. package/dist/components/IO/Attachments/JoystickAttachment.d.ts +53 -0
  9. package/dist/components/IO/Attachments/JoystickAttachment.js +90 -0
  10. package/dist/components/IO/Attachments/JoystickAttachment.js.map +1 -0
  11. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.d.ts +63 -0
  12. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js +489 -0
  13. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js.map +1 -0
  14. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.d.ts +44 -0
  15. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js +274 -0
  16. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js.map +1 -0
  17. package/dist/components/IO/Attachments/KeypadAttachment.d.ts +47 -0
  18. package/dist/components/IO/Attachments/KeypadAttachment.js +141 -0
  19. package/dist/components/IO/Attachments/KeypadAttachment.js.map +1 -0
  20. package/dist/components/IO/Attachments/LCDAttachment.d.ts +110 -0
  21. package/dist/components/IO/Attachments/LCDAttachment.js +716 -0
  22. package/dist/components/IO/Attachments/LCDAttachment.js.map +1 -0
  23. package/dist/components/IO/Attachments/SNESAttachment.d.ts +85 -0
  24. package/dist/components/IO/Attachments/SNESAttachment.js +184 -0
  25. package/dist/components/IO/Attachments/SNESAttachment.js.map +1 -0
  26. package/dist/components/IO/Empty.d.ts +9 -0
  27. package/dist/components/IO/Empty.js +5 -7
  28. package/dist/components/IO/Empty.js.map +1 -1
  29. package/dist/components/IO/GPIOCard.d.ts +5 -5
  30. package/dist/components/IO/GPIOCard.js.map +1 -1
  31. package/dist/components/IO/RAMBank.d.ts +37 -0
  32. package/dist/components/IO/RAMBank.js +63 -0
  33. package/dist/components/IO/RAMBank.js.map +1 -0
  34. package/dist/components/IO/RTC.d.ts +107 -0
  35. package/dist/components/IO/RTC.js +483 -0
  36. package/dist/components/IO/RTC.js.map +1 -0
  37. package/dist/components/IO/Sound.d.ts +120 -0
  38. package/dist/components/IO/Sound.js +622 -0
  39. package/dist/components/IO/Sound.js.map +1 -0
  40. package/dist/components/IO/Storage.d.ts +74 -0
  41. package/dist/components/IO/Storage.js +409 -0
  42. package/dist/components/IO/Storage.js.map +1 -0
  43. package/dist/components/IO/Terminal.d.ts +19 -0
  44. package/dist/components/IO/Terminal.js +33 -0
  45. package/dist/components/IO/Terminal.js.map +1 -0
  46. package/dist/components/IO/VIA.d.ts +105 -0
  47. package/dist/components/IO/VIA.js +597 -0
  48. package/dist/components/IO/VIA.js.map +1 -0
  49. package/dist/components/IO/Video.d.ts +141 -0
  50. package/dist/components/IO/Video.js +630 -0
  51. package/dist/components/IO/Video.js.map +1 -0
  52. package/dist/components/Machine.d.ts +20 -24
  53. package/dist/components/Machine.js +249 -166
  54. package/dist/components/Machine.js.map +1 -1
  55. package/dist/index.js +28 -14
  56. package/dist/index.js.map +1 -1
  57. package/dist/lib.d.ts +16 -16
  58. package/dist/lib.js +32 -32
  59. package/dist/lib.js.map +1 -1
  60. package/dist/tests/IO/ACIA.test.d.ts +1 -0
  61. package/dist/tests/IO/ACIA.test.js +423 -0
  62. package/dist/tests/IO/ACIA.test.js.map +1 -0
  63. package/dist/tests/IO/Attachments/Attachment.test.d.ts +1 -0
  64. package/dist/tests/IO/Attachments/Attachment.test.js +339 -0
  65. package/dist/tests/IO/Attachments/Attachment.test.js.map +1 -0
  66. package/dist/tests/IO/Attachments/JoystickAttachment.test.d.ts +1 -0
  67. package/dist/tests/IO/Attachments/JoystickAttachment.test.js +126 -0
  68. package/dist/tests/IO/Attachments/JoystickAttachment.test.js.map +1 -0
  69. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.d.ts +1 -0
  70. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js +779 -0
  71. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js.map +1 -0
  72. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.d.ts +1 -0
  73. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js +355 -0
  74. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js.map +1 -0
  75. package/dist/tests/IO/Attachments/KeypadAttachment.test.d.ts +1 -0
  76. package/dist/tests/IO/Attachments/KeypadAttachment.test.js +323 -0
  77. package/dist/tests/IO/Attachments/KeypadAttachment.test.js.map +1 -0
  78. package/dist/tests/IO/Attachments/LCDAttachment.test.d.ts +1 -0
  79. package/dist/tests/IO/Attachments/LCDAttachment.test.js +627 -0
  80. package/dist/tests/IO/Attachments/LCDAttachment.test.js.map +1 -0
  81. package/dist/tests/IO/Attachments/SNESAttachment.test.d.ts +1 -0
  82. package/dist/tests/IO/Attachments/SNESAttachment.test.js +331 -0
  83. package/dist/tests/IO/Attachments/SNESAttachment.test.js.map +1 -0
  84. package/dist/tests/IO/Empty.test.d.ts +1 -0
  85. package/dist/tests/IO/Empty.test.js +121 -0
  86. package/dist/tests/IO/Empty.test.js.map +1 -0
  87. package/dist/tests/IO/GPIOCard.test.js.map +1 -1
  88. package/dist/tests/IO/RAMBank.test.d.ts +1 -0
  89. package/dist/tests/IO/RAMBank.test.js +229 -0
  90. package/dist/tests/IO/RAMBank.test.js.map +1 -0
  91. package/dist/tests/IO/RTC.test.d.ts +1 -0
  92. package/dist/tests/IO/RTC.test.js +177 -0
  93. package/dist/tests/IO/RTC.test.js.map +1 -0
  94. package/dist/tests/IO/Sound.test.d.ts +1 -0
  95. package/dist/tests/IO/Sound.test.js +528 -0
  96. package/dist/tests/IO/Sound.test.js.map +1 -0
  97. package/dist/tests/IO/Storage.test.d.ts +1 -0
  98. package/dist/tests/IO/Storage.test.js +656 -0
  99. package/dist/tests/IO/Storage.test.js.map +1 -0
  100. package/dist/tests/IO/VIA.test.d.ts +1 -0
  101. package/dist/tests/IO/VIA.test.js +503 -0
  102. package/dist/tests/IO/VIA.test.js.map +1 -0
  103. package/dist/tests/IO/Video.test.d.ts +1 -0
  104. package/dist/tests/IO/Video.test.js +549 -0
  105. package/dist/tests/IO/Video.test.js.map +1 -0
  106. package/dist/tests/Machine.test.js +27 -42
  107. package/dist/tests/Machine.test.js.map +1 -1
  108. package/package.json +1 -1
  109. package/src/components/IO/{SerialCard.ts → ACIA.ts} +2 -2
  110. package/src/components/IO/{GPIOAttachments/GPIOAttachment.ts → Attachments/Attachment.ts} +2 -2
  111. package/src/components/IO/{GPIOAttachments/GPIOJoystickAttachment.ts → Attachments/JoystickAttachment.ts} +3 -3
  112. package/src/components/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.ts → Attachments/KeyboardEncoderAttachment.ts} +3 -3
  113. package/src/components/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.ts → Attachments/KeyboardMatrixAttachment.ts} +5 -5
  114. package/src/components/IO/{GPIOAttachments/GPIOKeypadAttachment.ts → Attachments/KeypadAttachment.ts} +3 -3
  115. package/src/components/IO/{GPIOAttachments/GPIOLCDAttachment.ts → Attachments/LCDAttachment.ts} +7 -7
  116. package/src/components/IO/{EmptyCard.ts → Empty.ts} +1 -1
  117. package/src/components/IO/{RAMCard.ts → RAMBank.ts} +8 -8
  118. package/src/components/IO/{RTCCard.ts → RTC.ts} +1 -1
  119. package/src/components/IO/{SoundCard.ts → Sound.ts} +2 -2
  120. package/src/components/IO/{StorageCard.ts → Storage.ts} +70 -73
  121. package/src/components/IO/{DevOutputBoard.ts → Terminal.ts} +2 -2
  122. package/src/components/IO/{GPIOCard.ts → VIA.ts} +64 -64
  123. package/src/components/IO/{VideoCard.ts → Video.ts} +1 -1
  124. package/src/components/Machine.ts +276 -176
  125. package/src/index.ts +34 -21
  126. package/src/lib.ts +16 -16
  127. package/src/tests/IO/{SerialCard.test.ts → ACIA.test.ts} +5 -5
  128. package/src/tests/IO/{GPIOAttachments/GPIOAttachment.test.ts → Attachments/Attachment.test.ts} +12 -12
  129. package/src/tests/IO/{GPIOAttachments/GPIOJoystickAttachment.test.ts → Attachments/JoystickAttachment.test.ts} +23 -23
  130. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts → Attachments/KeyboardEncoderAttachment.test.ts} +4 -4
  131. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts → Attachments/KeyboardMatrixAttachment.test.ts} +5 -5
  132. package/src/tests/IO/{GPIOAttachments/GPIOKeypadAttachment.test.ts → Attachments/KeypadAttachment.test.ts} +38 -38
  133. package/src/tests/IO/{GPIOAttachments/GPIOLCDAttachment.test.ts → Attachments/LCDAttachment.test.ts} +12 -12
  134. package/src/tests/IO/Empty.test.ts +143 -0
  135. package/src/tests/IO/{RAMCard.test.ts → RAMBank.test.ts} +33 -33
  136. package/src/tests/IO/{RTCCard.test.ts → RTC.test.ts} +6 -6
  137. package/src/tests/IO/{SoundCard.test.ts → Sound.test.ts} +6 -6
  138. package/src/tests/IO/{StorageCard.test.ts → Storage.test.ts} +34 -25
  139. package/src/tests/IO/{GPIOCard.test.ts → VIA.test.ts} +7 -7
  140. package/src/tests/IO/{VideoCard.test.ts → Video.test.ts} +13 -13
  141. package/src/tests/Machine.test.ts +31 -38
package/src/index.ts CHANGED
@@ -4,13 +4,15 @@ import figlet from 'figlet'
4
4
  import { Machine } from './components/Machine'
5
5
  import { Command, Option } from 'commander'
6
6
  import { SerialPort } from 'serialport'
7
- import { VideoCard } from './components/IO/VideoCard'
8
- import { DevOutputBoard } from './components/IO/DevOutputBoard'
9
- import { StorageCard } from './components/IO/StorageCard'
10
- import { SoundCard } from './components/IO/SoundCard'
7
+ import { Video } from './components/IO/Video'
8
+ import { Terminal } from './components/IO/Terminal'
9
+ import { Storage } from './components/IO/Storage'
10
+ import { Sound } from './components/IO/Sound'
11
11
  import sdl from '@kmamal/sdl'
12
+ import { readFile, writeFile } from 'fs/promises'
13
+ import { existsSync } from 'fs'
12
14
 
13
- const VERSION = '1.3.0'
15
+ const VERSION = '1.4.1'
14
16
  const WIDTH = 320
15
17
  const HEIGHT = 240
16
18
 
@@ -20,7 +22,7 @@ const AUDIO_CHANNELS = 1
20
22
  const AUDIO_FORMAT = 'f32'
21
23
  const AUDIO_BUFFERED = 2048
22
24
 
23
- // Joystick button bit masks (matching GPIOJoystickAttachment)
25
+ // Joystick button bit masks (matching JoystickAttachment)
24
26
  const BUTTON_UP = 0x01
25
27
  const BUTTON_DOWN = 0x02
26
28
  const BUTTON_LEFT = 0x04
@@ -92,21 +94,30 @@ class Emulator {
92
94
 
93
95
  private async loadBinaries(): Promise<void> {
94
96
  if (this.options.rom) {
95
- await this.machine.loadROM(this.options.rom)
97
+ const romData = await readFile(this.options.rom)
98
+ this.machine.loadROM(new Uint8Array(romData))
96
99
  console.log(`Loaded ROM: ${this.options.rom}`)
97
100
  } else {
98
101
  console.log('Loaded ROM: NONE')
99
102
  }
100
103
 
101
104
  if (this.options.cart) {
102
- await this.machine.loadCart(this.options.cart)
105
+ const cartData = await readFile(this.options.cart)
106
+ this.machine.loadCart(new Uint8Array(cartData))
103
107
  console.log(`Loaded Cart: ${this.options.cart}`)
104
108
  } else {
105
109
  console.log('Loaded Cart: NONE')
106
110
  }
107
111
 
108
112
  if (this.options.storage && this.options.target !== 'kim') {
109
- await (this.machine.io4 as StorageCard).loadFromFile(this.options.storage)
113
+ if (existsSync(this.options.storage)) {
114
+ const storageData = await readFile(this.options.storage)
115
+ ;(this.machine.io4 as Storage).loadData(new Uint8Array(storageData))
116
+ } else {
117
+ console.log(`Storage file not found: ${this.options.storage}`)
118
+ console.log('A new storage file will be created on exit.')
119
+ ;(this.machine.io4 as Storage).loadData(null)
120
+ }
110
121
  }
111
122
  }
112
123
 
@@ -193,11 +204,11 @@ class Emulator {
193
204
  buffered: AUDIO_BUFFERED,
194
205
  })
195
206
 
196
- // Configure SoundCard sample rate to match audio device
197
- ;(this.machine.io7 as SoundCard).sampleRate = this.audioDevice.frequency
207
+ // Configure Sound sample rate to match audio device
208
+ ;(this.machine.io7 as Sound).sampleRate = this.audioDevice.frequency
198
209
 
199
210
  // Connect the Machine's audio callback to the SDL audio device
200
- this.machine.pushAudioSamples = (samples: Float32Array) => {
211
+ this.machine.play = (samples: Float32Array) => {
201
212
  if (!this.audioDevice || this.audioDevice.closed) return
202
213
 
203
214
  const { channels, bytesPerSample } = this.audioDevice
@@ -322,13 +333,13 @@ class Emulator {
322
333
  this.window.render(renderWidth, renderHeight, renderWidth * 4, 'rgba32', rgbaBuffer)
323
334
  }
324
335
  } else if (this.options.target === 'cob' || this.options.target === 'vcs') {
325
- const videoCard = this.machine.io8 as VideoCard
336
+ const Video = this.machine.io8 as Video
326
337
  this.machine.render = () => {
327
338
  if (!this.window) { return }
328
- this.window.render(WIDTH, HEIGHT, WIDTH * 4, 'rgba32', videoCard.buffer)
339
+ this.window.render(WIDTH, HEIGHT, WIDTH * 4, 'rgba32', Video.buffer)
329
340
  }
330
341
  } else if (this.options.target === 'dev') {
331
- const devBoard = this.machine.io8 as DevOutputBoard
342
+ const devBoard = this.machine.io8 as Terminal
332
343
  const rgbaBuffer = Buffer.alloc(WIDTH * HEIGHT * 4)
333
344
  this.machine.render = () => {
334
345
  if (!this.window) { return }
@@ -516,7 +527,6 @@ class Emulator {
516
527
  }
517
528
  })
518
529
  }
519
- this.machine.end()
520
530
 
521
531
  const uptime = Date.now() - this.machine.startTime
522
532
 
@@ -531,9 +541,12 @@ class Emulator {
531
541
 
532
542
  // Save storage data if path was provided
533
543
  if (this.options.storage && this.options.target !== 'kim') {
534
- (this.machine.io4 as StorageCard).saveToFile(this.options.storage).then(() => {
544
+ const storageData = (this.machine.io4 as Storage).getData()
545
+ writeFile(this.options.storage, storageData).then(() => {
546
+ console.log(`Storage saved to: ${this.options.storage}`)
535
547
  process.exit(0)
536
- }).catch(() => {
548
+ }).catch((error) => {
549
+ console.error('Error saving storage file:', error)
537
550
  process.exit(1)
538
551
  })
539
552
  } else {
@@ -541,8 +554,8 @@ class Emulator {
541
554
  }
542
555
  }
543
556
 
544
- start(): void {
545
- this.machine.start()
557
+ run(): void {
558
+ this.machine.run()
546
559
  }
547
560
  }
548
561
 
@@ -573,7 +586,7 @@ const options = program.opts()
573
586
  async function main() {
574
587
  const emulator = new Emulator(options)
575
588
  await emulator.initialize()
576
- emulator.start()
589
+ emulator.run()
577
590
  }
578
591
 
579
592
  // Run the main function
package/src/lib.ts CHANGED
@@ -7,21 +7,21 @@ export { Cart } from './components/Cart'
7
7
  export type { IO } from './components/IO'
8
8
 
9
9
  // IO cards
10
- export { EmptyCard } from './components/IO/EmptyCard'
11
- export { GPIOCard } from './components/IO/GPIOCard'
12
- export { RAMCard } from './components/IO/RAMCard'
13
- export { RTCCard } from './components/IO/RTCCard'
14
- export { SerialCard } from './components/IO/SerialCard'
15
- export { SIDVoice, SoundCard } from './components/IO/SoundCard'
16
- export { StorageCard } from './components/IO/StorageCard'
17
- export { VideoCard } from './components/IO/VideoCard'
18
- export { DevOutputBoard } from './components/IO/DevOutputBoard'
10
+ export { Empty } from './components/IO/Empty'
11
+ export { VIA } from './components/IO/VIA'
12
+ export { RAMBank } from './components/IO/RAMBank'
13
+ export { RTC } from './components/IO/RTC'
14
+ export { ACIA } from './components/IO/ACIA'
15
+ export { SIDVoice, Sound } from './components/IO/Sound'
16
+ export { Storage } from './components/IO/Storage'
17
+ export { Video } from './components/IO/Video'
18
+ export { Terminal } from './components/IO/Terminal'
19
19
 
20
20
  // GPIO attachments
21
- export type { GPIOAttachment } from './components/IO/GPIOAttachments/GPIOAttachment'
22
- export { GPIOAttachmentBase } from './components/IO/GPIOAttachments/GPIOAttachment'
23
- export { GPIOJoystickAttachment } from './components/IO/GPIOAttachments/GPIOJoystickAttachment'
24
- export { GPIOKeyboardEncoderAttachment } from './components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment'
25
- export { GPIOKeyboardMatrixAttachment } from './components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment'
26
- export { GPIOKeypadAttachment } from './components/IO/GPIOAttachments/GPIOKeypadAttachment'
27
- export { GPIOLCDAttachment } from './components/IO/GPIOAttachments/GPIOLCDAttachment'
21
+ export type { Attachment } from './components/IO/Attachments/Attachment'
22
+ export { AttachmentBase } from './components/IO/Attachments/Attachment'
23
+ export { JoystickAttachment } from './components/IO/Attachments/JoystickAttachment'
24
+ export { KeyboardEncoderAttachment } from './components/IO/Attachments/KeyboardEncoderAttachment'
25
+ export { KeyboardMatrixAttachment } from './components/IO/Attachments/KeyboardMatrixAttachment'
26
+ export { KeypadAttachment } from './components/IO/Attachments/KeypadAttachment'
27
+ export { LCDAttachment } from './components/IO/Attachments/LCDAttachment'
@@ -1,10 +1,10 @@
1
- import { SerialCard } from '../../components/IO/SerialCard'
1
+ import { ACIA } from '../../components/IO/ACIA'
2
2
 
3
- describe('SerialCard (6551 ACIA)', () => {
4
- let serialCard: SerialCard
3
+ describe('ACIA (6551 ACIA)', () => {
4
+ let serialCard: ACIA
5
5
 
6
6
  beforeEach(() => {
7
- serialCard = new SerialCard()
7
+ serialCard = new ACIA()
8
8
  })
9
9
 
10
10
  describe('Initialization', () => {
@@ -399,7 +399,7 @@ describe('SerialCard (6551 ACIA)', () => {
399
399
  ]
400
400
 
401
401
  baudRates.forEach(([code, rate]) => {
402
- const card = new SerialCard()
402
+ const card = new ACIA()
403
403
  card.write(0x03, code as number) // Control register with baud rate code
404
404
  // Baud rate affects tick timing - verify no errors occur
405
405
  })
@@ -1,9 +1,9 @@
1
- import { GPIOAttachment, GPIOAttachmentBase } from '../../../components/IO/GPIOAttachments/GPIOAttachment'
1
+ import { Attachment, AttachmentBase } from '../../../components/IO/Attachments/Attachment'
2
2
 
3
3
  /**
4
- * Concrete implementation of GPIOAttachmentBase for testing
4
+ * Concrete implementation of AttachmentBase for testing
5
5
  */
6
- class TestGPIOAttachment extends GPIOAttachmentBase {
6
+ class TestAttachment extends AttachmentBase {
7
7
  public portAValue: number = 0xFF
8
8
  public portBValue: number = 0xFF
9
9
  public tickCount: number = 0
@@ -62,11 +62,11 @@ class TestGPIOAttachment extends GPIOAttachmentBase {
62
62
  }
63
63
  }
64
64
 
65
- describe('GPIOAttachmentBase', () => {
66
- let attachment: TestGPIOAttachment
65
+ describe('AttachmentBase', () => {
66
+ let attachment: TestAttachment
67
67
 
68
68
  beforeEach(() => {
69
- attachment = new TestGPIOAttachment()
69
+ attachment = new TestAttachment()
70
70
  })
71
71
 
72
72
  describe('Initialization', () => {
@@ -75,7 +75,7 @@ describe('GPIOAttachmentBase', () => {
75
75
  })
76
76
 
77
77
  it('should initialize with custom priority', () => {
78
- const customAttachment = new TestGPIOAttachment(5)
78
+ const customAttachment = new TestAttachment(5)
79
79
  expect(customAttachment.getPriority()).toBe(5)
80
80
  })
81
81
 
@@ -91,7 +91,7 @@ describe('GPIOAttachmentBase', () => {
91
91
  })
92
92
 
93
93
  it('should initialize with specified interrupt states', () => {
94
- const interruptAttachment = new TestGPIOAttachment(0, true, true, true, true)
94
+ const interruptAttachment = new TestAttachment(0, true, true, true, true)
95
95
  expect(interruptAttachment.hasCA1Interrupt()).toBe(true)
96
96
  expect(interruptAttachment.hasCA2Interrupt()).toBe(true)
97
97
  expect(interruptAttachment.hasCB1Interrupt()).toBe(true)
@@ -121,7 +121,7 @@ describe('GPIOAttachmentBase', () => {
121
121
  })
122
122
 
123
123
  it('should maintain priority after reset', () => {
124
- const priorityAttachment = new TestGPIOAttachment(10)
124
+ const priorityAttachment = new TestAttachment(10)
125
125
  priorityAttachment.reset()
126
126
  expect(priorityAttachment.getPriority()).toBe(10)
127
127
  })
@@ -129,15 +129,15 @@ describe('GPIOAttachmentBase', () => {
129
129
 
130
130
  describe('Priority', () => {
131
131
  it('should return correct priority value', () => {
132
- const lowPriority = new TestGPIOAttachment(0)
133
- const highPriority = new TestGPIOAttachment(10)
132
+ const lowPriority = new TestAttachment(0)
133
+ const highPriority = new TestAttachment(10)
134
134
 
135
135
  expect(lowPriority.getPriority()).toBe(0)
136
136
  expect(highPriority.getPriority()).toBe(10)
137
137
  })
138
138
 
139
139
  it('should support negative priority values', () => {
140
- const negativePriority = new TestGPIOAttachment(-5)
140
+ const negativePriority = new TestAttachment(-5)
141
141
  expect(negativePriority.getPriority()).toBe(-5)
142
142
  })
143
143
  })
@@ -1,10 +1,10 @@
1
- import { GPIOJoystickAttachment } from '../../../components/IO/GPIOAttachments/GPIOJoystickAttachment'
1
+ import { JoystickAttachment } from '../../../components/IO/Attachments/JoystickAttachment'
2
2
 
3
- describe('GPIOJoystickAttachment', () => {
4
- let joystick: GPIOJoystickAttachment
3
+ describe('JoystickAttachment', () => {
4
+ let joystick: JoystickAttachment
5
5
 
6
6
  beforeEach(() => {
7
- joystick = new GPIOJoystickAttachment(true, 0)
7
+ joystick = new JoystickAttachment(true, 0)
8
8
  })
9
9
 
10
10
  describe('constructor and reset', () => {
@@ -26,20 +26,20 @@ describe('GPIOJoystickAttachment', () => {
26
26
  })
27
27
 
28
28
  it('should check if button is pressed', () => {
29
- joystick.pressButton(GPIOJoystickAttachment.BUTTON_A)
30
- expect(joystick.isButtonPressed(GPIOJoystickAttachment.BUTTON_A)).toBe(true)
31
- expect(joystick.isButtonPressed(GPIOJoystickAttachment.BUTTON_B)).toBe(false)
29
+ joystick.pressButton(JoystickAttachment.BUTTON_A)
30
+ expect(joystick.isButtonPressed(JoystickAttachment.BUTTON_A)).toBe(true)
31
+ expect(joystick.isButtonPressed(JoystickAttachment.BUTTON_B)).toBe(false)
32
32
  })
33
33
 
34
34
  it('should press a button', () => {
35
- joystick.pressButton(GPIOJoystickAttachment.BUTTON_START)
36
- expect(joystick.getButtonState()).toBe(GPIOJoystickAttachment.BUTTON_START)
35
+ joystick.pressButton(JoystickAttachment.BUTTON_START)
36
+ expect(joystick.getButtonState()).toBe(JoystickAttachment.BUTTON_START)
37
37
  })
38
38
 
39
39
  it('should release a button', () => {
40
40
  joystick.updateJoystick(0xFF)
41
- joystick.releaseButton(GPIOJoystickAttachment.BUTTON_A)
42
- expect(joystick.getButtonState()).toBe(0xFF & ~GPIOJoystickAttachment.BUTTON_A)
41
+ joystick.releaseButton(JoystickAttachment.BUTTON_A)
42
+ expect(joystick.getButtonState()).toBe(0xFF & ~JoystickAttachment.BUTTON_A)
43
43
  })
44
44
 
45
45
  it('should release all buttons', () => {
@@ -51,7 +51,7 @@ describe('GPIOJoystickAttachment', () => {
51
51
 
52
52
  describe('port reading - Port A', () => {
53
53
  beforeEach(() => {
54
- joystick = new GPIOJoystickAttachment(true, 0) // Attach to Port A
54
+ joystick = new JoystickAttachment(true, 0) // Attach to Port A
55
55
  })
56
56
 
57
57
  it('should return inverted button state on Port A when attached', () => {
@@ -70,7 +70,7 @@ describe('GPIOJoystickAttachment', () => {
70
70
  })
71
71
 
72
72
  it('should handle individual button presses correctly', () => {
73
- joystick.updateJoystick(GPIOJoystickAttachment.BUTTON_UP)
73
+ joystick.updateJoystick(JoystickAttachment.BUTTON_UP)
74
74
  const result = joystick.readPortA(0x00, 0x00)
75
75
  expect(result & 0x01).toBe(0x00) // UP button bit should be low (pressed)
76
76
  expect(result & 0xFE).toBe(0xFE) // Other bits should be high (not pressed)
@@ -79,7 +79,7 @@ describe('GPIOJoystickAttachment', () => {
79
79
 
80
80
  describe('port reading - Port B', () => {
81
81
  beforeEach(() => {
82
- joystick = new GPIOJoystickAttachment(false, 0) // Attach to Port B
82
+ joystick = new JoystickAttachment(false, 0) // Attach to Port B
83
83
  })
84
84
 
85
85
  it('should return inverted button state on Port B when attached', () => {
@@ -100,20 +100,20 @@ describe('GPIOJoystickAttachment', () => {
100
100
 
101
101
  describe('button constants', () => {
102
102
  it('should have correct button bit values', () => {
103
- expect(GPIOJoystickAttachment.BUTTON_UP).toBe(0x01)
104
- expect(GPIOJoystickAttachment.BUTTON_DOWN).toBe(0x02)
105
- expect(GPIOJoystickAttachment.BUTTON_LEFT).toBe(0x04)
106
- expect(GPIOJoystickAttachment.BUTTON_RIGHT).toBe(0x08)
107
- expect(GPIOJoystickAttachment.BUTTON_A).toBe(0x10)
108
- expect(GPIOJoystickAttachment.BUTTON_B).toBe(0x20)
109
- expect(GPIOJoystickAttachment.BUTTON_SELECT).toBe(0x40)
110
- expect(GPIOJoystickAttachment.BUTTON_START).toBe(0x80)
103
+ expect(JoystickAttachment.BUTTON_UP).toBe(0x01)
104
+ expect(JoystickAttachment.BUTTON_DOWN).toBe(0x02)
105
+ expect(JoystickAttachment.BUTTON_LEFT).toBe(0x04)
106
+ expect(JoystickAttachment.BUTTON_RIGHT).toBe(0x08)
107
+ expect(JoystickAttachment.BUTTON_A).toBe(0x10)
108
+ expect(JoystickAttachment.BUTTON_B).toBe(0x20)
109
+ expect(JoystickAttachment.BUTTON_SELECT).toBe(0x40)
110
+ expect(JoystickAttachment.BUTTON_START).toBe(0x80)
111
111
  })
112
112
  })
113
113
 
114
114
  describe('priority and enabled', () => {
115
115
  it('should return correct priority', () => {
116
- const j = new GPIOJoystickAttachment(true, 5)
116
+ const j = new JoystickAttachment(true, 5)
117
117
  expect(j.getPriority()).toBe(5)
118
118
  })
119
119
 
@@ -1,10 +1,10 @@
1
- import { GPIOKeyboardEncoderAttachment } from '../../../components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment'
1
+ import { KeyboardEncoderAttachment } from '../../../components/IO/Attachments/KeyboardEncoderAttachment'
2
2
 
3
- describe('GPIOKeyboardEncoderAttachment', () => {
4
- let encoder: GPIOKeyboardEncoderAttachment
3
+ describe('KeyboardEncoderAttachment', () => {
4
+ let encoder: KeyboardEncoderAttachment
5
5
 
6
6
  beforeEach(() => {
7
- encoder = new GPIOKeyboardEncoderAttachment(5)
7
+ encoder = new KeyboardEncoderAttachment(5)
8
8
  })
9
9
 
10
10
  describe('Initialization', () => {
@@ -1,10 +1,10 @@
1
- import { GPIOKeyboardMatrixAttachment } from '../../../components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment'
1
+ import { KeyboardMatrixAttachment } from '../../../components/IO/Attachments/KeyboardMatrixAttachment'
2
2
 
3
- describe('GPIOKeyboardMatrixAttachment', () => {
4
- let keyboard: GPIOKeyboardMatrixAttachment
3
+ describe('KeyboardMatrixAttachment', () => {
4
+ let keyboard: KeyboardMatrixAttachment
5
5
 
6
6
  beforeEach(() => {
7
- keyboard = new GPIOKeyboardMatrixAttachment(0)
7
+ keyboard = new KeyboardMatrixAttachment(0)
8
8
  })
9
9
 
10
10
  describe('Initialization', () => {
@@ -22,7 +22,7 @@ describe('GPIOKeyboardMatrixAttachment', () => {
22
22
  })
23
23
 
24
24
  it('should have correct priority', () => {
25
- const kb = new GPIOKeyboardMatrixAttachment(5)
25
+ const kb = new KeyboardMatrixAttachment(5)
26
26
  expect(kb.getPriority()).toBe(5)
27
27
  })
28
28
  })
@@ -1,12 +1,12 @@
1
- import { GPIOKeypadAttachment } from '../../../components/IO/GPIOAttachments/GPIOKeypadAttachment'
1
+ import { KeypadAttachment } from '../../../components/IO/Attachments/KeypadAttachment'
2
2
 
3
- describe('GPIOKeypadAttachment', () => {
4
- let keypadA: GPIOKeypadAttachment // attached to Port A
5
- let keypadB: GPIOKeypadAttachment // attached to Port B
3
+ describe('KeypadAttachment', () => {
4
+ let keypadA: KeypadAttachment // attached to Port A
5
+ let keypadB: KeypadAttachment // attached to Port B
6
6
 
7
7
  beforeEach(() => {
8
- keypadA = new GPIOKeypadAttachment(true, 0)
9
- keypadB = new GPIOKeypadAttachment(false, 0)
8
+ keypadA = new KeypadAttachment(true, 0)
9
+ keypadB = new KeypadAttachment(false, 0)
10
10
  })
11
11
 
12
12
  // ---------------------------------------------------------------------------
@@ -36,7 +36,7 @@ describe('GPIOKeypadAttachment', () => {
36
36
  })
37
37
 
38
38
  it('should report the correct priority', () => {
39
- const kp = new GPIOKeypadAttachment(true, 7)
39
+ const kp = new KeypadAttachment(true, 7)
40
40
  expect(kp.getPriority()).toBe(7)
41
41
  })
42
42
 
@@ -62,134 +62,134 @@ describe('GPIOKeypadAttachment', () => {
62
62
  // ---------------------------------------------------------------------------
63
63
  describe('Key press → keypad value mapping', () => {
64
64
  // Helpers: assert OE (CA2/CB2 LOW) then press and read
65
- const pressAndReadA = (kp: GPIOKeypadAttachment, hid: number) => {
65
+ const pressAndReadA = (kp: KeypadAttachment, hid: number) => {
66
66
  kp.updateControlLines(false, false, false, true) // CA2 LOW → OE asserted for Port A
67
67
  kp.updateKey(hid, true)
68
68
  return kp.readPortA(0x00, 0x00)
69
69
  }
70
- const pressAndReadB = (kp: GPIOKeypadAttachment, hid: number) => {
70
+ const pressAndReadB = (kp: KeypadAttachment, hid: number) => {
71
71
  kp.updateControlLines(false, true, false, false) // CB2 LOW → OE asserted for Port B
72
72
  kp.updateKey(hid, true)
73
73
  return kp.readPortB(0x00, 0x00)
74
74
  }
75
75
 
76
76
  it('Left Arrow (0x50) → $00 ◄', () => {
77
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x50)).toBe(0x00)
77
+ expect(pressAndReadA(new KeypadAttachment(true), 0x50)).toBe(0x00)
78
78
  })
79
79
 
80
80
  it('Backspace is not on this keypad', () => {
81
- const kp = new GPIOKeypadAttachment(true)
81
+ const kp = new KeypadAttachment(true)
82
82
  kp.updateControlLines(false, false, false, true)
83
83
  kp.updateKey(0x2A, true) // Backspace – unmapped
84
84
  expect(kp.readPortA(0x00, 0x00)).toBe(0xFF)
85
85
  })
86
86
 
87
87
  it('1 (0x1E) → $01', () => {
88
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x1E)).toBe(0x01)
88
+ expect(pressAndReadA(new KeypadAttachment(true), 0x1E)).toBe(0x01)
89
89
  })
90
90
 
91
91
  it('2 (0x1F) → $02', () => {
92
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x1F)).toBe(0x02)
92
+ expect(pressAndReadA(new KeypadAttachment(true), 0x1F)).toBe(0x02)
93
93
  })
94
94
 
95
95
  it('3 (0x20) → $03', () => {
96
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x20)).toBe(0x03)
96
+ expect(pressAndReadA(new KeypadAttachment(true), 0x20)).toBe(0x03)
97
97
  })
98
98
 
99
99
  it('4 (0x21) → $04', () => {
100
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x21)).toBe(0x04)
100
+ expect(pressAndReadA(new KeypadAttachment(true), 0x21)).toBe(0x04)
101
101
  })
102
102
 
103
103
  it('5 (0x22) → $05', () => {
104
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x22)).toBe(0x05)
104
+ expect(pressAndReadA(new KeypadAttachment(true), 0x22)).toBe(0x05)
105
105
  })
106
106
 
107
107
  it('6 (0x23) → $06', () => {
108
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x23)).toBe(0x06)
108
+ expect(pressAndReadA(new KeypadAttachment(true), 0x23)).toBe(0x06)
109
109
  })
110
110
 
111
111
  it('7 (0x24) → $07', () => {
112
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x24)).toBe(0x07)
112
+ expect(pressAndReadA(new KeypadAttachment(true), 0x24)).toBe(0x07)
113
113
  })
114
114
 
115
115
  it('8 (0x25) → $08', () => {
116
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x25)).toBe(0x08)
116
+ expect(pressAndReadA(new KeypadAttachment(true), 0x25)).toBe(0x08)
117
117
  })
118
118
 
119
119
  it('9 (0x26) → $09', () => {
120
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x26)).toBe(0x09)
120
+ expect(pressAndReadA(new KeypadAttachment(true), 0x26)).toBe(0x09)
121
121
  })
122
122
 
123
123
  it('0 (0x27) → $0A', () => {
124
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x27)).toBe(0x0A)
124
+ expect(pressAndReadA(new KeypadAttachment(true), 0x27)).toBe(0x0A)
125
125
  })
126
126
 
127
127
  it('Right Arrow (0x4F) → $0B ►', () => {
128
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x4F)).toBe(0x0B)
128
+ expect(pressAndReadA(new KeypadAttachment(true), 0x4F)).toBe(0x0B)
129
129
  })
130
130
 
131
131
  it('Enter is not mapped to $0B (it maps to $14)', () => {
132
- const kp = new GPIOKeypadAttachment(true)
132
+ const kp = new KeypadAttachment(true)
133
133
  kp.updateControlLines(false, false, false, true)
134
134
  kp.updateKey(0x28, true) // Enter → $14
135
135
  expect(kp.readPortA(0x00, 0x00)).toBe(0x14)
136
136
  })
137
137
 
138
138
  it('f (0x09) → $0C F', () => {
139
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x09)).toBe(0x0C)
139
+ expect(pressAndReadA(new KeypadAttachment(true), 0x09)).toBe(0x0C)
140
140
  })
141
141
 
142
142
  it('e (0x08) → $0D E', () => {
143
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x08)).toBe(0x0D)
143
+ expect(pressAndReadA(new KeypadAttachment(true), 0x08)).toBe(0x0D)
144
144
  })
145
145
 
146
146
  it('d (0x07) → $0E D', () => {
147
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x07)).toBe(0x0E)
147
+ expect(pressAndReadA(new KeypadAttachment(true), 0x07)).toBe(0x0E)
148
148
  })
149
149
 
150
150
  it('c (0x06) → $0F C', () => {
151
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x06)).toBe(0x0F)
151
+ expect(pressAndReadA(new KeypadAttachment(true), 0x06)).toBe(0x0F)
152
152
  })
153
153
 
154
154
  it('Escape (0x29) → $10 ESC', () => {
155
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x29)).toBe(0x10)
155
+ expect(pressAndReadA(new KeypadAttachment(true), 0x29)).toBe(0x10)
156
156
  })
157
157
 
158
158
  it('Insert (0x49) → $11 INS', () => {
159
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x49)).toBe(0x11)
159
+ expect(pressAndReadA(new KeypadAttachment(true), 0x49)).toBe(0x11)
160
160
  })
161
161
 
162
162
  it('Page Up (0x4B) → $12 PGUP', () => {
163
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x4B)).toBe(0x12)
163
+ expect(pressAndReadA(new KeypadAttachment(true), 0x4B)).toBe(0x12)
164
164
  })
165
165
 
166
166
  it('a (0x04) → $13 A', () => {
167
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x04)).toBe(0x13)
167
+ expect(pressAndReadA(new KeypadAttachment(true), 0x04)).toBe(0x13)
168
168
  })
169
169
 
170
170
  it('Up Arrow (0x52) → $14 ▲', () => {
171
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x52)).toBe(0x14)
171
+ expect(pressAndReadA(new KeypadAttachment(true), 0x52)).toBe(0x14)
172
172
  })
173
173
 
174
174
  it('Enter (0x28) → $14 ▲', () => {
175
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x28)).toBe(0x14)
175
+ expect(pressAndReadA(new KeypadAttachment(true), 0x28)).toBe(0x14)
176
176
  })
177
177
 
178
178
  it('Delete (0x4C) → $15 DEL', () => {
179
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x4C)).toBe(0x15)
179
+ expect(pressAndReadA(new KeypadAttachment(true), 0x4C)).toBe(0x15)
180
180
  })
181
181
 
182
182
  it('Page Down (0x4E) → $16 PGDN', () => {
183
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x4E)).toBe(0x16)
183
+ expect(pressAndReadA(new KeypadAttachment(true), 0x4E)).toBe(0x16)
184
184
  })
185
185
 
186
186
  it('b (0x05) → $17 B', () => {
187
- expect(pressAndReadA(new GPIOKeypadAttachment(true), 0x05)).toBe(0x17)
187
+ expect(pressAndReadA(new KeypadAttachment(true), 0x05)).toBe(0x17)
188
188
  })
189
189
 
190
190
  it('should also map correctly on Port B', () => {
191
- expect(pressAndReadB(new GPIOKeypadAttachment(false), 0x1E)).toBe(0x01) // '1' → $01
192
- expect(pressAndReadB(new GPIOKeypadAttachment(false), 0x05)).toBe(0x17) // 'b' → $17
191
+ expect(pressAndReadB(new KeypadAttachment(false), 0x1E)).toBe(0x01) // '1' → $01
192
+ expect(pressAndReadB(new KeypadAttachment(false), 0x05)).toBe(0x17) // 'b' → $17
193
193
  })
194
194
  })
195
195