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