openMSX
SensorKid.cc
Go to the documentation of this file.
1 #include "SensorKid.hh"
2 #include "CliComm.hh"
3 #include "CommandController.hh"
4 #include "MSXException.hh"
5 #include "StringSetting.hh"
6 #include "serialize.hh"
7 
8 namespace 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 aquire analog data. "
18  "Input: port number (0-3). "
19  "Output: the value for that port (0-255).")
20 {
22 }
23 
24 void 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 
31 void 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 
60 byte 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  result = 0;
71  } else if ((mb4052_count < 10) && (mb4052_count > 1)) {
72  result = (mb4052_ana >> (mb4052_count - 2)) & 1;
73  } else {
74  result = 1;
75  }
76  return 0xFE | result; // other bits read as '1'.
77  } else {
78  // port 1
79  // returns two of the previously written bits (shuffled in different positions)
80  return 0xFC | ((prev >> 5) & 0x02) | ((prev >> 7) & 0x01);
81  }
82 }
83 
84 byte SensorKid::getAnalog(byte chi)
85 {
86  // bits 2 and 3 in the 'port-0' byte select between 4 possible channels
87  // for some reason bits 2 and 3 are swapped and then shifted down
88  byte port = ((chi >> 1) & 2) | ((chi >> 3) & 1);
89 
90  // Execute Tcl callback
91  // input: the port number (0-3)
92  // output: the analog value for that port (0-255)
93  // On the real cartrige
94  // port 0 is connected to a light sensor HIKARI
95  // port 1 is connector to a temperature sensor ONDO
96  // port 2 is connected to a microphone OTO
97  // port 3 is not connected, always return 255
98  int result = 255;
99  try {
100  auto obj = acquireCallback.execute(port);
101  if (obj != TclObject()) {
102  result = obj.getInt(getCommandController().getInterpreter());
103  if ((result < 0) || (result > 255)) {
104  throw MSXException("outside range 0..255");
105  }
106  }
107  } catch (MSXException& e) {
109  "Wrong result for callback function \"" +
110  acquireCallback.getSetting().getFullName() +
111  "\": " + e.getMessage());
112  }
113  return result;
114 }
115 
116 void SensorKid::putPort(byte data, byte diff)
117 {
118  // When the upper 2 bits (bit 6 and 7) change we send a message.
119  // I assume the cartridge also has two digital output pins?
120  if (diff & 0x80) {
121  //std::cout << "Status Port 0: " << int((data & 0x80) == 0) << std::endl;
122  portStatusCallback.execute(0, (data & 0x80) == 0);
123  }
124  if (diff & 0x40) {
125  //std::cout << "Status Port 1: " << int((data & 0x40) == 0) << std::endl;
126  portStatusCallback.execute(1, (data & 0x40) == 0);
127  }
128 }
129 
130 template<typename Archive>
131 void SensorKid::serialize(Archive& ar, unsigned /*version*/)
132 {
133  ar.template serializeBase<MSXDevice>(*this);
134  ar.serialize("prev", prev);
135  ar.serialize("mb4052_ana", mb4052_ana);
136  ar.serialize("mb4052_count", mb4052_count);
137 }
139 REGISTER_MSXDEVICE(SensorKid, "SensorKid");
140 
141 } // namespace openmsx
StringSetting & getSetting() const
Definition: TclCallback.hh:31
CliComm & getCliComm() const
Definition: MSXDevice.cc:151
const string_ref getFullName() const
Definition: Setting.hh:33
void printWarning(string_ref message)
Definition: CliComm.cc:20
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
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
TclObject execute()
Definition: TclCallback.cc:40
SensorKid(const DeviceConfig &config)
Definition: SensorKid.cc:10
void serialize(Archive &ar, unsigned version)
Definition: SensorKid.cc:131
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
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
const std::string & getMessage() const
Definition: MSXException.hh:13
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:135
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
CommandController & getCommandController() const
Definition: MSXDevice.cc:159
int getInt(Interpreter &interp) const
Definition: TclObject.cc:109
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
uint8_t * data()
const string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:407
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SensorKid.cc:24