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