1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 //
7 // This file is part of Nestopia.
8 //
9 // Nestopia is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Nestopia is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Nestopia; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 ////////////////////////////////////////////////////////////////////////////////////////
24 
25 #include <cstring>
26 #include "NstInpDevice.hpp"
27 #include "NstInpBarcodeWorld.hpp"
28 
29 namespace Nes
30 {
31 	namespace Core
32 	{
33 		namespace Input
34 		{
35 			#ifdef NST_MSVC_OPTIMIZE
36 			#pragma optimize("s", on)
37 			#endif
38 
BarcodeWorld(const Cpu & cpu)39 			BarcodeWorld::BarcodeWorld(const Cpu& cpu)
40 			: Device(cpu,Api::Input::BARCODEWORLD)
41 			{
42 				BarcodeWorld::Reset();
43 			}
44 
Reset()45 			void BarcodeWorld::Reset()
46 			{
47 				reader.Reset();
48 			}
49 
LoadState(State::Loader & loader,const dword id)50 			void BarcodeWorld::LoadState(State::Loader& loader,const dword id)
51 			{
52 				reader.LoadState( loader, id );
53 			}
54 
SaveState(State::Saver & saver,const byte id) const55 			void BarcodeWorld::SaveState(State::Saver& saver,const byte id) const
56 			{
57 				reader.SaveState( saver, id );
58 			}
59 
Reset()60 			void BarcodeWorld::Reader::Reset()
61 			{
62 				stream = data;
63 				std::memset( data, END, MAX_DATA_LENGTH );
64 			}
65 
IsDigitsSupported(uint count) const66 			bool BarcodeWorld::Reader::IsDigitsSupported(uint count) const
67 			{
68 				return count == NUM_DIGITS;
69 			}
70 
IsTransferring() const71 			bool BarcodeWorld::Reader::IsTransferring() const
72 			{
73 				return *stream != END;
74 			}
75 
LoadState(State::Loader & loader,const dword id)76 			void BarcodeWorld::Reader::LoadState(State::Loader& loader,const dword id)
77 			{
78 				if (id == AsciiId<'B','W'>::V)
79 				{
80 					Reset();
81 
82 					while (const dword chunk = loader.Begin())
83 					{
84 						switch (chunk)
85 						{
86 						case AsciiId<'P','T','R'>::V:
87 
88 							stream = data + (loader.Read8() & (MAX_DATA_LENGTH-1));
89 							break;
90 
91 						case AsciiId<'D','A','T'>::V:
92 
93 							loader.Uncompress( data );
94 							data[MAX_DATA_LENGTH-1] = END;
95 							break;
96 						}
97 
98 						loader.End();
99 					}
100 				}
101 			}
102 
SaveState(State::Saver & saver,const byte id) const103 			void BarcodeWorld::Reader::SaveState(State::Saver& saver,const byte id) const
104 			{
105 				saver.Begin( AsciiId<'B','W'>::R(0,0,id) );
106 
107 				if (Reader::IsTransferring())
108 				{
109 					saver.Begin( AsciiId<'P','T','R'>::V ).Write8( stream - data ).End();
110 					saver.Begin( AsciiId<'D','A','T'>::V ).Compress( data ).End();
111 				}
112 
113 				saver.End();
114 			}
115 
Transfer(cstring const string,const uint length)116 			bool BarcodeWorld::Reader::Transfer(cstring const string,const uint length)
117 			{
118 				NST_COMPILE_ASSERT( MAX_DATA_LENGTH >= 191 );
119 
120 				Reset();
121 
122 				if (!string || length != NUM_DIGITS)
123 					return false;
124 
125 				byte code[NUM_DIGITS+7];
126 
127 				for (uint i=0; i < NUM_DIGITS; ++i)
128 				{
129 					const int c = string[i];
130 
131 					if (c >= '0' && c <= '9')
132 						code[i] = c - '0' + Ascii<'0'>::V;
133 					else
134 						return false;
135 				}
136 
137 				code[NUM_DIGITS+0] = Ascii<'S'>::V;
138 				code[NUM_DIGITS+1] = Ascii<'U'>::V;
139 				code[NUM_DIGITS+2] = Ascii<'N'>::V;
140 				code[NUM_DIGITS+3] = Ascii<'S'>::V;
141 				code[NUM_DIGITS+4] = Ascii<'O'>::V;
142 				code[NUM_DIGITS+5] = Ascii<'F'>::V;
143 				code[NUM_DIGITS+6] = Ascii<'T'>::V;
144 
145 				byte* NST_RESTRICT output = data;
146 
147 				*output++ = 0x04;
148 
149 				for (uint i=0; i < NUM_DIGITS+7; ++i)
150 				{
151 					*output++ = 0x04;
152 
153 					for (uint j=0x01, c=code[i]; j != 0x100; j <<= 1)
154 						*output++ = (c & j) ? 0x00 : 0x04;
155 
156 					*output++ = 0x00;
157 				}
158 
159 				return true;
160 			}
161 
162 			#ifdef NST_MSVC_OPTIMIZE
163 			#pragma optimize("", on)
164 			#endif
165 
Read()166 			uint BarcodeWorld::Reader::Read()
167 			{
168 				if (Reader::IsTransferring())
169 				{
170 					uint next = *stream;
171 					stream += (next != END);
172 					return next;
173 				}
174 				else
175 				{
176 					return 0;
177 				}
178 			}
179 
Peek(uint port)180 			uint BarcodeWorld::Peek(uint port)
181 			{
182 				return port == 1 ? reader.Read() : 0;
183 			}
184 		}
185 	}
186 }
187