1 #include <stdint.h>
2 #include <stdbool.h>
3
4 #include "emulator.h"
5 #include "portability.h"
6 #include "dbvz.h"
7
8
9 bool ads7846PenIrqEnabled;
10
11 static const uint16_t ads7846DockResistorValues[EMU_PORT_END] = {0xFFF/*none*/, 0x1EB/*USB cradle*/, 0x000/*serial cradle, unknown*/, 0x000/*USB peripheral, unknown*/, 0x000/*serial peripheral, unknown*/};
12
13 static uint8_t ads7846BitsToNextControl;
14 static uint8_t ads7846ControlByte;
15 static uint16_t ads7846OutputValue;
16 static bool ads7846ChipSelect;
17
18
ads7846RangeMap(float oldMin,float oldMax,float value,float newMin,float newMax)19 static float ads7846RangeMap(float oldMin, float oldMax, float value, float newMin, float newMax){
20 return (value - oldMin) / (oldMax - oldMin) * (newMax - newMin) + newMin;
21 }
22
ads7846GetAdcBit(void)23 static bool ads7846GetAdcBit(void){
24 bool bit = !!(ads7846OutputValue & 0x8000);
25 ads7846OutputValue <<= 1;
26 return bit;
27 }
28
ads7846Reset(void)29 void ads7846Reset(void){
30 ads7846BitsToNextControl = 0;
31 ads7846ControlByte = 0x00;
32 ads7846PenIrqEnabled = true;
33 ads7846OutputValue = 0x0000;
34 ads7846ChipSelect = true;
35 #if !defined(EMU_NO_SAFETY)
36 m5XXRefreshTouchState();
37 #endif
38 }
39
ads7846StateSize(void)40 uint32_t ads7846StateSize(void){
41 uint32_t size = 0;
42
43 size += sizeof(uint8_t) * 4;
44 size += sizeof(uint16_t);
45
46 return size;
47 }
48
ads7846SaveState(uint8_t * data)49 void ads7846SaveState(uint8_t* data){
50 uint32_t offset = 0;
51
52 writeStateValue8(data + offset, ads7846PenIrqEnabled);
53 offset += sizeof(uint8_t);
54 writeStateValue8(data + offset, ads7846BitsToNextControl);
55 offset += sizeof(uint8_t);
56 writeStateValue8(data + offset, ads7846ControlByte);
57 offset += sizeof(uint8_t);
58 writeStateValue16(data + offset, ads7846OutputValue);
59 offset += sizeof(uint16_t);
60 writeStateValue8(data + offset, ads7846ChipSelect);
61 offset += sizeof(uint8_t);
62 }
63
ads7846LoadState(uint8_t * data)64 void ads7846LoadState(uint8_t* data){
65 uint32_t offset = 0;
66
67 ads7846PenIrqEnabled = readStateValue8(data + offset);
68 offset += sizeof(uint8_t);
69 ads7846BitsToNextControl = readStateValue8(data + offset);
70 offset += sizeof(uint8_t);
71 ads7846ControlByte = readStateValue8(data + offset);
72 offset += sizeof(uint8_t);
73 ads7846OutputValue = readStateValue16(data + offset);
74 offset += sizeof(uint16_t);
75 ads7846ChipSelect = readStateValue8(data + offset);
76 offset += sizeof(uint8_t);
77 }
78
ads7846SetChipSelect(bool value)79 void ads7846SetChipSelect(bool value){
80 //reset the chip when disabled, chip is active when chip select is low
81 if(value && !ads7846ChipSelect){
82 ads7846BitsToNextControl = 0;
83 ads7846ControlByte = 0x00;
84 ads7846PenIrqEnabled = true;
85 ads7846OutputValue = 0x0000;
86 #if !defined(EMU_NO_SAFETY)
87 m5XXRefreshTouchState();
88 #endif
89 }
90 ads7846ChipSelect = value;
91 }
92
ads7846ExchangeBit(bool bitIn)93 bool ads7846ExchangeBit(bool bitIn){
94 //chip data out is high when off
95 if(ads7846ChipSelect)
96 return true;
97
98 if(ads7846BitsToNextControl > 0)
99 ads7846BitsToNextControl--;
100
101 if(ads7846BitsToNextControl == 0){
102 //check for control bit
103 //a new control byte can be sent while receiving data
104 //this is valid behavior as long as the start of the last control byte was 16 or more clock cycles ago
105 if(bitIn){
106 ads7846ControlByte = 0x01;
107 ads7846BitsToNextControl = 15;
108 }
109 return ads7846GetAdcBit();
110 }
111 else if(ads7846BitsToNextControl >= 8){
112 ads7846ControlByte <<= 1;
113 ads7846ControlByte |= bitIn;
114 }
115 else if(ads7846BitsToNextControl == 6){
116 //control byte and busy cycle finished, get output value
117 bool bitMode = !!(ads7846ControlByte & 0x08);
118 bool differentialMode = !(ads7846ControlByte & 0x04);
119 uint8_t channel = ads7846ControlByte >> 4 & 0x07;
120 uint8_t powerSave = ads7846ControlByte & 0x03;
121
122 //debugLog("Accessed ADS7846 Ch:%d, %d bits, %s Mode, Power Save:%d, PC:0x%08X.\n", channel, bitMode ? 8 : 12, differentialMode ? "Diff" : "Normal", ads7846ControlByte & 0x03, flx68000GetPc());
123
124 //reference disabled currently isnt emulated, I dont know what the proper behavior for that would be
125
126 #if !defined(EMU_NO_SAFETY)
127 //trigger fake IRQs
128 ads7846OverridePenState(!(channel == 1 || channel == 3 || channel == 4 || channel == 5));
129 #endif
130
131 if(powerSave != 2){
132 //ADC enabled, get analog value
133 if(differentialMode){
134 switch(channel){
135 case 0:
136 //temperature 0, wrong mode
137 ads7846OutputValue = 0xFFF;
138 break;
139
140 case 1:
141 //touchscreen y
142 if(palmInput.touchscreenTouched)
143 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenY, 0x0EE, 0xEE4);
144 else
145 ads7846OutputValue = 0xFEF;//y is almost fully on when dorment
146 break;
147
148 case 2:
149 //battery, wrong mode
150 ads7846OutputValue = 0xFFF;
151 break;
152
153 case 3:
154 //touchscreen x relative to y
155 if(palmInput.touchscreenTouched)
156 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenX, 0x093, 0x600) + ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenY, 0x000, 0x280);
157 else
158 ads7846OutputValue = 0x000;
159 break;
160
161 case 4:
162 //touchscreen y relative to x
163 if(palmInput.touchscreenTouched)
164 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenY, 0x9AF, 0xF3F) + ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenX, 0x000, 0x150);
165 else
166 ads7846OutputValue = 0xFFF;
167 break;
168
169 case 5:
170 //touchscreen x
171 if(palmInput.touchscreenTouched)
172 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenX, 0x0FD, 0xF47);
173 else
174 ads7846OutputValue = 0x309;
175 break;
176
177 case 6:
178 //dock, wrong mode
179 ads7846OutputValue = 0xFFF;
180 break;
181
182 case 7:
183 //temperature 1, wrong mode, usualy 0xDFF/0xBFF, sometimes 0xFFF
184 ads7846OutputValue = 0xDFF;
185 break;
186 }
187 }
188 else{
189 if(!palmInput.touchscreenTouched){
190 switch(channel){
191 case 0:
192 //temperature 0, room temperature
193 ads7846OutputValue = 0x3E2;
194 break;
195
196 case 1:
197 //touchscreen y
198 if(palmInput.touchscreenTouched)
199 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenY, 0x0EE, 0xEE4);
200 else
201 ads7846OutputValue = 0xFFF;//y is almost fully on when dorment
202 break;
203
204 case 2:
205 //battery
206 //ads7846OutputValue = 0x600;//5%
207 //ads7846OutputValue = 0x61C;//30%
208 //ads7846OutputValue = 0x63C;//40%
209 //ads7846OutputValue = 0x65C;//60%
210 //ads7846OutputValue = 0x67C;//80%
211 //ads7846OutputValue = 0x68C;//100%
212 //ads7846OutputValue = 0x69C;//100%
213 ads7846OutputValue = ads7846RangeMap(0, 100, palmMisc.batteryLevel, 0x5FD, 0x68C);
214 break;
215
216 case 3:
217 //touchscreen x relative to y
218 if(palmInput.touchscreenTouched)
219 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenX, 0x093, 0x600) + ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenY, 0x000, 0x280);
220 else
221 ads7846OutputValue = 0x000;
222 break;
223
224 case 4:
225 //touchscreen y relative to x
226 if(palmInput.touchscreenTouched)
227 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenY, 0x9AF, 0xF3F) + ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenX, 0x000, 0x150);
228 else
229 ads7846OutputValue = 0xFFF;
230 break;
231
232 case 5:
233 //touchscreen x
234 if(palmInput.touchscreenTouched)
235 ads7846OutputValue = ads7846RangeMap(0.0, 1.0, 1.0 - palmInput.touchscreenX, 0x0FD, 0xF47);
236 else
237 ads7846OutputValue = 0x3FB;
238 break;
239
240 case 6:
241 //dock
242 ads7846OutputValue = ads7846DockResistorValues[palmMisc.dataPort];
243 break;
244
245 case 7:
246 //temperature 1, room temperature
247 ads7846OutputValue = 0x4A1;
248 break;
249 }
250 }
251 else{
252 //crosses lines with REF+(unverified)
253 ads7846OutputValue = 0xF80;
254 }
255 }
256 }
257 else{
258 //ADC disabled, return invalid data
259 if((channel == 3 || channel == 5) && !palmInput.touchscreenTouched)
260 ads7846OutputValue = 0x000;
261 else
262 ads7846OutputValue = 0xFFF;
263 }
264
265 //move to output position
266 ads7846OutputValue <<= 4;
267
268 //if 8 bit conversion, clear extra bits and shorten conversion by 4 bits
269 if(bitMode){
270 ads7846OutputValue &= 0xFF00;
271 ads7846BitsToNextControl -= 4;
272 }
273
274 ads7846PenIrqEnabled = !(powerSave & 0x01);
275 #if !defined(EMU_NO_SAFETY)
276 m5XXRefreshTouchState();
277 #endif
278 }
279
280 return ads7846GetAdcBit();
281 }
282