-
Notifications
You must be signed in to change notification settings - Fork 8
/
touchscreen.go
111 lines (97 loc) · 2.84 KB
/
touchscreen.go
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
package main
import (
"encoding/binary"
log "ndsemu/emu/logger"
"ndsemu/emu/spi"
)
var modTsc = log.NewModule("tsc")
type HwTouchScreen struct {
penX, penY int
penDown bool
}
func NewHwTouchScreen() *HwTouchScreen {
return &HwTouchScreen{}
}
var tscChanNames = [8]string{
"temp0", "touch_y", "battery", "touch_z1",
"touch_z2", "touch_x", "aux", "temp1",
}
func (ff *HwTouchScreen) SetPen(down bool, x, y int) {
ff.penX = x
ff.penY = y
ff.penDown = down
}
func (ff *HwTouchScreen) SpiTransfer(data []byte) ([]byte, spi.ReqStatus) {
cmd := data[0]
if cmd&0x80 == 0 {
return nil, spi.ReqFinish
}
powdown := cmd & 3
ref := (cmd >> 2) & 1
bits8 := (cmd>>3)&1 != 0
adchan := (cmd >> 4) & 7
modTsc.InfoZ("reading channel").
String("ch", tscChanNames[adchan]).
Hex8("value", cmd).
Bool("8bits", bits8).
Uint8("ref", ref).
Uint8("powdown", powdown).
End()
// Output value is always generated in the 12-bit range, and it is then
// optionally truncated to 8 bit
var output uint16
switch adchan {
case 0:
output = 0x800
case 1: // Y coord
if ff.penDown {
// FIXME: this is surely wrong. It is reading the calibration
// values from the RAM (where the firmware stores them) and
// performing a reverse mapping to report the ADC values that
// correspond to the mouse position.
// Surely the hardware is not aware of the calibration process
// and always returns values in a certain fixed range (that might
// vary across different units, but anyway).
adcY1 := binary.LittleEndian.Uint16(Emu.Mem.Ram[0x3FFC80+0x5A:])
scrY1 := Emu.Mem.Ram[0x3FFC80+0x5D]
adcY2 := binary.LittleEndian.Uint16(Emu.Mem.Ram[0x3FFC80+0x60:])
scrY2 := Emu.Mem.Ram[0x3FFC80+0x63]
output = uint16((ff.penY-int(scrY1)+1)*int(adcY2-adcY1)/int(scrY2-scrY1) + int(adcY1))
// log.Infof("coord Y:%d -> Out:%x", ff.penY, output)
} else {
output = 0xFFF
}
case 5: // X coord
if ff.penDown {
adcX1 := binary.LittleEndian.Uint16(Emu.Mem.Ram[0x3FFC80+0x58:])
scrX1 := Emu.Mem.Ram[0x3FFC80+0x5C]
adcX2 := binary.LittleEndian.Uint16(Emu.Mem.Ram[0x3FFC80+0x5E:])
scrX2 := Emu.Mem.Ram[0x3FFC80+0x62]
output = uint16((ff.penX-int(scrX1)+1)*int(adcX2-adcX1)/int(scrX2-scrX1) + int(adcX1))
// log.Infof("coord :%d -> Out:%x", ff.penC, output)
} else {
output = 0x0
}
case 6: // microphone
modTsc.InfoZ("reading microphone").End()
output = 0x0
default:
modTsc.WarnZ("unimplemented channel").String("chan", tscChanNames[adchan]).End()
}
// While sending, there is always one initial 0 bit, so we always need
// two bytes
if !bits8 {
return []byte{
uint8(output >> 5), // 7 bit + leading 0
uint8(output << 3),
}, spi.ReqFinish
} else {
output >>= 4
return []byte{
uint8(output >> 1),
uint8(output << 7),
}, spi.ReqFinish
}
}
func (ff *HwTouchScreen) SpiBegin() {}
func (ff *HwTouchScreen) SpiEnd() {}