From 5775c6372ddc8741e98660fc1302fd526a2290c2 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Tue, 15 Mar 2022 16:44:54 -0400 Subject: [PATCH] osVoice decomp (#15) --- Makefile | 2 + src/io/controller.h | 15 ++++ src/io/controller_voice.h | 59 ++++++++++++++++ src/voice/voicecheckresult.c | 23 ++++++ src/voice/voicecheckword.c | 116 +++++++++++++++++++++++++++++++ src/voice/voicecleardictionary.c | 28 ++++++++ src/voice/voicecontread2.c | 75 ++++++++++++++++++++ src/voice/voicecontread36.c | 73 +++++++++++++++++++ src/voice/voicecontrolgain.c | 22 ++++++ src/voice/voicecontwrite20.c | 77 ++++++++++++++++++++ src/voice/voicecontwrite4.c | 75 ++++++++++++++++++++ src/voice/voicecountsyllables.c | 59 ++++++++++++++++ src/voice/voicecrc.c | 40 +++++++++++ src/voice/voicegetreaddata.c | 94 +++++++++++++++++++++++++ src/voice/voicegetstatus.c | 61 ++++++++++++++++ src/voice/voiceinit.c | 40 +++++++++++ src/voice/voiceinternal.h | 10 +++ src/voice/voicemaskdictionary.c | 47 +++++++++++++ src/voice/voicesetadconverter.c | 70 +++++++++++++++++++ src/voice/voicesetword.c | 44 ++++++++++++ src/voice/voicestartreaddata.c | 35 ++++++++++ src/voice/voicestopreaddata.c | 44 ++++++++++++ tools/compile_sjis.py | 27 +++++++ tools/shiftjis_conv.py | 58 ++++++++++++++++ 24 files changed, 1194 insertions(+) create mode 100644 src/io/controller_voice.h create mode 100644 src/voice/voicecheckresult.c create mode 100644 src/voice/voicecheckword.c create mode 100644 src/voice/voicecleardictionary.c create mode 100644 src/voice/voicecontread2.c create mode 100644 src/voice/voicecontread36.c create mode 100644 src/voice/voicecontrolgain.c create mode 100644 src/voice/voicecontwrite20.c create mode 100644 src/voice/voicecontwrite4.c create mode 100644 src/voice/voicecountsyllables.c create mode 100644 src/voice/voicecrc.c create mode 100644 src/voice/voicegetreaddata.c create mode 100644 src/voice/voicegetstatus.c create mode 100644 src/voice/voiceinit.c create mode 100644 src/voice/voiceinternal.h create mode 100644 src/voice/voicemaskdictionary.c create mode 100644 src/voice/voicesetadconverter.c create mode 100644 src/voice/voicesetword.c create mode 100644 src/voice/voicestartreaddata.c create mode 100644 src/voice/voicestopreaddata.c create mode 100755 tools/compile_sjis.py create mode 100755 tools/shiftjis_conv.py diff --git a/Makefile b/Makefile index c6a2c47..07b5d4c 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,8 @@ $(BUILD_DIR)/src/mgu/rotate.marker: export VR4300MUL := ON $(BUILD_DIR)/src/os/%.marker: ASFLAGS += -P $(BUILD_DIR)/src/gu/%.marker: ASFLAGS += -P $(BUILD_DIR)/src/libc/%.marker: ASFLAGS += -P +$(BUILD_DIR)/src/voice/%.marker: OPTFLAGS += -DLANG_JAPANESE -I$(WORKING_DIR)/src -I$(WORKING_DIR)/src/voice +$(BUILD_DIR)/src/voice/%.marker: CC := tools/compile_sjis.py -D__CC=$(WORKING_DIR)/$(CC) $(BUILD_DIR)/%.marker: %.c cd $( + +typedef struct { + /* 0x0 */ u8 dummy; + /* 0x1 */ u8 txsize; + /* 0x2 */ u8 rxsize; + /* 0x3 */ u8 cmd; + /* 0x4 */ u8 addrh; + /* 0x5 */ u8 addrl; + /* 0x6 */ u8 data[2]; + /* 0x8 */ u8 datacrc; +} __OSVoiceRead2Format; + +typedef struct { + /* 0x0 */ u8 dummy; + /* 0x1 */ u8 txsize; + /* 0x2 */ u8 rxsize; + /* 0x3 */ u8 cmd; + /* 0x4 */ u8 addrh; + /* 0x5 */ u8 addrl; + /* 0x6 */ u8 data[36]; + /* 0x2A */ u8 datacrc; +} __OSVoiceRead36Format; + +typedef struct { + /* 0x0 */ u8 dummy; + /* 0x1 */ u8 txsize; + /* 0x2 */ u8 rxsize; + /* 0x3 */ u8 cmd; + /* 0x4 */ u8 addrh; + /* 0x5 */ u8 addrl; + /* 0x6 */ u8 data[4]; + /* 0xA */ u8 datacrc; +} __OSVoiceWrite4Format; + +typedef struct { + /* 0x0 */ u8 dummy; + /* 0x1 */ u8 txsize; + /* 0x2 */ u8 rxsize; + /* 0x3 */ u8 cmd; + /* 0x4 */ u8 addrh; + /* 0x5 */ u8 addrl; + /* 0x6 */ u8 data[20]; + /* 0x1A */ u8 datacrc; +} __OSVoiceWrite20Format; + +typedef struct { + /* 0x0 */ u8 txsize; + /* 0x1 */ u8 rxsize; + /* 0x2 */ u8 cmd; + /* 0x3 */ u8 data; + /* 0x4 */ u8 scrc; + /* 0x5 */ u8 datacrc; +} __OSVoiceSWriteFormat; + +#endif // CONTROLLER_VOICE_H diff --git a/src/voice/voicecheckresult.c b/src/voice/voicecheckresult.c new file mode 100644 index 0000000..6f615e1 --- /dev/null +++ b/src/voice/voicecheckresult.c @@ -0,0 +1,23 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +s32 __osVoiceCheckResult(OSVoiceHandle* hd, u8* stat) { + s32 ret; + u8 buf[2]; + + if (ret = __osVoiceGetStatus(hd->__mq, hd->__channel, stat), ret == 0) { + if (*stat & 1) { + ret = CONT_ERR_VOICE_NO_RESPONSE; + } else if (ret = __osVoiceContRead2(hd->__mq, hd->__channel, 0, buf), ret == 0) { + hd->cmd_status = buf[0] & 7; + + if (buf[0] & 0x40) { + ret = CONT_ERR_VOICE_NO_RESPONSE; + } else { + ret = buf[1] << 8; + } + } + } + return ret; +} \ No newline at end of file diff --git a/src/voice/voicecheckword.c b/src/voice/voicecheckword.c new file mode 100644 index 0000000..25c51fa --- /dev/null +++ b/src/voice/voicecheckword.c @@ -0,0 +1,116 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +s32 osVoiceCheckWord(u8* word) { + s32 k; + s32 ret = 0; + u16 sjis; + u16 old = 0; + + for (k = 0; word[k] != 0; k += 2) { + sjis = (word[k] << 8) + word[k + 1]; + if (((sjis != 'ー') && (sjis < 'ぁ')) + || ((sjis > 'ん') && (sjis < 'ァ')) + || (sjis == 0x837F) || (sjis > 'ヶ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if ((k == 0) && ((sjis == 'ー') || (sjis == 'ん') || (sjis == 'っ') + || (sjis == 'ゎ') || (sjis == 'ン') || (sjis == 'ッ') + || (sjis == 'ヮ') || (sjis == 'ヵ') || (sjis == 'ヶ')) + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ぁ') || (sjis == 'ァ')) + && (old != 'ふ') && (old != 'フ') && (old != 'ヴ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ぃ') || (sjis == 'ィ')) && (old != 'う') + && (old != 'て') && (old != 'で') && (old != 'ふ') + && (old != 'ウ') && (old != 'テ') && (old != 'デ') + && (old != 'フ') && (old != 'ヴ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ぅ') || (sjis == 'ゥ')) + && (old != 'と') && (old != 'ど') + && (old != 'ふ') + && (old != 'ト') && (old != 'ド') + && (old != 'フ') && (old != 'ヴ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ぇ') || (sjis == 'ェ')) + && (old != 'う') + && (old != 'し') && (old != 'じ') + && (old != 'ち') && (old != 'ぢ') + && (old != 'つ') && (old != 'ふ') && (old != 'ウ') + && (old != 'シ') && (old != 'ジ') + && (old != 'チ') && (old != 'ヂ') + && (old != 'ツ') && (old != 'フ') && (old != 'ヴ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ぉ') || (sjis == 'ォ')) + && (old != 'う') && (old != 'ふ') && (old != 'ウ') && (old != 'フ') && (old != 'ヴ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ゃ') || (sjis == 'ゅ') || (sjis == 'ょ') + || (sjis == 'ャ') || (sjis == 'ュ') || (sjis == 'ョ')) + && (old != 'き') && (old != 'し') && (old != 'ち') + && (old != 'に') && (old != 'ひ') && (old != 'み') + && (old != 'り') && (old != 'ぎ') && (old != 'じ') + && (old != 'ぢ') && (old != 'び') && (old != 'ぴ') + && (old != 'キ') && (old != 'シ') && (old != 'チ') + && (old != 'ニ') && (old != 'ヒ') && (old != 'ミ') + && (old != 'リ') && (old != 'ギ') && (old != 'ジ') + && (old != 'ヂ') && (old != 'ビ') && (old != 'ピ') + && (old != 'ヴ') + ) { + ret = CONT_ERR_VOICE_WORD; + } else if ((sjis == 'ー') + && ((old == 'ん') || (old == 'っ') + || (old == 'ン') || (old == 'ッ')) + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((sjis == 'ん') || (sjis == 'ン')) + && ((old == 'ん') || (old == 'ン')) + ) { + ret = CONT_ERR_VOICE_WORD; + } else if (((old == 'っ') || (old == 'ッ')) + && ((sjis == 'ー') + || (sjis == 'あ') || (sjis == 'い') || (sjis == 'う') || (sjis == 'え') || (sjis == 'お') + || (sjis == 'な') || (sjis == 'に') || (sjis == 'ぬ') || (sjis == 'ね') || (sjis == 'の') + || (sjis == 'ま') || (sjis == 'み') || (sjis == 'む') || (sjis == 'め') || (sjis == 'も') + || (sjis == 'や') || (sjis == 'ゆ') || (sjis == 'よ') + || (sjis == 'ら') || (sjis == 'り') || (sjis == 'る') || (sjis == 'れ') || (sjis == 'ろ') + || (sjis == 'わ') || (sjis == 'ゐ') || (sjis == 'ゑ') || (sjis == 'を') + || (sjis == 'ん') + || (sjis == 'ぁ') || (sjis == 'ぃ') || (sjis == 'ぅ') || (sjis == 'ぇ') || (sjis == 'ぉ') + || (sjis == 'ゃ') || (sjis == 'ゅ') || (sjis == 'ょ') + || (sjis == 'っ') || (sjis == 'ゎ') + + || (sjis == 'ア') || (sjis == 'イ') || (sjis == 'ウ') || (sjis == 'エ') || (sjis == 'オ') + || (sjis == 'ナ') || (sjis == 'ニ') || (sjis == 'ヌ') || (sjis == 'ネ') || (sjis == 'ノ') + || (sjis == 'マ') || (sjis == 'ミ') || (sjis == 'ム') || (sjis == 'メ') || (sjis == 'モ') + || (sjis == 'ヤ') || (sjis == 'ユ') || (sjis == 'ヨ') + || (sjis == 'ラ') || (sjis == 'リ') || (sjis == 'ル') || (sjis == 'レ') || (sjis == 'ロ') + || (sjis == 'ワ') || (sjis == 'ヰ') || (sjis == 'ヱ') || (sjis == 'ヲ') + || (sjis == 'ン') + || (sjis == 'ァ') || (sjis == 'ィ') || (sjis == 'ゥ') || (sjis == 'ェ') || (sjis == 'ォ') + || (sjis == 'ャ') || (sjis == 'ュ') || (sjis == 'ョ') + || (sjis == 'ッ') || (sjis == 'ヮ') + ) + ) { + ret = CONT_ERR_VOICE_WORD; + } + + if (ret != 0) { + return ret; + } + + old = sjis; + } + + if ((sjis == 'っ') || (sjis == 'ッ')) { + ret = CONT_ERR_VOICE_WORD; + } + + return ret; +} diff --git a/src/voice/voicecleardictionary.c b/src/voice/voicecleardictionary.c new file mode 100644 index 0000000..ef6388f --- /dev/null +++ b/src/voice/voicecleardictionary.c @@ -0,0 +1,28 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +s32 osVoiceClearDictionary(OSVoiceHandle* hd, u8 words) { + s32 ret; + u8 stat; + u8 buf[4]; + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)); + + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + *(u32*)buf = 0x02000000; + buf[2] = words; + + ERRCK(__osVoiceContWrite4(hd->__mq, hd->__channel, 0, buf)); + + ret = __osVoiceCheckResult(hd, &stat); + if (ret & 0xFF00) { + ret = CONT_ERR_INVALID; + } + + return ret; +} + diff --git a/src/voice/voicecontread2.c b/src/voice/voicecontread2.c new file mode 100644 index 0000000..ae4b07b --- /dev/null +++ b/src/voice/voicecontread2.c @@ -0,0 +1,75 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" +#include "io/controller_voice.h" + +#define READ2FORMAT(p) ((__OSVoiceRead2Format*)(ptr)) + +s32 __osVoiceContRead2(OSMesgQueue* mq, int channel, u16 address, u8* buffer) { + s32 ret; + u8 status; + int i; + u8* ptr; + int retry; + + retry = 2; + + __osSiGetAccess(); + + do { + + ptr = (u8*)&__osPfsPifRam.ramarray; + + if ((__osContLastCmd != CONT_CMD_READ2_VOICE) || (__osPfsLastChannel != channel)) { + __osContLastCmd = CONT_CMD_READ2_VOICE; + __osPfsLastChannel = channel; + + for (i = 0; i < channel; i++) { + *ptr++ = 0; + } + + __osPfsPifRam.pifstatus = CONT_CMD_EXE; + + READ2FORMAT(ptr)->dummy = CONT_CMD_NOP; + READ2FORMAT(ptr)->txsize = CONT_CMD_READ2_VOICE_TX; + READ2FORMAT(ptr)->rxsize = CONT_CMD_READ2_VOICE_RX; + READ2FORMAT(ptr)->cmd = CONT_CMD_READ2_VOICE; + READ2FORMAT(ptr)->datacrc = 0xFF; + + ptr[sizeof(__OSVoiceRead2Format)] = CONT_CMD_END; + } else { + ptr = (u8*)&__osPfsPifRam.ramarray + channel; + } + + READ2FORMAT(ptr)->addrh = address >> 3; + READ2FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5); + + __osSiRawStartDma(OS_WRITE, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + __osSiRawStartDma(OS_READ, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + + ret = CHNL_ERR(*READ2FORMAT(ptr)); + + if (ret == 0) { + if (__osVoiceContDataCrc(&READ2FORMAT(ptr)->data, ARRLEN(READ2FORMAT(ptr)->data)) != READ2FORMAT(ptr)->datacrc) { + ret = __osVoiceGetStatus(mq, channel, &status); + if (ret != 0) { + break; + } + + ret = CONT_ERR_CONTRFAIL; + } else { + bcopy(&READ2FORMAT(ptr)->data, buffer, ARRLEN(READ2FORMAT(ptr)->data)); + } + } else { + ret = CONT_ERR_NO_CONTROLLER; + } + + } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0)); + + __osSiRelAccess(); + + return ret; +} diff --git a/src/voice/voicecontread36.c b/src/voice/voicecontread36.c new file mode 100644 index 0000000..a3c80a4 --- /dev/null +++ b/src/voice/voicecontread36.c @@ -0,0 +1,73 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" +#include "io/controller_voice.h" + +#define READ36FORMAT(p) ((__OSVoiceRead36Format*)(ptr)) + +s32 __osVoiceContRead36(OSMesgQueue* mq, s32 channel, u16 address, u8* buffer) { + s32 ret; + u8 status; + s32 i; + u8* ptr; + s32 retry = 2; + + __osSiGetAccess(); + + do { + + ptr = (u8*)&__osPfsPifRam.ramarray; + + if ((__osContLastCmd != CONT_CMD_READ36_VOICE) || (__osPfsLastChannel != channel)) { + __osContLastCmd = CONT_CMD_READ36_VOICE; + __osPfsLastChannel = channel; + + for (i = 0; i < channel; i++) { + *ptr++ = 0; + } + + __osPfsPifRam.pifstatus = CONT_CMD_EXE; + + READ36FORMAT(ptr)->dummy = CONT_CMD_NOP; + READ36FORMAT(ptr)->txsize = CONT_CMD_READ36_VOICE_TX; + READ36FORMAT(ptr)->rxsize = CONT_CMD_READ36_VOICE_RX; + READ36FORMAT(ptr)->cmd = CONT_CMD_READ36_VOICE; + READ36FORMAT(ptr)->datacrc = 0xFF; + + ptr[sizeof(__OSVoiceRead36Format)] = CONT_CMD_END; + } else { + ptr = (u8*)&__osPfsPifRam + channel; + } + + READ36FORMAT(ptr)->addrh = address >> 3; + READ36FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5); + + __osSiRawStartDma(OS_WRITE, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + __osSiRawStartDma(OS_READ, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + + ret = CHNL_ERR(*READ36FORMAT(ptr)); + + if (ret == 0) { + if (__osVoiceContDataCrc(&READ36FORMAT(ptr)->data, ARRLEN(READ36FORMAT(ptr)->data)) != READ36FORMAT(ptr)->datacrc) { + ret = __osVoiceGetStatus(mq, channel, &status); + if (ret != 0) { + break; + } + + ret = CONT_ERR_CONTRFAIL; + } else { + bcopy(&READ36FORMAT(ptr)->data, buffer, ARRLEN(READ36FORMAT(ptr)->data)); + } + } else { + ret = CONT_ERR_NO_CONTROLLER; + } + + } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0)); + + __osSiRelAccess(); + + return ret; +} diff --git a/src/voice/voicecontrolgain.c b/src/voice/voicecontrolgain.c new file mode 100644 index 0000000..ffb833c --- /dev/null +++ b/src/voice/voicecontrolgain.c @@ -0,0 +1,22 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +s32 __osVoiceSetADConverter(OSMesgQueue*, int ch, u8 cmd); + +s32 osVoiceControlGain(OSVoiceHandle *hd, s32 analog, s32 digital) { + s32 ret; + u8 cmd = (u8) (analog == 0 ? 0x18 : 0x98); + static u8 digital_table[] = {0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0}; + + ERRCK(__osVoiceSetADConverter(hd->__mq,hd->__channel, cmd)); + + if ((digital < ARRLEN(digital_table)) && (digital >= 0)) { + cmd = digital_table[digital] + 2; + } else { + return CONT_ERR_INVALID; + } + + ERRCK(__osVoiceSetADConverter(hd->__mq,hd->__channel, cmd)); + return ret; +} diff --git a/src/voice/voicecontwrite20.c b/src/voice/voicecontwrite20.c new file mode 100644 index 0000000..3842e3c --- /dev/null +++ b/src/voice/voicecontwrite20.c @@ -0,0 +1,77 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" +#include "io/controller_voice.h" + +#define WRITE20FORMAT(p) ((__OSVoiceWrite20Format*)(ptr)) + +s32 __osVoiceContWrite20(OSMesgQueue* mq, int channel, u16 address, u8* buffer) { + s32 ret; + u8 status; + int i; + u8* ptr; + int retry; + u8 crc; + + retry = 2; + + __osSiGetAccess(); + + do { + + ptr = (u8*)&__osPfsPifRam; + + if ((__osContLastCmd != CONT_CMD_WRITE20_VOICE) || (__osPfsLastChannel != channel)) { + __osContLastCmd = CONT_CMD_WRITE20_VOICE; + __osPfsLastChannel = channel; + + for (i = 0; i < channel; i++) { + *ptr++ = 0; + } + + __osPfsPifRam.pifstatus = CONT_CMD_EXE; + + WRITE20FORMAT(ptr)->dummy = CONT_CMD_NOP; + WRITE20FORMAT(ptr)->txsize = CONT_CMD_WRITE20_VOICE_TX; + WRITE20FORMAT(ptr)->rxsize = CONT_CMD_WRITE20_VOICE_RX; + WRITE20FORMAT(ptr)->cmd = CONT_CMD_WRITE20_VOICE; + WRITE20FORMAT(ptr)->datacrc = 0xFF; + + ptr[sizeof(__OSVoiceWrite20Format)] = CONT_CMD_END; + } else { + ptr = (u8*)&__osPfsPifRam.ramarray + channel; + } + + WRITE20FORMAT(ptr)->addrh = address >> 3; + WRITE20FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5); + + bcopy(buffer, &WRITE20FORMAT(ptr)->data, 20); + + __osSiRawStartDma(OS_WRITE, &__osPfsPifRam); + crc = __osVoiceContDataCrc(buffer, 20); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + __osSiRawStartDma(OS_READ, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + + ret = (WRITE20FORMAT(ptr)->rxsize & 0xC0) >> 4; + + if (ret == 0) { + if (crc != WRITE20FORMAT(ptr)->datacrc) { + ret = __osVoiceGetStatus(mq, channel, &status); + if (ret != 0) { + break; + } + + ret = CONT_ERR_CONTRFAIL; + } + } else { + ret = CONT_ERR_NO_CONTROLLER; + } + + } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0)); + + __osSiRelAccess(); + + return ret; +} diff --git a/src/voice/voicecontwrite4.c b/src/voice/voicecontwrite4.c new file mode 100644 index 0000000..c2af86d --- /dev/null +++ b/src/voice/voicecontwrite4.c @@ -0,0 +1,75 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" +#include "io/controller_voice.h" + +#define WRITE4FORMAT(p) ((__OSVoiceWrite4Format*)(ptr)) + +s32 __osVoiceContWrite4(OSMesgQueue* mq, int channel, u16 address, u8 dst[4]) { + s32 ret; + u8 status; + int i; + u8* ptr; + s32 retry = 2; + u8 crc; + + __osSiGetAccess(); + + do { + + ptr = (u8*)&__osPfsPifRam; + + if ((__osContLastCmd != CONT_CMD_WRITE4_VOICE) || (__osPfsLastChannel != channel)) { + __osContLastCmd = CONT_CMD_WRITE4_VOICE; + __osPfsLastChannel = channel; + + for (i = 0; i < channel; i++) { + *ptr++ = 0; + } + + __osPfsPifRam.pifstatus = CONT_CMD_EXE; + + WRITE4FORMAT(ptr)->dummy = CONT_CMD_NOP; + WRITE4FORMAT(ptr)->txsize = CONT_CMD_WRITE4_VOICE_TX; + WRITE4FORMAT(ptr)->rxsize = CONT_CMD_WRITE4_VOICE_RX; + WRITE4FORMAT(ptr)->cmd = CONT_CMD_WRITE4_VOICE; + WRITE4FORMAT(ptr)->datacrc = 0xFF; + + ptr[sizeof(__OSVoiceWrite4Format)] = CONT_CMD_END; + } else { + ptr = (u8*)&__osPfsPifRam + channel; + } + + WRITE4FORMAT(ptr)->addrh = address >> 3; + WRITE4FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5); + + bcopy(dst, &WRITE4FORMAT(ptr)->data, 4); + + __osSiRawStartDma(OS_WRITE, &__osPfsPifRam); + crc = __osVoiceContDataCrc(dst, 4); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + __osSiRawStartDma(OS_READ, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + + ret = (WRITE4FORMAT(ptr)->rxsize & 0xC0) >> 4; + + if (ret == 0) { + if (crc != WRITE4FORMAT(ptr)->datacrc) { + ret = __osVoiceGetStatus(mq, channel, &status); + if (ret != 0) { + break; + } + + ret = CONT_ERR_CONTRFAIL; + } + } else { + ret = CONT_ERR_NO_CONTROLLER; + } + + } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0)); + + __osSiRelAccess(); + + return ret; +} diff --git a/src/voice/voicecountsyllables.c b/src/voice/voicecountsyllables.c new file mode 100644 index 0000000..89b4c63 --- /dev/null +++ b/src/voice/voicecountsyllables.c @@ -0,0 +1,59 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +// The VRU can store only 880 semisyllables of words in its dictionary. +// Use this function to determine the semisyllable count before adding a word with osVoiceSetWord, +// to properly see whether it will fit. + +void osVoiceCountSyllables(u8 *data, u32 *syllable) { + s32 k; + u16 sjis; + u16 old; + + old = 0; + *syllable = 1; + for (k = 0; data[k] != 0; k += 2) { + sjis = data[k + 1] + (data[k] << 8); + if ((sjis == 'あ') || (sjis == 'い') || (sjis == 'う') || (sjis == 'え') || (sjis == 'お') + || (sjis == 'ア') || (sjis == 'イ') || (sjis == 'ウ') || (sjis == 'エ') || (sjis == 'オ') + ) { + if (k == 0) { + *syllable += 2; + } else { + *syllable += 1; + } + } else if ((sjis == 'か') || (sjis == 'き') || (sjis == 'く') || (sjis == 'け') || (sjis == 'こ') + || (sjis == 'た') || (sjis == 'ち') || (sjis == 'つ') || (sjis == 'て') || (sjis == 'と') + || (sjis == 'ぱ') || (sjis == 'ぴ') || (sjis == 'ぷ') || (sjis == 'ぺ') || (sjis == 'ぽ') + || (sjis == 'カ') || (sjis == 'キ') || (sjis == 'ク') || (sjis == 'ケ') || (sjis == 'コ') + || (sjis == 'タ') || (sjis == 'チ') || (sjis == 'ツ') || (sjis == 'テ') || (sjis == 'ト') + || (sjis == 'パ') || (sjis == 'ピ') || (sjis == 'プ') || (sjis == 'ペ') || (sjis == 'ポ') + ) { + if (k == 0) { + *syllable += 2; + } else if ((old == 'っ') || (old == 'ッ')) { + *syllable += 2; + } else { + *syllable += 3; + } + } else if ((sjis == 'ぁ') || (sjis == 'ぃ') || (sjis == 'ぅ') || (sjis == 'ぇ') || (sjis == 'ぉ') + || (sjis == 'ゃ') || (sjis == 'ゅ') || (sjis == 'ょ') || (sjis == 'ゎ') + + || (sjis == 'ァ') || (sjis == 'ィ') || (sjis == 'ゥ') || (sjis == 'ェ') || (sjis == 'ォ') + || (sjis == 'ャ') || (sjis == 'ュ') || (sjis == 'ョ') || (sjis == 'ヮ') + || (sjis == 'ヵ') || (sjis == 'ヶ') + ) { + if ((old == 'あ') || (old == 'い') || (old == 'う') || (old == 'え') || (old == 'お') + || (old == 'ア') || (old == 'イ') || (old == 'ウ') || (old == 'エ') || (old == 'オ') + ) { + *syllable += 1; + } + } else if ((sjis == 'ん') || (sjis == 'ー') || (sjis == 'っ') || (sjis == 'ン') || (sjis == 'ッ')) { + *syllable += 1; + } else { + *syllable += 2; + } + old = sjis; + } +} diff --git a/src/voice/voicecrc.c b/src/voice/voicecrc.c new file mode 100644 index 0000000..95741e6 --- /dev/null +++ b/src/voice/voicecrc.c @@ -0,0 +1,40 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +#define VOICE_CRC_LENGTH 8 +#define VOICE_CRC_GENERATOR 0x85 + +u8 __osVoiceContDataCrc(u8* data, u32 length) { + s32 ret = 0; + u32 i; + u32 j; + + for (j = length; j != 0; j--, data++) { + // Loop over each i in the j starting with most significant + for (i = (1 << (VOICE_CRC_LENGTH - 1)); i != 0; i >>= 1) { + ret <<= 1; + if (*data & i) { + if (ret & (1 << VOICE_CRC_LENGTH)) { + // Same as ret++; ret ^= 0x85 since last i always 0 after the shift + ret ^= VOICE_CRC_GENERATOR - 1; + } else { + ret++; + } + } else if (ret & (1 << VOICE_CRC_LENGTH)) { + ret ^= VOICE_CRC_GENERATOR; + } + } + } + // Act like a j of zeros is appended to data + do { + ret <<= 1; + if (ret & (1 << VOICE_CRC_LENGTH)) { + ret ^= VOICE_CRC_GENERATOR; + } + j++; + } while (j < VOICE_CRC_LENGTH); + + // Discarding the excess is done automatically by the return type + return ret; +} \ No newline at end of file diff --git a/src/voice/voicegetreaddata.c b/src/voice/voicegetreaddata.c new file mode 100644 index 0000000..5627846 --- /dev/null +++ b/src/voice/voicegetreaddata.c @@ -0,0 +1,94 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" + +s32 osVoiceGetReadData(OSVoiceHandle* hd, OSVoiceData* micdata) { + s32 ret = 0; + s32 i; + u8 stat; + u8 temp[36]; + static u8 c; + + switch (hd->__mode) { + case 1: + ret = __osVoiceGetStatus(hd->__mq, hd->__channel, &stat); + if (ret != 0) { + return ret; + } else if (stat & 1) { + return CONT_ERR_NOT_READY; + } + + ERRCK(__osVoiceContRead2(hd->__mq, hd->__channel, 0, temp)); + + c = temp[0] & 7; + hd->cmd_status = c; + if ((c != 0) && (c != 7)) { + return CONT_ERR_NOT_READY; + } + case 2: + hd->__mode = 2; + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)) + + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + *(u32*)temp = 0x600; + ERRCK(__osVoiceContWrite4(hd->__mq, hd->__channel, 0, temp)); + + case 3: + hd->__mode = 3; + + ret = __osVoiceGetStatus(hd->__mq, hd->__channel, &stat); + if (ret != 0) { + return ret; + } else if (stat & 1) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + ERRCK(__osVoiceContRead36(hd->__mq, hd->__channel, 0, temp)); + + micdata->warning = temp[4] + (temp[5] << 8); + micdata->answer_num = temp[6]; + micdata->voice_level = temp[8] + (temp[9] << 8); + micdata->voice_sn = temp[10] + (temp[11] << 8); + micdata->voice_time = temp[12] + (temp[13] << 8); + + for (i = 0; i < 5; i++) { + micdata->answer[i] = temp[14 + (i << 2)] + (temp[15 + (i << 2)] << 8); + micdata->distance[i] = temp[16 + (i << 2)] + (temp[17 + (i << 2)] << 8); + } + + if (micdata->answer[0] == 0x7FFF) { + micdata->answer_num = 0; + } + + hd->cmd_status = temp[34] & 7; + if ((c == 0) || (hd->cmd_status == 0)) { + break; + } + case 4: + hd->__mode = 4; + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)); + + if (stat & 1) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + ERRCK(__osVoiceContRead2(hd->__mq, hd->__channel, 0, temp)); + + hd->cmd_status = temp[0] & 7; + if (temp[0] & 7) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + break; + default: + return CONT_ERR_INVALID; + } + hd->__mode = 0; + return ret; +} diff --git a/src/voice/voicegetstatus.c b/src/voice/voicegetstatus.c new file mode 100644 index 0000000..8d33f31 --- /dev/null +++ b/src/voice/voicegetstatus.c @@ -0,0 +1,61 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" + +s32 __osVoiceGetStatus(OSMesgQueue* mq, s32 port, u8* status) { + __OSContRequesFormatShort header; + s32 ret = 0; + s32 i; + u8* ptr = (u8*)&__osContPifRam.ramarray; + s32 retry = 2; + + __osSiGetAccess(); + + do { + if (ret != CONT_ERR_CONTRFAIL) { + __osContPifRam.pifstatus = CONT_CMD_EXE; + + for (i = 0; i < port; i++, *ptr++ = 0) { + ; + } + + *ptr++ = CONT_CMD_REQUEST_STATUS_TX; + *ptr++ = CONT_CMD_REQUEST_STATUS_RX; + *ptr = CONT_CMD_REQUEST_STATUS; + ptr += 4; + *ptr = CONT_CMD_END; + + __osContLastCmd = CONT_CMD_END; + ret = __osSiRawStartDma(OS_WRITE, &__osContPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + } + ret = __osSiRawStartDma(OS_READ, &__osContPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + + ptr = (u8*)&__osContPifRam.ramarray + port; + + header = *((__OSContRequesFormatShort*)ptr); + + ret = CHNL_ERR(header); + *status = header.status; + + if (ret == 0) { + if (header.typeh == 0 && header.typel == 1) { + if (header.status & 4) { + ret = CONT_ERR_CONTRFAIL; + } + } else { + ret = CONT_ERR_DEVICE; + } + } else if (ret & CONT_NO_RESPONSE_ERROR) { + ret = CONT_ERR_NO_CONTROLLER; + } else { + ret = CONT_ERR_CONTRFAIL; + } + } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0)); + + __osSiRelAccess(); + + return ret; +} diff --git a/src/voice/voiceinit.c b/src/voice/voiceinit.c new file mode 100644 index 0000000..a60f943 --- /dev/null +++ b/src/voice/voiceinit.c @@ -0,0 +1,40 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +s32 osVoiceInit(OSMesgQueue* mq, OSVoiceHandle* handle, int channel) { + s32 ret; + s32 i; + u8 stat = 0; + u8 buf[4]; + static u8 cmd[] = {0x1E, 0x6E, 0x08, 0x56, 0x03}; + + handle->__channel = channel; + handle->__mq = mq; + handle->__mode = 0; + + ERRCK(__osVoiceGetStatus(mq, channel, &stat)); + + if (__osContChannelReset(mq, channel) != 0) { + return CONT_ERR_CONTRFAIL; + } + + for (i = 0; i < ARRLEN(cmd); i++) { + ERRCK(__osVoiceSetADConverter(mq, channel, cmd[i])); + } + + ERRCK(__osVoiceGetStatus(mq, channel, &stat)); + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + *(u32*)buf = 0x100; + ERRCK(__osVoiceContWrite4(mq, channel, 0, buf)); + + ret = __osVoiceCheckResult(handle, &stat); + if (ret & 0xFF00) { + ret = CONT_ERR_INVALID; + } + + return ret; +} diff --git a/src/voice/voiceinternal.h b/src/voice/voiceinternal.h new file mode 100644 index 0000000..899c150 --- /dev/null +++ b/src/voice/voiceinternal.h @@ -0,0 +1,10 @@ +#ifndef VOICE_INTERNAL_H +#define VOICE_INTERNAL_H + +// Various prototypes and externs that don't show up in os_voice.h +extern s32 __osPfsLastChannel; + +u8 __osVoiceContDataCrc(u8* data, u32 length); +s32 __osVoiceCheckResult(OSVoiceHandle* hd, u8* stat); + +#endif diff --git a/src/voice/voicemaskdictionary.c b/src/voice/voicemaskdictionary.c new file mode 100644 index 0000000..a017e3d --- /dev/null +++ b/src/voice/voicemaskdictionary.c @@ -0,0 +1,47 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" + +s32 osVoiceMaskDictionary(OSVoiceHandle* hd, u8* pattern, int size) { + s32 ret; + s32 i; + s32 j; + u8 stat; + u8 buf[20]; + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)); + + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + if (size & 1) { + j = size + 1; + } else { + j = size; + } + + bzero(&buf, ARRLEN(buf)); + + buf[18 - j] = 4; + + for (i = 0; i < j; i += 2) { + buf[i + ARRLEN(buf) - j] = pattern[i]; + buf[i + ARRLEN(buf) - j + 1] = pattern[i + 1]; + } + + if (size & 1) { + buf[ARRLEN(buf) - 1] = 0; + } + + ret = __osVoiceContWrite20(hd->__mq, hd->__channel, 0, &buf); + if (ret == 0) { + ret = __osVoiceCheckResult(hd, &stat); + if (ret & 0xFF00) { + ret = CONT_ERR_INVALID; + } + } + + return ret; +} diff --git a/src/voice/voicesetadconverter.c b/src/voice/voicesetadconverter.c new file mode 100644 index 0000000..2287c0d --- /dev/null +++ b/src/voice/voicesetadconverter.c @@ -0,0 +1,70 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" +#include "io/controller_voice.h" + +#define SWRITEFORMAT(p) ((__OSVoiceSWriteFormat*)(p)) + +s32 __osVoiceSetADConverter(OSMesgQueue* mq, s32 channel, u8 data) { + s32 ret; + int i; + u8* ptr; + u8 status; + int retry = 2; + + __osSiGetAccess(); + + do { + + ptr = (u8*)__osPfsPifRam.ramarray; + + if ((__osContLastCmd != CONT_CMD_SWRITE_VOICE) || (__osPfsLastChannel != channel)) { + __osContLastCmd = CONT_CMD_SWRITE_VOICE; + __osPfsLastChannel = channel; + + for (i = 0; i < channel; i++) { + *ptr++ = 0; + } + + __osPfsPifRam.pifstatus = CONT_CMD_EXE; + + SWRITEFORMAT(ptr)->txsize = CONT_CMD_SWRITE_VOICE_TX; + SWRITEFORMAT(ptr)->rxsize = CONT_CMD_SWRITE_VOICE_RX; + SWRITEFORMAT(ptr)->cmd = CONT_CMD_SWRITE_VOICE; + SWRITEFORMAT(ptr)->datacrc = 0; + + ptr[sizeof(__OSVoiceSWriteFormat)] = CONT_CMD_END; + } else { + ptr = (u8*)&__osPfsPifRam + channel; + } + + SWRITEFORMAT(ptr)->data = data; + SWRITEFORMAT(ptr)->scrc = __osContAddressCrc(data * 8); + + __osSiRawStartDma(OS_WRITE, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + __osSiRawStartDma(OS_READ, &__osPfsPifRam); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + + ret = CHNL_ERR(*SWRITEFORMAT(ptr)); + + if (ret == 0) { + if (SWRITEFORMAT(ptr)->datacrc & 1) { + ret = __osVoiceGetStatus(mq, channel, &status); + if (ret != 0) { + break; + } + + ret = CONT_ERR_CONTRFAIL; + } + } else { + ret = CONT_ERR_NO_CONTROLLER; + } + + } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0)); + + __osSiRelAccess(); + + return ret; +} diff --git a/src/voice/voicesetword.c b/src/voice/voicesetword.c new file mode 100644 index 0000000..9a7ed6f --- /dev/null +++ b/src/voice/voicesetword.c @@ -0,0 +1,44 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" + +s32 osVoiceSetWord(OSVoiceHandle *hd, u8 *word) { + s32 j; + s32 k; + s32 ret; + u8 stat; + u8 buf[40]; + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)); + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + for (k = 0; word[k] != 0; k += 2) { + ; + } + + bzero(buf, ARRLEN(buf)); + + for (j = 0; j < k; j += 2) { + buf[ARRLEN(buf) - 1 - k + j] = word[j]; + buf[ARRLEN(buf) - 1 - k + j - 1] = word[j + 1]; + } + + buf[ARRLEN(buf) - 1 - j - 5] = 3; + + if (k >= 15) { + ERRCK(__osVoiceContWrite20(hd->__mq, hd->__channel, 0, buf)); + } + ERRCK(__osVoiceContWrite20(hd->__mq, hd->__channel, 0, buf + 20)); + ret = __osVoiceCheckResult(hd, &stat); + if (ret != 0) { + if (ret & 0x100) { + ret = CONT_ERR_VOICE_MEMORY; + } else if (ret & 0x200) { + ret = CONT_ERR_VOICE_WORD; + } else if (ret & 0xFF00) { + ret = CONT_ERR_INVALID; + } + } + return ret; +} diff --git a/src/voice/voicestartreaddata.c b/src/voice/voicestartreaddata.c new file mode 100644 index 0000000..0f9fc73 --- /dev/null +++ b/src/voice/voicestartreaddata.c @@ -0,0 +1,35 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" + +s32 osVoiceStartReadData(OSVoiceHandle* hd) { + s32 ret; + u8 stat; + u8 temp[4]; + + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)); + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + if (hd->__mode != 0) { + return CONT_ERR_INVALID; + } + + *(u32*)temp = 0x5000000; + ret = __osVoiceContWrite4(hd->__mq, hd->__channel, 0, temp); + + if (ret == 0) { + ret = __osVoiceCheckResult(hd, &stat); + + if (ret & 0xFF00) { + ret = CONT_ERR_INVALID; + } else { + hd->__mode = 1; + } + } + + return ret; +} \ No newline at end of file diff --git a/src/voice/voicestopreaddata.c b/src/voice/voicestopreaddata.c new file mode 100644 index 0000000..e5b97ca --- /dev/null +++ b/src/voice/voicestopreaddata.c @@ -0,0 +1,44 @@ +#include "PR/os_internal.h" +#include "io/controller.h" +#include "PR/os_voice.h" +#include "voiceinternal.h" + +s32 osVoiceStopReadData(OSVoiceHandle* hd) { + s32 ret; + s32 i; + u8 stat; + u8 temp[4]; + + ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat)); + + if (stat & 2) { + return CONT_ERR_VOICE_NO_RESPONSE; + } + + if (hd->__mode == 0) { + return CONT_ERR_INVALID; + } + + *(u32*)temp = 0x700; + ret = __osVoiceContWrite4(hd->__mq, hd->__channel, 0, temp); + + if (ret == 0) { + i = 0; + do { + ret = __osVoiceCheckResult(hd, &stat); + if (ret & 0xFF00) { + if (((ret & 7) == 0) || ((ret & 7) == 7)) { + ret = 0; + hd->__mode = 0; + } else { + ret = CONT_ERR_INVALID; + } + } else { + hd->__mode = 0; + } + i++; + } while ((ret == CONT_ERR_VOICE_NO_RESPONSE) && (i < 20)); + } + + return ret; +} \ No newline at end of file diff --git a/tools/compile_sjis.py b/tools/compile_sjis.py new file mode 100755 index 0000000..1905745 --- /dev/null +++ b/tools/compile_sjis.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import sys, os +from shiftjis_conv import sjis_process + +os.chdir("../../") +WORKING_DIR = os.getcwd() + +fb = [] +original_c_file = [i for i in sys.argv if ".c" in i][0] +CC = [i for i in sys.argv if "-D__CC=" in i][0][7:] + +output_c_file = original_c_file + +sys.argv[sys.argv.index(original_c_file)] = output_c_file + +original_c_file = "src/voice/" + original_c_file + +with open(original_c_file) as f: + fb = f.read() + +os.chdir("build/src/voice") + +with open(output_c_file, "w+") as outf: + sjis_process(fb, outf) + +os.system("%s %s" % (CC, " ".join(sys.argv[1:]))) diff --git a/tools/shiftjis_conv.py b/tools/shiftjis_conv.py new file mode 100755 index 0000000..73037d2 --- /dev/null +++ b/tools/shiftjis_conv.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +import sys + +# Converts a file with UTF-8 Japanese glyphs in char literals, +# into one that uses u16 constants + +# Follows the layout in the manual page for easier cross reference +sjis_table = { + "ー": 0x815B, "ぜ": 0x82BA, "へ": 0x82D6, "ァ": 0x8340, "ソ": 0x835C, "ペ": 0x8379, + "ぁ": 0x829F, "そ": 0x82BB, "べ": 0x82D7, "ア": 0x8341, "ゾ": 0x835D, "ホ": 0x837A, + "あ": 0x82A0, "ぞ": 0x82BC, "ぺ": 0x82D8, "ィ": 0x8342, "タ": 0x835E, "ボ": 0x837B, + "ぃ": 0x82A1, "た": 0x82BD, "ほ": 0x82D9, "イ": 0x8343, "ダ": 0x835F, "ポ": 0x837C, + "い": 0x82A2, "だ": 0x82BE, "ぼ": 0x82DA, "ゥ": 0x8344, "チ": 0x8360, "マ": 0x837D, + "ぅ": 0x82A3, "ち": 0x82BF, "ぽ": 0x82DB, "ウ": 0x8345, "ヂ": 0x8361, "ミ": 0x837E, + "う": 0x82A4, "ぢ": 0x82C0, "ま": 0x82DC, "ェ": 0x8346, "ッ": 0x8362, "ム": 0x8380, + "ぇ": 0x82A5, "っ": 0x82C1, "み": 0x82DD, "エ": 0x8347, "ツ": 0x8363, "メ": 0x8381, + "え": 0x82A6, "つ": 0x82C2, "む": 0x82DE, "ォ": 0x8348, "ヅ": 0x8364, "モ": 0x8382, + "ぉ": 0x82A7, "づ": 0x82C3, "め": 0x82DF, "オ": 0x8349, "テ": 0x8365, "ャ": 0x8383, + "お": 0x82A8, "て": 0x82C4, "も": 0x82E0, "カ": 0x834A, "デ": 0x8366, "ヤ": 0x8384, + "か": 0x82A9, "で": 0x82C5, "ゃ": 0x82E1, "ガ": 0x834B, "ト": 0x8367, "ュ": 0x8385, + "が": 0x82AA, "と": 0x82C6, "や": 0x82E2, "キ": 0x834C, "ド": 0x8368, "ユ": 0x8386, + "き": 0x82AB, "ど": 0x82C7, "ゅ": 0x82E3, "ギ": 0x834D, "ナ": 0x8369, "ョ": 0x8387, + "ぎ": 0x82AC, "な": 0x82C8, "ゆ": 0x82E4, "ク": 0x834E, "ニ": 0x836A, "ヨ": 0x8388, + "く": 0x82AD, "に": 0x82C9, "ょ": 0x82E5, "グ": 0x834F, "ヌ": 0x836B, "ラ": 0x8389, + "ぐ": 0x82AE, "ぬ": 0x82CA, "よ": 0x82E6, "ケ": 0x8350, "ネ": 0x836C, "リ": 0x838A, + "け": 0x82AF, "ね": 0x82CB, "ら": 0x82E7, "ゲ": 0x8351, "ノ": 0x836D, "ル": 0x838B, + "げ": 0x82B0, "の": 0x82CC, "り": 0x82E8, "コ": 0x8352, "ハ": 0x836E, "レ": 0x838C, + "こ": 0x82B1, "は": 0x82CD, "る": 0x82E9, "ゴ": 0x8353, "バ": 0x836F, "ロ": 0x838D, + "ご": 0x82B2, "ば": 0x82CE, "れ": 0x82EA, "サ": 0x8354, "パ": 0x8370, "ヮ": 0x838E, + "さ": 0x82B3, "ぱ": 0x82CF, "ろ": 0x82EB, "ザ": 0x8355, "ヒ": 0x8371, "ワ": 0x838F, + "ざ": 0x82B4, "ひ": 0x82D0, "ゎ": 0x82EC, "シ": 0x8356, "ビ": 0x8372, "ヰ": 0x8390, + "し": 0x82B5, "び": 0x82D1, "わ": 0x82ED, "ジ": 0x8357, "ピ": 0x8373, "ヱ": 0x8391, + "じ": 0x82B6, "ぴ": 0x82D2, "ゐ": 0x82EE, "ス": 0x8358, "フ": 0x8374, "ヲ": 0x8392, + "す": 0x82B7, "ふ": 0x82D3, "ゑ": 0x82EF, "ズ": 0x8359, "ブ": 0x8375, "ン": 0x8393, + "ず": 0x82B8, "ぶ": 0x82D4, "を": 0x82F0, "セ": 0x835A, "プ": 0x8376, "ヴ": 0x8394, + "せ": 0x82B9, "ぷ": 0x82D5, "ん": 0x82F1, "ゼ": 0x835B, "ヘ": 0x8377, "ヵ": 0x8395, + "ベ": 0x8378, "ヶ": 0x8396, +} + +skipTimer = 0 + +def sjis_process(buf, outfile): + global skipTimer + + for i, char in enumerate(buf): + if skipTimer > 0: + skipTimer -= 1 + continue + if char == "'" and buf[i+1] in sjis_table: + if sjis_table[buf[i+1]] == 0: + print("Error: Please map %s in %s" % (buf[i+1], sys.argv[0])) + exit(1) + outfile.write("0x%X" % sjis_table[buf[i+1]]) + skipTimer = 2 + else: + outfile.write(char) + +