You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
5.5 KiB
245 lines
5.5 KiB
import chalk from 'chalk'
|
|
import LCD from 'raspberrypi-liquid-crystal'
|
|
let lcd
|
|
|
|
const err = chalk.bold.redBright
|
|
const inf = chalk.blueBright
|
|
const wrn = chalk.yellowBright
|
|
const dbg = chalk.dim.gray
|
|
|
|
const SPIN_CHARS = [
|
|
[0x14,0x1c,0x15,0x1,0x6,0x0,0x00,0x0],
|
|
[0x14,0x1c,0x15,0x1,0x6,0x0,0x10,0x0],
|
|
[0x14,0x1c,0x15,0x1,0x6,0x0,0x14,0x0],
|
|
[0x14,0x1c,0x15,0x1,0x6,0x0,0x15,0x0]
|
|
]
|
|
const SPINNER = SPIN_CHARS.map((c, i) => i)
|
|
|
|
const STATUS_LINE = [
|
|
'Status: ______'
|
|
]
|
|
|
|
const states = {
|
|
idle: [
|
|
'Waiting for new game',
|
|
'Scan the card for ',
|
|
'instructions. ',
|
|
],
|
|
'ready-card': [
|
|
' ',
|
|
'Scan your card now!!',
|
|
' ',
|
|
],
|
|
'nc-wait-shutter': [
|
|
'New card detected! ',
|
|
'Please select the ' ,
|
|
'"No card" option ',
|
|
],
|
|
'nc-wait-dispense': [
|
|
'New card detected! ',
|
|
'Waiting for game to ' ,
|
|
'dispense a new card ',
|
|
],
|
|
'playing': [
|
|
'Game in progress, ',
|
|
'GLHF! Card id: ',
|
|
'____________________',
|
|
],
|
|
'gp-wait-dispense': [
|
|
'No card? Ask owner ',
|
|
'for one! Game data ',
|
|
'will be lost! '
|
|
],
|
|
'guest-playing': [
|
|
'No card? Ask owner ',
|
|
'for one! Game data ',
|
|
'will be lost! '
|
|
],
|
|
'oc-check-renewal': [
|
|
'Welcome back! ',
|
|
'Checking if card ' ,
|
|
'needs renewal... ',
|
|
],
|
|
'oc-wait-dispense': [
|
|
'Card renewed! ',
|
|
'Waiting for game to ' ,
|
|
'dispense a new card ',
|
|
]
|
|
}
|
|
|
|
export const INSTRUCTIONS = [
|
|
'1) Step on the gas ',
|
|
'2) Scan your card ',
|
|
'3) (Register card) ',
|
|
]
|
|
|
|
export const CARD_PRESENT = [
|
|
'Already scanned a ',
|
|
'card, please wait ',
|
|
'until new game. ',
|
|
]
|
|
|
|
export const GUEST_PLAYING = [
|
|
'Guest is currently ',
|
|
'playing, please wait',
|
|
'until new game. ',
|
|
]
|
|
|
|
export const REGISTR_ABORT = [
|
|
'Card registration is',
|
|
'aborted - time run ',
|
|
'out. Try again later',
|
|
]
|
|
|
|
export const RENEW_CARD = [
|
|
'Card renewed! ',
|
|
'Present or discarded',
|
|
'card data is lost :(',
|
|
]
|
|
|
|
export const THANKS_FOR_PLAYING = [
|
|
'Thanks for playing! ',
|
|
'Hope you had a good ',
|
|
'time. t. hj',
|
|
]
|
|
|
|
export const Logger = (prefix) => {
|
|
return {
|
|
warn(...string) {
|
|
console.warn(wrn('[!]') + prefix + ' ' + string.join(' '))
|
|
},
|
|
info(...string) {
|
|
console.info(inf('[ ]') + prefix + ' ' + string.join(' '))
|
|
},
|
|
error(...string) {
|
|
console.error(err('[!]') + prefix + ' ' + err(string.join(' ')))
|
|
},
|
|
debug(...string) {
|
|
console.error(dbg('[ ]' + prefix + ' ' + string.join(' ')))
|
|
}
|
|
}
|
|
}
|
|
|
|
export const DisplayController = ({ bus, noLCD }) => {
|
|
const logger = Logger(chalk.blue('[LCD]'))
|
|
|
|
const status = {
|
|
hasLCD: false,
|
|
spinnerIndex: 0,
|
|
spinner: SPINNER[0],
|
|
|
|
state: 'idle',
|
|
|
|
emuCard: false,
|
|
emuOpen: false,
|
|
|
|
cardId: '',
|
|
|
|
messageCountdown: 0,
|
|
message: null,
|
|
|
|
countdown: 0,
|
|
}
|
|
|
|
const quipSelect = () => {
|
|
if (status.messageCountdown > 0) {
|
|
return status.message || [
|
|
'All your base ',
|
|
' Are belong to us!!',
|
|
' (invalid message) ',
|
|
]
|
|
} else {
|
|
const statusQuip = states[status.state]
|
|
if (status.state === 'playing') {
|
|
statusQuip[2] = status.cardId.padEnd(20, ' ')
|
|
}
|
|
return statusQuip
|
|
}
|
|
}
|
|
|
|
const statusLineGenerator = () => {
|
|
let countdownI = status.countdown > 0
|
|
? `${status.countdown}`.padStart(3, ' ')
|
|
: ' '
|
|
let emuCardI = status.emuCard ? 'C' : '_'
|
|
let emuOpenI = status.emuOpen ? 'O' : '#'
|
|
if (status.emuCard === 'error') {
|
|
emuCardI = 'E'
|
|
emuOpenI = 'E'
|
|
}
|
|
return countdownI + emuCardI + emuOpenI + status.spinner
|
|
}
|
|
|
|
const lineGen = () => {
|
|
return STATUS_LINE[0].replace('______', statusLineGenerator())
|
|
}
|
|
|
|
const bufferGen = () => [ lineGen(), ...quipSelect() ]
|
|
|
|
return {
|
|
setState(state) {
|
|
status.state = state
|
|
},
|
|
setEmuCard(emuCard) {
|
|
status.emuCard = emuCard
|
|
},
|
|
setEmuOpen(emuOpen) {
|
|
status.emuOpen = emuOpen
|
|
},
|
|
setMessage(message) {
|
|
status.message = message
|
|
status.messageCountdown = 10 * 2
|
|
},
|
|
setCountdown(countdown) {
|
|
status.countdown = countdown
|
|
},
|
|
setCardId(cardId) {
|
|
status.cardId = cardId
|
|
},
|
|
initLCD() {
|
|
logger.info('Initializing LCD...')
|
|
|
|
const loop = () => {
|
|
const buffer = bufferGen()
|
|
|
|
this.advanceSpinner()
|
|
//lcd.clearSync()
|
|
buffer.forEach((line, i) => lcd.printLineSync(i, line.substring(0, 20)))
|
|
if (status.messageCountdown > 0) {
|
|
status.messageCountdown--
|
|
if (status.messageCountdown === 0) {
|
|
status.messageType = null
|
|
}
|
|
}
|
|
|
|
setTimeout(loop, 100)
|
|
}
|
|
|
|
lcd = new LCD(Number(bus), 0x27, 20, 4);
|
|
lcd
|
|
.begin()
|
|
.then(() => {
|
|
status.hasLCD = true
|
|
logger.info('LCD Initialized!')
|
|
lcd.clearSync()
|
|
lcd.printLineSync(0, 'Wangan Midnight ')
|
|
lcd.printLineSync(1, ' Maximum Tune 3DX+')
|
|
lcd.printLineSync(2, ' IC card support ')
|
|
lcd.printLineSync(3, ' by HJ (and GXTX)')
|
|
SPIN_CHARS.forEach((c, i) => {
|
|
lcd.createCharSync(i, c)
|
|
})
|
|
|
|
setTimeout(loop, 3000)
|
|
})
|
|
.catch((e) => {
|
|
status.hasLCD = false
|
|
this.warn('Error initializing LCD: ', e)
|
|
})
|
|
},
|
|
advanceSpinner() {
|
|
if (status.spinnerIndex >= SPINNER.length) status.spinnerIndex = 0
|
|
status.spinner = LCD.getChar(status.spinnerIndex++)
|
|
}
|
|
}
|
|
}
|
|
|