diff --git a/.gitignore b/.gitignore
index 5249613..7f27c27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.vs
*.elf
*.o
*.map
diff --git a/Makefile.atmega168 b/Makefile.atmega168
index af7cd3b..ef2b2e9 100644
--- a/Makefile.atmega168
+++ b/Makefile.atmega168
@@ -4,8 +4,9 @@ LD=$(CC)
PROGNAME=atmega168_extenmote
OBJDIR=objs-$(PROGNAME)
-CPU=atmega168a
+CPU=atmega168
CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=12000000L -Os -DWITH_SNES -DWITH_N64 -DWITH_GAMECUBE -DWITH_EEPROM -DWITH_DB9
+#CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=12000000L -Os -DWITH_SNES -DWITH_EEPROM
LDFLAGS=-mmcu=$(CPU) -Wl,-Map=$(PROGNAME).map
HEXFILE=$(PROGNAME).hex
AVRDUDE=avrdude -p m168 -P usb -c avrispmkII
diff --git a/Makefile.atmega328p b/Makefile.atmega328p
new file mode 100644
index 0000000..e1fc545
--- /dev/null
+++ b/Makefile.atmega328p
@@ -0,0 +1,63 @@
+CC=avr-gcc
+AS=$(CC)
+LD=$(CC)
+
+PROGNAME=atmega328p_extenmote
+OBJDIR=objs-$(PROGNAME)
+CPU=atmega328p
+CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=16000000L -Os -DWITH_SNES -DWITH_N64 -DWITH_GAMECUBE -DWITH_EEPROM -DWITH_DB9
+LDFLAGS=-mmcu=$(CPU) -Wl,-Map=$(PROGNAME).map
+HEXFILE=$(PROGNAME).hex
+AVRDUDE=avrdude -p m328p -P com5 -c avrisp -b 19200
+
+# - - - - - BOOTSZ1 BOOTSZ0 BOOTRST
+# 0 0 0 0 0 0 0 1
+# 1 1 1 1 1 0 0 1
+#EFUSE=0x01
+EFUSE=0xF9
+
+# RSTDISBL DWEN SPIEN WDTON EESAVE BODLEVEL2 BODLEVEL1 BODLEVEL0
+# 1 1 0 1 1 1 1 1
+HFUSE=0xdf
+#
+# CKDIV8 CKOUT SUT1 SUT0 CKSEL3 CKSEL2 CKSEL1 CKSEL0
+# 1 1 0 1 1 1 1 1
+#
+# 8mhz internal RC oscillator (Ok for NES/SNES only mode)
+LFUSE=0xDF
+
+OBJS=$(addprefix $(OBJDIR)/, main.o wiimote.o snes.o rlut.o n64.o gcn64_protocol.o gamecube.o eeprom.o classic.o analog.o tripleclick.o db9.o)
+
+all: $(HEXFILE)
+
+clean:
+ rm -f $(PROGNAME).elf $(PROGNAME).hex $(PROGNAME).map $(OBJS)
+
+$(OBJDIR)/%.o: %.S
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: %.c %.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(PROGNAME).elf: $(OBJS)
+ $(LD) $(OBJS) $(LDFLAGS) -o $(PROGNAME).elf
+
+$(PROGNAME).hex: $(PROGNAME).elf
+ avr-objcopy -j .data -j .text -O ihex $(PROGNAME).elf $(PROGNAME).hex
+ avr-size $(PROGNAME).elf
+
+fuse:
+ $(AVRDUDE) -e -Uefuse:w:$(EFUSE):m -Uhfuse:w:$(HFUSE):m -Ulfuse:w:$(LFUSE):m -B 20.0 -v
+
+flash: $(HEXFILE)
+ $(AVRDUDE) -Uflash:w:$(HEXFILE) -B 1.0 -F
+
+chip_erase:
+ $(AVRDUDE) -e -B 1.0 -F
+
+reset:
+ $(AVRDUDE) -B 1.0 -F
+
diff --git a/classic.c b/classic.c
index 3e8c23a..6abdbe9 100644
--- a/classic.c
+++ b/classic.c
@@ -13,6 +13,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Changes pertaining to SNES Mouse and NES lightgun Copyright (C) 2023 Akerasoft
+ * The author may be contacted at robert.kolski@akerasoft.com
*/
#include
@@ -55,6 +58,10 @@
* 'G' | 'C' Gamecube controller
* 'S' | 'F' SNES
* 'F' | 'C' NES
+ * (C) Akerasoft 2023 -- BEGIN --
+ * 'G' | 'N' NES Lightgun / Zapper
+ * 'M' | 'S' SNES Mouse
+ * (C) Akerasoft 2023 -- END --
*
* Writing at byte 6 might one day control the rumble motor. Rumbles on when non-zero.
*/
@@ -289,6 +296,26 @@ void dataToClassic(const gamepad_data *src, classic_pad_data *dst, char first_re
}
break;
+// (C) Akerasoft 2023 -- BEGIN --
+ case PAD_TYPE_MOUSE:
+ dst->controller_id[0] = 'M';
+ dst->controller_id[1] = 'S';
+ memcpy(dst->controller_raw_data, src->snes.raw_data, MOUSE_RAW_SIZE);
+
+ if (src->snes.buttons & MOUSE_BTN_L) { dst->buttons |= CPAD_BTN_X; }
+ if (src->snes.buttons & MOUSE_BTN_R) { dst->buttons |= CPAD_BTN_A; }
+ break;
+
+ case PAD_TYPE_GUN:
+ dst->controller_id[0] = 'G';
+ dst->controller_id[1] = 'N';
+ memcpy(dst->controller_raw_data, src->gun.raw_data, GUN_RAW_SIZE);
+
+ if (src->snes.buttons & GUN_BTN_TRIGGER) { dst->buttons |= CPAD_BTN_B; }
+ if (src->snes.buttons & GUN_BTN_SENSOR) { dst->buttons |= CPAD_BTN_A; }
+ break;
+// (C) Akerasoft 2023 -- END --
+
case PAD_TYPE_NES:
// if (first_read && src->nes.buttons & NES_BTN_START) {
// disable_config = 1;
diff --git a/gamepads.h b/gamepads.h
index bbf3b93..3b49f3e 100644
--- a/gamepads.h
+++ b/gamepads.h
@@ -13,6 +13,10 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Changes pertaining to SNES Mouse and NES lightgun Copyright (C) 2023 Akerasoft
+ * The author may be contacted at robert.kolski@akerasoft.com
+ *
*/
#ifndef _gamepad_h__
#define _gamepad_h__
@@ -25,9 +29,17 @@
#define PAD_TYPE_GAMECUBE 5
#define PAD_TYPE_MD 6
#define PAD_TYPE_SMS 7
+// (C) Akerasoft 2023 -- BEGIN --
+#define PAD_TYPE_GUN 8
+#define PAD_TYPE_MOUSE 9
+// (C) Akerasoft 2023 -- END --
#define NES_RAW_SIZE 1
#define SNES_RAW_SIZE 2
+// (C) Akerasoft 2023 -- BEGIN --
+#define MOUSE_RAW_SIZE 4
+#define GUN_RAW_SIZE 1
+// (C) Akerasoft 2023 -- END --
#define N64_RAW_SIZE 4
#define GC_RAW_SIZE 8
#define DB9_RAW_SIZE 2
@@ -90,6 +102,26 @@ typedef struct _snes_pad_data {
#define SNES_BTN_L 0x2000
#define SNES_BTN_R 0x1000
+// (C) Akerasoft 2023 -- BEGIN --
+typedef struct _mouse_pad_data {
+ unsigned char pad_type; // PAD_TYPE_MOUSE
+ unsigned short buttons;
+ unsigned char raw_data[MOUSE_RAW_SIZE];
+} mouse_pad_data;
+
+#define MOUSE_BTN_R 0x8000
+#define MOUSE_BTN_L 0x4000
+#define MOUSE_SENSITIVITY 0x3000
+
+typedef struct _gun_pad_data {
+ unsigned char pad_type; // PAD_TYPE_GUN
+ unsigned short buttons;
+ unsigned char raw_data[GUN_RAW_SIZE];
+} gun_pad_data;
+
+#define GUN_BTN_TRIGGER 0x0080
+#define GUN_BTN_SENSOR 0x0040
+// (C) Akerasoft 2023 -- END --
typedef struct _nes_pad_data {
unsigned char pad_type; // PAD_TYPE_NES
@@ -190,6 +222,10 @@ typedef struct _gamepad_data {
unsigned char pad_type; // PAD_TYPE_*
classic_pad_data classic;
snes_pad_data snes;
+// (C) Akerasoft 2023 -- BEGIN --
+ mouse_pad_data mouse;
+ gun_pad_data gun;
+// (C) Akerasoft 2023 -- END --
nes_pad_data nes;
n64_pad_data n64;
gc_pad_data gc;
diff --git a/main.c b/main.c
index bc4c86c..56e4e73 100644
--- a/main.c
+++ b/main.c
@@ -13,6 +13,10 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Changes pertaining to SNES Mouse and NES lightgun Copyright (C) 2023 Akerasoft
+ * The author may be contacted at robert.kolski@akerasoft.com
+ *
*/
#include
@@ -66,14 +70,20 @@ static void hwInit(void)
/* PORTD
* 0: out0
* 1: out0
- * 2: out0
- * 3: out0
+// (C) Akerasoft 2023 - proposal PORT D2 and D3 are for NES Zapper. When no other controller found
+// use NES Zapper / lightgun in the SNES.c file.
+ * 2: in
+ * 3: in
+// (C) Akerasoft 2023 - END
* 4: out1 // Tied to VCC on Multiuse PCB2 for routing reasons
* 5: out0
* 6: in-pu // Pulled to GND on mutluse db9 v3. Wired to VCC on multiuse PCB2.
* 7: out0
*/
- PORTD = 0x60;
+// (C) Akerasoft 2023 - proposal PORT D2 and D3 are for NES Zapper.
+ PORTD = 0x6C;
+// (C) Akerasoft 2023 - END
+
DDRD = 0xbf;
_delay_ms(1);
@@ -393,6 +403,18 @@ int main(void)
memcpy(raw, lastReadData.nes.raw_data, sizeof(lastReadData.nes.raw_data));
wm_newaction(raw, sizeof(lastReadData.nes.raw_data));
break;
+
+// (C) Akerasoft 2023 - BEGIN
+ case PAD_TYPE_GUN:
+ memcpy(raw, lastReadData.gun.raw_data, sizeof(lastReadData.gun.raw_data));
+ wm_newaction(raw, sizeof(lastReadData.gun.raw_data));
+ break;
+
+ case PAD_TYPE_MOUSE:
+ memcpy(raw, lastReadData.mouse.raw_data, sizeof(lastReadData.mouse.raw_data));
+ wm_newaction(raw, sizeof(lastReadData.mouse.raw_data));
+ break;
+// (C) Akerasoft 2023 - END
}
// TODO : Controller specific report format
diff --git a/snes.c b/snes.c
index 2b3000e..d20ff4c 100644
--- a/snes.c
+++ b/snes.c
@@ -21,6 +21,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* The author may be contacted at raph@raphnet.net
+ *
+ * Changes pertaining to SNES Mouse and NES lightgun Copyright (C) 2023 Akerasoft
+ * The author may be contacted at robert.kolski@akerasoft.com
*/
#include
#include
@@ -30,7 +33,14 @@
#include "gamepads.h"
#include "snes.h"
-#define GAMEPAD_BYTES 2
+// (C) Akerasoft 2023 -- BEGIN --
+// to support the mouse it has to be 4 bytes
+// 1 byte for NES
+// 1 byte for GUN
+// 2 bytes for SNES
+// 4 bytes for Mouse
+#define GAMEPAD_BYTES 4
+// (C) Akerasoft 2023 -- END --
/******** IO port definitions **************/
#define SNES_LATCH_DDR DDRC
@@ -65,6 +75,10 @@ static unsigned char last_read_controller_bytes[GAMEPAD_BYTES];
static unsigned char last_reported_controller_bytes[GAMEPAD_BYTES];
static char nes_mode = 0;
+// (C) Akerasoft 2023 -- BEGIN --
+static char gun_mode = 0;
+static char mouse_mode = 0;
+// (C) Akerasoft 2023 -- END --
static char snesInit(void)
{
@@ -115,7 +129,35 @@ static char snesInit(void)
13 none (always high)
14 none (always high)
15 none (always high)
- 16 none (always high)
+
+
+// (C) Akerasoft 2023 -- BEGIN --
+// Though this information came from:
+// https://www.repairfaq.org/REPAIR/F_SNES.html
+// So Rafael Assenat is the copyright holder anyway for this section
+
+ 16 none (always high) (SNES controller present)
+
+ 16 low - mouse present
+ 17 Y direction (0=up, 1=down)
+ 18 Y motion bit 6
+ 19 Y motion bit 5
+ 20 Y motion bit 4
+ 21 Y motion bit 3
+ 22 Y motion bit 2
+ 23 Y motion bit 1
+ 24 Y motion bit 0
+ 25 X direction (0=left, 1=right)
+ 26 X motion bit 6
+ 27 X motion bit 5
+ 28 X motion bit 4
+ 29 X motion bit 3
+ 30 X motion bit 2
+ 31 X motion bit 1
+ 32 X motion bit 0
+
+// (C) Akerasoft 2023 -- END --
+
*
*/
@@ -124,6 +166,15 @@ static char snesUpdate(void)
int i;
unsigned char tmp=0;
+// (C) Akerasoft 2023 -- BEGIN --
+ if (gun_mode)
+ {
+ tmp = (PIND & 0x0C) << 4;
+ last_read_controller_bytes[0] = tmp;
+ return 0;
+ }
+// (C) Akerasoft 2023 -- END --
+
SNES_LATCH_HIGH();
_delay_us(12);
SNES_LATCH_LOW();
@@ -154,6 +205,34 @@ static char snesUpdate(void)
SNES_CLOCK_HIGH();
}
last_read_controller_bytes[1] = tmp;
+// (C) Akerasoft 2023 -- BEGIN --
+ for (i=0; i<8; i++)
+ {
+ _delay_us(6);
+
+ SNES_CLOCK_LOW();
+
+ tmp <<= 1;
+ if (!SNES_GET_DATA()) { tmp |= 0x01; }
+
+ _delay_us(6);
+ SNES_CLOCK_HIGH();
+ }
+ last_read_controller_bytes[2] = tmp;
+ for (i=0; i<8; i++)
+ {
+ _delay_us(6);
+
+ SNES_CLOCK_LOW();
+
+ tmp <<= 1;
+ if (!SNES_GET_DATA()) { tmp |= 0x01; }
+
+ _delay_us(6);
+ SNES_CLOCK_HIGH();
+ }
+ last_read_controller_bytes[3] = tmp;
+// (C) Akerasoft 2023 -- END --
return 0;
}
@@ -166,23 +245,45 @@ static char snesChanged(void)
static void snesGetReport(gamepad_data *dst)
{
- unsigned char h, l;
+ unsigned char h, l, d2, d3;
if (dst != NULL)
{
l = last_read_controller_bytes[0];
h = last_read_controller_bytes[1];
-
+// (C) Akerasoft 2023 -- BEGIN --
+ d2 = last_read_controller_bytes[2];
+ d3 = last_read_controller_bytes[3];
+// (C) Akerasoft 2023 -- END --
// The 4 last bits are always high if an SNES controller
// is connected. With a NES controller, they are low.
// (High on the wire is a 0 here due to the snesUpdate() implementation)
//
- if ((h & 0x0f) == 0x0f) {
+
+// (C) Akerasoft 2023 -- BEGIN --
+ // The 3 just before last bits are high for the SNES mouse
+ // but the very last bit in byte 2 is low. So 0x1 is the expected value here
+ if (l == 0x00 && h == 0x00 && d2 == 0x00 && d3 == 0x00)
+ {
+ gun_mode = 1;
+ nes_mode = 0;
+ mouse_mode = 0;
+ } else if ((h & 0x0f) == 0x0f) {
nes_mode = 1;
+ gun_mode = 0;
+ mouse_mode = 0;
+ } else if ((h & 0x0f) == 0x01) {
+ mouse_mode = 1;
+ gun_mode = 0;
+ nes_mode = 0;
} else {
+ // SNES Controller
nes_mode = 0;
+ mouse_mode = 0;
+ gun_mode = 0;
}
+// (C) Akerasoft 2023 -- END --
if (nes_mode) {
// Nes controllers send the data in this order:
@@ -190,6 +291,20 @@ static void snesGetReport(gamepad_data *dst)
dst->nes.pad_type = PAD_TYPE_NES;
dst->nes.buttons = l;
dst->nes.raw_data[0] = l;
+// (C) Akerasoft 2023 -- BEGIN --
+ } else if (mouse_mode) {
+ dst->mouse.pad_type = PAD_TYPE_MOUSE;
+ dst->mouse.buttons = l;
+ dst->mouse.buttons |= h<<8;
+ dst->mouse.raw_data[0] = l;
+ dst->mouse.raw_data[1] = h;
+ dst->mouse.raw_data[2] = d2;
+ dst->mouse.raw_data[3] = d3;
+ } else if (gun_mode) {
+ dst->gun.pad_type = PAD_TYPE_GUN;
+ dst->gun.buttons = l;
+ dst->gun.raw_data[0] = l;
+// (C) Akerasoft 2023 -- END --
} else {
dst->nes.pad_type = PAD_TYPE_SNES;
dst->snes.buttons = l;