tag:blogger.com,1999:blog-29532833890873596312024-03-13T01:21:51.978-07:00Forty-twoYou know, I've always felt that there was something fundamentally wrong with the Universe...qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-2953283389087359631.post-42807447802850828532023-02-25T22:23:00.004-08:002023-02-26T17:26:36.541-08:00How to tune a filament profile in Cura<p></p><h1 style="text-align: left;">Overview</h1>Getting started with Cura, one problem you may run into fairly quickly is that when you want to switch between different types or brands of filaments, there isn't a good way to save the settings associated with that filament. By default, Cura has the ability to save "quality profiles" but those end up becoming cumbersome. Also, Cura <i>does</i> have the ability to choose between filaments, but doing so only changes a very small number of parameters, like print temperature, bed temperature, fan speed, and retraction. There are a lot more settings that are associated with the current filament, and it would be a lot easier if you could save them so that switching filaments automatically applied the relevant values to your slicing settings. Thankfully, you can! But that leads to a new problem. How do you determine the right values for each parameter? In this post, I will lay out a simple procedure that you can follow to tune in a new filament profile so you can bring up all of those tuned settings at any time with just a few clicks. This whole process will take an hour or two, maybe a bit more the first couple of times, but you only need to do it once per filament type, saving you a ton of time in the future.<div><br /><h1 style="text-align: left;">Cura settings layers</h1><div>The good news is that Cura is already designed in a way that is meant to allow for this kind of functionality. Cura stores all of its settings in different layers. These layers are applied on top of each other one at a time. If a setting is left blank in a given layer, the value from the previous layer is used. If the setting is not left blank, the value in the top-most layer overrides the values in the layers below. These layers include (from bottom to top):<br /><br />Printer > Extruder > Material > Quality > Overrides<br /><br />There are likely others as well, but these are the ones you're most likely to interact with. Each layer only includes a very small number of the settings available in Cura. For instance, the Printer layer includes things like the build volume and motion limits, the Material layer includes temperatures, cooling, and retraction, Quality includes (by default) things like layer height, wall thickness, and print speed, and the Overrides layer is everything that you manually type into the settings window. The reason for this is that something like the build volume shouldn't change just because you change to a different filament, or things like the temperature shouldn't change just because you want to print at a higher quality. So, this system is actually really well done, but the problem is that for most of the layers, there's no way to assign which settings go on which layer within the GUI. So, you're left with just the settings that Ultimaker decided to put in each layer.</div><div><br /></div><p></p><h2 style="text-align: left;">Install plugins</h2><div>Luckily, there are a few plugins available for Cura to allow us to do what we want. Honestly, this should be included in Cura directly, but for now that isn't the case, so we'll need to install a couple of plugins. First, and most importantly, is the <a href="https://marketplace.ultimaker.com/app/cura/plugins/fieldofview/MaterialSettingsPlugin" target="_blank">Material Settings</a> plugin. Second is the <a href="https://marketplace.ultimaker.com/app/cura/plugins/fieldofview/LinearAdvanceSettingPlugin" target="_blank">Linear Advance Settings</a> plugin. In order for the Linear Advance Settings plugin to be effective, you will need Linear Advance to be supported by your printer's controller and enabled in your printer's firmware. If the controller doesn't support Linear Advance, there isn't much you can do about it other than upgrade the controller board. If your controller does support it, but the firmware doesn't, you will need to install a custom firmware build in order to enable it. Building Marlin firmware from source is outside the scope of this guide, but if you want to look into it more, there's a good guide <a href="https://all3dp.com/2/linear-advance-cura-marlin/" target="_blank">here</a>. If you can't enable Linear Advance, you can still follow the rest of this guide, just skip anything that references Linear Advance.</div><div><br /></div><h2 style="text-align: left;">Configure Material Settings Plugin</h2><div>Now that the Materials Settings plugin is installed, you can assign any of Cura's settings to the Material layer. Under the Prepare view in Cura, click on the Extruder drop-down, then on the Material drop-down and down at the bottom select Manage Materials. Or, you can just use the keyboard shortcut Ctrl+K. In this dialog, you can create a new material if it doesn't already exist. One weird caveat in doing so is that the "Material Type" field should exactly match one that already exists. So, things like PLA Pro or Silk PLA should both have a material type of just "PLA", ASA should have a material type of "ABS", and TPU should have a material type of "TPU 95A" regardless of what its actual shore hardness is. This is just a weird quirk of Cura, and it will complain if you use a material type that it doesn't already know. The Display Name field can be anything you want, and should be where you specify materials like Silk PLA, ASA, etc. Once you've set up the basic parameters, click on the Print Settings tab and then click the Select Settings button at the bottom. This will open a new dialog that lists every setting that Cura supports. This can be rather intimidating at first glance, so here are the settings I recommend, and you can come back here and enable any other settings that you want at a later time. You don't actually have to calibrate all of these settings for every material, it's just good to have them available if you do. Some of these don't really belong in the Material layer, but there isn't a similar plugin for the Printer or Extruder layers, and the Quality layer doesn't allow overwriting any of the default profiles, so settings marked with an '*' are things that I basically just always set to a default value.<br /><br /><b>Quality</b></div><div>---</div><div>None<br /><br /></div><div><b>Walls</b></div><div>---</div><div>- Outer Wall Wipe Distance</div><div><br /></div><div>Top/Bottom</div><div>---</div><div>- Top Surface Skin Layers</div><div>--Top Surface Skin Line Width</div><div>-- Monotonic Top Surface Order * (always enable this)</div><div><br /></div><div>-Monotonic Top/Bottom Order * (always enable this)</div><div><br /></div><div>- Monotonic Ironing Order * (always enable this)</div><div><br /></div><div><b>Infill</b></div><div>---</div><div>--Skin Edge Support Layers</div><div><br /></div><div><b>Material</b></div><div>---</div><div>-Default Printing Temperature</div><div><br /></div><div>- Printing Temperature Initial Layer</div><div><br /></div><div>- Initial Printing Temperature</div><div><br /></div><div>- Build Plate Temperature</div><div><br /></div><div>- Build Plate Temperature Initial Layer</div><div><br /></div><div>- Flow</div><div>-- Wall Flow</div><div>-- Inner Wall(s) Flow</div><div><br /></div><div>- Top/Bottom Flow</div><div><br /></div><div>- Top Surface Skin Flow</div><div><br /></div><div>- Initial Layer Flow</div><div><br /></div><div>- Standby Temperature</div><div><br /></div><div>- Linear Advance Factor</div><div><br /></div><div><b>Speed</b></div><div>---</div><div>- Print Speed</div><div><br /></div><div>- Enable Acceleration Control * (always enable this)</div><div><br /></div><div>- Print Acceleration</div><div><br /></div><div>- Initial Layer Acceleration</div><div>-- Initial Layer Travel Acceleration</div><div><br /></div><div>- Enable Jerk Control * (always enable this)</div><div><br /></div><div>- Print Jerk</div><div><br /></div><div>- Initial Layer Jerk</div><div><br /></div><div><b>Travel</b></div><div>---</div><div>- Retraction Distance</div><div><br /></div><div>- Retraction Speed</div><div><br /></div><div>- Retraction Extra Prime Amount</div><div><br /></div><div>- Minimum Extrusion Distance Window</div><div><br /></div><div>- Limit Support Retractions</div><div><br /></div><div>- Combing Mode</div><div><br /></div><div>- Max Comb Distance With No Retract</div><div><br /></div><div>- Z Hop When Retracted</div><div><br /></div><div>- Z Hop Height</div><div><br /></div><div><b>Cooling</b></div><div>---</div><div>- Fan Speed</div><div><br /></div><div>- Initial Fan Speed</div><div><br /></div><div>--Regular Fan Speed at Layer</div><div><br /></div><div>- Minimum Layer Time</div><div><br /></div><div><b>Support</b></div><div>---</div><div>- Support Overhang Angle</div><div><br /></div><div><b>Build Plate Adhesion</b></div><div>(mostly just do this if you plan to print ABS/ASA without an enclosure so you can enable a brim)</div><div>---</div><div>-Build Plate Adhesion Type</div><div><br /></div><div>- Brim Width</div><div><br /></div><div>- Brim Distance</div><div><br /></div><div><b>Dual Extrusion</b></div><div>---</div><div>None</div><div><br /></div><div><b>Mesh Fixes</b></div><div>---</div><div>None</div><div><br /></div><div><b>Special Modes</b></div><div>---</div><div>None</div><div><br /></div><div><b>Experimental</b></div><div>---</div><div>- Enable Coasting</div><div><br /></div><div>- Coasting Volume</div><div><br /></div><div>- Overhanging Wall Angle</div><div><br /></div><div>- Overhanging Wall Speed</div><div><br /></div><div>- Enable Bridge Settings</div><div><br /></div><div>- Bridge Wall Coasting</div><div><br /></div><div>- Bridge Wall Speed</div><div><br /></div><div>- Bridge Wall Flow</div><div><br /></div><div>- Bridge Skin Speed</div><div><br /></div><div>- Bridge Skin Flow</div><div><br /></div><div>- Bridge Skin Density</div><div><br /></div><div>- Bridge Fan Speed</div><div><br /></div><div>- Bridge Has Multiple Layers</div><div><br /></div><h1 style="text-align: left;">TeachingTech Calibration Generators</h1><div>YouTuber TeachingTech has created <a href="https://teachingtechyt.github.io/calibration.html" target="_blank">a great website</a> for generating calibration patterns that can help greatly simplify the process of determining the right print settings, but I don't completely agree with the order of the tests, so I'll run through my process here. Instructions for each individual test are detailed on each page of the website, so I won't go into them here. Start with the machine basics like the Frame Check, PID Autotune, Extruder E-Steps, and First Layer. These have nothing to do with the material, but you'll need to have those done before you can get good results with the rest of the tests.</div><div><br /></div><h2 style="text-align: left;">Custom Start/End gcode</h2><div>Once you've got your machine squared away and ready to test, you'll want to grab the start and end gcode from Cura and add them to the calibration test gcode. You can do this by going to one of the tests like Temperature, check the "Additional start gcode" and "Additional end gcode" boxes, which should open up an extra text box where you can type in whatever gcode you want. You can get this gcode from Cura by selecting Settings>Printer>Manage Printers, and clicking Machine Settings. Copy the contents of Start G-code into the website's Additional start gcode field and Cura's End G-code into the website's Additional end gcode field. Then add 2 extra lines. At the <b>bottom</b> of the Additional start gcode, add:<br /><br />M900 K0.0 ;<br /><br />If you have already set up a similar filament of the same type, and happen to know the Linear Advance K-factor, you can put that in here instead of 0.0. Either way, you'll update this value later.<br /><br />At the <b>top</b> of the Additional end gcode, add:<br /><br />M400 ;<br /><br />In fact, you should probably add the M400 at the top of your End G-code in Cura as well, especially if you are running a custom build of Marlin with the gcode buffer size increased from the default. Otherwise, temperature changes are immediately applied, skipping over the gcode buffer, causing the hotend to be shut off as much as 30 seconds before the print is actually finished. If your custom start gcode includes bed leveling commands such as G28 or G29, you can set the bed leveling option in the website drop-down to None.</div><div><br /></div><h2 style="text-align: left;">Temperature</h2><div>Now, the first test to run on any new material is the temperature tower. Follow the instructions, and pick the best result. Enter the result into Cura by opening Manage Materials, selecting your material from the list, and opening the Print Settings tab. Enter the resulting temperature under Default Printing Temperature. For bed adhesion purposes, enter a value about 10 degrees higher for Printing Temperature Initial Layer and Initial Printing Temperature. Initial Printing Temperature will show a warning yellow if it is higher than the Default Printing Temperature, but this can be ignored.</div><div><br /></div><h2 style="text-align: left;">Linear Advance</h2><div>Follow the instructions for printing a Linear Advance test pattern, being sure to use the Default Printing Temperature value from the temperature tower, <b>not</b> the increased first layer temperature. In Cura's Print Settings, enter this value into the Linear Advance field.</div><div><br /></div><h2 style="text-align: left;">Print Speed</h2><div>Back to the TeachingTech website, open the Print Speed test tab. Enter the print temperature from the first test into the relevant field, and enter the Linear Advance K-value into the M900 line at the bottom of the Additional start gcode field. Then generate the test file and print it. After examining the result and determining the top speed, enter the result into Cura's Print Settings under Print Speed. PLA is a pretty good material to determine the actual maximum speed for the printer itself that can be used as a default in the future, and then you only really need to run this test for trickier materials like Silk PLA, PETG, or TPU if you want. Or, at least it will give you a good baseline to start from in the future.</div><div><br /></div><h2 style="text-align: left;">Acceleration</h2><div>This one is really something that should be assigned to the Extruder layer, not the Material layer, so once you run it once, you should just be able to reuse the value for future materials, unless you get into things that also have a drastically different Print Speed, like TPU. I suggest setting the Initial Layer acceleration values to something around 50-60% of the value you determine from the test.</div><div><br /></div><h2 style="text-align: left;">Retraction</h2><div>Retraction is pretty straightforward. Run the test, record the results in Cura.</div><div><br /></div><h2 style="text-align: left;">Flow Rate</h2><div>This one is a bit complicated. First, update the retraction distance and speed values using the previous test results. Then, in Cura, there are typically 3 different speeds, calculated as fractions of the default Print Speed that you actually configured in the profile. The default is used for several things like infill, top/bottom/etc. the second speed is used for walls, and the third is used for the initial layer. To get the best results from the flow rate test, you'll want to run it at each of the three speeds, then in Cura you'll use the result at each speed for each of the features that runs at that speed. For instance, use the feed test printed at the wall speed to configure the wall flow rate, and so on. Pay close attention to the Preview window and set the Color Scheme in the top-middle to Speed to make sure that the whole model is being printed at the same speed. If the walls are being set to a lower speed, the two places to check are that your wall speed is set to the same speed as your default speed (reset this once the tests are done), and also check that the minimum layer time is set high enough.<br /><br />Speaking of minimum layer time, if your box ends up looking really melted and distorted, then you need to reduce the minimum layer time for the material. The way you can dial this in is to set the value to something high like 30 seconds, then start reducing the print speed until the box is no longer melted. Then, to determine what minimum layer time corresponds to that print speed, leave the print speed at the speed that came out clean, reduce the minimum layer time, and slice the model, but don't print it, just look at the Preview window. Keep reducing the minimum layer time until the preview shows that the print speed has been reduced below the configured speed. The lowest minimum layer time that <i>doesn't</i> change the print speed is your actual minimum layer time that you'll want to configure in the material profile. You can add another second or two just to be safe if you want.<br /><br />If you do have to dial in the minimum layer time, you'll need to scale up the box in the slicer in order to perform the actual flow rate tests as outlined here. You don't need to scale the Z axis, just X and Y.</div><div><br /></div><div>Also, I have noticed that some of the other TeachingTech tests modify the flow rate to 97%. I'm not sure why (one obvious case is if you cancel the print speed test early, which will leave the flow rate at something other than 100%, but some of the other tests seem to change this as well), but you want to be sure this isn't the case before starting this test. On an Ender 3, you'll notice it says ">>97%" (or some number that isn't 100%) on the left side of the screen. An easy way to reset this is to just power cycle the printer before starting this test, or you can go through the menu and change the flow rate. You can also manually send<br /><br />M220 S100<br /><br />from the gcode terminal. Once you've performed the flow rate tests at the 3 key print speeds, go through the material profile and configure the flow rates for the associated print features.</div><div><br /></div><h1 style="text-align: left;">Other Calibration</h1><div>At this point, you're probably ready to go. There are plenty of other things that can be calibrated, but for the most part, I don't bother with further calibrations until they become necessary. Here are a couple of them.</div><div><br /></div><h2 style="text-align: left;">Cooling</h2><div>Usually, I just set my cooling to 50% after layer 2, except for high-temp filaments like ASA and PC, where I reduce it to the absolute minimum value that actually spins the fan (around 15% for me, might be different for you). However, if you think you need to dial in your cooling more precisely, TeachingTech also has a decent model for that. It's not on the calibration website, but you can download the model <a href="https://www.thingiverse.com/thing:3167063" target="_blank">here</a>.</div><div><br /></div><h2 style="text-align: left;">Bridging</h2><div>Bridging is another setting that I don't usually bother with until I really need to, because it's a pretty complex one to get right and can take awhile. For me, I go with the following settings as my baseline, and adjust as needed.<br /><br />Bridge Wall Coasting: 50%<br />Bridge Wall Speed/Bridge Skin Speed: ~25% of the default print speed, or slower<br />Bridge Wall/Skin Flow: 50%<br />Bridge Skin Density: 150%<br />Bridge Fan Speed: 100%</div><div><br /></div><div>If you want a test model, you can find several online, such as <a href="https://www.thingiverse.com/thing:284380" target="_blank">this</a> or <a href="https://www.thingiverse.com/thing:476845" target="_blank">this</a>. Take your pick.</div><div><br /></div><h2 style="text-align: left;">Coasting/Wipe</h2><div>I don't have a good calibration print for these, but coasting and wipe are good parameters to increase if you're dealing with gaps near your seam (increase outer wall wipe) or excess ooze with filaments like PETG or Silk PLA (increase coasting, can cause gaps, in which case also increase outer wall wipe).</div><div><br /></div><h1 style="text-align: left;">Conclusion</h1><div>If you find any other settings that you want to dial in that feel like they should be associated with the Material layer, you can always check the box later, run your tests, and save the results. Certain other parameters, like wall thickness, infill density, layer height, support settings, etc. should be left out of the Material layer and used in Quality profiles instead. These are the sorts of settings that are usually listed under print instructions for a model. That way, imagine you're printing something made of a bunch of parts, like a Voron, where those settings are specified in the build documents, but also imagine that you're using 2 different brands of filament for the 2 different colors. You want the "Voron Parts" settings to be stored in a quality profile, and the material settings stored in the material profile, so you can swap materials without changing the physical strength properties you get from the wall and infill settings. Understanding what the different layers are and what their purpose is will help you to use them the most effectively, and in turn, give you the most benefit. Hopefully this guide will help you get the most out of Cura, and the best results from your prints. Happy Printing!</div></div>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-74667265798989622352021-03-16T12:42:00.004-07:002021-03-29T11:42:30.914-07:00Ghidra Dark Theme (VS Dark color scheme)I've been using Ghidra for awhile now, but its default color scheme annoys me,
especially when all of my other development tools and editors are running dark
themes. While there is some support for recoloring certain aspects of the UI,
not everything can be modified, leading to a rather inconsistent UI experience.
The best guide I was able to find was this one:
http://enigmatrix.me/blog/2019/11/30/dark-ghidra/ but even it left several
dockable panes with the default white background, or even worse, black text in
areas that did apply the dark theme to the background colors, but not the text
for some reason. I have been able to extend that guide a bit further, and in the
process I also modified the color scheme to my preferred one, to try and match
the default dark theme from Visual Studio.<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1d0zauTs9LlnCmcdf_BSAZ9-o3dxg54Cm4myhxPIwa72aeBiH4AobtRehyNjEa-v6_g6hmKos6GbUTLFE98y5t94sCcL5ahPQt-PBAfNFLD8L9sbIA35tQYxbk5BlXhPvaKTIZSV52hgc/s1920/ghidra_vsdark.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1050" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1d0zauTs9LlnCmcdf_BSAZ9-o3dxg54Cm4myhxPIwa72aeBiH4AobtRehyNjEa-v6_g6hmKos6GbUTLFE98y5t94sCcL5ahPQt-PBAfNFLD8L9sbIA35tQYxbk5BlXhPvaKTIZSV52hgc/s320/ghidra_vsdark.png" width="320" /></a></div><br /><div><br /><br />As with the enigmatrix
tutorial, I chose to use FlatLaf as the base for my dark theme. You can find the
latest version on
<a href="https://search.maven.org/artifact/com.formdev/flatlaf" target="_blank">Maven</a>. Once you select a version, the download link will be in the top-right, and
you'll want to select "jar" from the drop-down menu. Or, you can just grab the
1.0 jar
<a href="https://search.maven.org/remotecontent?filepath=com/formdev/flatlaf/1.0/flatlaf-1.0.jar" target="_blank">here</a>. Once you download the jar file, I suggest placing it into your
%USERPROFILE%\.ghidra folder. Next, you'll need to modify a couple of Ghidra's launch files in order for Ghidra to be able to find it. First up, you'll want to add the full jar path to the CPATH lines in <GHIDRA_PATH>/support/launch.sh (launch.bat on Windows). The CPATH variable is a colon-delimited list (in the .sh file, the .bat file is semicolon-delimited), so just type a colon at the end, followed by the full path to the flatlaf jar file.<br /><br />Next, set FlatLaf as the systemlaf in <GHIDRA_PATH>/support/launch.properties. Just copy this at the bottom of the file:<br /><br /><blockquote>VMARGS=-Dswing.systemlaf=com.formdev.flatlaf.FlatDarkLaf</blockquote><br />Now open Ghidra and click Edit>Tool Options and select Tool. Under Swing Look And Feel, select System, and check the box for Use Inverted Colors. Click OK and close Ghidra. Using inverted colors is an important step for converting some of the hard-coded elements that might otherwise use a white background or black text on our new dark themed backgrounds. Next up is the color assignment. As I said, I'm using the Visual Studio dark theme as the basis for my theme. You're free to edit these as you like, but keep in mind that because Use Inverted Colors is enabled, you'll have to invert the RGB values that you actually want displayed (at least in most cases, some colors don't get inverted, it's really inconsistent and annoying).<br /><br />First of all, you'll want to edit %USERPROFILE%\.ghidra\<GHIDRA_VERSION>\tools\_code_browser.tcd. There are a lot of values to edit here. This file doesn't seem to support hex values, so if you want to change any of these from what I have here, you first have to invert the hex code, and then convert the result to a 32-bit signed integer. e.g. to get hex color #343A40, you would first invert it to #FFCBC5BF (the first FF is because you have to expand to 32-bits, so 00 inverts to FF), and then convert to signed 32-bit integer -3422785. You can do this using the Windows 10 calculator by switching to Programmer mode and clicking the word size button above the keypad until it displays "DWORD". Select Hex, enter your desired hex color value, and then XOR FFFFFFFF. The value displayed next to DEC should be the value to use.<br /><br /><script src="https://gist.github.com/qwertymodo/a03ff649b63d7dc125d1aa2581c90542.js"></script><br />Now, we're going to edit the FlatLaf theme itself. First of all, open up a text editor and copy the following contents into it. Note that unlike the _code_browser.tcd edits above, this is the full contents of the file, so you don't have to go through and edit a bunch of separate sections.<br /><div><br /><script src="https://gist.github.com/qwertymodo/8cdc1151c76188cfdc839b0e3193d3a8.js"></script></div><div>Save this file as FlatDarkLaf.properties (if on Windows, you may need to save the file using Unix LF line endings instead of the default CRLF). Next, rename the jar file you downloaded to .zip, or just open it directly with an archive tool like 7-zip. Browse to com\formdev\flatlaf and replace FlatDarkLaf.properties with the one you just created. Save the archive and rename back to .jar if necessary.</div><br />Now you're done! Reopen Ghidra, and you should be greeted with a nice dark theme.<br /><br />There are some weird orange and yellow colors, especially in dialog header, those are the result of inverting the hard-coded original blue colors. Aside from that, it should all be themed. I will say, there were a few colors in the properties files that I couldn't manage to match up to a UI element in the actual application. It's possible Ghidra doesn't use those theme elements, or it's possible that I just missed them. In most cases, if I couldn't find them, I left them as bright magenta (which may show up as bright green, depending on the inversion, it's not the darker purple like the selection color in the disassembly pane shown in the screenshot above), so if you happen to find something in the UI that is showing up as magenta or green, please let me know in the comments, and I'll see if I can track it down.<div class="separator" style="clear: both; text-align: center;"><br /></div><br /></div>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-3938541906526865392017-07-15T14:30:00.001-07:002018-03-16T14:27:02.096-07:00The MSU-1 Volume Fiasco, ExplainedIf you've ever tried one of the many amazing <a href="https://www.youtube.com/results?search_query=msu-1" target="_blank">SNES hacks utilizing the MSU-1 audio coprocessor</a>, you may have run across information about volume levels referencing "hardware" versions and "emulator" versions of the same hack, as well as "boosted" or "non-boosted" audio files, and may have been confused by the complicated, and often conflicting information about all of these different variants. I've explained the issue on several forums, but I wanted to go ahead and do a single, unified write-up explaining the issue, as well as the "correct" way to do things. Hopefully this will help clear up the confusion for people new to the MSU-1.<br />
<br />
First of all, before I dig into the full explanation, I'll just cut to the chase. THERE IS NO LONGER ANY NEED FOR SEPARATE VERSIONS. You only need one version, and that same version works everywhere. Many MSU-1 hack authors have fixed their hacks and released them as a single fixed version. However, since there are still a handful of un-fixed patches floating around, if you happen to have a patch with both "Hardware/SD2SNES" and "Emulator" versions, the correct combination is to use the "Hardware/SD2SNES" version of the patch with non-boosted audio files. However, if you can't find non-boosted audio files, then you can also use boosted audio files with the "Emulator" version of the patch, but that will not sound as good (see <a href="https://www.blogger.com/blogger.g?blogID=2953283389087359631#p3">Problem #3</a> below). If you're not sure whether your audio files are boosted or not, try out the Hardware/SD2SNES patch in an emulator. If the audio sounds really loud/distorted, you have boosted audio files.<br />
<br />
Also, if you have an older-revision SD2SNES, you'll need to go into the menu and set the MSU-1 audio boost to max (see <a href="https://www.blogger.com/blogger.g?blogID=2953283389087359631#lhw1">Less Hacky Workaround #1</a> below).<br />
<br />
Now, to explain the issue...<br />
<br />
First, we had higan. Audio was mixed properly, and .pcm audio files were more-or-less properly normalized. Let's call this the correct patch and correct audio files.<br />
<br />
<a href="https://www.blogger.com/null" name="p1"></a>
<br />
<h2>
<b>Problem #1:</b></h2>
<br />
The SD2SNES played MSU-1 audio too quietly. There was a lot of speculation as to why, but eventually ikari realized that the DAC output was high impedance, and the SNES analog mixing inputs were low impedance, which caused reduced volume. This means the problem is in the hardware, and can't be fully fixed without a board revision.<br />
<br />
<a href="https://www.blogger.com/null" name="hw1"></a>
<br />
<h2>
<b>Hacky Workaround #1:</b></h2>
<br />
SNES audio tends to be somewhere in the range of -10dBFS to -20dBFS RMS. This leaves a fair amount of headroom. Therefore, it's possible to simply amplify the .pcm files to remove that headroom, allowing them to be more or less the right volume when played on the SD2SNES. Let's call this boosted audio files.<br />
<br />
<a href="https://www.blogger.com/null" name="p2"></a>
<br />
<h2>
<b>Problem #2:</b></h2>
<br />
These newly boosted audio files are much too loud when played on higan. Maintaining 2 separate audio packs is not only a logistical pain in the butt, it's also a huge amount of storage and bandwidth increase.<br />
<br />
<a href="https://www.blogger.com/null" name="hw2"></a>
<br />
<h2>
<b>Hacky Workaround #2:</b></h2>
<br />
Instead of releasing separate audio packs, just modify the .asm code so that any time you write to the MSU-1 volume register, you write a smaller value instead of the original. Patch files are small, so uploading 2 versions of the patch is much easier than 2 versions of the audio files. Through rough trial-and-error, it was mostly settled on $60 being the value used for "full volume" and $30 for "half volume" with anything else such as fade effects being adjusted relative to those values. Let's call this the "emulator version", and the original is now the "hardware/SD2SNES version". These are sometimes also referred to as the "FF version" (aka the hardware version) and the "60 version" (aka emulator version). To reiterate, the hardware/FF version is the original, "correct" patch.<br />
<br />
<a href="https://www.blogger.com/null" name="lhw1"></a>
<br />
<h2>
<b>Less Hacky Workaround #1:</b></h2>
<br />
ikari realized that he could actually do this same audio boosting in firmware, in realtime, between reading the file and sending it to the DAC. This would allow using "correct audio" files and the "hardware/FF" patch, and still get more or less the correct audio levels. This essentially eliminated any need for HW#1, which in turn eliminated the need for HW#2.<br />
<br />
<a href="https://www.blogger.com/null" name="nhcf1"></a>
<br />
<h2>
<b>Non-Hacky, Correct Fix #1:</b></h2>
<br />
SD2SNES Rev. H includes a unity-gain op-amp on the output of the MSU-1 DAC, which solves the impedance problem, fixing the volume level. Along with LHW#1, all revisions of the SD2SNES can now output the correct volume levels. HW#1 and HW#2 are completely unnecessary.<br />
<br />
<h2>
Non-Hacky, Correct Fix #2:</h2>
<br />
For those of you with an
older hardware revision of the SD2SNES, it is possible to install a
hardware mod which upgrades the audio output circuit to match that of
the Rev. H. Rev. G. hardware requires an extra step in order to
"downgrade" to Rev. F first, but other than that, the process is
identical for all revisions. I outlined the process <a href="http://www.qwertymodo.com/hardware-projects/snes/sd2snes-dac-upgrade" target="_blank">here</a>,
but since writing that post, a guy by the username borti4938 has
created a simple PCB which greatly simplifies the process, so I would
suggest checking that out. Once the mod is installed, the hardware is
essentially identical to Rev. H, and the previous instructions will
apply. Use the proper "SD2SNES/FF" patch with properly normalized audio
files, and completely disable the MSU-1 audio boost in the firmware
menu.<br />
<br />
Now, technically, with HW#2, boosted audio and the "emulator/60" patch cancel each other out, resulting in the correct levels, so why not just use that version for everything? After all, a lot of patch creators were really annoyed at having to go to all the trouble of boosting their files for HW#1, along with re-uploading everything and writing new documentation, and they really didn't want to go through all of that again. Unfortunately, that leaves us with...<br />
<br />
<a href="https://www.blogger.com/null" name="p3"></a>
<br />
<h2>
<b>Problem #3:</b></h2>
<br />
Actually, this is several problems. First of all, most of the boosted audio files were actually peak normalized to 0dBFS. On the one hand, thankfully this wouldn't cause any clipping, but it does mean that the audio files aren't actually normalized relative to each other. If you don't understand the difference between RMS and peak normalization, the ELI5 version is that with peak normalization, the ONLY THING that matters is the single loudest sample in the entire track. Imagine you have 2 tracks, one is really loud all the way through, and one just has a loud cymbal crash at the end, while the rest of the track is really silent. Peak normalizing these two tracks to the same level means that loud crash at the end will be the same loudness as the entire loud track, so if you listen to them side by side, the entire quiet track will be much quieter than the loud one. This is an extreme example, but if you've ever looked at a waveform visually, this is basically true of any track with a lot of really large "spikes" in volume (the "quiet" tracks) vs tracks which are very "dense" and consistently the same volume. The "spiky" tracks will end up sounding much quieter. RMS normalization accounts for this by "averaging" the volume over time, which gives a better comparison between tracks. Basically, long story short, peak normalized tracks are no longer properly normalized relative to each other.<br />
<br />
Now, that's assuming that the tracks were peak normalized to 0dBFS. Some people didn't do that, they just "cranked up the volume", which actually resulted in clipping, permanently damaging the files. The only way to fix them is to reconvert from the original source files.<br />
<br />
Also, some games don't actually have a single normalized level for their entire OST, and instead use a wide dynamic range. Super Metroid is probably the most extreme example I've found, but a lot of the JRPG's do as well. You completely lose this dynamic range in the boosted tracks, which really kills a lot of the impact of that dynamic range (imagine the Arrival on Brinstar track being as loud as the Ridley fight... it's just wrong).<br />
<br />
So, you <i>could</i> stick with HW#2, but it's ugly, and it's still wrong for several reasons. Thankfully, I've gotten a lot of people on board with understanding this and have been working to remove and replace boosted audio packs with properly normalized ones. It's been a bit of an uphill battle, it's not 100% complete, and in some instances I've just had to do the work myself, but the hardest part was convincing people that this was really the right way to do it, and on that front, at least, I've pretty much succeeded. This means no more need for separate patches, or hacky workarounds, the ONLY workaround that needs to be mentioned is the MSU-1 boost option in the SD2SNES menu for older hardware revisions, OR the <a href="http://www.qwertymodo.com/hardware-projects/snes/sd2snes-dac-upgrade" target="_blank">op-amp installation mod</a>, which essentially upgrades the hardware to Rev. H. Then, all you need is the correct patch (aka "hardware/FF" version), and the correctly-leveled audio tracks, and we can go back to (mostly) pretending that this whole fiasco never happened.<br />
<br />qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-57979271432620147752016-05-29T00:57:00.000-07:002016-05-29T00:58:46.609-07:00Why I should never be allowed to name softwareI have this thing about coming up with funny (at least I think so), quirky, or... <i>colorful</i> names for software projects. I've come to the conclusion that perhaps I should not be allowed to do so. I don't really remember all of the names I've come up with, but here is the list of the ones that I do. Some of these products exist, others exist under other names, others still exist only in my mind... and should perhaps stay that way.<br />
<br />
<ul>
<li>Personally, I think <a href="http://techblog.netflix.com/2012/07/chaos-monkey-released-into-wild.html" rel="nofollow" target="_blank">Chaos Monkey</a> passed up a perfectly good opportunity to be called ClusterF*%#</li>
<li>In a similar vein, the <a href="http://www.gluster.org/" rel="nofollow" target="_blank">GlusterFS distributed file system</a> really needs a command analogous to the Unix fsck... named, of course, glusterfsck</li>
<li>I once wrote an I2C slave interface library for the AVR USI module, called USI2C. It's pronounced you-see two-see</li>
<li>If anybody ever builds a BSD-based smartphone OS, I'd call it BSD Mobile, aka BSDM</li>
<li>PwnAFriend. I don't know what it does yet, but it sounds cool.</li>
</ul>
qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-67141090499214170252015-06-08T18:45:00.000-07:002015-06-08T18:45:00.381-07:00USBDriveBiteA few months back, I learned of the <a href="http://samy.pl/usbdriveby/" target="_blank">USBDriveby</a> device developed by Samy Kamkar that was able to infect MacOS computers by posing as a USB keyboard and mouse and executing a scripted sequence of mouse movements and key presses. His device used the Teensy 3.0 microcontroller dev board and requires a micro-USB cable to plug into. In my classic fashion of never having any good ideas of my own, but seeing other people's cool ideas and thinking "I can do that better" I started thinking of ways that I could improve on the hardware used, rather than utilizing a general purpose dev board like the Teensy.<br />
<br />
I immediately knew that I wanted to use my favorite USB microcontroller, the PIC16F1455. It comes in packages with as few as 14 pins, or as small as a QFN-16, and requires no external components beyond a pair of simple bypass capacitors, making it perfect for small, simple USB devices. It's also supported by the free USB M-Stack, which means I'm not tied down by the frustrating license stipulations of the Microchip USB stack.<br /><br />The real design revelation came when I tore apart a cheap $2 DealExtreme Bluetooth dongle to find that all of the electronics, including the actual USB pads, were all on a single PCB that could be easily removed from the shell.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCA6K2NZRbJqOJWNONo7hjd7Me8Q6Kf4ifGfV7vLrhgw7z4o7Zh-3UR0ILz6eRo75UNruZn7FGLdNJUtG5By4GkusnDiLd7cTsk2xodd9vlWoGB5QjnmvbyeBXmK7qrG23f3dGpr0sMtpa/s1600/IMG_0297.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCA6K2NZRbJqOJWNONo7hjd7Me8Q6Kf4ifGfV7vLrhgw7z4o7Zh-3UR0ILz6eRo75UNruZn7FGLdNJUtG5By4GkusnDiLd7cTsk2xodd9vlWoGB5QjnmvbyeBXmK7qrG23f3dGpr0sMtpa/s320/IMG_0297.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnpwQeKjZRobXYNpNpyFatqCba4dmz1ooHExmOgAiIyg8RqkvjoHbLbxXihJFQfyYyB7f4-ME7SCknIgV16tdI1gf6axgrj8eGEwAhMAzwaaxEwKpFYw5U9tVElPvOD631qszlHLfvD5Bk/s1600/IMG_0299.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnpwQeKjZRobXYNpNpyFatqCba4dmz1ooHExmOgAiIyg8RqkvjoHbLbxXihJFQfyYyB7f4-ME7SCknIgV16tdI1gf6axgrj8eGEwAhMAzwaaxEwKpFYw5U9tVElPvOD631qszlHLfvD5Bk/s320/IMG_0299.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The tricky part was that the PCB was 0.6mm thick, and finding a manufacturer willing to produce boards at that thickness for less than $100 took some doing. Once I realized SeeedStudio would handle such a board, it was a simple matter of measuring the original board and throwing together a replacement in EAGLE.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG-bA_z5VKPXc22JuLX-NsYARsrRQkDjpRZl_vJJmXtwn6Ww3fYznuDYtF1z4YA5Sc-T_LcpKDzaHhT70gzShs6MIwUt_ZX4NmirWvoCQymYa_l-EQFEqqCkzw_9jlHGRx8gK8xT6gl76D/s1600/IMG_0302.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG-bA_z5VKPXc22JuLX-NsYARsrRQkDjpRZl_vJJmXtwn6Ww3fYznuDYtF1z4YA5Sc-T_LcpKDzaHhT70gzShs6MIwUt_ZX4NmirWvoCQymYa_l-EQFEqqCkzw_9jlHGRx8gK8xT6gl76D/s320/IMG_0302.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUk8ZdhFmGbfi_1cqfUCN02vy6SdOEADlrB3Qp_zJYdV8v2U55cLF6_NYO3dk50ayOPJlOuEn121qeApWeAS6-0IEQaagWBHwPn2n97aVV0qCIwLGmHwEk9EhRPf_E0AGvCL2WgGw7CEZn/s1600/IMG_0304.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUk8ZdhFmGbfi_1cqfUCN02vy6SdOEADlrB3Qp_zJYdV8v2U55cLF6_NYO3dk50ayOPJlOuEn121qeApWeAS6-0IEQaagWBHwPn2n97aVV0qCIwLGmHwEk9EhRPf_E0AGvCL2WgGw7CEZn/s320/IMG_0304.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The firmware isn't quite done yet, but I do have the device enumerating as a keyboard and mouse and can send arbitrary mouse movements and button presses, as well as keyboard key presses, so all that really remains is setting up a queue-based event processor and then feeding it the original USBDriveby script. All in all, I'm pretty happy with how it turned out, and now I'm trying to come up with other ideas for how to use this thing, since I'm probably not going to get much use out of it as a MacOS exploit. The board has a single push button and LED (plus an additional power LED), so I can probably find another purpose for it eventually.</div>
qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-86950133478620545042015-05-26T19:58:00.000-07:002015-05-26T19:58:42.235-07:00Generating tiles for Google Maps API<div class="tr_bq">
I use Google Maps API to render the maps on my Zelda Parallel Worlds walkthrough, and as a result I needed to generate the necessary tiles for the Maps API to use. My source image was a 4,096x4,096 image, and I needed to generate 256x256 tiles at various zoom levels, starting at fully zoomed out, where the entire map was contained in a single tile, up to however large I could reasonable render (which ended up being a whopping 16,384x16,384). GIMP's script-fu functionality was perfect for the task, but I couldn't find a script that quite did what I wanted, including scaling the map to the various zoom levels, so I made my own. I used the <a href="http://registry.gimp.org/node/20868" target="_blank">tiles-to-files plugin</a> as my starting point and went from there. The end result gives the following options</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyDMS-D_qwctWxU_B-gNpY1JcJ2d-dylMumN4Q6Md3a5fn2KYZskl8N8vFWsTj3qJPtdEJl7Up4b6QPjJOHHcP_Jss8Iv24CYg98fI2bN0SR_bUBY4233Hw0f8d3DsL87hMSYzL6YXEom_/s1600/script-fu-google-maps-tiles.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyDMS-D_qwctWxU_B-gNpY1JcJ2d-dylMumN4Q6Md3a5fn2KYZskl8N8vFWsTj3qJPtdEJl7Up4b6QPjJOHHcP_Jss8Iv24CYg98fI2bN0SR_bUBY4233Hw0f8d3DsL87hMSYzL6YXEom_/s320/script-fu-google-maps-tiles.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Tile size is adjustable (though I've only tested powers of 2, such as 64, 128, and 256)<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Max zoom level determines how many zoom levels should be generated. The lowest zoom level is 0, which is a single tile in size.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Output file type is selectable between PNG and JPEG<br /><br />Interpolation mode can be chosen separately for shrinking and growing. In my case, I didn't want any interpolation when growing, since I was growing a pixel-perfect image by a factor of 2 each zoom level, so I wanted to retain the pixel-perfect aspect and just create "big pixels".<br /><br />Here's the script:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<blockquote style="clear: both;">
<span style="color: white;">; Google Maps Tiles, V1.0<br />;<br />; Based on the tiles-to-files script by theilr<br />; http://registry.gimp.org/node/20868<br />;<br />; http://www.qwertymodo.com<br />;<br />(define (script-fu-google-maps-tiles inImage inDrawable inTileSize inMaxZoom<br /> inFileType inShrinkMethod inGrowMethod outDir)<br /> (gimp-image-undo-group-start inImage)<br /> (let* (<br /> (fullWidth (car (gimp-image-width inImage)))<br /> (fullHeight (car (gimp-image-height inImage)))<br /> (tileWidth inTileSize)<br /> (tileHeight inTileSize)<br /> (zoomWidth tileWidth)<br /> (zoomHeight tileHeight)<br /> (newImage (car (gimp-image-new tileWidth tileHeight RGB)))<br /> (tmpImage)<br /> (tmpLayer)<br /> (selLayer)<br /> (outfname)<br /> (hcnt 0)<br /> (vcnt 0)<br /> (zcnt 0)<br /> )<br /> <br /> (set! zcnt 0)<br /> (while (<= zcnt inMaxZoom)<br /> (set! zoomWidth (* tileWidth (expt 2 zcnt)))<br /> (set! zoomHeight (* tileHeight (expt 2 zcnt)))<br /> <br /> (gimp-rect-select inImage<br /> 0<br /> 0<br /> fullWidth<br /> fullHeight<br /> CHANNEL-OP-ADD FALSE 0)<br /> <br /> (gimp-edit-copy-visible inImage)<br /> (gimp-selection-none inImage)<br /> <br /> (set! tmpImage<br /> (car (gimp-image-new zoomWidth zoomHeight RGB)))<br /> <br /> (set! tmpLayer<br /> (car (gimp-layer-new tmpImage fullWidth fullHeight<br /> RGB-IMAGE "Background" 100<br /> NORMAL-MODE))) <br /> (gimp-image-add-layer tmpImage tmpLayer -1)<br /> (set! selLayer<br /> (car (gimp-edit-paste tmpLayer FALSE)))<br /> (gimp-floating-sel-anchor selLayer)<br /> <br /> (if (< zoomWidth fullWidth)<br /> (begin<br /> (gimp-context-set-interpolation inShrinkMethod)<br /> (gimp-layer-scale tmpLayer zoomWidth zoomHeight FALSE)<br /> (gimp-image-resize-to-layers tmpImage)<br /> )<br /> )<br /> <br /> (if (> zoomWidth fullWidth)<br /> (begin<br /> (gimp-context-set-interpolation inGrowMethod)<br /> (gimp-layer-scale tmpLayer zoomWidth zoomHeight FALSE)<br /> (gimp-image-resize-to-layers tmpImage)<br /> )<br /> )<br /> <br /> (set! hcnt 0)<br /> (while (< (* hcnt tileWidth) zoomWidth)<br /> (set! vcnt 0)<br /> (while (< (* vcnt tileHeight) zoomHeight)<br /> (gimp-rect-select tmpImage<br /> (* tileWidth hcnt)<br /> (* tileHeight vcnt)<br /> tileWidth<br /> tileHeight<br /> CHANNEL-OP-ADD FALSE 0)<br /> (gimp-edit-copy-visible tmpImage)<br /> (gimp-selection-none tmpImage)<br /> <br /> (set! tmpLayer<br /> (car (gimp-layer-new newImage tileWidth tileHeight<br /> RGB-IMAGE "Background" 100<br /> NORMAL-MODE)))<br /> (gimp-image-add-layer newImage tmpLayer -1)<br /> (set! selLayer<br /> (car (gimp-edit-paste tmpLayer FALSE)))<br /> (gimp-floating-sel-anchor selLayer)<br /> <br /> (if (= inFileType 0)<br /> (begin<br /> (set! outfname (string-append outDir<br /> "/"<br /> (number->string zcnt)<br /> "-"<br /> (number->string hcnt)<br /> "-"<br /> (number->string vcnt)<br /> ".png"))<br /> <br /> (file-png-save RUN-NONINTERACTIVE<br /> newImage<br /> tmpLayer<br /> outfname<br /> outfname<br /> 0 9 1 0 0 1 1 ) <br /> )<br /> )<br /> <br /> (if (= inFileType 1)<br /> (begin<br /> (set! outfname (string-append outDir<br /> "/"<br /> (number->string zcnt)<br /> "-"<br /> (number->string hcnt)<br /> "-"<br /> (number->string vcnt)<br /> ".jpg"))<br /> <br /> (file-jpeg-save RUN-NONINTERACTIVE<br /> newImage<br /> tmpLayer<br /> outfname<br /> outfname<br /> 0.95 ; JPEG compression level<br /> 0 ; Smoothing<br /> 1 ; Optimize<br /> 1 ; Progressive<br /> "" ; Comment<br /> 0 ; Subsampling (0-4)<br /> 1 ; Baseline<br /> 0 ; Restart<br /> 0 ; DCT<br /> ) <br /> )<br /> )<br /> <br /> (set! vcnt (+ vcnt 1))<br /> )<br /> (set! hcnt (+ hcnt 1))<br /> )<br /> <br /> (gimp-image-delete tmpImage)<br /> <br /> (set! zcnt (+ zcnt 1))<br /> )<br /> <br /> (gimp-image-delete newImage)<br /> (gimp-image-undo-group-end inImage)<br /> (gimp-displays-flush)<br /> )<br />)<br />(script-fu-register<br /> "script-fu-google-maps-tiles" ; function name<br /> "<Image>/Filters/Tiles/_Google Maps" ; menu label<br /> "Split an image into tiles suitable\ ; description<br /> for use with Google Maps API"<br /> "qwertymodo" ; author<br /> "(c) 2015, qwertymodo" ; copyright notice<br /> "25 May 2015" ; date created<br /> "RGB*" ; image type<br /> SF-IMAGE "Image" 0<br /> SF-DRAWABLE "Drawable" 0<br /> SF-ADJUSTMENT "Tile Size (px)" '(128 8 1024 1 8 0 SF-SPINNER)<br /> SF-ADJUSTMENT "Max Zoom Level" '(4 0 10 1 2 0 SF-SPINNER)<br /> SF-OPTION "Output File Type" '("png" "jpg")<br /> SF-ENUM "Interpolation (Shrink)" '("InterpolationType" "cubic")<br /> SF-ENUM "Interpolation (Grow)" '("InterpolationType" "cubic")<br /> SF-DIRNAME "Output Folder" "tiles"<br />)</span></blockquote>
qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-72323570747113536972013-08-27T01:12:00.001-07:002015-03-14T23:39:24.348-07:00Roll-Your-Own EEPROM BurnerIt's been awhile since I've written anything, mostly because I've been busy actually making stuff, but I figured I'd take some time out to do some writing instead. Something I've been working with lately is building SNES reproduction carts. I see a lot of people buying and using Willem-based programmers to burn their EEPROMs, and from what I can tell, they're way more trouble than they're worth, and more expensive too. I chose to go a different route and build my own programmer. EEPROM programming is a pretty straightforward microcontroller exercise. The main trouble is finding a microcontroller with enough I/O pins. Personally, I used a <a href="https://www.pjrc.com/store/teensypp.html" target="_blank">Teensy++ 2.0</a> development board. One of the most common chips used for SNES reproduction is the AM29F032B, used with a TSOP-to-DIP36 breakout board, usually <a href="http://www.buyicnow.com/fincat.php?cat=396" target="_blank">the one made and sold by BuyICNow.com</a>. So, for lack of anything better to do, I'm going to explain how to go about creating a programmer for the AM29F032B, though much of the information can be adapted to any EEPROM.<br />
<br />
First of all, you'll need to build yourself an adapter in order to connect the microcontroller to the ROM. For the sake of cleaner code, logically contiguous pins on the ROM, such as A0-A22, D0-D7, should be connected to logically contiguous pins on the microcontroller (an 8-bit microcontroller will only have 8-bit ports, so a good compromise is to utilize full ports as much as possible, e.g. A0->PORTX0, A1->PORTX1 . . . A7->PORTX7, A8->PORTY0, A9->PORTY1, etc.). For my Teensy++ adapter, it looked like this:<br />
<br />
(I'm trying to figure out how to create a custom part in <a href="http://fritzing.org/" target="_blank">Fritzing</a> so I can post a nice image representation of this circuit, but for now you'll have to live with a pin table)<br />
<br />
<pre><code>ROM Teensy
Vcc Vcc
Gnd Gnd
A0-7 D0-7
A8-15 C0-7
A16-22 F0-6
D0-7 B0-7
/CE E7
/OE E6
/WE E1
</code></pre>
<br />
Ok, so now that we have everything wired up (or, in my case, I created a socketed PCB), we can start writing code. The most basic functions are reading and writing a single byte. The function prototypes will look something like this.<br />
<br />
<pre><code>
uint8_t ReadByte(uint32_t address);
void WriteByte(uint32_t address, uint8_t value);
</code></pre>
<pre><code>
</code></pre>
<br />
In order to understand how to implement these functions, we first need to look at the function waveforms in the datasheet. Here's the read function:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUBSJVvT_tNhL2Hm-MawPf0lNLxn98HidyFXSJHpxE67d1oplM8TZhb9sAybmVULWCjp219zOzKsFrgPYi3p5GCRi4cZLlzu_sTClsZaSuhwt6BivNUdhnb3n_v_LEDRjZHYBYiEclLQtv/s1600/am29f032b_read.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUBSJVvT_tNhL2Hm-MawPf0lNLxn98HidyFXSJHpxE67d1oplM8TZhb9sAybmVULWCjp219zOzKsFrgPYi3p5GCRi4cZLlzu_sTClsZaSuhwt6BivNUdhnb3n_v_LEDRjZHYBYiEclLQtv/s640/am29f032b_read.png" height="334" width="640" /></a></div>
<br />
We can ignore the actual timings right now, all we really care about is the sequence. From the diagram, we can see that the sequence goes like this:<br />
<br />
Set CE# high, OE# high, and WE# high (in any order, or simultaneously)<br />
Set up the address<br />
Set CE# low<br />
Set OE# low<br />
Wait for a short time<br />
Read the data<br />
Set CE# high and OE# high (in any order, or simultaneously)<br />
<br />
<br />
In code, it looks like this:<br />
<br />
<pre><code>
uint8_t ReadByte(uint32_t address)
{
// Set data line as input, pulled high
DATA_DDR = 0x00;
DATA_PORT = 0xFF;
// Pull all control lines high
CS_PORT |= CS_BIT;
OE_PORT |= OE_BIT;
WE_PORT |= WE_BIT;
// Set up address
ADDR_PORT_0 = address & 0xFF;
ADDR_PORT_1 = (address >> 8) & 0xFF;
ADDR_PORT_2 = ((address >> 16) & 0x7F);
// Pull CS low, then OE low
CS_PORT &= ~CS_BIT;
OE_PORT &= ~OE_BIT;
delayMicroseconds(1);
// Read data
uint8_t data = DATA_PIN;
// Pull all control lines high
OE_PORT |= OE_BIT;
CS_PORT |= CS_BIT;
return data;
}
</code></pre>
<br />
<br />
As you can see, I've #defined a few values here to make the code cleaner. That's all done based on the pinout specified above. For instance:<br />
<br />
<pre><code>
#define DATA_PORT PORTB
#define DATA_PIN PINB
#define DATA_DDR DDRB
#define CS_PORT PORTE
#define CS_DDR DDRE
#define CS_BIT (1<<7)
</code></pre>
<br />
<br />
...and so on. Writing is almost identical, though you wouldn't think it, looking at the waveform in the datasheet.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTADu57LE1DbXCi-mfYZ5LYaLXZCZPXXvMfn-GgpLtoaFqUIQv-gLgJ99aHCX4_MvtAx_9c8I7l5oOJ360MlI9m5QxzudrOQA1Kn8f6wniS2d64AllnDMIbm8SZTt8kLtFbl-jhVxUulU8/s1600/am29f032b_write.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTADu57LE1DbXCi-mfYZ5LYaLXZCZPXXvMfn-GgpLtoaFqUIQv-gLgJ99aHCX4_MvtAx_9c8I7l5oOJ360MlI9m5QxzudrOQA1Kn8f6wniS2d64AllnDMIbm8SZTt8kLtFbl-jhVxUulU8/s640/am29f032b_write.png" height="506" width="640" /></a></div>
<br />
The reason that this looks so complicated is that Flash ROMs actually require you to write several command bytes for every byte of data you actually want to program. However, we want to first write the code to write a single byte, then it's easy to write multiple bytes in a row by making consecutive calls to that function. To make it easier, the sequence is:<br />
<br />
Set CE# high, OE# high, and WE# high (in any order, or simultaneously)<br />
Set up the address<br />
Set CE# low<br />
Set WE# low<br />
Set up the data<br />
Wait for a short time<br />
Set CE# high and WE# high (in any order, or simultaneously)<br />
<br />
The write operation actually occurs when CE# or WE# is pulled high, which latches the data lines and then performs the write.<br />
<br />
No code this time, it should be trivial. Copy and paste the read function and make the necessary changes.<br />
<br />
Next, we want to be able to program information to the chip. As mentioned before, this is done by writing several command bytes, followed by the actual data byte. This varies from chip to chip, but for the AM29F032B, the sequence is:<br />
<br />
<pre><code>
Addr Data
0x555 0xAA
0x2AA 0x55
0x555 0xA0
addr data
</code></pre>
<br />
<br />
where the final "addr" and "data" are the actual address and data that you want to program on the chip. All you have to do is call your WriteByte 4 times in a row with those addresses and data values.<br />
<br />
Now, the final function we need to write is to erase the chip. EEPROMs, including Flash ROMs, must be erased before they can be written to. This is because the program function can only change a 1 to a 0, it can't change a 0 to a 1. Because of that, in order to change a 0 to a 1, you have to change EVERYTHING to 1's by erasing the chip, then you can go back and program the 0's. It's just how it is. Anyway, erasing a Flash ROM is achieved by a command sequence. Again, this varies from chip to chip, but for the AM29F032B, the sequence is:<br />
<br />
<br />
<pre><code>Addr Data
0x555 0xAA
0x2AA 0x55
0x555 0x80
0x555 0xAA
0x2AA 0x55
0x555 0x10
</code></pre>
<br />
One last thing is that we need to know when the erase function has completed. There are several ways to do so, as described in the data sheet. The lazy way to do it is to continuously read any address (I usually pick 0x000) until the data returned is 0xFF. The reason for this is that during an erase procedure, the result of any read, instead of being the data at that address, is actually a status register. The status register will never equal 0xFF, but once the chip is erased, the whole chip will be all 1's, so any read should return 0xFF. Like I said, it's the lazy way to do it.<br />
<br />
So now, we have 4 functions that pretty much handle everything that we need in order to burn code to our Flash ROM:<br />
<br />
<pre><code>
uint8_t ReadByte(uint32_t address);
void WriteByte(uint32_t address, uint8_t value);
void ProgramByte(uint32_t address, uint8_t value);
void EraseChip();
</code></pre>
<br />
Now, you have to figure out how to actually transfer data between the PC and the microcontroller. I use <a href="http://realterm.sourceforge.net/" target="_blank">RealTerm</a>, because it has the ability to transmit binary files over a serial connection. I then set up my Teensy++ main loop with a simple serial interface that resembles a command-line application, with various commands and flags, then I use RealTerm's send function for programming, and its capture function for reading. Once I've programmed the ROM, I read it back to a file, and compare the file against the original ROM file to make sure that they match (be sure you've padded your ROM file or else trim the file you read back to match the original file size or you may get an incorrect mis-match). Because I'm using the Teensy++'s CDC virtual-serial-port-over-USB interface, it would be entirely possible to write a full PC-side host application tailor-made for this device, but there really isn't much point, seeing as all it would be doing is sending a file to a serial port, or capturing data from that serial port. Better to just use an existing application, if it fits our needs, and RealTerm does just that.<br />
<br />
[Minor Edit]<br />RealTerm apparently does a really terrible job of packet utilization for USB-CDC virtual serial devices, an issue which I've <a href="http://sourceforge.net/p/realterm/bugs/52/" target="_blank">submitted to their bug tracker</a>, though it hasn't generated any response, so it's unlikely to be fixed. For that reason, I've switched to <a href="http://en.sourceforge.jp/projects/ttssh2/" target="_blank">Tera Term</a>, as it speeds up write speeds by a factor of about 20-30, which makes the difference between taking 45 minutes to burn a chip with RealTerm vs about 90 seconds with Tera Term. This doesn't change the fact that I'm still using the same code on the microcontroller side.<br />
<br />
Anyway, I'll probably throw up some more pictures at some point, but for the most part, I wanted to describe the process, rather than just handing out schematics and code. This is a relatively simple feat to accomplish, and from what I've seen of a lot of the SNES reproduction makers, I feel it should be something of a rite of passage. If you want to just go out and buy yourself a Willem, go ahead. But be warned that nobody really wants to help repro makers with their crappy Willems. Be a man, roll your own burner.<br />
<br />
Here's mine:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg240tGbi-7M8Ke1tXfFbld4ZcnZDAD_JYV8sZSlSSSZXAtFqw-EKIaCMgkdELFCer3s14jznrsznzo8SXB8mt3aSrN-KKPD-_ACeBKjiJn5dAqWc7Th0af8mi8mgpqOhPBZRaVDpdJpQwE/s1600/IMG_20130514_223831.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg240tGbi-7M8Ke1tXfFbld4ZcnZDAD_JYV8sZSlSSSZXAtFqw-EKIaCMgkdELFCer3s14jznrsznzo8SXB8mt3aSrN-KKPD-_ACeBKjiJn5dAqWc7Th0af8mi8mgpqOhPBZRaVDpdJpQwE/s640/IMG_20130514_223831.jpg" height="480" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">An original SNES MaskROM, used for my initial read-only testing</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVhBlKiFCjaatpGLiUu2ylXXx6ivfL8qAEz7lysuVF7L91b-PVn6SPR0qCe4DAq7fpIyfkLyzcRuh9MZi9nDfmFd-4PXmeZNOVw8Vx11r2Ndr-TVv-zRxWvgJXj-o2CIc_rs6gjP7Xjr7Y/s1600/IMG_20130514_223824.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVhBlKiFCjaatpGLiUu2ylXXx6ivfL8qAEz7lysuVF7L91b-PVn6SPR0qCe4DAq7fpIyfkLyzcRuh9MZi9nDfmFd-4PXmeZNOVw8Vx11r2Ndr-TVv-zRxWvgJXj-o2CIc_rs6gjP7Xjr7Y/s640/IMG_20130514_223824.jpg" height="480" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The double-sided PCB design cut down on PCB size, and as a result, cost</td></tr>
</tbody></table>
<br />qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-20057156710437301732013-06-21T17:35:00.003-07:002013-06-21T17:39:46.412-07:00Year in reviewWell, school really caught up with me, and although I've had a few pretty neat projects over the last several months, I haven't had the time to post any of them here. For one, I finally got around to trying reflow soldering, and created a <a href="http://forums.benheck.com/viewtopic.php?p=487041#p487041" target="_blank">second revision</a> of my <a href="http://blog.qwertymodo.com/2013/01/super-nintendo-classic-controller-for.html" target="_blank">SNES Wii Classic Controller mod</a> which turned out really nicely. I'm actually working on a third revision now, which may not actually be possible, but if I can manage to get it working, it'll be REALLY nice, so fingers crossed there.<br />
<br />
<br />
Another project I put a lot of time into was the Altera EMP7064S development board I built for my CST231 class. A large part of this class was devoted to building a wire-wrap board around the Altera CPLD for the purposes of simultaneously building the board and learning to program it in Verilog. I chose to put my PCB manufacturing experience to good use and go ahead and build a PCB version of the wire-wrap board we built in class. Here's the board we built in class (the wiring wasn't *quite* complete in the second photo, but it gives a pretty good indication of how much wire wrapping was involved)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG2JtLDNEUOVvMSHkpVHEYsQyMqOh4-RhUT1VF5sJRP9hY0L6swFPFCQoC3o_R0u2VpmHPlWvFLQzMi8zAbW6NPhyphenhyphenpD3cmY7fUd7G1IiGGlh1uT9I5p_epQ_FYA9-ODJyhJVqrHrV3FL1-/s1600/IMG_20130316_223630.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG2JtLDNEUOVvMSHkpVHEYsQyMqOh4-RhUT1VF5sJRP9hY0L6swFPFCQoC3o_R0u2VpmHPlWvFLQzMi8zAbW6NPhyphenhyphenpD3cmY7fUd7G1IiGGlh1uT9I5p_epQ_FYA9-ODJyhJVqrHrV3FL1-/s400/IMG_20130316_223630.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1Exk0Y2eGu151FNl6jPLL54itr1G99E2CDZU-080WK5BoVUwJ6CrM9hVTL5QKmayWFTGVLS6flXm4Zwlr3h_azYUhalRLB70MnjaYKaLa9jlmdO7hC4sWNlOcO6lWACeKokkI9FFeRwIw/s1600/IMG_20130316_180918.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1Exk0Y2eGu151FNl6jPLL54itr1G99E2CDZU-080WK5BoVUwJ6CrM9hVTL5QKmayWFTGVLS6flXm4Zwlr3h_azYUhalRLB70MnjaYKaLa9jlmdO7hC4sWNlOcO6lWACeKokkI9FFeRwIw/s400/IMG_20130316_180918.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
And here's the PCB that I made from the same schematic:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdgMaXeYFRcoCVUGVpENJ_f4m_8VyzxKYmKXiRTdVgwsuRGasXaw2Ftoec_9d0gSp8q2LgraK3m0HlKZymHANRwCeQeUAxo50yNkIyIl3Oj5fVgDe9k4W3UhQ1Mxt2vf3YQvFTy4uvF3b-/s1600/IMG_20130610_200157.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdgMaXeYFRcoCVUGVpENJ_f4m_8VyzxKYmKXiRTdVgwsuRGasXaw2Ftoec_9d0gSp8q2LgraK3m0HlKZymHANRwCeQeUAxo50yNkIyIl3Oj5fVgDe9k4W3UhQ1Mxt2vf3YQvFTy4uvF3b-/s400/IMG_20130610_200157.jpg" width="400" /></a></div>
<br />
<br />
As you can see, I made good use of surface-mount parts for the LED current-limiting resistors, as well as the traffic light LEDs. I also added a DC power jack and a 7805 regulator so I can just hook up a power plug without the need for a bench power supply. I also made a nice little clock generator from a dual 555-timer IC that plugs into the 4-pin header directly above the main chip socket, so I don't need a function generator for most stuff either. I'm pretty happy with this board. My professor really liked it too, and he bought one of the extra boards from me.<br />
<br />
<br />
In other news, I'm also still working on the Zelda: Parallel Worlds mapping/walkthrough site. I finally managed to build my first SNES reproduction cart, of ZPW, of course (I built one of Metroid: Super Zero Mission as well...), and have managed to play through the entire game on the actual console hardware, so yay :) The one major change coming to the website is that I hope to replace WorldKit with Google Maps API. I currently have a test page up and running and properly displaying the overworld map, but I'm having a few issues, most of which probably stem from my lack of understanding of the Projection class. I also have yet to try messing around with markers to see if they'll work for my purposes, but I suspect they'll do fine. So, be watching for that to roll out site-wide soon (I hope...).<br />
<br />
<br />
I have a bunch of other small projects I've been working on that aren't really in any shape for a write-up yet, lots of fun with the Super Nintendo and other stuff, but I'll get around to them eventually...qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-10910692902487576732013-01-08T23:19:00.001-08:002013-01-08T23:31:19.134-08:00Super Nintendo Classic Controller for WiiAwhile back, Nintendo released an awesome Wii controller as a Club Nintendo Japan exclusive, the Wii Super Famicom Classic Controller.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZf_P12l09p98tLqwyOyzXj6HvuD6S-fr6wUDFZ7DDuwgoYeG23EINyONV8LAO82G48c0yOkZTtTPuJfV3Xx55GhIM8m9tzNK-yRAoaM3dwVXKkmAsFL1eYD-VWxcAOiH-vwJqtRxPqNkj/s1600/pa.112911.2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZf_P12l09p98tLqwyOyzXj6HvuD6S-fr6wUDFZ7DDuwgoYeG23EINyONV8LAO82G48c0yOkZTtTPuJfV3Xx55GhIM8m9tzNK-yRAoaM3dwVXKkmAsFL1eYD-VWxcAOiH-vwJqtRxPqNkj/s400/pa.112911.2.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This thing is beautiful. The only problem is, not only is it only available through Club Nintendo, it's a Japanese exclusive. It's been out long enough to have found its way onto Ebay and other resellers, but it typically goes for about $100. Not cool, Nintendo. Not cool. There are 3rd party versions of this controller, but like the cheap Ebay knockoff SNES controllers, they're crap. So what's a guy to do? Let's build one!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So, obviously we have to start with an official SNES controller (or, just because I want to, a Super Famicom controller). I found <a href="https://gitorious.org/wii-retropad-adapter" target="_blank">this project</a> implementing a classic controller adapter in a cheap AVR microcontroller and figured I could improve the hardware design. The existing design was incredibly simple, and the AVR came in a surface-mount package, so I figured I could shrink the board sufficiently to fit it inside the controller itself. Actually, there's a ton of room inside the controller, so I could have even fit the DIP version inside if I'd wanted to. But I wanted to do better. So I did. The PCB did shrink down nicely, and here's the result:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD468bAZw-jY1BO9YOsWE9bdupb7kb-q5aAqZTcBrflJDMSRDHcWXCYFKIZVTUfjikOa1u7de__dUnSBelvh5Do573SuJPaUs8oLgcpgmHl8meBnj7pIhj7_B-nnK50kpmTxSCu1jGGV7Q/s1600/Wii+Classic+Controller.brd.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD468bAZw-jY1BO9YOsWE9bdupb7kb-q5aAqZTcBrflJDMSRDHcWXCYFKIZVTUfjikOa1u7de__dUnSBelvh5Do573SuJPaUs8oLgcpgmHl8meBnj7pIhj7_B-nnK50kpmTxSCu1jGGV7Q/s320/Wii+Classic+Controller.brd.png" width="194" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">With a minimum of external parts, the final<br />
PCB shrunk down quite nicely</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0dqtAWM8oAAM7UMb03oQfnmQYaOa3Xe_5_hwbM8tiRY65VnONTgTCuGTqgn7HxARUDyOrGUL5JrCNVzbYXFPOmmlgr8-S5Sqp-O3PwdGSkACibknvSqlIP_jDgcm4_f4uGyDc0SqKT945/s1600/IMG_20130107_193650.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0dqtAWM8oAAM7UMb03oQfnmQYaOa3Xe_5_hwbM8tiRY65VnONTgTCuGTqgn7HxARUDyOrGUL5JrCNVzbYXFPOmmlgr8-S5Sqp-O3PwdGSkACibknvSqlIP_jDgcm4_f4uGyDc0SqKT945/s400/IMG_20130107_193650.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The board fits perfectly over the pin header from the original cable</td></tr>
</tbody></table>
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3TtHwPhXeYPDnP3bKNo09E9mmCApikZz7iqh52CxioeifxCDTQNaFdDrHOoRuok5_llB7hi8H7m7LcO5UjaJcQaHfx5Pk4HJ3bdad_uxBqRopJ_lTB-0Y5Md9YQTWEPaXZVoq22psdusp/s1600/IMG_20130107_193848.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3TtHwPhXeYPDnP3bKNo09E9mmCApikZz7iqh52CxioeifxCDTQNaFdDrHOoRuok5_llB7hi8H7m7LcO5UjaJcQaHfx5Pk4HJ3bdad_uxBqRopJ_lTB-0Y5Md9YQTWEPaXZVoq22psdusp/s400/IMG_20130107_193848.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The placement of the PCB avoids all of the spacer posts, meaning no<br />
cutting or other modification to the controller shell is necessary</td></tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1VcS2ImDqwFxgSTgPNIpIKHYizaII9_HeoknlYUQ816yl5V8lY07DJgq9E3RXVVVAa2ZfKm5bULARRftsHCpyCE5x240NjWXe9BpTM2JsXNYx4gXH0OuU3uTZ1jEhBQo2eR8l48qHd15R/s1600/IMG_20130108_022214.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1VcS2ImDqwFxgSTgPNIpIKHYizaII9_HeoknlYUQ816yl5V8lY07DJgq9E3RXVVVAa2ZfKm5bULARRftsHCpyCE5x240NjWXe9BpTM2JsXNYx4gXH0OuU3uTZ1jEhBQo2eR8l48qHd15R/s400/IMG_20130108_022214.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Voila!</td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can find more info, including source and PCB design files, at the <a href="https://sites.google.com/a/qwertymodo.com/www/hardware-projects/super-nintendo-classic-controller-for-wii" target="_blank">project page</a> on my site.</div>
qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com7tag:blogger.com,1999:blog-2953283389087359631.post-4860017084793707832012-11-07T23:15:00.000-08:002012-11-07T23:43:05.492-08:00Arduino HID Gamepad, Part 2Well, I'm finally getting around to moving forward with my Arduino HID Gamepad project (<a href="http://blog.qwertymodo.com/2012/07/arduino-hid-gamepad-part-1.html" target="_blank">part 1 here</a>). I finished the wiring on the gamepad shield, and started trying to get the gamepad device report descriptor and event handlers added to the Arduino libraries. First of all, you need to add the device report descriptor to HID.cpp, located in hardware\arduino\cores\arduino. Sorry, I can't explain this very well, I barely understand it myself, but <a href="http://www.frank-zhao.com/cache/hid_tutorial_1.php" target="_blank">this page</a> helped me stumble through. Add the following to const u8 _hidReportDescriptor[] (near the top of the .cpp file), above the #if RAWHID_ENABLED directive:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //<span class="Apple-tab-span" style="white-space: pre;"> </span>Gamepad</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x05, 0x01, // USAGE_PAGE (Generic Desktop)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x09, 0x05, // USAGE (Game Pad)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0xa1, 0x01, // COLLECTION (Application)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0xa1, 0x00, // COLLECTION (Physical)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x85, 0x03, // REPORT_ID (3)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x05, 0x09, // USAGE_PAGE (Button)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x19, 0x01, // USAGE_MINIMUM (Button 1)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x29, 0x08, // USAGE_MAXIMUM (Button 8)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x15, 0x00, // LOGICAL_MINIMUM (0)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x25, 0x01, // LOGICAL_MAXIMUM (1)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x95, 0x04, // REPORT_COUNT (4)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x75, 0x01, // REPORT_SIZE (1)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x81, 0x02, // INPUT (Data,Var,Abs)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x05, 0x01, // USAGE_PAGE (Generic Desktop)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x09, 0x30, // USAGE (X)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x09, 0x31, // USAGE (Y)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x15, 0xff, // LOGICAL_MINIMUM (-1)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x25, 0x01, // LOGICAL_MAXIMUM (1)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x95, 0x02, // REPORT_COUNT (2)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x75, 0x02, // REPORT_SIZE (2)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0x81, 0x02, // INPUT (Data,Var,Abs)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0xc0, // END_COLLECTION</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 0xc0 // END_COLLECTION</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: inherit;">This defines a 2-axis, 4-button gamepad. Next, you need to add the Gamepad class and event handlers to USBAPI.h:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">class Gamepad_</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">private:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>uint8_t _buttons;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">public:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Gamepad_(void);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>void begin(void);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>void end(void);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>void press(uint8_t b);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>void release(uint8_t b);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>bool isPressed(uint8_t b);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">};</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">extern Gamepad_ Gamepad;</span><br />
<br />
<br />
Now you need to put the class definitions in HID.cpp:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">//================================================================================</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">//================================================================================</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">//<span class="Apple-tab-span" style="white-space: pre;"> </span>Gamepad</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Gamepad_::Gamepad_(void) : _buttons(0)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void Gamepad_::begin(void)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void Gamepad_::end(void)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void Gamepad_::press(uint8_t b)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>_buttons |= b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>HID_SendReport(3,&_buttons,1);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void Gamepad_::release(uint8_t b)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>_buttons &= ~b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>HID_SendReport(3,&_buttons,1);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">bool Gamepad_::isPressed(uint8_t b)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if ((b & _buttons) > 0) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return true;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return false;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span><span style="font-family: inherit;">Finally, you need to instantiate the Gamepad singleton. At the top of HID.cpp, add the following line under the Mouse and Keyboard instantiations:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Gamepad_ Gamepad;</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Now, you should be able to call Gamepad.begin() in your sketch setup() function, and then call Gamepad.press() and Gamepad.release() to send button press and release reports. As you can see, Windows now recognizes my new 2-axis, 4-button gamepad :)</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNPFdLdOE4tR7u9iUcB08j9chZHg9hw7wiy86MTTiUC46s9Q_ghHPFG6ZSEDlCHnEoyIzM1nM5tkIpISVSIrR9SGkKdM1YpSDIoQ8rsLY4u1MmDtnSO2Rj0-2gkp82w9QM4XNc7NO5exNk/s1600/LeonardoGamepad.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNPFdLdOE4tR7u9iUcB08j9chZHg9hw7wiy86MTTiUC46s9Q_ghHPFG6ZSEDlCHnEoyIzM1nM5tkIpISVSIrR9SGkKdM1YpSDIoQ8rsLY4u1MmDtnSO2Rj0-2gkp82w9QM4XNc7NO5exNk/s320/LeonardoGamepad.png" width="287" /></a></div>
<span style="font-family: inherit;"><br /></span>
<br />
<br />qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-62154366643930593382012-10-23T12:22:00.000-07:002012-10-23T12:22:01.679-07:00I have a domain :)I just finished registering my very own domain :) This blog can now be found at <a href="http://blog.qwertymodo.com/">blog.qwertymodo.com</a>, and my Zelda: Parallel Worlds mapping site can be found at <a href="http://zelda.qwertymodo.com/">zelda.qwertymodo.com</a>.qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-43608755866008448142012-10-16T22:56:00.000-07:002012-10-16T22:56:15.135-07:00Non-volatile N64 Controller PakEver since I read <a href="http://forums.benheck.com/viewtopic.php?f=5&t=37099" target="_blank">this post</a> on the BenHeck forums about modding an N64 Controller Pak to eliminate the need for a battery to maintain the save data. I decided to take it one step further and build one from scratch. The first step was to draw up the schematic for the existing Controller Pak, and modify it from there. For that, I needed a pinout for the card edge. I found one with a few errors, used it to fill out the schematic, and determined the function of the remaining contacts from there. Here's the working pinout:<br /><br />
<pre style="white-space: pre-wrap; word-wrap: break-word;"> Pin Name
--------------
1 GND
2 A14
3 A12
4 A7
5 A6
6 A5
7 A4
8 A3
9 A2
10 A1
11 A0
12 D0
13 D1
14 Detect*
15 3V3
16 D2
17 GND
18 CE1
19 /CE2
20 /WE
21 A13
22 A8
23 A9
24 A11
25 /OE
26 A10
27 D7
28 D6
29 D5
30 D4
31 3V3
32 D3</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">
</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">The Detect line is pulled low inside the controller through a pull-down resistor. The Controller Pak connects Detect to 3V3 to indicate the presence of a cart in the slot (this is true for both the Controller Pak and the Rumble Pak; the controller determines which type of cart it is by strobing a specific address and reading the response).</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">
</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">From this, it's fairly trivial to connect an FRAM chip in place of the original SRAM. I chose to use the Ramtron FM28V020, though the any of the FM18*08 chips should work as well. If we don't really care about the dual CE lines, we can ignore CE1 and connect /CE2 directly to the RAM. After that, all that is needed is a pull-up resistor on the /CE line (10Kohm is a good value) and a smoothing cap between 3V3 and GND (100nF is good).</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">
</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">I'll be working on a 4x version soon, using a 1Mbit FRAM chip (Ramtron FM28V100). The basic wiring for this is the same as above, but add pull-up resistors on the A15 and A16 lines, then connect those lines to a 4-position switch that connects to GND. Use diodes to isolate the connections between the address lines and the switch, since one position on the switch will pull both lines to GND, but you don't want *every* position to do that.</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">
</pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">If you'd like to buy a pre-assembled, nonvolatile N64 Controller Pak (1x or 4x), shoot me an email. I have a lot of extras sitting around...</pre>
qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-36600816169019988562012-08-29T01:03:00.000-07:002012-08-29T01:03:05.845-07:00Progress on Parallel WorldsWell, in case you haven't seen it (or haven't seen it recently), head over to <a href="http://parallelworldsmaps.appspot.com/" target="_blank">http://parallelworldsmaps.appspot.com</a> to check out the new visual overhaul I've finally given to my mapping project for the game Legend of Zelda: Parallel Worlds. For those of you who don't know, Parallel Worlds is a ROM hack of Legend of Zelda: A Link to the Past, resulting in a completely new game, with all an all-new story, fully redone dungeons and maps, and some minor graphical changes to go with all that. The game is HARD. Like, Contra hard. And what's worse is, because the map and dungeons are all new, there aren't any maps to show you where everything is when you inevitably get lost. I have found a single walkthrough floating around on the internet that has maps, but other than that, you're s.o.l. So, I took it upon myself to map the entire game, in full, lossless resolution. After completing the Light World Overworld map (well, I still have some touch-up work to do...), I discovered an awesome piece of software called <a href="http://worldkit.org/" target="_blank">Worldkit</a> which would allow me to turn my shiny new really-big-picture into a fully interactive map with zoom and pan, as well as geotag annotations for tagging items and important landmarks. So I got it all loaded up and decided to host it on Google's App Engine framework (which is kind of a weird use of the App Engine framework, but there are plenty of other people hosting static websites on GAE, so whatever...). As of yet, I can't seem to get annotations working on the web (they work great on the local dev server that comes with the GAE SDK... frustrating), but I have finally gotten around to giving the page itself a facelift from the previous blank-page-with-embedded-flash-object-slapped-into-the-corner. It is now a presentable web page, with a nice template that will allow me to easily deploy new pages as I finish the maps. Also, speaking of finishing maps, I managed to map all of Din's Catacombs, which is a pretty nice achievement (if I do say so myself) in that the entire dungeon is normally pitch-black, making mapping via screenshot extremely tedious at best and nearly impossible at worst. The walkthrough I mentioned earlier with screenshots of all of the dungeons actually doesn't have one for Din's Catacombs. So I may be the first to have mapped it. Go me :) Anyway, the Din's Catacombs page is a bit of a mess right now, I was trying out a different template which really isn't working so well, but I'll fix it up soon. I've also started work on the Icy World Overworld map, which I currently have about 20% complete, so hopefully that will be online soon as well.qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-16763519896280228902012-08-17T12:02:00.001-07:002012-08-17T12:02:31.346-07:00New Zelda: Parallel Worlds Interactive MapI have discovered a means to make my Zelda Parallel Worlds mapping project much more interesting and useful by creating a fully interactive map with navigation and annotation features using an awesome piece of software called <a href="http://worldkit.org/">WorldKit</a>. I am hosting the project using Google's App Engine framework, and have uploaded my current Light World overworld map to test the software and deployment functionality. I have not yet added any annotations (and I probably won't until I have the Icy World map done), but you can test the zoom and pan features. Unfortunately, the zoomify software I'm using to generate the zoom tiles only works with JPEG images, so it does get lossy at full zoom, but I suppose that's really the best route to go anyway, then I can offer the full-resolution, lossless PNG for download from a separate link. I'm still brushing up on my HTML so I can actually have a nice page rather than the current blank page with the embedded map viewer. It's a work in progress, but check it out at <a href="http://parallelworldsmaps.appspot.com/" target="_blank">http://parallelworldsmaps.appspot.com/</a><span id="goog_1239455263"></span><span id="goog_1239455264"></span><a href="http://www.blogger.com/"></a>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-15647601350575396212012-07-24T08:05:00.000-07:002012-07-24T08:05:11.331-07:00The Legend of Zelda: Parallel Worlds Mapping ProjectI've decided to undertake the mapping of the Zelda 3 ROM hack called Parallel Worlds. Being a hack, not a lot of documentation exists out there other than a few walkthroughs, almost all of which are exclusively text-based, and many of which are incomplete. I've decided to create a full-resolution map of all areas of the game, starting with the overworld(s) and then moving on to the dungeons. So far, I have a significant portion of the Light World Overworld completed, and so I've decided to start a page to publish my progress. You can check it out <a href="http://qwertymodo.blogspot.com/p/the-legend-of-zelda-parallel-worlds-maps.html">here</a>. You can check out the hack's homepage at <a href="https://sites.google.com/site/zeldaparallelworlds/">https://sites.google.com/site/zeldaparallelworlds/</a>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com1tag:blogger.com,1999:blog-2953283389087359631.post-36976393613601306542012-07-13T21:28:00.002-07:002012-11-07T23:39:24.736-08:00Arduino HID Gamepad, part 1<span style="font-family: inherit; font-size: x-small;">Note: This post mostly outlines my shield design and a quick test of the hardware using the Mouse example included with the Arduino library. If you're looking for the actual HID gamepad implementation, have a look at <a href="http://blog.qwertymodo.com/2012/11/arduino-hid-gamepad-part-2.html" target="_blank">part 2</a></span><br />
<br />
I have been thinking for quite some time about a project which I hope to shape into a Senior Project for my Embedded Systems and Software Engineering degrees, but I've gotten a bit impatient and have kind of jumped the gun to start working on it. The first step in this project requires implementing a generic HID gamepad. The Arduino Leonardo recently launched with USB HID profile support, thanks to the on-chip USB support of the on-board Atmega32U4 microcontroller. This makes prototyping much simpler, and it actually reduces the cost of the Leonardo compared to the Uno--which is otherwise the most comparable Arduino model out there--due to not needing a separate microcontroller to handle the USB-serial connection. Now, I know there are a lot of Arduino haters out there, but the fact is, it is fantastic for prototyping. I get as annoyed as anybody when I see somebody enclose an entire Arduino into a finished product rather than redesigning for the bare microcontroller (which I fully intend to do), but it's a nice prototyping platform with great community support.<br />
<br />
Anyway, I got my Leonardo today and immediately loaded up the button mouse example sketch to try it out and lo and behold, it just worked. Well, it would have just worked if I had built the circuit the way I was supposed to. As it was, I didn't feel like breadboarding it with pull-down resistors, so I changed the code around to enable the internal pull-up resistors and then changed the logic to be low-triggered rather than high-triggered:<br />
<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">const int upButton = 2; </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">const int downButton = 3; </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">const int leftButton = 4;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">const int rightButton = 5;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">const int mouseButton = 6;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">int range = 5; // output range of X or Y movement; affects movement speed</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">int responseDelay = 10; // response delay of the mouse, in ms</span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">void setup() {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // initialize the buttons' inputs:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> pinMode(upButton, INPUT); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> pinMode(downButton, INPUT); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> pinMode(leftButton, INPUT); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> pinMode(rightButton, INPUT); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> pinMode(mouseButton, INPUT);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> digitalWrite(upButton, HIGH);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> digitalWrite(downButton, HIGH);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> digitalWrite(leftButton, HIGH);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> digitalWrite(rightButton, HIGH);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> digitalWrite(mouseButton, HIGH);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // initialize mouse control:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Mouse.begin();</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">void loop() {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // read the buttons:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int upState = digitalRead(upButton);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int downState = digitalRead(downButton);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int rightState = digitalRead(rightButton);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int leftState = digitalRead(leftButton);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int clickState = digitalRead(mouseButton);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // calculate the movement distance based on the button states:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int xDistance = (leftState - rightState)*range;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> int yDistance = (upState - downState)*range;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // if X or Y is zero, move:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if ((xDistance == 0) || (yDistance == 0)) {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Mouse.move(xDistance, yDistance, 0);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // if the mouse button is pressed:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if (clickState == LOW) {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // if the mouse is not pressed, press it:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if (!Mouse.isPressed(MOUSE_LEFT)) {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Mouse.press(MOUSE_LEFT); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> } </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // else the mouse button is not pressed:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> else {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // if the mouse is pressed, release it:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if (Mouse.isPressed(MOUSE_LEFT)) {</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Mouse.release(MOUSE_LEFT); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // a delay so the mouse doesn't move too fast:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> delay(responseDelay);</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
Anyway, the next thing to do was to build myself a gamepad that I could plug in to the Leonardo for testing. I plan to use the SNES controller in my final project, but for prototyping, I decided to go with NES instead. The NES uses the exact same control protocol as the SNES, just with fewer buttons, so that meant fewer parts, as well as fewer IO pins for my debug setup. I had a few empty protoshields lying around, so I figured that would be perfect for this build. I also had a CD4021 shift register in my parts drawer from an NES controller I cannibalized awhile back. If you're looking to build a DIY NES controller, please, for heaven's sake, just go out and buy a 4021 and a few resistors and do it from scratch. Don't destroy an NES controller just for its IC. I've seen so many <a href="http://ultra-awesome.blogspot.com/2008/05/nes-coffee-table-final-post-rah.html">awesome mods</a> that just piss me off because after all that hard work, they have <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmapPpX0IugWDCo3Lg8C8bQLZBlwFUKtP02AWnSjySMkhBQLcaq_6iQUVFVeA13-c7rqqjS8kl5zu2DGKBC0VODYYBG679ag0F3zTCi47tuGLjQIaC6HyuqZYLbgBfRTVMY4fXLsh6ssGc/s1600-h/4.JPG">this wiring</a> on the inside. Seriously, <a href="http://www.jameco.com/webapp/wcs/stores/servlet/Product_10001_10001_12829_-1">this is all you need</a> (plus a couple of resistors). Or, if you want to get really fancy, hit me up for <a href="http://forums.benheck.com/viewtopic.php?f=57&t=49986">one of these</a> (scroll down to my last post for a picture with a size comparison to an SD card. Anyway, despite that rant, I used the IC from an original controller, because I had already used the rest of the controller for various other stuff, and happened to have the IC left over. I have a stash of the SMD 4021's, but alas, the protoshield's SOIC footprint is only 14 pins, so I needed the DIP version, and this one was the only one I had.<br />
<br />
Ok, now that I'm done with that rant, time for pictures :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg87obBG9Og9qxxc5xnzeh15qyBAIVnrwLf5T8QKZTWum94Z54Fmm_vg1LdykjhRywGNGTn9I8UdLXOspvaIgRyN4nOUw2PujiqUx8PodP_LrJnXbP1U47pmLe_BoEIOF3LtsU40ly3alii/s1600/IMG_20120713_183439.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg87obBG9Og9qxxc5xnzeh15qyBAIVnrwLf5T8QKZTWum94Z54Fmm_vg1LdykjhRywGNGTn9I8UdLXOspvaIgRyN4nOUw2PujiqUx8PodP_LrJnXbP1U47pmLe_BoEIOF3LtsU40ly3alii/s320/IMG_20120713_183439.jpg" width="320" /></a></div>
I ran out of solder, so nothing is connected yet. However, all of the parts are mounted, so I just need to get more solder (and perhaps some finer gauge wire than what I have on hand at the moment would be good too). Apparently, RadioShack no longer carries through-hole mounted tact switches, but thankfully, the spacing on the SMD feet lined up well enough with the board holes. The plan is to hook each button up directly to a digital I/O, as well as hooking them up to the 4021 and connecting its latch, clock, and data lines to the remaining digital IO's in order to implement the NES protocol as well. This way, I can read the buttons either directly or via the NES protocol all from the same shield configuration.<br />
<br />
<br />
Also, in case you're looking for the correct stacking headers for the Arduino shields, I've managed to track down a manufacturer that makes them. Unfortunately, the stackable header kits on SparkFun and elsewhere don't actually have the right pin counts. They sell kits with 2x6-pin headers and 2x8-pin headers. Arduino shields actually use 1x6, 2x8, and 1x10. You don't, strictly speaking, need the other four pins, but all of the official shields have them. Digikey carries these headers, but they don't seem to carry them with tails quite as long as the ones on official shields. There's not a lot of clearance with the ones I have. So anyway, here are part numbers for the headers that you'll want, they aren't quite the same as the ones Digikey has (DK carries the -03 variety rather than the -04, which I explain below).<br />
<br />
<br />
Samtec<br />
1x10 pins: SSQ-110-04-T-S<br />
1x8 pins: SSQ-108-04-T-S<br />
1x6 pins: SSQ-106-04-T-S<br />
<br />
<br />
Some variations on these part numbers:<br />
-04 is the length of the tail. -03 or shorter will make for very little clearance above the barrel jack. On the older boards with full-sized USB-B plugs, you won't be able to clear the USB jack. However, Digikey doesn't seem to carry anything longer than -03. If you can find another distributor that stocks the longer tails, let me know in the comments<br />
<br />
<br />
-T is tin plated pins, replace it with -G for gold plated.<br />
The -110, -108, and -106 are the pin count. If you want dual row, the numbering is -2XX (i.e. -205 would be 2x5 pins, etc.).<br />
<br />
Anyway, that's it for now. I'm super busy working two jobs this summer, so hopefully I'll get some free time now and then to work on some of this stuff. Once I get USB HID down, I plan to move on to bluetooth HID (which is just a simple wrapper around the USB HID protocol, so it should be simple enough). Then I'll be working on building the host module. Fun times.<br />
<br />qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com2tag:blogger.com,1999:blog-2953283389087359631.post-46247649139197606782012-06-22T23:24:00.000-07:002012-11-18T23:31:16.516-08:00Today is a good day. On Monday, I randomly made an image and posted it on Twitter, @wilw (Wil Wheaton). He called it "awesome" and reposted it to the world. "Awesome" is exactly how I feel right now.<div>
<br /></div>
<div>
<a href="http://wilwheaton.tumblr.com/post/25351167078/this-was-made-by-qwertymodo-and-it-is-awesome">http://wilwheaton.tumblr.com/post/25351167078/this-was-made-by-qwertymodo-and-it-is-awesome</a></div>
qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com1tag:blogger.com,1999:blog-2953283389087359631.post-9481167436653787252011-12-26T23:59:00.000-08:002012-01-23T16:57:28.904-08:00Migrating your Droid X to CyanogenModI recently migrated from a stock Gingerbread Moto Blur install of Android on my VZW Droid X to CyanogenMod7 (specifically RevNumbers's CM4DX-GB kang, if you happen to care) and found it to be a rather arduous task to carry all of my data and settings to the new ROM. I was talking to my cousin over Christmas break and she was curious to learn how to go about doing it as she had never installed a custom ROM before and needed step-by-step instructions (as she didn't feel like bricking like I did a good dozen times or so while I was figuring all of this out). So I figured I would try to compile a step-by-step guide of how to go from stock to CM7 with *almost* everything still intact.<br />
<div>
<br /></div>
<div>
I will start by outlining the process and then going back and filling in the details as I get the chance, so this may be a bit sparse in some steps until I get more time. I'll probably do a ToC section link block too eventually, but it's late and I'm just throwing this all down before I go to bed. Also, there are steps in here specific to the Droid X because that's what I have, but some of this information may be useful to other phones as well.<br />
<br />
<span style="font-size: large;">Update your device</span><br />
<span style="font-size: small;">NOTE: If you are currently on Froyo and have already rooted your phone, you need to back up your apps and data first, then sbf to a fresh install of Froyo, then continue. Updating to stock GB from rooted Froyo messes up your ability to root on GB. If you have never rooted before, these aren't the warnings you're looking for, move along. </span><br />
<br />
<span style="font-size: small;">To begin with, you want to make sure you are running the most up-to-date version of Android available from Verizon. The reason for using an official update is that there are some things that cannot be updated (or are more difficult to update) from unofficial sources. These include the kernel and the baseband (the firmware for your phone's radio), and perhaps other things I don't know about. You can check what version you are currently running by pressing the Menu key and selecting Settings>About Phone.</span><br />
<br />
<span style="font-size: small;">As of this posting, the current Android System version available from Verizon for the Droid X is 2.3.3, and the current Baseband version is BP_C</span>_01.09.13P. If you have these versions, you're set. Otherwise, hit Check For Updates. Go ahead and let the update finish and your phone should reboot.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Root your device</span></div>
Once you're running stock Gingerbread, you can go ahead and root your phone. Read up on how to do that <a href="http://rootzwiki.com/topic/3216-rootunroot-droid-3-root-instructions-one-click-added-for-windows-linux-osx/">here</a> (it says it's for the Droid 3, but it works just fine for the Droid X). NOTE: DO NOT TRY THIS IF YOU PREVIOUSLY HAD ROOT ON FROYO WHEN YOU UPDATED TO GB. If this is the case, you will have to sbf before rooting, meaning you won't be able to do a full backup. Backup what you can, sbf, and then root.<br /><div>
<br /></div>
<div>
<span style="font-size: large;">Install useful tools</span></div>
<div>
The 3 most useful applications I have found for dealing with data backup, ROM customization, and other stuff here are ROM Manager, ROM Toolbox, and Titanium Backup. All 3 of these have free versions and are available in the Android Market. I suggest purchasing the Pro versions of each, they have additional features and plus you'll be supporting the developers that make this stuff possible. If you don't want to purchase them all, I would say ROM Toolbox and Titanium Backup are the most worth it. Regardless, install whichever version you wish but get all 3 apps.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Install ClockworkMod Recovery</span></div>
<div>
Open ROM Manager and click Flash ClockworkMod Recovery. If you're on the Droid X, when it asks you to confirm phone model, you have the choice between Droid X and Droid X (2nd init). Select the one that says 2nd init. The other option is currently useless because 2nd-init is required since the bootloader is locked and it won't work without 2nd-init. If it prompts you for superuser access, say yes and check the box to remember (basically just do this any time you get this prompt as long as you trust the app; the 3 apps I am using in this guide are all trustworthy).</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Understanding each type of backup</span></div>
<div>
There are two main backups going on here, a NANDroid backup and a Titanium Backup, then there is the SMS backup. There is a reason you are doing both of these. The NANDroid backup is a system image that allows you to restore your entire phone back to the state it was in at the moment you create the backup. The Titanium backup backs up all of your applications and associated data in a format that you can then reinstall once you have flashed your new ROM. This allows you to reinstall all of your apps without having to download them all, and also retains all of your data like game saves and such. Backing up your SMS allows you to keep all of your text messages (but so far there doesn't seem to be a way to back up your MMS, so you'll need to have saved any photos to your SD card manually). The SMS database in the stock ROM is incompatible with the one that CyanogenMod uses, so you'll have to use a 3rd party backup solution that stores the messages in a separate format.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Create a Nandroid (system image) backup</span></div>
<div>
<b>Note: The size of a Nandroid backup will vary, but I would suggest having at least 1.5-2GB free on your SD card before attempting this</b></div>
<div>
Once you have flashed ClockworkMod Recovery, click Reboot into Recovery. Your phone should reboot and you will be in a text based menu. You navigate the menu with the volume up/down buttons, the camera button to select, and the hardware "back" button to return to the previous menu. The power button just turns the screen on and off so if you accidentally hit it and the screen goes off, just hit it again and it will come back. Select backup and restore->backup and then just wait for it to complete. Once it's done, back out to the main menu and select reboot phone now.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Backup your applications and data</span></div>
<div>
<b>Note: The size of the backup will vary greatly depending on how many apps you have installed and what you choose to back up. Again, I suggest having at least 1GB free on your SD card before attempting the backup.</b></div>
<div>
Open Titanium Backup and press the hardware Menu button and select Batch. At the very least, select Backup all user apps, but you can backup system data if you want too. You won't be able to restore the system data into an incompatible ROM, but if it gives you peace of mind to have it backed up, go for it.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Backup your text messages</span></div>
<div>
There are many ways to backup SMS messages, but if you use a 3rd party SMS client, it may very likely have the option to back up your messages. I use GoSMS Pro, and the option is found by pressing the hardware Menu button and going to the Services tab and selecting SMS B&R.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Install CyanogenMod (CM4DX-GB)</span></div>
<div>
Because the Droid X has still not received a stable release of CyanogenMod, you're stuck installing a nightly release. Also, the mainline CM7 does not support the Gingerbread kernel, so you'll want to install the RevNumbers releases, which do support the GB kernel. The kernel does not get updated when you install a ROM, so you need to already have the correct kernel installed before you flash the ROM or you will brick your phone. Open ROM Toolbox (since the RevNumbers Nightlies in ROM Manager are not kept up-to-date) and select ROM Manager (the button inside of ROM Toolbox, not the app named ROM Manager). Under the ROM list select RevNumbers CM7 Nightlies (you can pick any ROM you want, but I highly suggest CM7, at least for your first ROM). Pick the newest version and select download. Wait for the download to finish. Also download the latest version of Google Apps, or you won't have an Android Market.<br />
<br />
Update: For more up-to-date releases of CM4DX-GB, follow <a href="http://rootzwiki.com/topic/10191-updated-info-on-revnumbers-cm4dx-gb/">this thread</a>, as ROM Toolbox hasn't updated their list in quite awhile. </div>
<div>
<br /></div>
<div>
I'm going to outline how to install the ROM manually, since ROM Toolbox hasn't been working right with automating ClockworkMod Recovery tasks, although they may have fixed that, I don't know...</div>
<div>
<br /></div>
<div>
In the main menu of ROM Toolbox, select Rebooter, then Reboot Recovery, and you should be back to the text menu of ClockworkMod Recovery. Select Factory Reset/wipe data, then select install update zip. Choose select zip from sd card and browse to romtoolbox/downloads/RevNumbers and select the zip in that folder (or browse to the location where you downloaded it, if you got an updated release from the forum thread above). Repeat with romtoolbox/downloads/gapps. Now reboot your phone and (if all goes well), it should boot into CyanogenMod. The first boot WILL take a long time, but if it just plain doesn't boot, check out the troubleshooting guide below.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Restore your applications</span></div>
<div>
Install Titanium Backup. Batch>Restore User Apps (NOT system data)</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Restore your text messages</span></div>
<div>
Use the same app you used to back them up in the first place</div>
<div>
<br /></div>
<div>
TROUBLESHOOTING</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Unbricking</span></div>
<div>
It's late, I'm getting tired, for now, Google "[your phone model] Gingerbread sbf" to get the files and probably a guide. You'll also need an app called RSD Lite, the latest version (AFAIK) is 4.9. There is a bug in the software resulting in an error, something like invalid file or filename or something I don't remember, but that error is bogus and there is a workaround I'll get around to posting later... bah... should be enough info to get started, so for now goodnight.</div>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-29696967012710415072011-06-03T21:00:00.000-07:002012-03-14T00:10:52.167-07:00Build and install custom Rock Band DLC on an unmodded XBox 360<b>UPDATE:</b> <a href="http://rockband.scorehero.com/forum/viewtopic.php?t=34542">RB3Maker</a> can do a lot of this automatically, including album art conversion. I still prefer doing it manually so that I can pack it for RB2 instead, but it's a really nice tool, and if he ever adds support for outputting RB2 .con's then I may convert to that method entirely. If you want to continue to use this guide, I believe RB3Maker can be used in place of MahoppianGoon's DLC Tools to extract the .rba, and you can also use it to convert the album art for you.<br />
<br />
I have been a long-time user of <a href="http://rawksd.japaneatahand.com/wiki/Main_Page">RawkSD</a> for custom Rock Band DLC (user-made songs) on the Wii, but just recently heard that it was possible to install custom DLC on an un-modded XBox 360. I got really excited about this, since the Wii version of Rock Band 3 is so full of software bugs that it never should have been released in its current state, and because of the way the Wii is, it will most likely (99% certainty) never receive an update to fix these bugs. With XBox 360 customs possible on an unmodded console, I can enjoy customs, a better engine, and the improvements made in the newest installment of the game, all without wanting to tear my hair out on a regular basis. Also, since the XBox 360 already supports the internal HD for saving DLC, I also get that particular upgrade over the Wii without any need for additional hacks (which tend to increase the frequency of Rock Band entirely freezing on my Wii).<br />
<br />
Anyway, enough random backstory and on to the actual build-and-install. MahoppianGoon <a href="http://sites.google.com/site/mahoppiangoon/customrbdlc">has a great tutorial already</a>, but many of the steps require manually creating files that you could just use Harmonix's official tools to create for you, so this guide will show you step-by-step how to set up and use Magma, Harmonix's official Rock Band Network tool, to create the files necessary for custom DLC and then how to repack and install them.<br />
<br />
Note: This is for Rock Band 2 DLC, not Rock Band 3. Really the only reason you would need to create RB3 DLC is if you want to chart keyboard or PRO Guitar, as you can play Rock Band 2 DLC in Rock Band 3 as-is. Also, since this is RB2 DLC, you will need Magma v1, which is no longer available on the RBN download site, so I have mirrored it.<br />
<br />
First of all, here are the programs you will need:<br />
<a href="http://dl.dropbox.com/u/28075862/Rock%20Band/Magma/MagmaSetup_1.20.exe">Magma v1.20</a><br />
<a href="http://audacity.googlecode.com/files/audacity-win-unicode-1.3.13.exe">Audacity 1.3.13 beta</a><br />
<a href="https://sites.google.com/site/mahoppiangoon/home">MahoppianGoon's DLC Tools</a><br />
<a href="http://skunkiebutt.com/Le%20Fluffie%20App.zip">Le Fluffie</a><br />
<a href="http://www.game-tuts.com/community/modio.php">Modio</a><br />
<a href="http://dl.dropbox.com/u/28075862/Rock%20Band/GH2ImageCon.exe">GH2ImageCon</a><br />
<br />
Now to start building your custom DLC.<br />
<br />
Skip to:<br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#MIDI">Chart/MIDI</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#Audio">Audio</a><br />
-<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#Dryvox">Recording a dryvox track (for lipsync animations)</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#Magma">Magma</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#Extracting">Extracting the RBA</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#DTA">DTA Editing</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#Art">Album Art</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#LeFluffie">Building the DLC file</a><br />
<a href="http://qwertymodo.blogspot.com/2011/06/build-and-install-custom-rock-band-dlc.html#Installing">Installing</a><br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="MIDI"></a><br />
<span style="font-size: large;">Chart/MIDI</span><br />
For the purpose of this tutorial, I am going to assume you already have your .mid file created. If not, check out <a href="http://rockband.scorehero.com/forum/viewforum.php?f=1039&sid=6b66010dcda913409f4c9ce8ed85ff3f">the Rock Band section of ScoreHero</a> for tips on charting, or download one from someone else.<br />
<br />
Some things to note:<br />
Magma v1.20 introduced the requirement that all difficulties of guitar use all 5 gems. If your chart does not do this, it won't pass the midi check stage of the compiler. You can try <a href="http://dl.dropbox.com/u/28075862/Rock%20Band/Magma/MagmaSetup_1.10.exe">v1.10</a> if this is your chart's only issue.<br />
<br />
If you absolutely don't want to get your chart up to Magma's specs (which is usually a crash waiting to happen), you can use <a href="http://dl.dropbox.com/u/28075862/Rock%20Band/barebones.mid">this .mid</a> in Magma to get your song to compile. Just be sure to use your real .mid in the final .con file. Also, if you use that .mid and your song has a vocals track, use <a href="http://dl.dropbox.com/u/28075862/Rock%20Band/barebones_dryvox.wav">this file</a> for your dryvox audio.<br />
<br />
If you want lipsync animations, in addition to creating the dryvox audio (described in the audio section), you WILL have to fix your chart to pass Magma's checks, and you will need to have charted vocals. Otherwise, Magma won't be able to generate lipsync animations.<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="Audio"></a><br />
<span style="font-size: large;">Audio</span><br />
UPDATE: I have come up with a method for creating .mogg files longer than Magma's normal 12 minute limit. Magma still won't allow a MIDI file longer than that, but you can get around that by feeding Magma a dummy MIDI file then swapping it out in the final .con. However, you lose Magma's validity parsing ability if you don't feed the real .mid to it, so proceed with caution. The tool is <a href="http://rockband.scorehero.com/forum/viewtopic.php?p=655652#655652">here</a>.<br />
<br />
If you somehow happen to possess actual master tracks for the song you're working with, you simply need to mix down each instrument's track into a stereo, 44.1kHz WAV file. If you're not so lucky and are just using a stereo audio file for your song, you will need to do the same, but most likely it will require a few extra steps.<br />
<br />
First, open your audio file in Audacity.<br />
<br />
Next, you need to determine whether or not the song requires an audio delay (this will most likely have been indicated on the page where you got the chart).<br />
<br />
If your audio needs a delay, make sure the cursor is at the beginning of the song (by pressing the <|<| button while the song is stopped) and select Generate>Silence. Type in the length of silence (you may have to change the time breakdown in the drop-down menu to allow you to enter milliseconds) and press Ok.<br />
<br />
Select File>Export and select WAV under Save As type.<br />
<br />
Next, if you don't have master tracks, you're going to need blank audio tracks. First, delete the current audio tracks by clicking the X in the upper left corner of the track. Then select Tracks>Add New>Stereo Track. Then select Generate>Silence and enter 60 seconds. Export this track as WAV.<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="Dryvox"></a><br />
Finally, the dryvox track. If you don't care about lipsync animations, or your chart doesn't have a vocals track, you can skip this part. If you want lipsync animations, you need to record yourself singing along to the song. If you can't sing very well, I suggest you get a friend who can to do it for you, or just skip this part. Also, you MUST HAVE A VOCALS CHART or else you can't generate lipsync animations, so just skip this.<br />
<br />
First of all, open the first WAV you exported from Audacity back into Audacity (remove any other tracks that might be there).<br />
<br />
Open the Device Toolbar (View>Toolbars>Device Toolbar) and next to the microphone icon, select the input you are going to use (Note: the Logitech universal USB microphone works as a plug-and-play microphone on Windows).<br />
<br />
Hit the record button and make some noise into your microphone to test that it's working. Hit stop to stop recording, then delete the recording you just made.<br />
<br />
Make sure that you can actually hear the song playing while you are recording. If not, select Edit>Preferences>Recording and check the box that says "Overdub: Play other tracks while recording new one"<br />
<br />
Now, hit record and sing along to the song and hit stop when the song is done.<br />
<br />
Tips:<br />
-Enunciate well. You actually have to sing the words. If you just hum along, the animations are going to do the same thing and that defeats the purpos.<br />
<br />
-Sing the right notes. If you don't sing the right notes, the weights compiler will factor that into the scoring for the song<br />
<br />
-Use headphones. That way you won't get the audio from the song itself bleeding into your recording.<br />
<br />
Once you have your track recorded, remove the song track from Audacity, leaving only your recording. Next, select the drop-down box in the lower-left corner of the window labeled "Project Rate (Hz)" and select 16000.<br />
<br />
Export as WAV.<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="Magma"></a><br />
<span style="font-size: large;">Magma</span><br />
Now, we're going to set up Magma. Open Magma and under the Information tab fill in all of the fields for Artist, Title, Album, etc. Don't worry about album art, you won't be able to use it anyway. Under the Build To field, put it wherever you want, but name it after the song ID that you are going to use for this custom. A simple song ID is the song title in all lowercase with no spaces or punctuation. If it's a really long title, you can shorten it for the ID. The main thing is that every song needs a unique ID, so just make sure it's unique (i.e. "My Cool Song" could have the song ID "mycoolsong"). Remember this ID for later.<br />
<br />
Next, under the Audio tab, if you have master tracks, put them in here. If not, put your song track in as the backing, and the silence track in for every instrument that has a chart. If you have vocals, you'll need to have the dryvox track made.<br />
<br />
Under the Game Data tab, put your .mid in and set the difficulty for each instrument.<br />
<br />
Now, save your .rbproj and try to build. If you get errors with your chart, fix them. If you get other errors that you don't understand, try the Rock Band section of the ScoreHero forums. Rinse, lather, and repeat until you successfully generate an .rba file.<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="Extracting"></a><br />
<span style="font-size: large;">Extracting the RBA</span><br />
Open MahoppianGoon's Rock Band DLC Tools to the RBA Extractor tab. Open your .rba file and click "Extract All", then close Rock Band DLC Tools.<br />
<br />
Rename the extracted files according to the song ID your chose. The files should be named like this (assuming my song ID is "mycoolsong")<br />
<br />
mycoolsong.mid<br />
mycoolsong.milo_xbox <br />
mycoolsong.mogg (it will originally be .ogg, you need to rename the extension as well)<br />
mycoolsong_weights.bin<br />
songs.dta<br />
<br />
Now you will need to create an empty .pan file. Right-click in Windows Explorer and select New>Text File (not any other file type) and rename the file mycoolsong.pan. Right-click on it and select Properties and the size should be 0 bytes.<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="DTA"></a><br />
<span style="font-size: large;">Editing the DTA</span><br />
The songs.dta generated by Magma needs a few changes to make it work for DLC. Open it in your favorite text editor, it's just a text file. First of all, at the very top of the file you should see:<br />
<br />
(<br />
'song'<br />
<br />
Here, you need to replace 'song' with your song ID:<br />
<br />
(<br />
'mycoolsong'<br />
<br />
A bit further down you will find<br />
<br />
(<br />
'song'<br />
(<br />
'name'<br />
"songs/song/song"<br />
<br />
Here, you will leave 'song' but change the line after 'name' to reflect your song ID:<br />
<br />
(<br />
'song'<br />
(<br />
'name'<br />
"songs/mycoolsong/mycoolsong"<br />
<br />
Scroll down again and find:<br />
<br />
(<br />
'midi_file'<br />
"songs/song/song.mid"<br />
<br />
Again, replace the word song with your song ID:<br />
<br />
<br />
(<br />
'midi_file'<br />
"songs/mycoolsong/mycoolsong.mid"<br />
<br />
Now, if you want to fine-tune the difficulty ratings for your song, find the following lines (the numbers will be different):<br />
<br />
(<br />
'rank'<br />
('drum' 123)<br />
('guitar' 123)<br />
('bass' 123)<br />
('vocals' 123)<br />
('band' 123)<br />
)<br />
<br />
Change these to set the exact difficulty you want. Check out <a href="http://rawksd.japaneatahand.com/wiki/Tiers">this page</a> for comparison with existing songs.<br />
<br />
Finally, find the following line<br />
<br />
('ugc' 1)<br />
<br />
and delete the line entirely. Now save and close the file.<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="Art"></a><br />
<span style="font-size: large;">Album Art </span><br />
Update: Technicolor over at ScoreHero has implemented this info into an all-in-one tool that converts an RBA to a CON. It's only for RB3, but if you just want the album art, it leaves all intermediate files, so you can just grab the artwork from there. <a href="http://rockband.scorehero.com/forum/viewtopic.php?t=33768&postdays=0&postorder=asc&start=681">Get RB3Maker here</a><br />
<br />
Album art is possible using Nachyoz's GH2 Image Converter, but the colors are all messed up. I HAVE figured how to fix the colors, but for now it requires manually hex-editing the image so for now I'm going to wait to post here until I can type up a decent explanation or code my own converter. Sorry...<br />
<br />
If you are willing to try it, the basic steps (with no explanation yet, you'll have to figure it out yourself) are:<br />
<br />
-Save the image as a 256-color, indexed bitmap (also known as 8-bit bitmap)<br />
-Use Nachyoz's GH2ImageCon to convert to .bmp_ps2<br />
-Manually hex-edit the color index in the .bmp_ps2. You need to make 2 changes.<br />
*.bmp_ps2 images store the color index as RGBA, .png_xbox expects ARGB. Just shuffle the values around.<br />
*change the alpha channel values to 0xFF (the default value is 0x80)<br />
-Save the file as [songid]_keep.png_xbox (i.e. mycoolsong_keep.png_xbox) and place it in the gen folder<br />
<br />
<a href="http://dl.dropbox.com/u/28075862/Rock%20Band/coverart.zip">Here is a working example</a><br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="LeFluffie"></a><br />
<span style="font-size: large;">Building the XBox DLC file</span><br />
Open Le Fluffie and select File>Package Creation and choose STFS from the drop-down menu and click OK. Enter the following information:<br />
<br />
Package Type (the drop-down menu that says "None" by default): SavedGame<br />
Title ID: 45410869<br />
Description (Be sure to select the radio button for "Description" instead of "Display Title"): "My Cool Song" (Replace this with whatever the song title actually is, include the quotes).<br />
Internal Title: Rock Band 2<br />
<br />
Now, right-click on each of the two small white squares to the right of the info pane and click Add Image. This is where you select the image you'll see in the XBox System Settings menu. You can use any 64x64 .png image (official DLC uses a scaled down copy of the song's album art), but here's the official RB package icons if you prefer:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
RB1 Icon:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOaxWF4BtGQpUumM2Hb0kjTAKmbvU6kFa96sf1J-7iEMa5N5KMUx_VEhLBVY-CmSwSOirG_yTYiwbtpVg8Ct_rlXN03VX-GkP-sap_PnEKfN2p_HGgZTfY__V6ZbKMAzPBKYmJJQ8_6EIJ/s1600/RB1_icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOaxWF4BtGQpUumM2Hb0kjTAKmbvU6kFa96sf1J-7iEMa5N5KMUx_VEhLBVY-CmSwSOirG_yTYiwbtpVg8Ct_rlXN03VX-GkP-sap_PnEKfN2p_HGgZTfY__V6ZbKMAzPBKYmJJQ8_6EIJ/s1600/RB1_icon.png" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
RB2 Icon:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZB2pka61sgMi5XE93jenZTn6Z_VVWox5qu_1Fp4LVSc7Y1G_Ctol4NU4aemJoxd0PWQ7FxNCtUDqcUqzvVBZlUWeC85p-8rimgtWLT48vWhqJ9OKRNxTF4UJmYc_x68ceZ42uRuANiOUI/s1600/RB2_icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZB2pka61sgMi5XE93jenZTn6Z_VVWox5qu_1Fp4LVSc7Y1G_Ctol4NU4aemJoxd0PWQ7FxNCtUDqcUqzvVBZlUWeC85p-8rimgtWLT48vWhqJ9OKRNxTF4UJmYc_x68ceZ42uRuANiOUI/s1600/RB2_icon.png" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
RB3 Icon: <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAGBy2zCHng_FjmqA4RLwTR73VkiHtnO4yPqB2kyhXGc9rGN42__3bRW2BLhHMLNY3i5f7H-yZ8eSynShVvr3-7yvGFB6dhua565EPFb5QzkZFYnV0aPJ4quwN6v77a6A1Wv-52tiHB22h/s1600/RB3_icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAGBy2zCHng_FjmqA4RLwTR73VkiHtnO4yPqB2kyhXGc9rGN42__3bRW2BLhHMLNY3i5f7H-yZ8eSynShVvr3-7yvGFB6dhua565EPFb5QzkZFYnV0aPJ4quwN6v77a6A1Wv-52tiHB22h/s1600/RB3_icon.png" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
A couple of RawkSD icons I made: <br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzobM5e1zjOvGsst3QCUIAs0Ywk6W44sBmceU_AU-lZna5pNscsgBmuxLwvummiJPUE2jalcdqDita_fV3ENquCKpKhv9wQscdJDR5b3biYe3JkySUnSzjNnps7iYZSpoiPQpzYO5U4H32/s1600/rawk_icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzobM5e1zjOvGsst3QCUIAs0Ywk6W44sBmceU_AU-lZna5pNscsgBmuxLwvummiJPUE2jalcdqDita_fV3ENquCKpKhv9wQscdJDR5b3biYe3JkySUnSzjNnps7iYZSpoiPQpzYO5U4H32/s1600/rawk_icon.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6rhRPCm1e7UYZqmeD4lkdXLf-1IYY52gs-KbTb0nssK5SLVyvXlwQwFOxAPgUY_MiNeQ4YbS6t7gN6ZCctiPmvr7F7_VaL8Be7-XR_gS3Tx-Kx5thnt355ZQvWkKidvDyXzYjmuen0EIP/s1600/rawk_icon2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6rhRPCm1e7UYZqmeD4lkdXLf-1IYY52gs-KbTb0nssK5SLVyvXlwQwFOxAPgUY_MiNeQ4YbS6t7gN6ZCctiPmvr7F7_VaL8Be7-XR_gS3Tx-Kx5thnt355ZQvWkKidvDyXzYjmuen0EIP/s1600/rawk_icon2.png" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
Next, in the upper-left pane, right-click on the word "root" and select Add Folder. Name this folder "songs" (no quotes). Now click the '+' next to root and right-click on "songs" and Add Folder. Name the folder your song ID with no quotes. Click the '+' next to your song ID, and add a folder named "gen" (again, no quotes). Click the '+', then select "gen".<br />
<br />
Right-click in the right-hand pane under where it says "file" and select Add Files. Select the .milo_xbox and the _weights.bin files. Next select the song ID folder and add the .mid, .mogg, and .pan. Select the songs folder and add the .dta. Your files should be in this hierarchy:<br />
<br />
\songs\songs.dta<br />
\songs\mycoolsong\mycoolsong.mid<br />
\songs\mycoolsong\mycoolsong.mogg<br />
\songs\mycoolsong\mycoolsong.pan<br />
\songs\mycoolsong\gen\mycoolsong.milo_xbox<br />
\songs\mycoolsong\gen\mycoolsong_weights.bin<br />
<br />
Now click on the Finalization tab. Select STFS Type 0 in the drop-down box and the radio button for CON (Provided KV) and click Create Package. Name it whatever you want, but I suggest [song ID].con (i.e. mycoolsong.con).<br />
<br />
<a href="http://www.blogger.com/post-edit.g?blogID=2953283389087359631&postID=2969696701271041507&from=pencil" name="Installing"></a><br />
<span style="font-size: large;">Installing</span><br />
The easiest way to install is if you have a spare flash drive at least 1GB in size. Clear everything off of the flash drive, then format it by going to the XBox 360 System Settings menu>Memory>USB Storage Device>Configure Now (or Customize if you want to manually specify how much of the flash drive to devote to XBox storage). Note: This will delete everything off of the flash drive. You have been warned!<br />
<br />
Once it is configured, navigate to your data for Rock Band 2 (either on the hard drive or the internal memory) and copy the Rock Band 2 Song Cache to the flash drive you just configured (nothing special about the song cache, you just need SOME file from RB2 on the flash drive in order to create the proper folder on the flash drive)<br />
<br />
Unplug the flash drive from the XBox and plug it in to your PC, then open Modio and select Explore a device<br />
<br />
In the new window that comes up, select File>Open/Close Drive.<br />
<br />
Navigate to Content\Downloads\Rock Band 2\Game Saves.<br />
<br />
Right-click in the right-hand pane and select Insert File. Browse to and select your .con file.<br />
<br />
Select File>Open/Close Drive to close the drive, then eject it and insert it into the XBox. If you did everything correctly, the song should show up on the flash drive and in the Rock Band 2 song list. If it works, you can copy it off of the flash drive to your hard drive or internal memory if you like.<br />
<br />
Have fun :) <br />
<div class="separator" style="clear: both; text-align: center;">
</div>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com4tag:blogger.com,1999:blog-2953283389087359631.post-49956197546589725342011-01-30T19:58:00.000-08:002011-02-04T12:14:39.307-08:00SNES to USB controller with internal flash memory modI've been toying around with the idea of an SNES controller USB mod for awhile now, but I finally broke down and decided to get my hands dirty and actually make one. I found <a href="http://raphnet.net/index_en.php">this awesome site</a> with all sorts of neat controller mods and decided to go with his <a href="http://raphnet.net/electronique/snes_nes_usb/index_en.php">SNES/NES gamepad (and mouse) to USB adapter</a> guide for my build. After looking into the necessary parts for building the adapter, I decided it would just be simpler (and actually cheaper too) to buy a <a href="http://www.raphnet-tech.com/products/nes2usb/">pre-assembled and pre-programmed circuit board</a>. Once I had the adapter circuit, I decided to take things one step further and combine this mod with a mod one of the guys in my hall had done with an NES controller in which he converted a nonfunctional NES controller into a USB flash drive.<br />
<br />
The first step was finding an appropriate USB hub for this mod. I settled for this IOGear hub:<br />
<br />
<div style="text-align: left;"></div><div style="text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSIBX5en2i0J1r-DpJRBU1cTCKvLi7_8qlmHO_Ywf_CkXW8kAOCaYqVNCRz9p1HoVRgaxHKoo9LDDm6g7_HDcd23Uoi6K39iLG_01V_oG5GwiGXl3v6-5X56JT94UgLm1Jg9u-XUUyOd4c/s1600/0127011227.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSIBX5en2i0J1r-DpJRBU1cTCKvLi7_8qlmHO_Ywf_CkXW8kAOCaYqVNCRz9p1HoVRgaxHKoo9LDDm6g7_HDcd23Uoi6K39iLG_01V_oG5GwiGXl3v6-5X56JT94UgLm1Jg9u-XUUyOd4c/s320/0127011227.jpg" width="320" /></a> </div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"></div><div style="text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCpE4fLCDK6NZYgVEyilehDC_9uNU8mAoQZtcJSsfQKxv7PaDquMt5ao_IC3dsMvCC2WC3YkIqrzdtY64VoP3mFOKAZc1weoGLPoG9NszUIhFN1eU2Cnv90iNqy_0EWxxRMK3NlhcZ0iKs/s1600/0127011230.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCpE4fLCDK6NZYgVEyilehDC_9uNU8mAoQZtcJSsfQKxv7PaDquMt5ao_IC3dsMvCC2WC3YkIqrzdtY64VoP3mFOKAZc1weoGLPoG9NszUIhFN1eU2Cnv90iNqy_0EWxxRMK3NlhcZ0iKs/s320/0127011230.jpg" width="320" /> </a></div><div style="text-align: left;"><br />
I would guess any hub with this sort of design where there is a recess in the case for the cable would work well, because all of the circuitry gets shoved over to the other side of the board to make room for the recess, leaving the two ports next to the recess as just long traces on the board without any circuitry, which is perfect later on when I cut the hub's board in half to fit it into the controller shell.<br />
<br />
</div><div style="text-align: left;"></div><div style="text-align: left;">I had also considered this Targus hub because it was cheap and it was the only one at Wal-Mart, but decided against it because of the circuitboard design. Because of the shell design (without any recess for cable storage), the circuitry is laid throughout the length of the entire board, making it impossible to remove the two unneeded USB ports.</div><div style="text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDsblK9lxI56PdqtGFlAb43tlkugKd_YyCGyjm7Yh1W5Jn6RtaMV-Y07tqnF7M3ggSkG3aGKIXlAMkdX089qF5t98YJ5DGrkHMxWAhFaNw3N77WI0aWooJSfme1MSezx7uqgOxnrNsQV-p/s1600/ACH74US_accessories_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDsblK9lxI56PdqtGFlAb43tlkugKd_YyCGyjm7Yh1W5Jn6RtaMV-Y07tqnF7M3ggSkG3aGKIXlAMkdX089qF5t98YJ5DGrkHMxWAhFaNw3N77WI0aWooJSfme1MSezx7uqgOxnrNsQV-p/s1600/ACH74US_accessories_b.jpg" /></a></div><div style="text-align: left;"><br />
Here's the internals of the hub I used:<br />
<br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF79Z3sXl2KThtloKEYuIXVk7gT-d9jH-b29_zo3r_2VarQrCDNDwGRwfWpADs0YWOP8TQYeiYf03PYH6sYn-t5P5V55lo5p5Iv1j6b-FnHswU4WV3Z48sz1kczvQL_9rcr3ho-N1ggB3J/s1600/0127011232.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF79Z3sXl2KThtloKEYuIXVk7gT-d9jH-b29_zo3r_2VarQrCDNDwGRwfWpADs0YWOP8TQYeiYf03PYH6sYn-t5P5V55lo5p5Iv1j6b-FnHswU4WV3Z48sz1kczvQL_9rcr3ho-N1ggB3J/s320/0127011232.jpg" width="320" /> </a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-uZRulvXz2DUV9e5MP04xrPMJ7eK-1rjNql9sTdNRFhyphenhyphen-HtzzkeMHtXWT0_5Ts5vKPEIxVqYTbNOKAW2BWpABoTbl46SXOndYvJqkMfalHmf2l5Ke9upTQyUYP4zdc_X9d4vMOZrZHRuM/s1600/0127011233a.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-uZRulvXz2DUV9e5MP04xrPMJ7eK-1rjNql9sTdNRFhyphenhyphen-HtzzkeMHtXWT0_5Ts5vKPEIxVqYTbNOKAW2BWpABoTbl46SXOndYvJqkMfalHmf2l5Ke9upTQyUYP4zdc_X9d4vMOZrZHRuM/s320/0127011233a.jpg" width="320" /></a> </div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">You can see from the picture above how the two rightmost ports have no vital circuitry anywhere near them. This became important later on. The first thing I did was to desolder and remove one of the USB ports. (I practiced this on one of the two ports I later cut off of the hub's board entirely. I then soldered wires in place of the port (26 gauge ended up being just about perfect. To be honest, cleanly removing the USB port from the hub board was the hardest part of the entire mod. I first removed as much solder as I could from all 4 through-board leads and the through-board anchor tabs, then I used a pair of needle-nosed pliers to break the leads in the rear of the port, then finally used the pliers to break the port off of the board by bending back and forth until the anchor tabs broke. This then left me with leads and anchors poking through the board still anchored with solder. I intentionally left enough of each lead intact poking out from the board so I could grip each lead with the needle-nosed pliers, then I picked up the entire board by the pliers and carefully applied the soldering iron to the opposite side of the board and let gravity pull the board off of the lead when the solder softened.</div><div class="separator" style="clear: both; text-align: left;"> </div><div class="separator" style="clear: both; text-align: left;">I then soldered wires through the lead holes and attached them to the adapter circuit according to the instructions in the conveniently provided <a href="http://www.raphnet-tech.com/downloads/M_NSDB9_PCB_ENG3.pdf">owner's manual</a> (you have to get it from the site, it doesn't come with a hardcopy when you order it). Once I had tested that the hub still functioned and that the controller adapter was properly detected (even without soldering the adapter to the controller itself, the chip itself will be detected so you can test your soldering at this point before you continue). Once it was tested, I sawed off the extra two ports, just to the right of the LED (since I didn't know if the LED was required or not, and it didn't take up that much extra space anyway...).</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1UBGFJSjCA2MIezsLOw63UsYVlbJW59wLp7cm_qk7Nytg7yABA7kS8YaXreYE34TG33pSCFDnOtUh1NkCDMQ5TJ9y6BkSjV0saxppFxc5vqtOwxxJUGdje2C5ryYqC1BVtB5smUBLpa9R/s1600/0128011936.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1UBGFJSjCA2MIezsLOw63UsYVlbJW59wLp7cm_qk7Nytg7yABA7kS8YaXreYE34TG33pSCFDnOtUh1NkCDMQ5TJ9y6BkSjV0saxppFxc5vqtOwxxJUGdje2C5ryYqC1BVtB5smUBLpa9R/s320/0128011936.jpg" width="320" /></a></div><div style="text-align: left;"><br />
Next, I picked up <a href="http://www.amazon.com/Kingston-DataTraveler-Flash-DTMSN-4GB/dp/B001D7LIT6">this flash drive</a> for my internal memory (shop around, the OIT bookstore had these for half the price they're asking for on Amazon). <a href="http://www.lacie.com/us/products/product.htm?pid=11546">Here's another even smaller drive, if you're interested.</a><br />
</div><div style="text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaTP_xXgGe3gZqeUJdAPSVywB4_C6upzBmeoK_ezayCuktlU-Eu4rEPMKoXQiF5Q0x9B8_e5KifDtpg9f9yGS5DT2NC2seq3WHEFWIxidnq5ntUluUsOR4csffim1M7ijsXhS8lAIv7OAq/s1600/0128011941.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaTP_xXgGe3gZqeUJdAPSVywB4_C6upzBmeoK_ezayCuktlU-Eu4rEPMKoXQiF5Q0x9B8_e5KifDtpg9f9yGS5DT2NC2seq3WHEFWIxidnq5ntUluUsOR4csffim1M7ijsXhS8lAIv7OAq/s320/0128011941.jpg" width="320" /></a></div><div style="text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrtwmGo_wOSAODSXiuM4UnkOScJj_7vOzpX4X1ETzUmtnU9gmZA4EzuL3jFq_nsWaBdvU_Ds8plbFwR7KLodV3XweCI2uugU-6Eq-yVbQp_eCh6r2W0rsP5aXCh3uE_XUkDEVuYC0MbHoG/s1600/0128011942.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrtwmGo_wOSAODSXiuM4UnkOScJj_7vOzpX4X1ETzUmtnU9gmZA4EzuL3jFq_nsWaBdvU_Ds8plbFwR7KLodV3XweCI2uugU-6Eq-yVbQp_eCh6r2W0rsP5aXCh3uE_XUkDEVuYC0MbHoG/s320/0128011942.jpg" width="320" /></a></div><div style="text-align: left;"><br />
Here's the complete package:<br />
<br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxpiV_X2kZ2zIgYWdcJTzhy4Tdw_WNaTmtIE-y49rHunlI8WNVChcP5C0EJzYGEecZ0MHe8ewXF6N0De071mj1SQ0TkDlRc1ySfSqzOJx6NkMTPjhch54UdTeQlvJfNXn_L6E0RNxpQ421/s1600/0128011939a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxpiV_X2kZ2zIgYWdcJTzhy4Tdw_WNaTmtIE-y49rHunlI8WNVChcP5C0EJzYGEecZ0MHe8ewXF6N0De071mj1SQ0TkDlRc1ySfSqzOJx6NkMTPjhch54UdTeQlvJfNXn_L6E0RNxpQ421/s320/0128011939a.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihrxOXiXPauH_ovlGJRYiYWqhsbQ1S0VncswUvlpnXUMsAwJBe1SPwaYx-GDy5VrfTUSKb1SRQ3RkwaOCLkCN9f0S3mTeBFTYLNvQa4EsTlcEqWt81oR4NUz5DTUoTn2-6t2kOW_bFfchY/s1600/0128011936a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihrxOXiXPauH_ovlGJRYiYWqhsbQ1S0VncswUvlpnXUMsAwJBe1SPwaYx-GDy5VrfTUSKb1SRQ3RkwaOCLkCN9f0S3mTeBFTYLNvQa4EsTlcEqWt81oR4NUz5DTUoTn2-6t2kOW_bFfchY/s320/0128011936a.jpg" width="320" /></a></div><div style="text-align: left;"><br />
</div><div style="text-align: left;">Next, I had to Dremel out the back side of the controller case in order to accommodate for this extra circuitry.<br />
<br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgccGYkZqRQcjs_zYWUKBmGl0kud20XA6zmHSYhA6ChQafjQOK2DWaE1MQeo2L8JlVqqcLGA_N-niI_3su9BhEyjLkkuPfSor3TjX9pSFrevYaRtNdApR2zGqq6_eVO4-gitpdq1H9jn6vI/s1600/0130011430a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgccGYkZqRQcjs_zYWUKBmGl0kud20XA6zmHSYhA6ChQafjQOK2DWaE1MQeo2L8JlVqqcLGA_N-niI_3su9BhEyjLkkuPfSor3TjX9pSFrevYaRtNdApR2zGqq6_eVO4-gitpdq1H9jn6vI/s320/0130011430a.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTkBXtkjkFgtzke_2zQiDCvkVIKd9lPMwHWdYYEEgK_9YgS_PTec6sY2PJ_SO40gUKotx7psLNyjl3c7kcVr50Tk6SBEn2nVLSdZtNAgssJJRL3C7fFAKynnzojVuUBV-yQwGzQKeTkHWY/s1600/0130011431.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTkBXtkjkFgtzke_2zQiDCvkVIKd9lPMwHWdYYEEgK_9YgS_PTec6sY2PJ_SO40gUKotx7psLNyjl3c7kcVr50Tk6SBEn2nVLSdZtNAgssJJRL3C7fFAKynnzojVuUBV-yQwGzQKeTkHWY/s320/0130011431.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9UySQZRUlWEYu0Gy5YkiQPU4sHvvRuzOu255Uz2sfZT4NDAJwiJKGMxisEOSsl0rYHzhTEN1NdhBUKOiiYqeirWg7gCAxPCRwQJJl0lFiCYrZuRvEf8WEe_AsFz0x9Sm46qoQTkU400e6/s1600/0130011431a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9UySQZRUlWEYu0Gy5YkiQPU4sHvvRuzOu255Uz2sfZT4NDAJwiJKGMxisEOSsl0rYHzhTEN1NdhBUKOiiYqeirWg7gCAxPCRwQJJl0lFiCYrZuRvEf8WEe_AsFz0x9Sm46qoQTkU400e6/s320/0130011431a.jpg" width="320" /></a></div><div style="text-align: left;"><br />
</div><div style="text-align: left;">After I finished adding extra real estate inside the controller shell, all I had left to do was wire the adapter into the controller itself. I decided to leave the original cable connector intact and instead soldered wires onto the backside of the cable connector. I also had to resolder the chip to the hub using longer wires, since I ended up changing the arrangement of the chips from my original plan after everything started coming together. At this point, I tested it and after an initial mishap with two wires being accidentally switched, it worked, so I closed up the case. The only thing left to do is replace the USB cable with a full-length one, but that will have to wait until the order comes in from NewEgg sometime next week. For now, I have a 6' USB extension cable that works just fine.<br />
<br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ALZc6FplDWkR3De38KJm3OC4azCs-ZvR0p2zRjpBZkEH530jQLJrbjqYHk9DnR3ifsMnsi8yhTj6u7NZp_Yb78fzHzPdzqNgyKWoOdvgGxoqPmQqE2sgijppnIgVbgSq0EM92MFW7-xc/s1600/0130011433.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ALZc6FplDWkR3De38KJm3OC4azCs-ZvR0p2zRjpBZkEH530jQLJrbjqYHk9DnR3ifsMnsi8yhTj6u7NZp_Yb78fzHzPdzqNgyKWoOdvgGxoqPmQqE2sgijppnIgVbgSq0EM92MFW7-xc/s320/0130011433.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrXMm64WGVaYqFEEfThCmwfn189QrDXwH_IH0WoArviayFtQ87j-4ZjT5QPahV6TGyV_VC78Azu33j18nu7TFH5eDl4QKjpas9NCXhhwad5jXCs7CYzbhrknotcel8-RRBXhVcCtt4ax6V/s1600/0130011434.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrXMm64WGVaYqFEEfThCmwfn189QrDXwH_IH0WoArviayFtQ87j-4ZjT5QPahV6TGyV_VC78Azu33j18nu7TFH5eDl4QKjpas9NCXhhwad5jXCs7CYzbhrknotcel8-RRBXhVcCtt4ax6V/s320/0130011434.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9QFdVViQS9XKc5hYWut01taD9N4-WMdukpKIgE4W-ltEllHFU7AQegfsHKUSZNcQwpetp3kcMF4zCdyuhQOdsD9kxWskftOlxLYhWqRcATkR5NaGPgfgRPdoItHFrHnH7vIGMq0gXqAXf/s1600/0130011434a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9QFdVViQS9XKc5hYWut01taD9N4-WMdukpKIgE4W-ltEllHFU7AQegfsHKUSZNcQwpetp3kcMF4zCdyuhQOdsD9kxWskftOlxLYhWqRcATkR5NaGPgfgRPdoItHFrHnH7vIGMq0gXqAXf/s320/0130011434a.jpg" width="320" /> </a></div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">The final result (sans full-length cable): </div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqzCgzLAX0VnGqtABvrZinU-pJnJR3s-7URCD-qC3HzAH2wyKWLV2hzspv2Y-ajySOaZFyWez4Vy32H8CaBJaGLEgPhcaG_ke9ULq55ES1EErRC-NldIrFwGImtxr94evXCRtwN4wvpkoF/s1600/0130011603a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqzCgzLAX0VnGqtABvrZinU-pJnJR3s-7URCD-qC3HzAH2wyKWLV2hzspv2Y-ajySOaZFyWez4Vy32H8CaBJaGLEgPhcaG_ke9ULq55ES1EErRC-NldIrFwGImtxr94evXCRtwN4wvpkoF/s320/0130011603a.jpg" width="320" /> </a></div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Screenshots of the controller in action: </div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8L3GFyxMXMNou9PN-gjPYkVcUUECSDwQSUJTGRcpeybiuczZFtnoX3Y0EY4cvF8glmL_5O0KAvSKP9gfHEc8YOeR2I98m-rHTygnotk58bHhGF4VfYkIz8DxDZTW8E0NOF3f24Nb64_ie/s1600/Controller.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8L3GFyxMXMNou9PN-gjPYkVcUUECSDwQSUJTGRcpeybiuczZFtnoX3Y0EY4cvF8glmL_5O0KAvSKP9gfHEc8YOeR2I98m-rHTygnotk58bHhGF4VfYkIz8DxDZTW8E0NOF3f24Nb64_ie/s320/Controller.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1tjcmcoKIUpDXGubc_rFq8LGGXN4V6FRhDS4vXKE3wwZ-PA7FJZFKpXDdhEm6Qp0U3F82rsApLm6uw3Ae92WHVP915mSASHj0m7tUTFXwRqZPX5bYhqMAvRQva2_OGBmF-4_MVLbWBffV/s1600/Flash+Drive.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1tjcmcoKIUpDXGubc_rFq8LGGXN4V6FRhDS4vXKE3wwZ-PA7FJZFKpXDdhEm6Qp0U3F82rsApLm6uw3Ae92WHVP915mSASHj0m7tUTFXwRqZPX5bYhqMAvRQva2_OGBmF-4_MVLbWBffV/s320/Flash+Drive.png" width="320" /></a></div><br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-uZRulvXz2DUV9e5MP04xrPMJ7eK-1rjNql9sTdNRFhyphenhyphen-HtzzkeMHtXWT0_5Ts5vKPEIxVqYTbNOKAW2BWpABoTbl46SXOndYvJqkMfalHmf2l5Ke9upTQyUYP4zdc_X9d4vMOZrZHRuM/s1600/0127011233a.jpg" style="margin-left: 1em; margin-right: 1em;"></a> </div><div style="text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Update:</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">I've begun the process of loading up all of the software I plan to use on my newly converted controller. To start off with, I'm using the latest <a href="http://portableapps.com/news/2010-07-17_-_portableapps.com_platform_2.0_beta_5_released">beta</a> of the <a href="http://www.portableapps.com/">PortableApps.com</a> Menu, along with a fixed version of ZSNES Portable. I also decided to load up FCEUX as well so I can play NES games as well as SNES. I'm also including a few utilities, such as Nach's SNES ROM Tool, GoodTools, JoyToKey and Xpadder. I may also install WinAmp Portable along with the ChipAmp plugin pack for chiptune playback, we'll see (I have 4GB to work with, so I have way more than I'll be taking up with ROMs and saves...).</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtxZ6cQYYzIkaDFlFg6Llikx61Oa2q2RyOeIrdYGbDmuqDOasUpVhSw-5K731PHmYqaoF1yS4sfPE0tCQc3cwvXnBnaDbPzEpeolXjIm1cjz8nolwhSytbaDxCXIs5mUTKV5EganQnmnEV/s1600/MenuScreenShot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtxZ6cQYYzIkaDFlFg6Llikx61Oa2q2RyOeIrdYGbDmuqDOasUpVhSw-5K731PHmYqaoF1yS4sfPE0tCQc3cwvXnBnaDbPzEpeolXjIm1cjz8nolwhSytbaDxCXIs5mUTKV5EganQnmnEV/s320/MenuScreenShot.png" width="226" /></a></div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div style="text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSIBX5en2i0J1r-DpJRBU1cTCKvLi7_8qlmHO_Ywf_CkXW8kAOCaYqVNCRz9p1HoVRgaxHKoo9LDDm6g7_HDcd23Uoi6K39iLG_01V_oG5GwiGXl3v6-5X56JT94UgLm1Jg9u-XUUyOd4c/s1600/0127011227.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br />
</a></div>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-74330549554332660722010-09-12T16:20:00.000-07:002010-09-12T16:20:47.669-07:00New Acekard skin: Chrono TriggerI finished this new Chrono Trigger skin up awhile back, thought I'd share:<br />
<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuPEad9uedpA1taf-cMwLNHn4XyV3f-NGKB6HN9V5arvsVPeA6UXS6NgAvQIuP0lxLoqLuhxzVqmAqoGj2U1cXNYFpd_I95NzMwQLiWgHprX51hajNKi2bWFxmfZEIcr9bRgSfMafg70YP/s1600/preview.gif" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuPEad9uedpA1taf-cMwLNHn4XyV3f-NGKB6HN9V5arvsVPeA6UXS6NgAvQIuP0lxLoqLuhxzVqmAqoGj2U1cXNYFpd_I95NzMwQLiWgHprX51hajNKi2bWFxmfZEIcr9bRgSfMafg70YP/s320/preview.gif" /></a><br />
<a href="http://www.ndsthemes.com/themes/details/t/20e36c3e2a"><br />
</a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<a href="http://www.ndsthemes.com/themes/details/t/20e36c3e2a">Download it here </a><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-57769862525718572922010-08-22T23:15:00.000-07:002010-08-24T16:33:51.884-07:00Thing A Day update 1So today I noticed that yellow.wood.goblin finally updated the Wood R4 source code on the woodrpg GoogleCode page, and as far as I can tell, this revision is fully up-to-date with the latest release (v1.12), so I've been compiling for the last 2 hours, hoping that my patch will build fine with the latest source.<br />
<br />
I've had a few bumps along the way. The changelog for v1.11 indicated that the update included fixes for building on the latest toolchain, so I finally went ahead and updated my devkitARM and libnds to the latest versions and tried building the latest source. About 20 seconds in I had my first fatal build error. So the Wood firmwares are still not playing nice with the latest toolchain. I tried just downgrading libnds, hoping that the changelog wasn't mistaken and that at least I could build with the latest devkitARM, even if my libraries weren't entirely up-to-date. 20 minutes into the build and it seems to be going well, no problems yet. <br />
<br />
...and then just as I finished typing that I ran into an error. Strangely, it's a permission denied error, which indicates the problem is one of those really weird ones that just decides to rear its ugly head for no apparent reason. Darn. Well, I need to go to bed, since I have work tomorrow.<br />
<br />
Update: After reverting my toolchain to the older version, it built fine, and I'm up and running on Wood R4 v1.12 w/my 3in1+ patch :)<br />
<br />
Also, I created a really awesome Super Metroid skin for Wood R4, since I couldn't find a single Metroid skin for the Acekard/Wood firmware.<br />
<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi73Tzy9v-FR-nbbmthw2Yc60BdfWlGT9-hLxEdv1ogN9N-8LaOjzMoAQOLcy0oFRHxLupSKhux7Mo3o6tVRtY5CX_wZmMLgWIk5oVMQeYp06Ziw2ZOnNcfZbqNiTavabPYTym2txu5HFh8/s1600/preview.gif" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi73Tzy9v-FR-nbbmthw2Yc60BdfWlGT9-hLxEdv1ogN9N-8LaOjzMoAQOLcy0oFRHxLupSKhux7Mo3o6tVRtY5CX_wZmMLgWIk5oVMQeYp06Ziw2ZOnNcfZbqNiTavabPYTym2txu5HFh8/s320/preview.gif" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">My Super Metroid Ak2/Wood skin</td></tr>
</tbody></table>qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com0tag:blogger.com,1999:blog-2953283389087359631.post-84389263133144245082010-08-18T23:25:00.000-07:002011-08-29T19:55:32.259-07:00Thing A DayI realized recently that I have a ton of random projects started that I tend to work on for awhile and then abandon or I get too busy and forget about them. I also spend a lot of time online just browsing through internet forums (mostly PortableApps and GBATemp). So rather than continuing to waste so much time just reading random postings online, I've decided to compile a list of my current projects and then do my best to commit to spend time doing at least one thing on that list every day. In homage to Jonathan Coulton's Thing A Week project, I've decided to name my project Thing A Day. Unlike Thing A Week, the goal here isn't to force myself to complete a project in a specified timeframe, only to set aside time that I would otherwise most likely waste and instead actually accomplish something.<br />
<br />
Here's the current list (in no particular order).<br />
<br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#StartABlog">Start a blog</a> <b>(check)</b><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#BlogBanner">Create a cool banner image for my new blog</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#UpdateU3Apps">Update my U3 applications</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#U3Appstop">Recode my U3 appstop from scratch</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#RB2Pans">Figure out the specs for the Rock Band 2 pan files</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#RB2Milos">Figure out the stupid endianness of the Rock Band 2 milo files</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#GHLipsyncAnims">Generate lipsync animations for all of the Guitar Hero games from World Tour and up for RawkSD</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#CrystalFlashAnims">Create a venue track for Inimitable's Crystal Flash chart</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#RBWorship">Rock Band Worship Team charts</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#SuperMetroidSprites">Finish (or at least continue) my Super Metroid sprite sheet</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#WoodR4Patch">Finish my 3in1+ patch for the Wood R4 firmware</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#VCButtonRemapping">Create Ocarina codes to remap buttons in Wii VC titles</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#VCOcarinaLoader">Create a standalone VC launcher that will patch my VC titles with the remapped buttons</a><br />
<a href="http://qwertymodo.blogspot.com/2010/08/thing-day.html#AHBPROTChannels">Modify an existing WAD packer (probably CustomizeMii) to enable AHBPROT</a><br />
<br />
<a href="" name="StartABlog"></a><span style="font-size: large;">Start a blog:</span><br />
Well, that one's pretty self-explanatory. Also, it is obviously completed.<br />
<br />
<a href="" name="BlogBanner"></a><span style="font-size: large;">Create a cool banner image for my new blog:</span><br />
I won't give away any details other than it involves the digital rain effect from The Matrix, and that it's gonna be sweet.<br />
<br />
<a href="" name="UpdateU3Apps"></a><span style="font-size: large;">Update My U3 applications:</span><br />
I have a software project hosted on SourceForge.net where I take applications and build launchers for them so they can be run from SanDisk's now-dead U3 platform, which allows you to install the program on to your U3-enabled flash drive and carry it with you to any PC. Unfortunately, most of my apps are really out-of-date, and I need to update them.<br />
<br />
<a href="" name="U3Appstop"></a><span style="font-size: large;">Recode my U3 appstop from scratch:</span><br />
One part of the U3 program is that you have to be able to close the program automatically if the user ejects the flash drive. I wrote an app that handles this, but now that I actually know the difference between good code and bad code, it's become painfully obvious just how terrible that app really is. Also, I've lost the source code to that particular version of the app, technically leaving me in violation of my own license for it (GPLv2). So it would seem it is time to start from scratch and actually do a decent job this time around. <br />
<br />
<a href="" name="RB2Pans"></a><span style="font-size: large;">Figure out the specs for the Rock Band 2 pan files:</span><br />
The best I can tell, the pan files handle stereo pan and audio leveling for the audio files in Rock Band. However, the RawkSD devs don't currently utilize the pan files because they don't care to figure out how they work, and instead it seems they handle volume control by adjusting the gain on each channel during transcoding. It would be way better to actually be able to generate these pan files instead of changing the gain during transcoding, because then you can change the pan values without having to further degrade the audio.<br />
<br />
<a href="" name="RB2Milos"></a><span style="font-size: large;">Figure out the stupid endianness of the Rock Band 2 milo files:</span><br />
This one has bugged me for awhile. I want to be able to generate lipsync animations for my Rock Band custom songs. The only way to do this is using the official song compiler from Harmonix called Magma. Magma generates files targeted for the XBox 360, and I need them for the Wii. They are almost identical files, except that a section in the middle of the file needs to be endian-swapped. Unfortunately, I can't make heads or tails of the file header to figure out where that section starts and ends (although I do understand the structure of the section itself, thankfully). So I want to be able to convert the lipsync animation file from the XBox format to the Wii format. Yes, AerialX of the RawkSD team has already written an app to do that, but I want to integrate it into a slightly more complicated app instead of having to run separate command-line apps to do each of the separate steps.<br />
<br />
<a href="" name="GHLipsyncAnims"></a><span style="font-size: large;">Generate lipsync animations for all of the Guitar Hero games from World Tour and up for RawkSD:</span><br />
The purpose of the afformentioned "slightly more complicated app" that involves converting lipsync animation files will be to generate those animation files for the Guitar Hero games, which can be imported into Rock Band 2 via RawkSD. This can be done for all of the Guitar Hero games after and including World Tour (GH4), because they have vocal charts and separate audio stems for the vocals. However, generating the animations for each of the songs is going to be a very involved process, so I would like to make the process more automated by way of the milo converter from the previous project on the list.<br />
<br />
<a href="" name="CrystalFlashAnims"></a><span style="font-size: large;">Create a venue track for Inimitable's Crystal Flash chart:</span><br />
Inimitable, who has charted many a Rock Band custom, has charted a Super Metroid mega-mix called Crystal Flash. Unfortunately, it is too long to pass through Magma, so he was unable to generate default animations for it, so it's really boring because as you play you just watch your drummer sitting there and nobody's playing their instruments and there are no lighting effects or camera movements. Just boring. I am in the process of charting those animations and camera and lighting events in order to make this epic song just that much better.<br />
<br />
<a href="" name="RBWorship"></a><span style="font-size: large;">Rock Band Worship Team charts:</span><br />
At the suggestion of my pastor at OIT, Billy Redd, I am currently working on a project to chart 5-6 worship songs for Rock Band, so we can do a week of Rock Band worship for the Sunday morning Chi Alpha service. I am currently working on "I Am Free" by Newsboys, which I have finished charting on expert difficulty (although the drum chart needs some serious cleanup), and "In the Secret (I Want To Know You)" by SONICFLOOd. If I can actually finish the charts, it should be a blast.<br />
<br />
<a href="" name="SuperMetroidSprites"></a><span style="font-size: large;">Finish (or at least continue) my Super Metroid sprite sheet:</span><br />
Last summer I started ripping a bunch of sprites from Super Metroid in order to convert them to Windows cursor files. I have a much more complete set of Samus sprites than any video game sprite site I've ever found. It's fun, but tedious work. I'd like to fill out the sprite sheet some more, perhaps with some enemies as well instead of just Samus.<br />
<br />
<a href="" name="WoodR4Patch"></a><span style="font-size: large;">Finish my 3in1+ patch for the Wood R4 firmware:</span><br />
The R4 flashcart was basically the first all-in-one solution for Nintendo DS backup loading. Unfortunately, they got sued by Nintendo and got their warehouses raided. The R4 team ceased to manufacture the carts and stopped updating their firmware and basically the R4 just became obsolete in the light of newer carts like the Acekard 2.1/2i. However, along came a developer by the username yellow.wood.goblin, who was working on a custom firmware for the Acekard RPG. He decided that there was no reason his custom firmware couldn't also be made to run on the R4. And so, Wood R4 was born, giving new life to the old cart. However, yellow.wood.goblin only added support for the one GBA expansion kit he owned, an original v1 EZ-Flash 3in1. The 3in1 is arguably the best GBA expansion out there, but there have been 2 updates to the hardware since the v1, but neither the v2 nor the v3 are supported on Wood R4. Turns out, the 3in1 that Margaret owns is the v3. So she was out of luck and unable to play her GBA games until I came across a post on the EZ-Flash forums regarding updated source code that was supposed to enable support for the new expansions (the EZ-Flash team released these updates along with the hardware so developers could support the new hardware). The source code didn't seem too complicated, so I grabbed the Wood R4 source and the EZ-Flash team update and set out to add 3in1+ (v3) support to Wood R4. I was surprised how easy the patch really was. At this point, my patch is about 85% working, I'm just trying to iron out one last issue involving the Nintendo DS web browser ROM. Once I get the patch working, yellow.wood.goblin has indicated that he intends to merge my patch into the official release. This is good news not only for the fact that it's cool to have my work recognized, but also because if he is interested in my work he may be able to assist me with the remaining bug. Also, Normatt has offered some advice, so between the two of them I'm in good hands.<br />
<br />
<a href="" name="VCButtonRemapping"></a><span style="font-size: large;">Create Ocarina codes to remap buttons in Wii VC titles:</span><br />
Margaret recently bought me this awesome game controller adapter that has ports for the NES/SNES/N64/Sega Genesis controllers and on the other end it plugs into a GameCube controller port. This means I can use original controllers on my Wii to play games on their respective emulators using the original controllers. Unfortunately, due to the design of the GameCube controller, some of the N64 buttons are not properly mapped (specifically the Z and L buttons), so I'm trying to figure out if it's possible to modify the button mapping to fix this issue. I've seen button remapping ocarina codes before, but they seemed to be game-specific. This one's going to take some serious work as well as making contact with someone who owns a USB Gecko and has experience generating codes.<br />
<br />
<a href="" name="VCOcarinaLoader"></a><span style="font-size: large;">Create a standalone VC launcher that will patch my VC titles with the remapped buttons:</span><br />
If I can actually manage to get ahold of button remapping codes, I'm going to need a launcher that will load the game with the codes enabled. For the time being there are loaders out there that will do that, but I'd like something a bit more transparent. I am looking into converting my VC titles into hidden channels, then creating a loader that will take the VC title's place in the menu and seamlessly load the ocarina codes and then launch the hidden title... not sure if it's possible, but it's a cool idea. <br />
<span style="font-size: large;"><br />
</span><br />
<span style="font-size: large;"><a href="" name="AHBPROTChannels"></a>Modify an existing WAD packer (probably CustomizeMii) to enable AHBPROT:</span><br />
The latest version of the Homebrew Channel for Wii has done away with DVDX for hardware access to the DVD drive, and instead accesses the hardware directly using a method known as AHBPROT, which basically means setting a permissions flag which gives access to every single piece of hardware in the console all from the PPC side. This functionality requires both the loader and the application itself to support it, and current WAD packers don't set this flag. I would like to figure out how to get a WAD packer to set this flag, or else try setting it in a single WAD and using that WAD as a base and see if the flag stays set after repacking. Either way, I would just really like to update all of my custom channels with AHBPROT.<br />
<br />
<br />
Well, that's all for now. At least all that I can remember. So you can see, I do manage to keep myself busy.qwertymodohttp://www.blogger.com/profile/17335329668705867365noreply@blogger.com1