openMSX
SensorKid.cc
Go to the documentation of this file.
1#include "SensorKid.hh"
2#include "CliComm.hh"
4#include "MSXException.hh"
5#include "StringSetting.hh"
6#include "serialize.hh"
7
8namespace openmsx {
9
11 : MSXDevice(config)
12 , portStatusCallback(getCommandController(),
13 getName() + "_port_status_callback",
14 "Tcl proc to call when an Sensor Kid port status is changed")
15 , acquireCallback(getCommandController(),
16 getName() + "_acquire_callback",
17 "Tcl proc called to acquire analog data. "
18 "Input: port number (0-3). "
19 "Output: the value for that port (0-255).")
20{
22}
23
24void SensorKid::reset(EmuTime::param /*time*/)
25{
26 prev = 255; // previously written value to port 0
27 mb4052_ana = 0; // the analog value that's currently being read
28 mb4052_count = 0; // keep track of which bit we're reading
29}
30
31void SensorKid::writeIO(word port, byte value, EmuTime::param /*time*/)
32{
33 if ((port & 1) != 0) return;
34
35 byte diff = prev ^ value;
36 prev = value;
37
38 if (diff & 0xC0) {
39 // upper two bits changed
40 putPort(value, diff);
41 }
42
43 if (diff & 0x10) {
44 // CS bit changed
45 if (value & 0x10) {
46 // 0 -> 1 : start of A/D convert
47 mb4052_ana = getAnalog(value & 0x0C);
48 mb4052_count = 12;
49 } else {
50 // 1 -> 0 : end of A/D convert
51 mb4052_count = 0;
52 }
53 }
54 if ((diff & 0x01) && (value & 0x01)) {
55 // CLK changed 0 -> 1
56 if (mb4052_count > 0) --mb4052_count;
57 }
58}
59
60byte SensorKid::readIO(word port, EmuTime::param /* time */)
61{
62 if ((port & 1) == 0) {
63 // port 0
64 // mb4052_count can take on values [0, 12]
65 // for 12,11,1,0 we return 1
66 // for 10 we return 0
67 // for 9..2 we return one of the analog bits
68 byte result = [&] {
69 if (mb4052_count == 10) {
70 return 0;
71 } else if ((mb4052_count < 10) && (mb4052_count > 1)) {
72 return (mb4052_ana >> (mb4052_count - 2)) & 1;
73 } else {
74 return 1;
75 }
76 }();
77 return 0xFE | result; // other bits read as '1'.
78 } else {
79 // port 1
80 // returns two of the previously written bits (shuffled in different positions)
81 return 0xFC | ((prev >> 5) & 0x02) | ((prev >> 7) & 0x01);
82 }
83}
84
85byte SensorKid::getAnalog(byte chi)
86{
87 // bits 2 and 3 in the 'port-0' byte select between 4 possible channels
88 // for some reason bits 2 and 3 are swapped and then shifted down
89 byte port = ((chi >> 1) & 2) | ((chi >> 3) & 1);
90
91 // Execute Tcl callback
92 // input: the port number (0-3)
93 // output: the analog value for that port (0-255)
94 // On the real cartridge
95 // port 0 is connected to a light sensor HIKARI
96 // port 1 is connector to a temperature sensor ONDO
97 // port 2 is connected to a microphone OTO
98 // port 3 is not connected, always return 255
99 int result = 255;
100 try {
101 auto obj = acquireCallback.execute(port);
102 if (obj != TclObject()) {
104 if ((result < 0) || (result > 255)) {
105 throw MSXException("outside range 0..255");
106 }
107 }
108 } catch (MSXException& e) {
110 "Wrong result for callback function \"",
111 acquireCallback.getSetting().getFullName(),
112 "\": ", e.getMessage());
113 }
114 return result;
115}
116
117void SensorKid::putPort(byte data, byte diff)
118{
119 // When the upper 2 bits (bit 6 and 7) change we send a message.
120 // I assume the cartridge also has two digital output pins?
121 if (diff & 0x80) {
122 //std::cout << "Status Port 0: " << int((data & 0x80) == 0) << '\n';
123 portStatusCallback.execute(0, (data & 0x80) == 0);
124 }
125 if (diff & 0x40) {
126 //std::cout << "Status Port 1: " << int((data & 0x40) == 0) << '\n';
127 portStatusCallback.execute(1, (data & 0x40) == 0);
128 }
129}
130
131template<typename Archive>
132void SensorKid::serialize(Archive& ar, unsigned /*version*/)
133{
134 ar.template serializeBase<MSXDevice>(*this);
135 ar.serialize("prev", prev,
136 "mb4052_ana", mb4052_ana,
137 "mb4052_count", mb4052_count);
138}
141
142} // namespace openmsx
std::string_view getFullName() const
Definition: Setting.hh:37
void printWarning(std::string_view message)
Definition: CliComm.cc:10
virtual Interpreter & getInterpreter()=0
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:34
CliComm & getCliComm() const
Definition: MSXDevice.cc:141
CommandController & getCommandController() const
Definition: MSXDevice.cc:149
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:125
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: SensorKid.cc:60
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SensorKid.cc:24
void serialize(Archive &ar, unsigned version)
Definition: SensorKid.cc:132
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: SensorKid.cc:31
SensorKid(const DeviceConfig &config)
Definition: SensorKid.cc:10
TclObject execute()
Definition: TclCallback.cc:35
StringSetting & getSetting() const
Definition: TclCallback.hh:31
int getInt(Interpreter &interp) const
Definition: TclObject.cc:73
constexpr double e
Definition: Math.hh:20
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:730
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021