OSCR
Open Source Cartridge Reader
Loading...
Searching...
No Matches
PinControl.h
1/********************************************************************
2* Open Source Cartridge Reader *
3********************************************************************/
4#pragma once
5#ifndef PINCONTROL_H_
6#define PINCONTROL_H_
7
8#include "config.h"
9#include "common/Util.h"
10
11#define BANKSET_MAX_BANKS 4
12
13namespace OSCR
14{
15 namespace Hardware
16 {
17 enum PinBank: uint8_t
18 {
19 kPinBankA = 0, // [0] Port A
20 kPinBankC, // [1] Port C
21 kPinBankF, // [2] Port F
22 kPinBankH, // [3] Port H
23 kPinBankK, // [4] Port K
24 kPinBankL, // [5] Port L
25 // Used pin by pin
26 kPinBankG, // [6] Port G
27 kPinBankMax // Max/Number of banks
28 };
29
30 enum class PinDirection : bool
31 {
32 kIn = 0,
33 kOut = 1,
34
35 // Aliases
36 kInput = kIn,
37 kOutput = kOut,
38 };
39
40 enum DataMode: bool
41 {
42 kRead = 0,
43 kWrite = 1,
44
45 // Aliases
46 kR = kRead,
47 kW = kWrite,
48 };
49
50 struct BankSet
51 {
52 PinBank banks[BANKSET_MAX_BANKS];
53 uint8_t width;
54
55 bool addBank(PinBank bank)
56 {
57 if (bank >= PinBank::kPinBankMax) return false;
58
59 for (uint_fast8_t i = 0; i < BANKSET_MAX_BANKS; ++i)
60 {
61 if (banks[i] == bank) return true;
62
63 if (banks[i] == PinBank::kPinBankMax)
64 {
65 banks[i] = bank;
66 width++;
67 return true;
68 }
69 }
70
71 return false;
72 }
73
74 void reset()
75 {
76 for (uint_fast8_t i = 0; i < BANKSET_MAX_BANKS; ++i)
77 {
78 banks[i] = PinBank::kPinBankMax;
79 }
80 width = 0;
81 }
82
83 BankSet()
84 {
85 reset();
86 }
87 };
88
89 extern PinBank getPinBank(uint_fast8_t bank);
90 extern volatile uint8_t& getPinFromBank(PinBank bank);
91 extern volatile uint8_t& getDDRFromBank(PinBank bank);
92 extern volatile uint8_t& getPortFromBank(PinBank bank);
93
94 // Bitwise shifts to get the pin number
95 constexpr uint8_t const kPinConfigPin1 = 0;
96 constexpr uint8_t const kPinConfigPin2 = 1;
97 constexpr uint8_t const kPinConfigPin3 = 2;
98
99 // Mask used to extract the pin number
100 constexpr uint8_t const kPinConfigMaskPin = (1 << kPinConfigPin1) + (1 << kPinConfigPin2) + (1 << kPinConfigPin3);
101
102 // Bitwise shifts for masking the direction flag
103 constexpr uint8_t const kPinConfigDir = 3;
104
105 // Bitwise shifts for masking the pullup flag
106 constexpr uint8_t const kPinConfigPullup = 4;
107
108 // Bitwise shifts to get the bank number
109 constexpr uint8_t const kPinConfigBank1 = 5;
110 constexpr uint8_t const kPinConfigBank2 = 6;
111 constexpr uint8_t const kPinConfigBank3 = 7;
112
113 // Mask used to extract the bank number
114 constexpr uint8_t const kPinConfigMaskBank = (1 << kPinConfigBank1) + (1 << kPinConfigBank2) + (1 << kPinConfigBank3);
115
116 struct PinConfig
117 {
118 PinConfig(uint8_t __pin, PinBank __bank, PinDirection __dir, bool __pullup): config(5)
119 {
120 set(__pin, __bank, __dir, __pullup);
121 }
122
123 void set(uint8_t __pin, PinBank __bank, PinDirection __dir, bool __pullup)
124 {
125 pin(__pin);
126 dir(__dir);
127 bank(__bank);
128 pullup(__pullup);
129 }
130
131 //
132 // Pin Number
133
134 uint8_t pin()
135 {
136 return (config[kPinConfigPin1] << 0) | (config[kPinConfigPin2] << 1) | (config[kPinConfigPin3] << 2);
137 }
138
139 void pin(uint8_t __pin)
140 {
141 config[kPinConfigPin1] = (__pin & 0b001) ? true : false;
142 config[kPinConfigPin2] = (__pin & 0b010) ? true : false;
143 config[kPinConfigPin3] = (__pin & 0b100) ? true : false;
144 }
145
146 //
147 // Bank Number
148
149 PinBank bank()
150 {
151 return static_cast<PinBank>((config[kPinConfigBank1] << 0) | (config[kPinConfigBank2] << 1) | (config[kPinConfigBank3] << 2));
152 }
153
154 void bank(uint8_t __bank)
155 {
156 config[kPinConfigBank1] = (__bank & 0b001) ? true : false;
157 config[kPinConfigBank2] = (__bank & 0b010) ? true : false;
158 config[kPinConfigBank3] = (__bank & 0b100) ? true : false;
159 }
160
161 //
162 // Data Direction
163
164 PinDirection dir()
165 {
166 return static_cast<PinDirection>(static_cast<bool>(config[kPinConfigDir]));
167 }
168
169 void dir(PinDirection __dir)
170 {
171 config[kPinConfigDir] = static_cast<bool>(__dir);
172 }
173
174 //
175 // Pullup
176
177 bool pullup()
178 {
179 return config[kPinConfigPullup];
180 }
181
182 void pullup(bool __pullup)
183 {
184 config[kPinConfigPullup] = !!__pullup;
185 }
186
187 protected:
188 OSCR::Util::bitset config;
189 };
190
191 struct Pin
192 {
193 PinConfig config;
194
195 Pin(PinDirection dir, bool pullup, PinBank bank = PinBank::kPinBankMax, uint8_t number = 0): config(number, bank, dir, pullup)
196 {
197 // ...
198 }
199
200 void reset()
201 {
202 if (config.bank() != PinBank::kPinBankMax)
203 {
204 if (config.pullup() && config.dir() == PinDirection::kIn && config.pin() < 8)
205 {
206 // Disable the pullup first
207 getPortFromBank(config.bank()) &= ~(1 << config.pin());
208 }
209
210 config.bank(PinBank::kPinBankMax);
211 }
212
213 config.pin(0);
214 }
215
216 void init()
217 {
218 switch(config.dir())
219 {
220 case PinDirection::kIn:
221 getDDRFromBank(config.bank()) |= 0x00;
222 getPortFromBank(config.bank()) = (config.pullup() ? 0xFF : 0x00);
223
224 if (config.pullup()) getPortFromBank(config.bank()) = (1 << config.pin());
225 else getPortFromBank(config.bank()) &= ~(1 << config.pin());
226
227 return;
228
229 case PinDirection::kOut:
230 getDDRFromBank(config.bank()) = 0xFF;
231 getPortFromBank(config.bank()) = 0x00;
232
233 return;
234 }
235 }
236
237 void setPin(PinBank newBank, uint8_t newNumber)
238 {
239 reset();
240
241 config.bank(newBank);
242 config.pin(newNumber);
243
244 init();
245 }
246
247 bool read()
248 {
249 if (config.bank() >= PinBank::kPinBankMax) return false; // Reading an invalid pin
250 return (getPinFromBank(config.bank()) << (config.pin() * 8)) > 0;
251 }
252
253 void write(bool state)
254 {
255 if (config.bank() >= PinBank::kPinBankMax) return; // Writing to an invalid pin
256 if (state) getPinFromBank(config.bank()) |= (1 << config.pin());
257 else getPinFromBank(config.bank()) &= ~(1 << config.pin());
258 }
259 };
260
262 {
263 public:
264 void reset(bool resetBanks = false, bool resetAllPins = true)
265 {
266 address->reset();
267 data->reset();
268
269 if (resetAllPins)
270 {
271 clockReadPin->reset();
272 clockWritePin->reset();
273 latchPin->reset();
274
275 pullup = false;
276 clockPeriodWrite = 0;
277 clockPeriodRead = 0;
278 }
279
280 if (resetBanks)
281 {
282 for (uint_fast8_t i = 0; i < PinBank::kPinBankMax; ++i)
283 {
284 setBankDir(getPinBank(i), PinDirection::kIn);
285 }
286 }
287 }
288
289 void usePullup(bool usePullup, bool resetBanks = false)
290 {
291 pullup = usePullup;
292 reset(resetBanks, false);
293 }
294
295 void addAddressBank(PinBank bank)
296 {
297 address->addBank(bank);
298 setBankDir(bank, PinDirection::kOut);
299 }
300
301 template <typename T, typename ... Ts>
302 OSCR::Util::enable_if_t<(OSCR::Util::is_same<T, Ts>::value && ...), void>
303 addAddressBank(T bank, Ts ... banks)
304 {
305 addAddressBank(bank);
306 addAddressBank(banks...);
307 }
308
309 void addDataBank(PinBank bank)
310 {
311 data->addBank(bank);
312 setBankDir(bank, PinDirection::kIn);
313 }
314
315 template <typename T, typename ... Ts>
316 OSCR::Util::enable_if_t<(OSCR::Util::is_same<T, Ts>::value && ...), void>
317 addDataBank(T bank, Ts ... banks)
318 {
319 addDataBank(bank);
320 addDataBank(banks...);
321 }
322
323 void setClockWritePin(PinBank bank, uint8_t pin)
324 {
325 clockWritePin->setPin(bank, pin);
326 }
327
328 void setClockReadPin(PinBank bank, uint8_t pin)
329 {
330 clockReadPin->setPin(bank, pin);
331 }
332
333 void setLatchPin(PinBank bank, uint8_t pin)
334 {
335 latchPin->setPin(bank, pin);
336 useLatchPin = true;
337 }
338
339 void waitLatch()
340 {
341 if (!useLatchPin) return;
342
343 while(!latchPin->read()) NOP;
344 }
345
346 void clockRead()
347 {
348 if (clockPeriodRead > 0)
349 {
350 clockReadPin->write(true);
351 delayMicroseconds(clockPeriodRead);
352 clockReadPin->write(false);
353 }
354 }
355
356 void clockWrite()
357 {
358 if (clockPeriodWrite > 0)
359 {
360 clockReadPin->write(true);
361 delayMicroseconds(clockPeriodWrite);
362 clockReadPin->write(false);
363 }
364 }
365
366 template <typename T>
367 void setAddress(T newAddress)
368 {
369 uint8_t const size = sizeof(T);
370
371 for (uint8_t i = 0; i < size; i++)
372 {
373 getPort(address->banks[i]) = (newAddress >> (i * 8)) & 0xFF;
374 }
375 }
376
377 template <typename T>
378 T readData()
379 {
380 uint8_t const size = sizeof(T);
381 T out = 0;
382
383 clockRead();
384 waitLatch();
385
386 for (uint8_t i = 0; i < size; i++)
387 {
388 out |= getPin(data->banks[i]) << (i * 8);
389 }
390
391 return out;
392 }
393
394 template <typename TD, typename TA>
395 TD readAddress(TA newAddress)
396 {
397 setAddress(newAddress);
398 return readData<TD>();
399 }
400
401 template <typename TD, typename TA>
402 void setPosition(TA newAddress)
403 {
404 setAddress(newAddress);
405 lastAddress = newAddress;
406 }
407
408 template <typename TD>
409 TD readNext()
410 {
411 TD read = readData<TD>();
412 size_t nextAddress = (data->width * 8) + lastAddress;
413 setAddress(nextAddress);
414 lastAddress = nextAddress;
415 return read;
416 }
417
418 template <typename TA>
419 TA getPosition()
420 {
421 return lastAddress;
422 }
423
424 template <typename T>
425 void writeData(T outputData)
426 {
427 uint8_t const size = sizeof(T);
428
429 for (uint8_t i = 0; i < size; i++)
430 {
431 getPort(data->banks[i]) = (outputData >> (i * 8)) & 0xFF;
432 }
433
434 clockWrite();
435 }
436
437 uint8_t readBank(PinBank bank)
438 {
439 uint8_t out = 0;
440 out |= getPin(bank);
441 return out;
442 }
443
444 volatile uint8_t& getDDR(PinBank bank)
445 {
446 switch(bank)
447 {
448 case PinBank::kPinBankA: return DDRA;
449 case PinBank::kPinBankC: return DDRC;
450 case PinBank::kPinBankF: return DDRF;
451 case PinBank::kPinBankH: return DDRH;
452 case PinBank::kPinBankK: return DDRK;
453 case PinBank::kPinBankL: return DDRL;
454 case PinBank::kPinBankG: return DDRG;
455 case PinBank::kPinBankMax: break;
456 }
457 exit(1);
458 }
459
460 volatile uint8_t& getPort(PinBank bank)
461 {
462 switch(bank)
463 {
464 case PinBank::kPinBankA: return PORTA;
465 case PinBank::kPinBankC: return PORTC;
466 case PinBank::kPinBankF: return PORTF;
467 case PinBank::kPinBankH: return PORTH;
468 case PinBank::kPinBankK: return PORTK;
469 case PinBank::kPinBankL: return PORTL;
470 case PinBank::kPinBankG: return PORTG;
471 case PinBank::kPinBankMax: break;
472 }
473 exit(1);
474 }
475
476 volatile uint8_t& getPin(PinBank bank)
477 {
478 switch(bank)
479 {
480 case PinBank::kPinBankA: return PINA;
481 case PinBank::kPinBankC: return PINC;
482 case PinBank::kPinBankF: return PINF;
483 case PinBank::kPinBankH: return PINH;
484 case PinBank::kPinBankK: return PINK;
485 case PinBank::kPinBankL: return PINL;
486 case PinBank::kPinBankG: return PING;
487 case PinBank::kPinBankMax: break;
488 }
489 exit(1);
490 }
491
492 void setBankDir(PinBank bank, PinDirection dir)
493 {
494 switch(dir)
495 {
496 case PinDirection::kIn:
497 getDDR(bank) = 0x00;
498 getPort(bank) = (pullup ? 0xFF : 0x00);
499 return;
500 case PinDirection::kOut:
501 getDDR(bank) = 0xFF;
502 getPort(bank) = 0x00;
503 return;
504 }
505 }
506
507 void setMode(DataMode mode)
508 {
509 PinDirection pinDir = ((mode == DataMode::kWrite) ? PinDirection::kOut : PinDirection::kIn);
510
511 for (uint8_t i = 0; i < data->width && data->banks[i] != kPinBankMax; i++)
512 {
513 setBankDir(data->banks[i], pinDir);
514 }
515 }
516
517 protected:
518 BankSet * address = new BankSet;
519 BankSet * data = new BankSet;
520
521 Pin * latchPin = new Pin(PinDirection::kIn, false);
522 Pin * clockReadPin = new Pin(PinDirection::kOut, false);
523 Pin * clockWritePin = new Pin(PinDirection::kOut, false);
524
525 bool useLatchPin = false;
526 uint16_t clockPeriodRead = 0;
527 uint16_t clockPeriodWrite = 0;
528
529 bool pullup = false;
530 size_t lastAddress = 0;
531 };
532 }
533}
534
535#endif /* PINCONTROL_H_ */
Definition PinControl.h:262
Definition Util.h:524
Main program.
Definition Storage.h:13
Definition PinControl.h:51
Definition PinControl.h:117
Definition PinControl.h:192