1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#include "defines.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include "bits.h"
#include "gamepad.h"
#define LED_ON unset_bit(PORTB, 2)
#define LED_OFF set_bit(PORTB, 2)
volatile uint8_t nes_button_data;
volatile uint8_t shift;
volatile uint8_t turbo_counter;
// Clock
ISR(INT0_vect)
{
shift <<= 1;
if (nes_button_data & shift)
PORTD |= 1;
else
PORTD &= ~1;
}
// Strobe
ISR(INT1_vect)
{
shift = 1;
if (nes_button_data & shift)
PORTD |= 1;
else
PORTD &= ~1;
}
uint16_t get_template_buttons()
{
uint16_t snes_buttons;
if ((snes_buttons&0x0FFF) != 0x0FFF)
do
{
PORTB ^= (1<<2);
_delay_ms(50);
snes_buttons = get_snes_gamepad();
} while ((snes_buttons&0x0FFF) != 0x0FFF);
LED_OFF;
_delay_ms(200);
int hold_time = 0;
do
{
PORTB ^= (1<<2);
_delay_ms(50);
snes_buttons = get_snes_gamepad();
if ((snes_buttons&0x0FFF) != 0x0FFF)
hold_time++;
else
hold_time = 0;
} while (hold_time < 30);
LED_OFF;
_delay_ms(500);
return snes_buttons;
}
int main (void)
{
set_bit(DDRD, 0); // Данные - на выход
unset_bit2(DDRD, 2, 3); // clock, strobe - на ввод
set_bit(DDRB, 2); // Светодиод на вывод
set_bit2(MCUCR, ISC11, ISC10); // Прерывание при растущем strobe
set_bit2(MCUCR, ISC01, ISC00); // Прерывание при растущем clock
set_bit(GICR, INT0); set_bit(GICR, INT1); // Активируем их
sei(); // Глобальная активация прерываний
// Right, Left, Down, Up, Start, Select, B, A
init_snes_gamepad();
int lr_hold_time = 0;
uint16_t l_template = 0x0FFF;
uint16_t r_template = 0x0FFF;
eeprom_read_block(&r_template, (void*)0, 2);
eeprom_read_block(&l_template, (void*)2, 2);
while(1)
{
// R, L, X, A, Right, Left, Down, Up, Start, Select, Y, B
uint16_t snes_buttons = get_snes_gamepad();
if ((snes_buttons&0x0FFF) != 0x0FFF)
{
LED_ON;
} else {
LED_OFF;
}
if (((snes_buttons&0x0FFF) == 0x07FB) || ((snes_buttons&0x0FFF) == 0x0BFB)) // R + select or L + select
{
if (lr_hold_time++ == 200)
{
nes_button_data = 0xFF; // Unpress nes buttons
uint16_t template_buttons = get_template_buttons();
template_buttons |= (0b11<<10); // Exclude L&R
if ((snes_buttons&0x0FFF) == 0x07FB)
{
r_template = template_buttons;
eeprom_write_block(&r_template, (void*)0, 2);
} else {
l_template = template_buttons;
eeprom_write_block(&l_template, (void*)2, 2);
}
snes_buttons = 0x0FFF;
}
} else lr_hold_time = 0;
if (!(snes_buttons&(1<<11))) snes_buttons &= r_template;
if (!(snes_buttons&(1<<10))) snes_buttons &= l_template;
uint8_t tmp = snes_buttons & 0b11111100;
tmp |= (snes_buttons>>8)&1; // A
tmp |= (snes_buttons&1)<<1; // B
if (!(snes_buttons&(1<<9)) && ((turbo_counter%8) <= 3)) tmp &= ~1; // X -> Turbo A
if (!(snes_buttons&(1<<1)) && ((turbo_counter%8) <= 3)) tmp &= ~2; // Y -> Turbo B
if (!(snes_buttons&(1<<7)) && !(snes_buttons&(1<<6))) tmp |= 1<<7; // No left+right!
if (!(snes_buttons&(1<<5)) && !(snes_buttons&(1<<4))) tmp |= 1<<5; // No up+down!
nes_button_data = tmp;
_delay_ms(10);
turbo_counter++;
}
}
|