diff --git a/applications/plugins/wii_ec_anal/LICENSE b/applications/plugins/wii_ec_anal/LICENSE new file mode 100644 index 000000000..95e544a06 --- /dev/null +++ b/applications/plugins/wii_ec_anal/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 BlueChip + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/plugins/wii_ec_anal/README.md b/applications/plugins/wii_ec_anal/README.md new file mode 100644 index 000000000..8d439c7e0 --- /dev/null +++ b/applications/plugins/wii_ec_anal/README.md @@ -0,0 +1,234 @@ +# [FlipperZero] Wii Extension Controller Protocol Analyser +This Protocol Analyser offers a full Test and Calibrate system for Wii Extension Controllers. + +__Disclaimer:__ *Use of this plugin, and notably connecting an Extension Controller to the FlipperZero is performed entirely at your own risk.* + +# Notes +This plugin has (todate) only been tested with official Nintendo Nunchucks and Classic Controllers - namely Nunchucks and Classic Controllers. + +# Encryption +This plugin has SOME code to handle encryption, but it it unused, untested, and some of it is known to un-work. + +This plugin (currently) only works with Extension Controllers which implement the encryption-bypass strategy. IE. `i2c_write(0xf0, 0x55) ; i2c_write(0xfb, 0x00)` + +If you need this functionality, either raise an Issue or, better still, a Pull Request. + +# Screen: SPLASH +
+The SPLASH Screen is displayed when the Plugin starts. It can be cleared by pressing any key, else it will auto-clear after 3.5 seconds. + +# Screen: WAIT +   

+The WAIT screen will display which pins you need to connect between the flipper and the Wii Extension Controller. + +__Disclaimer:__ Use of this plugin, and notably connecting the Controller to the FlipperZero is performed entirely at your own risk. + +Looking in to the exposed side of the Extension Controller plug, with the notch on the bottom + +| EC Pin # | EC Position | EC Pin ID | Pin Function | FZ GPIO Pin Name | FZ GPIO Pin # | +| :---: | :---: | :---: | :---: | :---: | :---: | +| 1 | top-left | +3v3 | Power | 3v3 | 9 | +| 2 | bottom-left | SCL | i2c clock | C0 | 16 | +| 3 | top-centre | EN | ¿detect? | | | +| 4 | bottom-centre | -x- | -none- | | | +| 5 | top-right | SDA | i2c data | C1 | 15 | +| 6 | bottom-right | Gnd | Power | Gnd | 18 | + +Keys: +* Left - Show splash screen +* Back - exit plugin + +The easiest way to connect a Wii Extension Controller to a FlipperZero is arguably with a ["WiiChuck"](https://www.ebay.co.uk/sch/?_nkw=wiichuck) or a ["Nunchucky"](https://www.solarbotics.com/product/31040)

+ + + + + +
WiiChuckNunchucky
+ +### ** WARNING ** +Neither the WiiChuck, nor the Nunchucky have a pin polarisation mechanism.
+If you plug the adaptor in the wrong way around you WILL apply voltage to the Controller the wrong way round!!
+I have no idea if THIS WILL PERMANENTLY KILL THE CONTROLLER ...Who wants to try it? + +On all the WiiChucks I have seen: +* The WiiChuck has THREE connectors on one side, and TWO connectors on the other. +* The side with TWO connectors should go against the side of the Controller plug with the big indent. +``` ++-------------+ +| _________ | +| | = = = | | +| |_=_____=_| | <-- notice missing pin +| ___ | +| | | | <-- notice indent ++----+ +----+ +``` +
+ +...BUT I *highly* recommend you check the pins on your adaptor to make sure everything goes well. + +I believe the unconnected pin on the top is a "presence detect" function, but I have not (yet) verified this.
+This feature is NOT required by this plugin, as the detection is performed by means of an i2c handshake. + +When a device is connected it will be immediately recognised. If it is not, either: +* The Controller is not correctly connected
+...This may be as simple as a broken wire. +* The controller board in the Controller is faulty.
+...Repair of which is beyond the scope of this document. + +To get the list of "known" Controllers, run `./info.sh`
+As of writing this, that returns: +```c +[PID_UNKNOWN ] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "Unknown Perhipheral", SCENE_DUMP, +[PID_NUNCHUCK ] = { {0x00, 0x00, 0xA4, 0x20, 0x00, 0x00}, "Nunchuck", SCENE_NUNCHUCK, +[PID_CLASSIC ] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x01}, "Classic Controller", SCENE_CLASSIC, +[PID_BALANCE ] = { {0x00, 0x00, 0xA4, 0x20, 0x04, 0x02}, "Balance Board", SCENE_DUMP, +[PID_GH_GUITAR ] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x03}, "Guitar Hero Guitar", SCENE_DUMP, +[PID_GH_DRUMS ] = { {0x01, 0x00, 0xA4, 0x20, 0x01, 0x03}, "Guitar Hero World Tour Drums", SCENE_DUMP, +[PID_TURNTABLE ] = { {0x03, 0x00, 0xA4, 0x20, 0x01, 0x03}, "DJ Hero Turntable", SCENE_DUMP, +[PID_TAIKO_DRUMS] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x11}, "Taiko Drum Controller)", SCENE_DUMP, + +``` + +You can see that there are EIGHT known devices. One is the default for an unknown controller; SEVEN devices are known by name; and TWO (of those seven) have bespoke "scenes" (ie. SCENE_NUNCHUCK & SCENE_CLASSIC). + +# Screen: NUNCHUCK - MAIN +
+When you connect a Nunchuck, you will see a screen displaying: +* Accelerometer{X,Y,Z} values +* Joystick{X,Y} values +* Joystick graphic +* Button{C,Z} + +Keys: +* Left - Go to the DUMP screen +* Right - Go to the NUNCHUCK_ACC accelerometers screen +* Up/Down/OK - [qv. Peak Meters] +* Short-Back - Reset controller +* Long-Back - Exit plugin + +# Screen: NUNCHUCK - ACCELEROMETERS + +   
+ +| Axis | Movement | Lower | Higher | +| :---: | :---: | :---: | :---: | +| X | Left / Right | Left | Right | +| Y | Fwd / Bkwd | Fwd | Bkwd | +| Z | Down / Up | Down | Up | + +* Movement in the direction of an axis changes that axis reading +* Twisting/tilting around an axis changes the other two readings +* EG. + * Move left (along the X axis) will effect X + * Turn left (a rotation around the Y axis) will effect X and Z + +Keys: +* Left - go to the main NUNCHUCK screen +* Up + * Auto-Pause Disabled --> Enable Auto-Pause + * Paused at the end of a page --> Restart scanner + * Running with Auto-Pause Enabled --> Disable Auto-Pause +* Nunchuck-Z - Toggle pause +* Nunchuck-C - Toggle auto-pause +* Long-OK - Enter Software Calibration mode [qv. Calibration] + * Calibration mode on the Accelerometer screen will ONLY calibrate the accelerometer +* Short-OK - Leave Software Calibration mode *and* Calibrate CENTRE position(s) +* Short-Back - Reset controller +* Long-Back - Exit plugin + +NB. Code DOES exist to scroll the display, but the LCD refresh rate is too low, and it looks awful + +# Screen: CLASSIC +
+When you connect a Classic Controller [Pro], you will see a screen displaying a Classic Controller +* The Classic Controller will animate in line with controller events +* The scan rate is set to 30fps, but in reality there is a bit of lag with the LCD screen, so YMMV. + +Keys: +* Left - go to the DUMP screen +* Right - show analogue readings (Left to hide them again) +* Up/Down/OK - [qv. Peak Meters] +* Short-Back - Reset controller +* Long-Back - Exit plugin + +# Screen: DUMP +
+The Dump screen will show you the raw readings from the device.
+If you connect a device which does not have a bespoke `_decode()` function (etc.), you will see (only) this screen. +* SID - String ID - human-readable name (from the `info` table) +* PID - Peripheral ID - The 6 bytes which identify the device. +* Cal - Calibration data - 16 bytes +* The bottom row of hex shows the SIX bytes of Controller data + * Below each hex digit is the binary representation of that digit + * By example. With a Nunchuck connected, click the Z button, and watch the bit on the far right + +Keys: +* Right - return to controller-specific screen (if there is one) +* Short-Back - Reset controller +* Long-Back - Exit plugin + +# Peak Meters (Calibration values) + +On any Controller-specific screen with a Peak/Trough menu displayed: +* Up - [toggle] only show peak values +* Down - [toggle] only show trough values +* Long-OK - Enter Software Calibration mode [qv. Calibration] +* Short-OK - Leave Software Calibration mode / Calibrate CENTRE position(s) + +# Calibration +
+ +* __This project handles Calibration of Analogue Controls, but has NO understanding of Accelerometer values (yet).__ + +Digital buttons do NOT require Calibration. + +Some Calibration data is calculated at the factory, and stored in memory (¿OTP?) on the Controller. + +Each device has a different way to interpret the Calibration Data.
+EG. A Nunchuck has one joystick, and an accelerometer ...whereas a Classic Controller has 2 joysticks and 2 analogue buttons. + +I have personally found the calibration data to be inaccurate (when compared to actual readings), I guess Controllers drift over the years‽ +If the factory-values LIMIT movement, this is easily resolved - by expanding them on-the-fly.
+BUT, I have seen Controllers with factory calibration data that suggests the limits are FURTHER than the joystick can reach ...and this requires a full re-calibration of the Controller! + +Probably the best way to calibrate is to: +* Take a/some reading(s) while the Controller is 'at rest', IE. perfectly still and level. +* Move the Controller to all extremes and store the extreme {peak/trough} values. + +Nintendo (allegedly) take the 'at rest' reading immediately after the Controller is connected, and a 're-calibration' can be performed at any time by pressing {`A`, `B`, `+`, `-`} at the same time, for at least 3 seconds. Although I have no details on what this actually does. + +### This tool calibrates as such: +* When the Controller is first recognised + * The factory Calibration data is used to decide the Centre/Middle position and extreme values (eg. far-left & far-right) for each analogue Control +* Long-OK button press (on the FlipperZero) ...Do NOT touch ANY of the analogue controllers while you are pressing Long-OK + * Start the calibrate button flashing + * Take the current reading as the Centre position + * Set the range limits to "no range" + * You must now move the Control between its extremes, so the code can work out the new Calibration/range/peak+trough values + * When done, press Short-OK to end Software Calibration mode +* Short-OK button press (on the FlipperZero) ...Do NOT touch ANY of the analogue controllers while you are pressing Short-OK + * Stop the calibrate button flashing + * Calibrate the centre position of all analogue controls (accelerometers not supported (yet)) + +# Screen: DEBUG +
+On any screen (except SPLASH) you may press Long-Down to enter Debug mode. + +You can (at any time) attach to the FlipperZero (via USB) with a serial console {`minicom`, `putty`, whatever} and start the `log` function to see the debug messages. + +When you enter the DEBUG screen, the real-time scanner will be stopped. And the following keys made available: +* Up - Attempt to initialise the attached Controller +* OK - Take a reading from the attached Controller +* Long-Down - Restart the real-time scanner and return to the WAIT screen + +You can limit the messages at compile-time [see `./info.sh`], or at runtime [FZ->Settings->System->LogLevel]
+ +[This is probably irrelevant since the introduction of FAP support]
+If you have memory issues, limiting the messages at compile-time will make the plugin smaller.
+But (¿obviously?) the more you limit the messsages, the less debug information will be sent to the logger. + +# TODO + +* FZ Bug: At the time of writing this, there are problems with the i2c FZ functions [qv `i2c_workaround.c`] + diff --git a/applications/plugins/wii_ec_anal/README.txt b/applications/plugins/wii_ec_anal/README.txt new file mode 100644 index 000000000..e7ebe7a4c --- /dev/null +++ b/applications/plugins/wii_ec_anal/README.txt @@ -0,0 +1,67 @@ + ,-------. +---( Files )--- + `-------' + + README.md - User Manual : Body [github markdown] + _images/ - User Manual : Images + _images/GIMP/ - User Manual : GIMP image masters + + LICENSE - Tech Docs : MIT Licence file + README.txt - Tech Docs : Dev notes + notes.txt - Tech Docs : Random dev notes + info.sh - Tech Docs : Retrieve info from source code + + application.fam - FAP : Header file + WiiEC.png - FAP : Icon {10x10} + + gfx/ - Analyser : Images [generated by bc_image_tool] + wii_anal.c|h - Analyser : Main application + wii_anal_ec.c|h - Analyser : Extension controller actions + wii_anal_keys.c|h - Analyser : Keyboard handling + wii_anal_lcd.c|h - Analyser : LCD handling + + i2c_workaround.h - Temporary workaround for i2c bug in FZ code + err.h - Errors + bc_logging.h - Logging macros - especially LOG_LEVEL + + wii_i2c.c|h - i2c functionality + + wii_ec.c|h - Extension Controller basic functions + wii_ec_macros.h - Bespoke Extension Controller handy-dandy MACROs + wii_ec_classic.c|h - EC: Classic Controller Pro scene + wii_ec_nunchuck.c|h - EC: Nunchuck scene + wii_ec_udraw.c|h - EC: UDraw scene - not written + + ,----------------------------------. +---( Adding a new Extension Controller )--- + `----------------------------------' + +//! I'll finish this when I write the UDraw code + +Create a new Extension Controller called "mydev" + +Create wii_ec_mydev.c and wii_ec_mydev.h + +In wii_ec_mydev.c|h + Create the functions [& prototypes] + bool mydev_init (wiiEC_t* const) ; // Additional initialisation code + void mydev_decode (wiiEC_t* const) ; // Decode controller input data + void mydev_msg (wiiEC_t* const, FuriMessageQueue* const) ; // Put event messages in the event queue + void mydev_calib (wiiEC_t* const, ecCalib_t) ; // Controller calibration function + void mydev_show (Canvas* const, state_t* const) ; // Scene LCD display + bool mydev_key (const eventMsg_t* const, state_t* const) ; // Scene key controls + +In wii_ec.h + Include the new header + #include "wii_ec_mydev.h" + Add a perhipheral id to enum ecPid + PID_MYDEV + +In wii_anal.h + As a scene name to enum scene + SCENE_MYDEV + +In wii_ec.c + Add the device definition to the ecId[] array + [PID_MYDEV] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "My Device", SCENE_MYDEV, + mydev_init, mydev_decode, mydev_msg, mydev_calib, mydev_show, mydev_key }, diff --git a/applications/plugins/wii_ec_anal/WiiEC.png b/applications/plugins/wii_ec_anal/WiiEC.png new file mode 100644 index 000000000..6e1afcb0c Binary files /dev/null and b/applications/plugins/wii_ec_anal/WiiEC.png differ diff --git a/applications/plugins/wii_ec_anal/_image_tool/LICENSE b/applications/plugins/wii_ec_anal/_image_tool/LICENSE new file mode 100644 index 000000000..95e544a06 --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 BlueChip + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/plugins/wii_ec_anal/_image_tool/README b/applications/plugins/wii_ec_anal/_image_tool/README new file mode 100644 index 000000000..979605a08 --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/README @@ -0,0 +1,30 @@ +1. Prepare the image + a. Open your *black and white* image in GIMP + b. File -> Export As + filename: EXAMPLE.c + Type : "C source code" + [Export] + prefixed name: gimp_image + Comment : + [x] Use GLib types + [ ] <> + Opacity : 100% + [Export] + +2. Prepare conversion tool [stored in (eg.) /path/] + a. cp _convert*.* /path/ + b. cp EXAMPLE.c /path/ + +3. Run the conversion tool + a. cd /path/ + b. ./_convert.sh EXAMPLE.c + +4. All being well, you will see an ascii version of your image. + If not, then you're gonna have to submit a bug report + +5. You should now have a directory called img_/ + In that directory should be + img_EXAMPLE.c - The data for your new image + img_*.c - The data for other images + images.h - A header for ALL images that have been created in this directory + images.c - A sample FlipperZero show() function [not optimised] diff --git a/applications/plugins/wii_ec_anal/_image_tool/_convert.c b/applications/plugins/wii_ec_anal/_image_tool/_convert.c new file mode 100644 index 000000000..267985e8d --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/_convert.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +int main (int argc, char* argv[]) +{ + const unsigned char* pp = NULL; + uint32_t pix = 0; + int bit = 0; + + uint8_t b = 0; + uint8_t bcnt = 0; + + unsigned int lcnt = 0; + static const int lmax = 16; // max hex values per line + + uint8_t* buf = NULL; + uint8_t* bp = NULL; + unsigned int blen = 0; + + uint8_t* cmp = NULL; + uint8_t* cp = NULL; + unsigned int clen = 0; + uint8_t ctag = 0xFF; + uint32_t tag[256] = {0}; + uint32_t tmax = UINT32_MAX; + + unsigned int x, y, z; + + const char* name = argv[1]; + FILE* fh = fopen(argv[2], "wb"); + + uint32_t white = 0xFF; + + int rv = 0; // assume success + + // allocate buffers + blen = ((img.w * img.h) +0x7) >>3; + bp = (buf = calloc(blen +1, 1)); + cp = (cmp = calloc(blen +4, 1)); + + // sanity check + if (!fh || !buf || !cmp) { + printf("! fopen() or malloc() fail.\n"); + rv = 255; + goto bail; + } + + // Find white value + for (x = 1; x < img.bpp; x++) + white = (white << 8) | 0xFF ; + + // build bit pattern + // create the comment as we go + for (pp = img.b, y = 0; y < img.h; y++) { + fprintf(fh, "// "); + for (x = 0; x < img.w; x++) { + // read pixel + for (pix = 0, z = 0; z < img.bpp; pix = (pix << 8) | *pp++, z++) ; + // get bit and draw + if (pix < white) { + b = (b << 1) | 1; + fprintf(fh, "##"); + } else { + b <<= 1; + fprintf(fh, ".."); + } + // got byte + if ((++bcnt) == 8) { + *bp++ = b; + tag[b]++; + bcnt = (b = 0); + } + } + fprintf(fh, "\n"); + } + fprintf(fh, "\n"); + // padding + if (bcnt) { + b <<= (bcnt = 8 - bcnt); + *bp++ = b; + tag[b]++; + } + // Kill the compression + *bp = ~bp[-1]; // https://youtube.com/clip/Ugkx-JZIr16hETy7hz_H6yIdKPtxVe8C5w_V + + // Byte run length compression + // Find a good tag + for (x = 0; tmax && (x < 256); x++) { + if (tag[x] < tmax) { + tmax = tag[x]; + ctag = x; + } + } + + // compress the data + for (bp = buf, x = 0; (clen < blen) && (x < blen); x++) { + // need at least 4 the same to be worth it + // must compress tag (if it occurs) + if ((bp[x] == bp[x+1]) && (bp[x] == bp[x+2]) && (bp[x] == bp[x+3]) || (bp[x] == ctag)) { + for (y = 1; (y < 255) && (bp[x] == bp[x+y]); y++) ; + *cp++ = ctag; // tag + *cp++ = y; // length + *cp++ = bp[x]; // byte + x += y -1; + clen += 3; + } else { + *cp++ = bp[x]; + clen++; + } + } + + // create struct + fprintf(fh, "#include \"images.h\"\n\n"); + fprintf(fh, "const image_t img_%s = { %d, %d, ", name, img.w, img.h); + + if (clen < blen) { // dump compressed? + fprintf(fh, "true, %d, 0x%02X, { // orig:%d, comp:%.2f%%\n\t", + clen, ctag, blen, 100.0-((clen*100.0)/blen)); + for (x = 0; x < clen; x++) + if (x == clen -1) fprintf(fh, "0x%02X\n}};\n", cmp[x]) ; + else fprintf(fh, "0x%02X%s", cmp[x], (!((x+1)%16)) ? ",\n\t" : ", ") ; + + } else { // dump UNcompressed + fprintf(fh, "false, %d, 0, {\n\t", blen); + for (x = 0; x < blen; x++) + if (x == blen -1) fprintf(fh, "0x%02X\n}};\n", buf[x]) ; + else fprintf(fh, "0x%02X%s", buf[x], (!((x+1)%16)) ? ",\n\t" : ", ") ; + } + +bail: + if (fh) fclose(fh) ; + if (buf) free(buf) ; + if (cmp) free(cmp) ; + + return rv; +} diff --git a/applications/plugins/wii_ec_anal/_image_tool/_convert.sh b/applications/plugins/wii_ec_anal/_image_tool/_convert.sh new file mode 100644 index 000000000..aaa7977b5 --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/_convert.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +[ -z $1 ] && { + echo "Specify an image" + echo "gimp -> export -> c source file -> [x] gunit names" + exit 2 +} + +echo $* + +for N in $* ; do + + [ ! -f $N ] && { + echo "!! File missing $N" + continue + } + + # filename (sans extension) + FN=$(basename -- "$N") + EXT="${FN##*.}" + NAME="${FN%.*}" + + OUTDIR=img_/ + mkdir -p ${OUTDIR} + + HDR=${OUTDIR}/images.h + SRC=${OUTDIR}/images.c + + OUT=${OUTDIR}/img_${NAME}.c + + echo -e "\n¦${N}¦ == ¦${NAME}¦ -> ¦${OUT}¦" + + TESTX=test_${NAME} + TESTC=test_${NAME}.c + + # compile name + CONV=${NAME}_ + + # clean up gimp output + sed -e "s/gimp_image/img/g" \ + -e 's/guint8/unsigned char/g' \ + -e 's/width/w/g' \ + -e 's/height/h/g' \ + -e 's/bytes_per_pixel/bpp/g' \ + -e 's/pixel_data/b/g' \ + -e 's/guint/unsigned int/g' \ + $N \ + | grep -v ^/ \ + | grep -v ^$ \ + > ${CONV}.c + + # append conversion code + cat _convert.c >> ${CONV}.c + + # compile & run converter + rm -f ${CONV} + gcc ${CONV}.c -DIMGTEST -o ${CONV} + ./${CONV} ${NAME} ${OUT} + rm -f ${CONV} ${CONV}.c + + # (create &) update header + [[ ! -f ${HDR} ]] && cp _convert_images.h ${HDR} + sed -i "/ img_${NAME};/d" ${HDR} + sed -i "s#//\[TAG\]#//\[TAG\]\nextern const image_t img_${NAME};#" ${HDR} + + # sample FZ code + [[ ! -f images.c ]] && cp _convert_images.c ${SRC} + + # test + ROOT=${PWD} + pushd ${OUTDIR} >/dev/null + sed "s/zzz/${NAME}/" ${ROOT}/_convert_test.c > ${TESTC} + rm -f ${TESTX} + gcc ${TESTC} ${OUT##*/} -DIMGTEST -o ${TESTX} + ./${TESTX} + rm -f ${TESTX} ${TESTC} + popd >/dev/null + +done diff --git a/applications/plugins/wii_ec_anal/_image_tool/_convert_images.c b/applications/plugins/wii_ec_anal/_image_tool/_convert_images.c new file mode 100644 index 000000000..57046e9a3 --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/_convert_images.c @@ -0,0 +1,141 @@ +#include // GUI (screen/keyboard) API + +#include "images.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +static Canvas* _canvas; +static uint8_t _tlx; +static uint8_t _tly; + +static uint8_t _x; +static uint8_t _y; + +static const image_t* _img; + +static bool _blk; +static Color _set; +static Color _clr; + +//+============================================================================ +static +void _showByteSet (const uint8_t b) +{ + for (uint8_t m = 0x80; m; m >>= 1) { + if (b & m) // plot only SET bits + canvas_draw_dot(_canvas, (_tlx +_x), (_tly +_y)) ; + if ( ((++_x) == _img->w) && !(_x = 0) && ((++_y) == _img->h) ) break ; + } +} + +//+============================================================================ +static +void _showByteClr (const uint8_t b) +{ + for (uint8_t m = 0x80; m; m >>= 1) { + if (!(b & m)) // plot only CLR bits + canvas_draw_dot(_canvas, (_tlx +_x), (_tly +_y)) ; + if ( ((++_x) == _img->w) && !(_x = 0) && ((++_y) == _img->h) ) break ; + } +} + +//+============================================================================ +static +void _showByteAll (const uint8_t b) +{ + for (uint8_t m = 0x80; m; m >>= 1) { + if ((!!(b & m)) ^ _blk) { // Change colour only when required + canvas_set_color(_canvas, ((b & m) ? _set : _clr)); + _blk = !_blk; + } + canvas_draw_dot(_canvas, (_tlx +_x), (_tly +_y)) ; + if ( ((++_x) == _img->w) && !(_x = 0) && ((++_y) == _img->h) ) break ; + } +} + +//+============================================================================ +// available modes are SHOW_SET_BLK - plot image pixels that are SET in BLACK +// SHOW_XOR - same as SET_BLACK +// SHOW_SET_WHT - plot image pixels that are SET in WHITE +// SHOW_CLR_BLK - plot image pixels that are CLEAR in BLACK +// SHOW_CLR_WHT - plot image pixels that are CLEAR in WHITE +// SHOW_ALL - plot all images pixels as they are +// SHOW_ALL_INV - plot all images pixels inverted +// +void show (Canvas* const canvas, const uint8_t tlx, const uint8_t tly, + const image_t* img, const showMode_t mode) +{ + void(*fnShow)(const uint8_t) = NULL; + + const uint8_t* bp = img->data; + + // code size optimisation + switch (mode & SHOW_INV_) { + case SHOW_NRM_: + _set = ColorBlack; + _clr = ColorWhite; + break; + + case SHOW_INV_: + _set = ColorWhite; + _clr = ColorBlack; + break; + + case SHOW_BLK_: + canvas_set_color(canvas, ColorBlack); + break; + + case SHOW_WHT_: + canvas_set_color(canvas, ColorWhite); + break; + + } + switch (mode & SHOW_INV_) { + case SHOW_NRM_: + case SHOW_INV_: + fnShow = _showByteAll; + canvas_set_color(canvas, ColorWhite); + _blk = 0; + break; + + case SHOW_BLK_: + case SHOW_WHT_: + switch (mode & SHOW_ALL_) { + case SHOW_SET_: + fnShow = _showByteSet; + break; + case SHOW_CLR_: + fnShow = _showByteClr; + break; + } + break; + } + furi_check(fnShow); + + // I want nested functions! + _canvas = canvas; + _img = img; + _tlx = tlx; + _tly = tly; + _x = 0; + _y = 0; + + // Compressed + if (img->c) { + for (unsigned int i = 0; i < img->len; i++, bp++) { + // Compressed data? {tag, length, value} + if (*bp == img->tag) { + for (uint16_t c = 0; c < bp[1]; c++) fnShow(bp[2]) ; + bp += 3 -1; + i += 3 -1; + + // Uncompressed byte + } else { + fnShow(*bp); + } + } + + // Not compressed + } else { + for (unsigned int i = 0; i < img->len; i++, bp++) fnShow(*bp) ; + } +} diff --git a/applications/plugins/wii_ec_anal/_image_tool/_convert_images.h b/applications/plugins/wii_ec_anal/_image_tool/_convert_images.h new file mode 100644 index 000000000..bfc44568e --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/_convert_images.h @@ -0,0 +1,53 @@ +#ifndef IMAGES_H_ +#define IMAGES_H_ + +#include +#include + +//----------------------------------------------------------------------------- ---------------------------------------- +typedef + enum showMode { + // {INV:--:WHT:BLK::--:--:CLR:SET} + SHOW_SET_ = 0x01, + SHOW_CLR_ = 0x02, + SHOW_ALL_ = SHOW_SET_ | SHOW_CLR_, + + SHOW_BLK_ = 0x10, + SHOW_WHT_ = 0x20, + SHOW_NRM_ = 0x00, + SHOW_INV_ = SHOW_BLK_ | SHOW_WHT_, + + SHOW_SET_BLK = SHOW_SET_ | SHOW_BLK_, + SHOW_SET_WHT = SHOW_SET_ | SHOW_WHT_, + + SHOW_CLR_BLK = SHOW_CLR_ | SHOW_BLK_, + SHOW_CLR_WHT = SHOW_CLR_ | SHOW_WHT_, + + SHOW_ALL = SHOW_ALL_ | SHOW_NRM_, + SHOW_ALL_INV = SHOW_ALL_ | SHOW_INV_, + } +showMode_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +typedef + struct image { + uint8_t w; // width + uint8_t h; // height + bool c; // compressed? + uint16_t len; // image data length + uint8_t tag; // rle tag + uint8_t data[]; // image data + } +image_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +//[TAG] + +//----------------------------------------------------------------------------- ---------------------------------------- +#ifndef IMGTEST +# include + void show (Canvas* const canvas, const uint8_t tlx, const uint8_t tly, + const image_t* img, const showMode_t mode) ; +#endif + +#endif //IMAGES_H_ diff --git a/applications/plugins/wii_ec_anal/_image_tool/_convert_test.c b/applications/plugins/wii_ec_anal/_image_tool/_convert_test.c new file mode 100644 index 000000000..4bdb531d5 --- /dev/null +++ b/applications/plugins/wii_ec_anal/_image_tool/_convert_test.c @@ -0,0 +1,59 @@ +#include +#include + +#include "images.h" + +//----------------------------------------------------------------------------- +// This will be the plot function out of your graphics library +// +#define PLOT(x,y,c) do { \ + printf("%s", (c ? "#" : ".")); \ + if (x == img->w -1) printf("\n") ; \ +}while(0) + +//+============================================================================ +// The pain we endure to avoid code duplication cleanly +// +#define PLOTBYTE(b) do { \ + for (uint8_t m = 0x80; m; m>>=1) { \ + PLOT(x,y, (b & m)); \ + if ( ((++x) == img->w) && !(x = 0) && ((++y) == img->h) ) break ; \ + } \ +}while(0) + +void show (const image_t* img) +{ + // Some variables + const uint8_t* bp = img->data; + unsigned int x = 0; + unsigned int y = 0; + + // Compressed + if (img->c) { + for (unsigned int i = 0; i < img->len; i++, bp++) { + // Compressed data? {tag, length, value} + if (*bp == img->tag) { + for (uint16_t c = 0; c < bp[1]; c++) PLOTBYTE(bp[2]) ; + bp += 3 -1; + i += 3 -1; + + // Uncompressed byte + } else { + PLOTBYTE(*bp); + } + } + + // Not compressed + } else { + for (unsigned int i = 0; i < img->len; i++, bp++) PLOTBYTE(*bp) ; + } +} + +#undef PLOTBYTE + +//+============================================================================ +int main (void) +{ + show(&img_zzz); + return 0; +} diff --git a/applications/plugins/wii_ec_anal/_images/CLASSIC.png b/applications/plugins/wii_ec_anal/_images/CLASSIC.png new file mode 100644 index 000000000..aa5318b33 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/CLASSIC.png differ diff --git a/applications/plugins/wii_ec_anal/_images/CLASSIC_N.png b/applications/plugins/wii_ec_anal/_images/CLASSIC_N.png new file mode 100644 index 000000000..24f4ac225 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/CLASSIC_N.png differ diff --git a/applications/plugins/wii_ec_anal/_images/DEBUG.png b/applications/plugins/wii_ec_anal/_images/DEBUG.png new file mode 100644 index 000000000..bca35c693 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/DEBUG.png differ diff --git a/applications/plugins/wii_ec_anal/_images/DUMP.png b/applications/plugins/wii_ec_anal/_images/DUMP.png new file mode 100644 index 000000000..dc9328aab Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/DUMP.png differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/Nunchuck_acc.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/Nunchuck_acc.xcf new file mode 100644 index 000000000..67f70139e Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/Nunchuck_acc.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/RIP.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/RIP.xcf new file mode 100644 index 000000000..0058fe9c8 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/RIP.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/Wiring.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/Wiring.xcf new file mode 100644 index 000000000..aa8078db8 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/Wiring.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/classic.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/classic.xcf new file mode 100644 index 000000000..6fd152675 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/classic.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/csLogo.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/csLogo.xcf new file mode 100644 index 000000000..f4e33844a Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/csLogo.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/fonts.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/fonts.xcf new file mode 100644 index 000000000..d05d03fc7 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/fonts.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/frame.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/frame.xcf new file mode 100644 index 000000000..31705cf72 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/frame.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/port.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/port.xcf new file mode 100644 index 000000000..10fcd2de2 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/port.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/GIMP/social.xcf b/applications/plugins/wii_ec_anal/_images/GIMP/social.xcf new file mode 100644 index 000000000..377eaa63b Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/GIMP/social.xcf differ diff --git a/applications/plugins/wii_ec_anal/_images/NUNCHUCK.png b/applications/plugins/wii_ec_anal/_images/NUNCHUCK.png new file mode 100644 index 000000000..bc31ae386 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/NUNCHUCK.png differ diff --git a/applications/plugins/wii_ec_anal/_images/NUNCHUCK_acc.png b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_acc.png new file mode 100644 index 000000000..895c85e4c Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_acc.png differ diff --git a/applications/plugins/wii_ec_anal/_images/NUNCHUCK_anal.png b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_anal.png new file mode 100644 index 000000000..e821d7ee2 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_anal.png differ diff --git a/applications/plugins/wii_ec_anal/_images/NUNCHUCK_cal.gif b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_cal.gif new file mode 100644 index 000000000..72d807a54 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_cal.gif differ diff --git a/applications/plugins/wii_ec_anal/_images/NUNCHUCK_cal.png b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_cal.png new file mode 100644 index 000000000..f9d34bb93 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/NUNCHUCK_cal.png differ diff --git a/applications/plugins/wii_ec_anal/_images/Nunchucky.png b/applications/plugins/wii_ec_anal/_images/Nunchucky.png new file mode 100644 index 000000000..3af395da6 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/Nunchucky.png differ diff --git a/applications/plugins/wii_ec_anal/_images/RIP.png b/applications/plugins/wii_ec_anal/_images/RIP.png new file mode 100644 index 000000000..0acfe0c00 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/RIP.png differ diff --git a/applications/plugins/wii_ec_anal/_images/SPLASH.png b/applications/plugins/wii_ec_anal/_images/SPLASH.png new file mode 100644 index 000000000..a5c3f093a Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/SPLASH.png differ diff --git a/applications/plugins/wii_ec_anal/_images/WAIT.png b/applications/plugins/wii_ec_anal/_images/WAIT.png new file mode 100644 index 000000000..776edc3f1 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/WAIT.png differ diff --git a/applications/plugins/wii_ec_anal/_images/WiiChuck.png b/applications/plugins/wii_ec_anal/_images/WiiChuck.png new file mode 100644 index 000000000..532ce3096 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/WiiChuck.png differ diff --git a/applications/plugins/wii_ec_anal/_images/Wiring.png b/applications/plugins/wii_ec_anal/_images/Wiring.png new file mode 100644 index 000000000..300c07ee4 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/Wiring.png differ diff --git a/applications/plugins/wii_ec_anal/_images/plug.png b/applications/plugins/wii_ec_anal/_images/plug.png new file mode 100644 index 000000000..c418f43b1 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/plug.png differ diff --git a/applications/plugins/wii_ec_anal/_images/social.png b/applications/plugins/wii_ec_anal/_images/social.png new file mode 100644 index 000000000..1d3eddcc5 Binary files /dev/null and b/applications/plugins/wii_ec_anal/_images/social.png differ diff --git a/applications/plugins/wii_ec_anal/application.fam b/applications/plugins/wii_ec_anal/application.fam new file mode 100644 index 000000000..ac11d260e --- /dev/null +++ b/applications/plugins/wii_ec_anal/application.fam @@ -0,0 +1,36 @@ +# qv. https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppManifests.md + +App( + # --- App Info + appid="wii_ec_anal", + name="Wii EC Analyser", + + # --- Entry point + apptype=FlipperAppType.EXTERNAL, + entry_point="wii_ec_anal", + + # --- Interaction + cdefines=["APP_WII_EC_ANAL"], + requires=[ + "gui", + ], + +# conflicts="", +# sdk_headers="", + + # --- Run-time info + stack_size=2 * 1024, + order=20, + + # --- FAP details + sources=["wii_*.c", "gfx/*.c"], + +# fap_weburl="https://github.com/csBlueChip/FlipperZero_plugin_WiiChuck/", +# fap_author="BlueChip", + +# fap_description="Wii Extension Controller Protocol Analyser", +# fap_version=(1,0), + + fap_icon="WiiEC.png", + fap_category="Misc", +) diff --git a/applications/plugins/wii_ec_anal/bc_logging.h b/applications/plugins/wii_ec_anal/bc_logging.h new file mode 100644 index 000000000..d9bb48c92 --- /dev/null +++ b/applications/plugins/wii_ec_anal/bc_logging.h @@ -0,0 +1,70 @@ +#ifndef BC_LOGGING_H_ +#define BC_LOGGING_H_ + +#include +#include "err.h" // appName + +//! WARNING: There is a bug in Furi such that if you crank LOG_LEVEL up to 6=TRACE +//! AND you have menu->settings->system->logLevel = trace +//! THEN this program will cause the FZ to crash when the plugin exits! +#define LOG_LEVEL 4 + +//----------------------------------------------------------------------------- ---------------------------------------- +// The FlipperZero Settings->System menu allows you to set the logging level at RUN-time +// ... LOG_LEVEL lets you limit it at COMPILE-time +// +// FURI logging has 6 levels (numbered 1 thru 6} +// 1. None +// 2. Errors FURI_LOG_E +// 3. Warnings FURI_LOG_W +// 4. Information FURI_LOG_I +// 5. Debug FURI_LOG_D +// 6. Trace FURI_LOG_T +// +// --> furi/core/log.h +// + +// The FlipperZero Settings->System menu allows you to set the logging level at RUN-time +// This lets you limit it at COMPILE-time +#ifndef LOG_LEVEL +# define LOG_LEVEL 6 // default = full logging +#endif + +#if (LOG_LEVEL < 2) +# undef FURI_LOG_E +# define FURI_LOG_E(tag, fmt, ...) +#endif + +#if (LOG_LEVEL < 3) +# undef FURI_LOG_W +# define FURI_LOG_W(tag, fmt, ...) +#endif + +#if (LOG_LEVEL < 4) +# undef FURI_LOG_I +# define FURI_LOG_I(tag, fmt, ...) +#endif + +#if (LOG_LEVEL < 5) +# undef FURI_LOG_D +# define FURI_LOG_D(tag, fmt, ...) +#endif + +#if (LOG_LEVEL < 6) +# undef FURI_LOG_T +# define FURI_LOG_T(tag, fmt, ...) +#endif + +//---------------------------------------------------------- +// Logging helper macros +// +#define ERROR(fmt, ...) FURI_LOG_E(appName, fmt __VA_OPT__(,) __VA_ARGS__) +#define WARN(fmt, ...) FURI_LOG_W(appName, fmt __VA_OPT__(,) __VA_ARGS__) +#define INFO(fmt, ...) FURI_LOG_I(appName, fmt __VA_OPT__(,) __VA_ARGS__) +#define DEBUG(fmt, ...) FURI_LOG_D(appName, fmt __VA_OPT__(,) __VA_ARGS__) +#define TRACE(fmt, ...) FURI_LOG_T(appName, fmt __VA_OPT__(,) __VA_ARGS__) + +#define ENTER TRACE("(+) %s", __func__) +#define LEAVE TRACE("(-) %s", __func__) + +#endif //BC_LOGGING_H_ diff --git a/applications/plugins/wii_ec_anal/err.h b/applications/plugins/wii_ec_anal/err.h new file mode 100644 index 000000000..9398a3fb8 --- /dev/null +++ b/applications/plugins/wii_ec_anal/err.h @@ -0,0 +1,69 @@ +// Avoid circular/nested/mulitple inclusion +#ifndef ERR_H_ +#define ERR_H_ + +//----------------------------------------------------------------------------- ---------------------------------------- +// Application name +// +static const char* const appName = "Wii_i2c"; //$ Name used in log files + +//----------------------------------------------------------------------------- ---------------------------------------- +// Error codes and messages +// + +// You should only ever (need to) edit this list +// ...Watch out for extraneous whitespace after the terminating backslashes +#define FOREACH_ES(esPrial) \ + /* The first line MUST define 'ERR_OK = 0' */ \ + esPrial( 0, ERR_OK , "OK (no error)") \ +\ + esPrial( 1, ERR_MALLOC_QUEUE , "malloc() fail - queue") \ + esPrial( 2, ERR_MALLOC_STATE , "malloc() fail - state") \ + esPrial( 3, ERR_MALLOC_TEXT , "malloc() fail - text") \ + esPrial( 4, ERR_MALLOC_VIEW , "malloc() fail - viewport") \ + esPrial( 5, ERR_NO_MUTEX , "Cannot create mutex") \ + esPrial( 6, ERR_NO_GUI , "Cannot open GUI") \ + esPrial( 7, ERR_NO_TIMER , "Cannot create timer") \ + esPrial( 8, ERR_NO_NOTIFY , "Cannot acquire notifications handle") \ +\ + esPrial(10, ERR_MUTEX_BLOCK , "Mutex block failed") \ + esPrial(11, ERR_MUTEX_RELEASE , "Mutex release failed") \ +\ + esPrial(20, ERR_QUEUE_RTOS , "queue - Undefined RTOS error") \ + esPrial(21, DEBUG_QUEUE_TIMEOUT, "queue - Timeout") \ + esPrial(22, ERR_QUEUE_RESOURCE , "queue - Resource not available") \ + esPrial(23, ERR_QUEUE_BADPRM , "queue - Bad parameter") \ + esPrial(24, ERR_QUEUE_NOMEM , "queue - Out of memory") \ + esPrial(25, ERR_QUEUE_ISR , "queue - Banned in ISR") \ + esPrial(26, ERR_QUEUE_UNK , "queue - Unknown") \ +\ + esPrial(30, WARN_SCAN_START , "Scan - Already started") \ + esPrial(31, WARN_SCAN_STOP , "Scan - Already stopped") \ + esPrial(32, ERR_TIMER_START , "Scan - Cannot start timer") \ + esPrial(33, ERR_TIMER_STOP , "Scan - Cannot stop timer") \ +//[EOT] + +// Declare list extraction macros +#define ES_ENUM(num, ename, string) ename = num, +#define ES_STRING(num, ename, string) string"\r\n", + +// Build the enum +typedef + enum err { FOREACH_ES(ES_ENUM) } +err_t ; + +// You need to '#define ERR_C_' in precisely ONE source file +#ifdef ERR_C_ + // Build the string list + const char* const wii_errs[] = { FOREACH_ES(ES_STRING) }; +#else + // Give access to string list + extern const char* const wii_errs[]; +#endif + +// This is a header file, clean up +#undef ES_ENUM +#undef ES_STRING +#undef FOREACH_ES + +#endif // ERR_H_ diff --git a/applications/plugins/wii_ec_anal/gfx/images.c b/applications/plugins/wii_ec_anal/gfx/images.c new file mode 100644 index 000000000..57046e9a3 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/images.c @@ -0,0 +1,141 @@ +#include // GUI (screen/keyboard) API + +#include "images.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +static Canvas* _canvas; +static uint8_t _tlx; +static uint8_t _tly; + +static uint8_t _x; +static uint8_t _y; + +static const image_t* _img; + +static bool _blk; +static Color _set; +static Color _clr; + +//+============================================================================ +static +void _showByteSet (const uint8_t b) +{ + for (uint8_t m = 0x80; m; m >>= 1) { + if (b & m) // plot only SET bits + canvas_draw_dot(_canvas, (_tlx +_x), (_tly +_y)) ; + if ( ((++_x) == _img->w) && !(_x = 0) && ((++_y) == _img->h) ) break ; + } +} + +//+============================================================================ +static +void _showByteClr (const uint8_t b) +{ + for (uint8_t m = 0x80; m; m >>= 1) { + if (!(b & m)) // plot only CLR bits + canvas_draw_dot(_canvas, (_tlx +_x), (_tly +_y)) ; + if ( ((++_x) == _img->w) && !(_x = 0) && ((++_y) == _img->h) ) break ; + } +} + +//+============================================================================ +static +void _showByteAll (const uint8_t b) +{ + for (uint8_t m = 0x80; m; m >>= 1) { + if ((!!(b & m)) ^ _blk) { // Change colour only when required + canvas_set_color(_canvas, ((b & m) ? _set : _clr)); + _blk = !_blk; + } + canvas_draw_dot(_canvas, (_tlx +_x), (_tly +_y)) ; + if ( ((++_x) == _img->w) && !(_x = 0) && ((++_y) == _img->h) ) break ; + } +} + +//+============================================================================ +// available modes are SHOW_SET_BLK - plot image pixels that are SET in BLACK +// SHOW_XOR - same as SET_BLACK +// SHOW_SET_WHT - plot image pixels that are SET in WHITE +// SHOW_CLR_BLK - plot image pixels that are CLEAR in BLACK +// SHOW_CLR_WHT - plot image pixels that are CLEAR in WHITE +// SHOW_ALL - plot all images pixels as they are +// SHOW_ALL_INV - plot all images pixels inverted +// +void show (Canvas* const canvas, const uint8_t tlx, const uint8_t tly, + const image_t* img, const showMode_t mode) +{ + void(*fnShow)(const uint8_t) = NULL; + + const uint8_t* bp = img->data; + + // code size optimisation + switch (mode & SHOW_INV_) { + case SHOW_NRM_: + _set = ColorBlack; + _clr = ColorWhite; + break; + + case SHOW_INV_: + _set = ColorWhite; + _clr = ColorBlack; + break; + + case SHOW_BLK_: + canvas_set_color(canvas, ColorBlack); + break; + + case SHOW_WHT_: + canvas_set_color(canvas, ColorWhite); + break; + + } + switch (mode & SHOW_INV_) { + case SHOW_NRM_: + case SHOW_INV_: + fnShow = _showByteAll; + canvas_set_color(canvas, ColorWhite); + _blk = 0; + break; + + case SHOW_BLK_: + case SHOW_WHT_: + switch (mode & SHOW_ALL_) { + case SHOW_SET_: + fnShow = _showByteSet; + break; + case SHOW_CLR_: + fnShow = _showByteClr; + break; + } + break; + } + furi_check(fnShow); + + // I want nested functions! + _canvas = canvas; + _img = img; + _tlx = tlx; + _tly = tly; + _x = 0; + _y = 0; + + // Compressed + if (img->c) { + for (unsigned int i = 0; i < img->len; i++, bp++) { + // Compressed data? {tag, length, value} + if (*bp == img->tag) { + for (uint16_t c = 0; c < bp[1]; c++) fnShow(bp[2]) ; + bp += 3 -1; + i += 3 -1; + + // Uncompressed byte + } else { + fnShow(*bp); + } + } + + // Not compressed + } else { + for (unsigned int i = 0; i < img->len; i++, bp++) fnShow(*bp) ; + } +} diff --git a/applications/plugins/wii_ec_anal/gfx/images.h b/applications/plugins/wii_ec_anal/gfx/images.h new file mode 100644 index 000000000..87f2b89b7 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/images.h @@ -0,0 +1,134 @@ +#ifndef IMAGES_H_ +#define IMAGES_H_ + +#include +#include + +//----------------------------------------------------------------------------- ---------------------------------------- +typedef + enum showMode { + // {INV:--:WHT:BLK::--:--:CLR:SET} + SHOW_SET_ = 0x01, + SHOW_CLR_ = 0x02, + SHOW_ALL_ = SHOW_SET_ | SHOW_CLR_, + + SHOW_BLK_ = 0x10, + SHOW_WHT_ = 0x20, + SHOW_NRM_ = 0x00, + SHOW_INV_ = SHOW_BLK_ | SHOW_WHT_, + + SHOW_SET_BLK = SHOW_SET_ | SHOW_BLK_, + SHOW_SET_WHT = SHOW_SET_ | SHOW_WHT_, + + SHOW_CLR_BLK = SHOW_CLR_ | SHOW_BLK_, + SHOW_CLR_WHT = SHOW_CLR_ | SHOW_WHT_, + + SHOW_ALL = SHOW_ALL_ | SHOW_NRM_, + SHOW_ALL_INV = SHOW_ALL_ | SHOW_INV_, + } +showMode_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +typedef + struct image { + uint8_t w; // width + uint8_t h; // height + bool c; // compressed? + uint16_t len; // image data length + uint8_t tag; // rle tag + uint8_t data[]; // image data + } +image_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +//[TAG] +extern const image_t img_csLogo_Small; +extern const image_t img_3x5_v; +extern const image_t img_3x5_9; +extern const image_t img_3x5_8; +extern const image_t img_3x5_7; +extern const image_t img_3x5_6; +extern const image_t img_3x5_5; +extern const image_t img_3x5_4; +extern const image_t img_3x5_3; +extern const image_t img_3x5_2; +extern const image_t img_3x5_1; +extern const image_t img_3x5_0; +extern const image_t img_key_Ui; +extern const image_t img_key_OKi; +extern const image_t img_RIP; +extern const image_t img_cc_trg_R4; +extern const image_t img_cc_trg_R3; +extern const image_t img_cc_trg_R2; +extern const image_t img_cc_trg_R1; +extern const image_t img_cc_trg_L4; +extern const image_t img_cc_trg_L3; +extern const image_t img_cc_trg_L2; +extern const image_t img_cc_trg_L1; +extern const image_t img_cc_Joy; +extern const image_t img_cc_Main; +extern const image_t img_cc_Cable; +extern const image_t img_key_Back; +extern const image_t img_key_OK; +extern const image_t img_6x8_Z; +extern const image_t img_6x8_Y; +extern const image_t img_6x8_X; +extern const image_t img_key_U; +extern const image_t img_key_D; +extern const image_t img_csLogo_FULL; +extern const image_t img_6x8_7; +extern const image_t img_key_R; +extern const image_t img_key_L; +extern const image_t img_5x7_7; +extern const image_t img_5x7_F; +extern const image_t img_5x7_E; +extern const image_t img_5x7_D; +extern const image_t img_5x7_C; +extern const image_t img_5x7_B; +extern const image_t img_5x7_A; +extern const image_t img_5x7_9; +extern const image_t img_5x7_8; +extern const image_t img_5x7_6; +extern const image_t img_5x7_5; +extern const image_t img_5x7_4; +extern const image_t img_5x7_3; +extern const image_t img_5x7_2; +extern const image_t img_5x7_1; +extern const image_t img_5x7_0; +extern const image_t img_6x8_v; +extern const image_t img_6x8_n; +extern const image_t img_6x8_G; +extern const image_t img_6x8_F; +extern const image_t img_6x8_E; +extern const image_t img_6x8_d; +extern const image_t img_6x8_C; +extern const image_t img_6x8_B; +extern const image_t img_6x8_A; +extern const image_t img_6x8_9; +extern const image_t img_6x8_8; +extern const image_t img_6x8_6; +extern const image_t img_6x8_5; +extern const image_t img_6x8_4; +extern const image_t img_6x8_3; +extern const image_t img_6x8_2; +extern const image_t img_6x8_1; +extern const image_t img_6x8_0; +extern const image_t img_ecp_SDA; +extern const image_t img_ecp_SCL; +extern const image_t img_ecp_port; +extern const image_t img_cc_pad_UD1; +extern const image_t img_cc_pad_LR1; +extern const image_t img_cc_btn_Y1; +extern const image_t img_cc_btn_X1; +extern const image_t img_cc_btn_B1; +extern const image_t img_cc_btn_A1; +extern const image_t img_6x8_D; + +//----------------------------------------------------------------------------- ---------------------------------------- +#ifndef IMGTEST +# include + void show (Canvas* const canvas, const uint8_t tlx, const uint8_t tly, + const image_t* img, const showMode_t mode) ; +#endif + +#endif //IMAGES_H_ diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_0.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_0.c new file mode 100644 index 000000000..975d98d35 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_0.c @@ -0,0 +1,11 @@ +// ###### +// ##..## +// ##..## +// ##..## +// ###### + +#include "images.h" + +const image_t img_3x5_0 = { 3, 5, false, 2, 0, { + 0xF6, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_1.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_1.c new file mode 100644 index 000000000..0d9dc3fe4 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_1.c @@ -0,0 +1,11 @@ +// ####.. +// ..##.. +// ..##.. +// ..##.. +// ###### + +#include "images.h" + +const image_t img_3x5_1 = { 3, 5, false, 2, 0, { + 0xC9, 0x2E +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_2.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_2.c new file mode 100644 index 000000000..d98bf4e93 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_2.c @@ -0,0 +1,11 @@ +// ###### +// ....## +// ###### +// ##.... +// ###### + +#include "images.h" + +const image_t img_3x5_2 = { 3, 5, false, 2, 0, { + 0xE7, 0xCE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_3.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_3.c new file mode 100644 index 000000000..8d08ed1b6 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_3.c @@ -0,0 +1,11 @@ +// ###### +// ....## +// ..#### +// ....## +// ###### + +#include "images.h" + +const image_t img_3x5_3 = { 3, 5, false, 2, 0, { + 0xE5, 0x9E +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_4.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_4.c new file mode 100644 index 000000000..795e9b76f --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_4.c @@ -0,0 +1,11 @@ +// ##.... +// ##..## +// ###### +// ....## +// ....## + +#include "images.h" + +const image_t img_3x5_4 = { 3, 5, false, 2, 0, { + 0x97, 0x92 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_5.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_5.c new file mode 100644 index 000000000..377853507 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_5.c @@ -0,0 +1,11 @@ +// ###### +// ##.... +// ###### +// ....## +// ###### + +#include "images.h" + +const image_t img_3x5_5 = { 3, 5, false, 2, 0, { + 0xF3, 0x9E +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_6.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_6.c new file mode 100644 index 000000000..d3af64071 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_6.c @@ -0,0 +1,11 @@ +// ####.. +// ##.... +// ###### +// ##..## +// ###### + +#include "images.h" + +const image_t img_3x5_6 = { 3, 5, false, 2, 0, { + 0xD3, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_7.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_7.c new file mode 100644 index 000000000..2c3b1e0b9 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_7.c @@ -0,0 +1,11 @@ +// ###### +// ....## +// ..##.. +// ..##.. +// ..##.. + +#include "images.h" + +const image_t img_3x5_7 = { 3, 5, false, 2, 0, { + 0xE5, 0x24 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_8.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_8.c new file mode 100644 index 000000000..5cb6d3354 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_8.c @@ -0,0 +1,11 @@ +// ###### +// ##..## +// ###### +// ##..## +// ###### + +#include "images.h" + +const image_t img_3x5_8 = { 3, 5, false, 2, 0, { + 0xF7, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_9.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_9.c new file mode 100644 index 000000000..ee5e82b87 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_9.c @@ -0,0 +1,11 @@ +// ###### +// ##..## +// ###### +// ....## +// ..#### + +#include "images.h" + +const image_t img_3x5_9 = { 3, 5, false, 2, 0, { + 0xF7, 0x96 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_3x5_v.c b/applications/plugins/wii_ec_anal/gfx/img_3x5_v.c new file mode 100644 index 000000000..dcf3f631d --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_3x5_v.c @@ -0,0 +1,11 @@ +// ...... +// ...... +// ##..## +// ##..## +// ..##.. + +#include "images.h" + +const image_t img_3x5_v = { 3, 5, false, 2, 0, { + 0x02, 0xD4 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_0.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_0.c new file mode 100644 index 000000000..c59852f19 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_0.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ##....#### +// ##..##..## +// ####....## +// ##......## +// ..######.. + +#include "images.h" + +const image_t img_5x7_0 = { 5, 7, false, 5, 0, { + 0x74, 0x67, 0x5C, 0xC5, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_1.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_1.c new file mode 100644 index 000000000..4bd08f89c --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_1.c @@ -0,0 +1,13 @@ +// ..####.... +// ##..##.... +// ....##.... +// ....##.... +// ....##.... +// ....##.... +// ########## + +#include "images.h" + +const image_t img_5x7_1 = { 5, 7, false, 5, 0, { + 0x65, 0x08, 0x42, 0x13, 0xE0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_2.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_2.c new file mode 100644 index 000000000..1270393f7 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_2.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ........## +// ......##.. +// ....##.... +// ..##...... +// ########## + +#include "images.h" + +const image_t img_5x7_2 = { 5, 7, false, 5, 0, { + 0x74, 0x42, 0x22, 0x23, 0xE0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_3.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_3.c new file mode 100644 index 000000000..e26bac523 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_3.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ........## +// ....####.. +// ........## +// ##......## +// ..######.. + +#include "images.h" + +const image_t img_5x7_3 = { 5, 7, false, 5, 0, { + 0x74, 0x42, 0x60, 0xC5, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_4.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_4.c new file mode 100644 index 000000000..e0dc5687f --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_4.c @@ -0,0 +1,13 @@ +// ##........ +// ##........ +// ##....##.. +// ##....##.. +// ########## +// ......##.. +// ......##.. + +#include "images.h" + +const image_t img_5x7_4 = { 5, 7, false, 5, 0, { + 0x84, 0x25, 0x2F, 0x88, 0x40 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_5.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_5.c new file mode 100644 index 000000000..81747376f --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_5.c @@ -0,0 +1,13 @@ +// ########## +// ##........ +// ##........ +// ########.. +// ........## +// ........## +// ########.. + +#include "images.h" + +const image_t img_5x7_5 = { 5, 7, false, 5, 0, { + 0xFC, 0x21, 0xE0, 0x87, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_6.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_6.c new file mode 100644 index 000000000..455c874dc --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_6.c @@ -0,0 +1,13 @@ +// ..######.. +// ##........ +// ##........ +// ########.. +// ##......## +// ##......## +// ..######.. + +#include "images.h" + +const image_t img_5x7_6 = { 5, 7, false, 5, 0, { + 0x74, 0x21, 0xE8, 0xC5, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_7.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_7.c new file mode 100644 index 000000000..73e813a21 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_7.c @@ -0,0 +1,13 @@ +// ########## +// ........## +// ......##.. +// ......##.. +// ....##.... +// ....##.... +// ....##.... + +#include "images.h" + +const image_t img_5x7_7 = { 5, 7, false, 5, 0, { + 0xF8, 0x44, 0x22, 0x10, 0x80 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_8.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_8.c new file mode 100644 index 000000000..0f04a48bf --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_8.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ##......## +// ..######.. +// ##......## +// ##......## +// ..######.. + +#include "images.h" + +const image_t img_5x7_8 = { 5, 7, false, 5, 0, { + 0x74, 0x62, 0xE8, 0xC5, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_9.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_9.c new file mode 100644 index 000000000..2b1e978c6 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_9.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ##......## +// ..######## +// ........## +// ........## +// ..######.. + +#include "images.h" + +const image_t img_5x7_9 = { 5, 7, false, 5, 0, { + 0x74, 0x62, 0xF0, 0x85, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_A.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_A.c new file mode 100644 index 000000000..a6b049f01 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_A.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ##......## +// ########## +// ##......## +// ##......## +// ##......## + +#include "images.h" + +const image_t img_5x7_A = { 5, 7, false, 5, 0, { + 0x74, 0x63, 0xF8, 0xC6, 0x20 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_B.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_B.c new file mode 100644 index 000000000..06b36599c --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_B.c @@ -0,0 +1,13 @@ +// ########.. +// ##......## +// ##......## +// ##..####.. +// ##......## +// ##......## +// ########.. + +#include "images.h" + +const image_t img_5x7_B = { 5, 7, false, 5, 0, { + 0xF4, 0x63, 0x68, 0xC7, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_C.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_C.c new file mode 100644 index 000000000..c058d09a9 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_C.c @@ -0,0 +1,13 @@ +// ..######.. +// ##......## +// ##........ +// ##........ +// ##........ +// ##......## +// ..######.. + +#include "images.h" + +const image_t img_5x7_C = { 5, 7, false, 5, 0, { + 0x74, 0x61, 0x08, 0x45, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_D.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_D.c new file mode 100644 index 000000000..3425e3648 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_D.c @@ -0,0 +1,13 @@ +// ..######.. +// ##..##..## +// ....##..## +// ....##..## +// ....##..## +// ##..##..## +// ..######.. + +#include "images.h" + +const image_t img_5x7_D = { 5, 7, false, 5, 0, { + 0x75, 0x4A, 0x52, 0xD5, 0xC0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_E.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_E.c new file mode 100644 index 000000000..c7bbc301a --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_E.c @@ -0,0 +1,13 @@ +// ########## +// ##........ +// ##........ +// ######.... +// ##........ +// ##........ +// ########## + +#include "images.h" + +const image_t img_5x7_E = { 5, 7, false, 5, 0, { + 0xFC, 0x21, 0xC8, 0x43, 0xE0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_5x7_F.c b/applications/plugins/wii_ec_anal/gfx/img_5x7_F.c new file mode 100644 index 000000000..440c37eae --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_5x7_F.c @@ -0,0 +1,13 @@ +// ########## +// ##........ +// ##........ +// ######.... +// ##........ +// ##........ +// ##........ + +#include "images.h" + +const image_t img_5x7_F = { 5, 7, false, 5, 0, { + 0xFC, 0x21, 0xC8, 0x42, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_0.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_0.c new file mode 100644 index 000000000..b8b4c7d9a --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_0.c @@ -0,0 +1,14 @@ +// ..########.. +// ############ +// ####....#### +// ####....#### +// ####....#### +// ####....#### +// ############ +// ..########.. + +#include "images.h" + +const image_t img_6x8_0 = { 6, 8, false, 6, 0, { + 0x7B, 0xFC, 0xF3, 0xCF, 0x3F, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_1.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_1.c new file mode 100644 index 000000000..91e2b2cfa --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_1.c @@ -0,0 +1,14 @@ +// ..######.... +// ########.... +// ....####.... +// ....####.... +// ....####.... +// ....####.... +// ############ +// ############ + +#include "images.h" + +const image_t img_6x8_1 = { 6, 8, false, 6, 0, { + 0x73, 0xC3, 0x0C, 0x30, 0xCF, 0xFF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_2.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_2.c new file mode 100644 index 000000000..7d24c64d6 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_2.c @@ -0,0 +1,14 @@ +// ..########.. +// ############ +// ........#### +// ......###### +// ....####.... +// ..####...... +// ############ +// ############ + +#include "images.h" + +const image_t img_6x8_2 = { 6, 8, false, 6, 0, { + 0x7B, 0xF0, 0xC7, 0x31, 0x8F, 0xFF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_3.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_3.c new file mode 100644 index 000000000..3a8f9f211 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_3.c @@ -0,0 +1,14 @@ +// ..########.. +// ############ +// ........#### +// ....######## +// ....######## +// ........#### +// ############ +// ..########.. + +#include "images.h" + +const image_t img_6x8_3 = { 6, 8, false, 6, 0, { + 0x7B, 0xF0, 0xCF, 0x3C, 0x3F, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_4.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_4.c new file mode 100644 index 000000000..c5ae9efef --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_4.c @@ -0,0 +1,14 @@ +// ####........ +// ####........ +// ####..####.. +// ####..####.. +// ############ +// ############ +// ......####.. +// ......####.. + +#include "images.h" + +const image_t img_6x8_4 = { 6, 8, false, 6, 0, { + 0xC3, 0x0D, 0xB6, 0xFF, 0xF1, 0x86 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_5.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_5.c new file mode 100644 index 000000000..787e39ea6 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_5.c @@ -0,0 +1,14 @@ +// ############ +// ############ +// ####........ +// ##########.. +// ############ +// ........#### +// ############ +// ##########.. + +#include "images.h" + +const image_t img_6x8_5 = { 6, 8, false, 6, 0, { + 0xFF, 0xFC, 0x3E, 0xFC, 0x3F, 0xFE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_6.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_6.c new file mode 100644 index 000000000..8f07f1bfc --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_6.c @@ -0,0 +1,14 @@ +// ..########.. +// ##########.. +// ####........ +// ##########.. +// ############ +// ####....#### +// ############ +// ..########.. + +#include "images.h" + +const image_t img_6x8_6 = { 6, 8, false, 6, 0, { + 0x7B, 0xEC, 0x3E, 0xFF, 0x3F, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_7.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_7.c new file mode 100644 index 000000000..cad50c65d --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_7.c @@ -0,0 +1,14 @@ +// ############ +// ############ +// ........#### +// ......####.. +// ......####.. +// ....####.... +// ....####.... +// ....####.... + +#include "images.h" + +const image_t img_6x8_7 = { 6, 8, false, 6, 0, { + 0xFF, 0xF0, 0xC6, 0x18, 0xC3, 0x0C +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_8.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_8.c new file mode 100644 index 000000000..a38b2110d --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_8.c @@ -0,0 +1,14 @@ +// ..########.. +// ############ +// ####....#### +// ..########.. +// ############ +// ####....#### +// ############ +// ..########.. + +#include "images.h" + +const image_t img_6x8_8 = { 6, 8, false, 6, 0, { + 0x7B, 0xFC, 0xDE, 0xFF, 0x3F, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_9.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_9.c new file mode 100644 index 000000000..b740c7f90 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_9.c @@ -0,0 +1,14 @@ +// ..########.. +// ############ +// ####....#### +// ############ +// ..########## +// ........#### +// ..########## +// ..########.. + +#include "images.h" + +const image_t img_6x8_9 = { 6, 8, false, 6, 0, { + 0x7B, 0xFC, 0xFF, 0x7C, 0x37, 0xDE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_A.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_A.c new file mode 100644 index 000000000..fa3aed598 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_A.c @@ -0,0 +1,14 @@ +// ..########.. +// ############ +// ####....#### +// ####....#### +// ############ +// ############ +// ####....#### +// ####....#### + +#include "images.h" + +const image_t img_6x8_A = { 6, 8, false, 6, 0, { + 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_B.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_B.c new file mode 100644 index 000000000..14c1e28c6 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_B.c @@ -0,0 +1,14 @@ +// ##########.. +// ############ +// ####....#### +// ##########.. +// ##########.. +// ####....#### +// ############ +// ##########.. + +#include "images.h" + +const image_t img_6x8_B = { 6, 8, false, 6, 0, { + 0xFB, 0xFC, 0xFE, 0xFB, 0x3F, 0xFE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_C.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_C.c new file mode 100644 index 000000000..6d8f7aa32 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_C.c @@ -0,0 +1,14 @@ +// ..########## +// ############ +// ####........ +// ####........ +// ####........ +// ####........ +// ############ +// ..########## + +#include "images.h" + +const image_t img_6x8_C = { 6, 8, false, 6, 0, { + 0x7F, 0xFC, 0x30, 0xC3, 0x0F, 0xDF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_D.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_D.c new file mode 100644 index 000000000..474e4a235 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_D.c @@ -0,0 +1,14 @@ +// ##########.. +// ############ +// ..####..#### +// ..####..#### +// ..####..#### +// ..####..#### +// ############ +// ##########.. + +#include "images.h" + +const image_t img_6x8_D = { 6, 8, false, 6, 0, { + 0xFB, 0xF6, 0xDB, 0x6D, 0xBF, 0xFE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_E.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_E.c new file mode 100644 index 000000000..00f2cb559 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_E.c @@ -0,0 +1,14 @@ +// ############ +// ############ +// ####........ +// ########.... +// ########.... +// ####........ +// ############ +// ############ + +#include "images.h" + +const image_t img_6x8_E = { 6, 8, false, 6, 0, { + 0xFF, 0xFC, 0x3C, 0xF3, 0x0F, 0xFF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_F.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_F.c new file mode 100644 index 000000000..8958a0419 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_F.c @@ -0,0 +1,14 @@ +// ############ +// ############ +// ####........ +// ########.... +// ########.... +// ####........ +// ####........ +// ####........ + +#include "images.h" + +const image_t img_6x8_F = { 6, 8, false, 6, 0, { + 0xFF, 0xFC, 0x3C, 0xF3, 0x0C, 0x30 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_G.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_G.c new file mode 100644 index 000000000..f5e8f03f4 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_G.c @@ -0,0 +1,14 @@ +// ..########## +// ############ +// ####........ +// ####........ +// ####..###### +// ####....#### +// ############ +// ..########## + +#include "images.h" + +const image_t img_6x8_G = { 6, 8, false, 6, 0, { + 0x7F, 0xFC, 0x30, 0xDF, 0x3F, 0xDF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_X.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_X.c new file mode 100644 index 000000000..7b162baf3 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_X.c @@ -0,0 +1,14 @@ +// ####....#### +// ####....#### +// ..####..##.. +// ....######.. +// ..######.... +// ..##..####.. +// ####....#### +// ####....#### + +#include "images.h" + +const image_t img_6x8_X = { 6, 8, false, 6, 0, { + 0xCF, 0x36, 0x8E, 0x71, 0x6C, 0xF3 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_Y.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_Y.c new file mode 100644 index 000000000..b39392948 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_Y.c @@ -0,0 +1,14 @@ +// ####....#### +// ####....#### +// ####....#### +// ####....#### +// ..########.. +// ....####.... +// ....####.... +// ....####.... + +#include "images.h" + +const image_t img_6x8_Y = { 6, 8, false, 6, 0, { + 0xCF, 0x3C, 0xF3, 0x78, 0xC3, 0x0C +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_Z.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_Z.c new file mode 100644 index 000000000..9904d08b4 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_Z.c @@ -0,0 +1,14 @@ +// ############ +// ############ +// ........#### +// ......####.. +// ....####.... +// ..####...... +// ############ +// ############ + +#include "images.h" + +const image_t img_6x8_Z = { 6, 8, false, 6, 0, { + 0xFF, 0xF0, 0xC6, 0x31, 0x8F, 0xFF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_d_.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_d_.c new file mode 100644 index 000000000..2a00713fd --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_d_.c @@ -0,0 +1,14 @@ +// ........#### +// ........#### +// ........#### +// ..########## +// ############ +// ####....#### +// ############ +// ..########## + +#include "images.h" + +const image_t img_6x8_d = { 6, 8, false, 6, 0, { + 0x0C, 0x30, 0xDF, 0xFF, 0x3F, 0xDF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_n_.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_n_.c new file mode 100644 index 000000000..086bdd2de --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_n_.c @@ -0,0 +1,14 @@ +// ............ +// ............ +// ..########.. +// ############ +// ####....#### +// ####....#### +// ####....#### +// ####....#### + +#include "images.h" + +const image_t img_6x8_n = { 6, 8, false, 6, 0, { + 0x00, 0x07, 0xBF, 0xCF, 0x3C, 0xF3 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_6x8_v_.c b/applications/plugins/wii_ec_anal/gfx/img_6x8_v_.c new file mode 100644 index 000000000..c897aadff --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_6x8_v_.c @@ -0,0 +1,14 @@ +// ............ +// ............ +// ##........## +// ####....#### +// ####....#### +// ############ +// ..########.. +// ....####.... + +#include "images.h" + +const image_t img_6x8_v = { 6, 8, false, 6, 0, { + 0x00, 0x08, 0x73, 0xCF, 0xF7, 0x8C +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_RIP.c b/applications/plugins/wii_ec_anal/gfx/img_RIP.c new file mode 100644 index 000000000..55cb7bfc2 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_RIP.c @@ -0,0 +1,122 @@ +// ################################################################################################################################################################################################################################################################ +// ################################################################################################################################################################################################################################################################ +// ####........................................................................................................................................................................................................................................................#### +// ####..##..##........................................................................................................................................................................................................................................##..##..#### +// ####....##....................##############..........########........##################........................##############......##..........##......##############......##############......##############......##############....................##....#### +// ####..##..##..................##############............######..........################........................##############....######......######....##############......##############......##############......##############..................##..##..#### +// ####....................................######..........##..##......................######....................####........######..######......######..####........######..######......######..............######..######......######........................#### +// ####........................######......######..........##..##..........######......##..##....................######......##..##..##..##......##..##..######......######..######......######..######......######..######......##..##........................#### +// ####........................######......##..##..........##..##..........######......##..##....................##..##......######..##..##......##..##..######......##..##..##..##......##..##..######......##..##..##..##......##..##........................#### +// ####........................##..##......##..##..........##..##..........##..##......##..##....................##..##..............##..##......##..##..##..##......##..##..##..##......##..##..##..##......##..##..##..##......##..##........................#### +// ####........................##..##......##..##..........##..##..........##..##......##..##....................##..##..............##..##......##..##..##..##......##..##..##..##......##..##..##..##......##..##..##..##......######........................#### +// ####........................##..##......######..........##..##..........##..##......######....................##..##..............##..##......##..##..##..##......######..##..##..##..##..##..##..##......######..##..##....................................#### +// ####........................##..##########..............##..##..........##..##########........................##..##..............######......######..##..##########......##..##......##..##..##..##########......##..##....................................#### +// ####........................##..##########..............##..##..........##..##########........................##..##................##############....##..##########......##..##......##..##..##..##########......##..##..########..........................#### +// ####........................##..##....######............##..##..........##..##................................##..##..................####..####......##..##......######..##..##..##..##..##..##..##....######....##..##..##########........................#### +// ####........................##..##....##..##............##..##..........##..##................................##..##....................##..##........##..##......##..##..##..##......##..##..##..##....##..##....##..##......##..##........................#### +// ####........................##..##....##..##............##..##..........##..##................................##..##....................##..##........##..##......##..##..##..##......##..##..##..##....##..##....##..##......##..##........................#### +// ####........................##..##....##..##............##..##..........##..##................................######......######........##..##........##..##......##..##..##..##......##..##..##..##....##..##....######......##..##........................#### +// ####........................##..##....##..##............##..##..........##..##................................######......##..##........##..##........######......######..######......######..##..##....##..##....######......##..##........................#### +// ####........................##..##....##..##............##..##..........##..##................................####........######........######........######......######..######......######..##..##....##..##....####........######........................#### +// ####........................######....######....####....######..####....######..####............................##############..........######..........##############......##############....######....######......##############..........................#### +// ####........................######......######..####..########..####..########..####............................##############........##########........##############......##############....######......######....##############..........................#### +// ####........................................................................................................................................................................................................................................................#### +// ####........................................................................................................................................................................................................................................................#### +// ####..........................................................................................................................................................................................####......####..............##############....................#### +// ####......................................................................................................................................##................................................##....##..##....##........####..............####................#### +// ####..........######..##..##..######......######..##..##..######..######..######..####..####..######......##......##..######..##....##..##..######......######..######......................####..##..####..##......##......................##..............#### +// ####............##....##..##..##..........##......##..##..##........##....##......##..##..##..##..........##......##..##..##..####..##........##........##..##..##............................####......####......##......##########..........##............#### +// ####............##....######..####........######....##....######....##....####....##..##..##..######......##..##..##..##..##..##..####........##........####....####..............................##..##........##......##..........##........##............#### +// ####............##....##..##..##..............##....##........##....##....##......##......##......##......##..##..##..##..##..##....##........##........##..##..##..................................##..........##....##..............##......##............#### +// ####............##....##..##..######......######....##....######....##....######..##......##..######......####..####..######..##....##........##........######..######............................######........##....##......####....##......##............#### +// ####............................................................................................................................................................................................##......##......##....##....##....##..##......##............#### +// ####..........................................................................................................................................................................................##........##......##....##....##..##....##......##............#### +// ####..........................................................................................................................................................................................##........##......##....##....##........##......##............#### +// ####..........######..##..##..######......######..######..####..####..######......##......##..######..######..##..##..######..##..##..######......##..##..######..##..##........................##........######......##......########......##..............#### +// ####............##....##..##..##..........##......##..##..##..##..##..##..........##......##....##......##....##..##..##..##..##..##....##........##..##..##..##..##..##........................##..............##......##..................####............#### +// ####............##....######..####........######..######..##..##..##..####........##..##..##....##......##....######..##..##..##..##....##..........##....##..##..##..##..........................##..............##########..............##....##..........#### +// ####............##....##..##..##..............##..##..##..##......##..##..........##..##..##....##......##....##..##..##..##..##..##....##..........##....##..##..##..##..........................##......................################........##........#### +// ####............##....##..##..######......######..##..##..##......##..######......####..####..######....##....##..##..######..######....##..........##....######..######............................####..........................................##........#### +// ####....................................................................................................................................................................................................##########################################..........#### +// ####........................................................................................................................................................................................................................................................#### +// ####........................................................................................................................................................................................................................................................#### +// ####......................................##########......##############......##############......##############............................##############......##############......##############......##############......................................#### +// ####......................................##########......##############......##############......##############............................##############......##############......##############......##############......................................#### +// ####......................................##..##..##....######......######..######......######..######......######........................######......######..######......######..######......######..######......######....................................#### +// ####..........................................##..##....######......######..##..##......######..######......######........................##..##......##..##..######......######..##..##......##..##..##..##......##..##....................................#### +// ####..........................................##..##....##..##......##..##..######......##..##..##..##......##..##........................######......##..##..##..##......##..##..######......##..##..######......##..##....................................#### +// ####..........................................##..##....##..##......##..##..............##..##..##..##......##..##....................................##..##..##..##......##..##..............##..##..............##..##....................................#### +// ####..........................................##..##....##..##......##..##..............##..##..##..##....####..##....................................##..##..##..##....####..##..............##..##..............##..##....................................#### +// ####..........................................##..##....######......##..##..............######..##..##....####..##....................................######..##..##....####..##..............######..............######....................................#### +// ####..........................................######........##########..##..............######..##..##..##..##..##....################........############....##..##..##..##..##......############........############......................................#### +// ####..........................................######........##########..##..........######......##..##..##..##..##....##............##......############......##..##..##..##..##....############........############........................................#### +// ####..........................................##..##................##..##..........######......##..####....##..##....################....######..............##..####....##..##..######..............######................................................#### +// ####..........................................##..##................##..##..........##..##......##..####....##..##........................##..##..............##..####....##..##..##..##..............##..##................................................#### +// ####..........................................##..##................##..##..........##..##......##..##......##..##........................##..##..............##..##......##..##..##..##..............##..##................................................#### +// ####..........................................##..##................##..##..........##..##......##..##......##..##........................##..##..............##..##......##..##..##..##..............##..##................................................#### +// ####..........................................##..##................######..........##..##......######......######........................##..##..............######......######..##..##..............##..##................................................#### +// ####..........................................##..##................######..........##..##......######......######........................##..##........####..######......######..##..##........####..##..##........####....................................#### +// ####..##..##..............................##############....############............######........##############..........................##################....##############....##################..##################............................##..##..#### +// ####....##..............................##################..############............######........##############..........................##################....##############....##################..##################..............................##....#### +// ####..##..##........................................................................................................................................................................................................................................##..##..#### +// ####........................................................................................................................................................................................................................................................#### +// ################################################################################################################################################################################################################################################################ +// ################################################################################################################################################################################################################################################################ + +#include "images.h" + +const image_t img_RIP = { 128, 64, true, 837, 0x06, { // orig:1024, comp:18.26% + 0x06, 0x20, 0xFF, 0xC0, 0x06, 0x0E, 0x00, 0x03, 0xD4, 0x06, 0x0E, 0x00, 0x2B, 0xC8, 0x01, 0xFC, + 0x1E, 0x1F, 0xF0, 0x00, 0xFE, 0x20, 0x8F, 0xE3, 0xF8, 0xFE, 0x3F, 0x80, 0x13, 0xD4, 0x01, 0xFC, + 0x0E, 0x0F, 0xF0, 0x00, 0xFE, 0x71, 0xCF, 0xE3, 0xF8, 0xFE, 0x3F, 0x80, 0x2B, 0xC0, 0x00, 0x0E, + 0x0A, 0x00, 0x38, 0x01, 0x87, 0x71, 0xD8, 0x77, 0x1C, 0x07, 0x71, 0xC0, 0x03, 0xC0, 0x03, 0x8E, + 0x0A, 0x0E, 0x28, 0x01, 0xC5, 0x51, 0x5C, 0x77, 0x1D, 0xC7, 0x71, 0x40, 0x03, 0xC0, 0x03, 0x8A, + 0x0A, 0x0E, 0x28, 0x01, 0x47, 0x51, 0x5C, 0x55, 0x15, 0xC5, 0x51, 0x40, 0x03, 0xC0, 0x02, 0x8A, + 0x0A, 0x0A, 0x28, 0x01, 0x40, 0x51, 0x54, 0x55, 0x15, 0x45, 0x51, 0x40, 0x03, 0xC0, 0x02, 0x8A, + 0x0A, 0x0A, 0x28, 0x01, 0x40, 0x51, 0x54, 0x55, 0x15, 0x45, 0x51, 0xC0, 0x03, 0xC0, 0x02, 0x8E, + 0x0A, 0x0A, 0x38, 0x01, 0x40, 0x51, 0x54, 0x75, 0x55, 0x47, 0x50, 0x00, 0x03, 0xC0, 0x02, 0xF8, + 0x0A, 0x0B, 0xE0, 0x01, 0x40, 0x71, 0xD7, 0xC5, 0x15, 0x7C, 0x50, 0x00, 0x03, 0xC0, 0x02, 0xF8, + 0x0A, 0x0B, 0xE0, 0x01, 0x40, 0x3F, 0x97, 0xC5, 0x15, 0x7C, 0x57, 0x80, 0x03, 0xC0, 0x02, 0x9C, + 0x0A, 0x0A, 0x00, 0x01, 0x40, 0x1B, 0x14, 0x75, 0x55, 0x4E, 0x57, 0xC0, 0x03, 0xC0, 0x02, 0x94, + 0x0A, 0x0A, 0x00, 0x01, 0x40, 0x0A, 0x14, 0x55, 0x15, 0x4A, 0x51, 0x40, 0x03, 0xC0, 0x02, 0x94, + 0x0A, 0x0A, 0x00, 0x01, 0x40, 0x0A, 0x14, 0x55, 0x15, 0x4A, 0x51, 0x40, 0x03, 0xC0, 0x02, 0x94, + 0x0A, 0x0A, 0x00, 0x01, 0xC7, 0x0A, 0x14, 0x55, 0x15, 0x4A, 0x71, 0x40, 0x03, 0xC0, 0x02, 0x94, + 0x0A, 0x0A, 0x00, 0x01, 0xC5, 0x0A, 0x1C, 0x77, 0x1D, 0x4A, 0x71, 0x40, 0x03, 0xC0, 0x02, 0x94, + 0x0A, 0x0A, 0x00, 0x01, 0x87, 0x0E, 0x1C, 0x77, 0x1D, 0x4A, 0x61, 0xC0, 0x03, 0xC0, 0x03, 0x9C, + 0xCE, 0xCE, 0xC0, 0x00, 0xFE, 0x0E, 0x0F, 0xE3, 0xF9, 0xCE, 0x3F, 0x80, 0x03, 0xC0, 0x03, 0x8E, + 0xDE, 0xDE, 0xC0, 0x00, 0xFE, 0x1F, 0x0F, 0xE3, 0xF9, 0xC7, 0x3F, 0x80, 0x03, 0xC0, 0x06, 0x0E, + 0x00, 0x03, 0xC0, 0x06, 0x0E, 0x00, 0x03, 0xC0, 0x06, 0x0A, 0x00, 0x01, 0x8C, 0x07, 0xF0, 0x03, + 0xC0, 0x06, 0x07, 0x00, 0x04, 0x00, 0x00, 0x02, 0x52, 0x18, 0x0C, 0x03, 0xC1, 0xD5, 0xC7, 0x57, + 0x77, 0x6D, 0xC4, 0x5D, 0x2B, 0x8E, 0xE0, 0x03, 0x5A, 0x20, 0x02, 0x03, 0xC0, 0x95, 0x04, 0x54, + 0x24, 0x55, 0x04, 0x55, 0xA1, 0x0A, 0x80, 0x01, 0x8C, 0x47, 0xC1, 0x03, 0xC0, 0x9D, 0x87, 0x27, + 0x26, 0x55, 0xC5, 0x55, 0x61, 0x0C, 0xC0, 0x00, 0x50, 0x88, 0x21, 0x03, 0xC0, 0x95, 0x01, 0x21, + 0x24, 0x44, 0x45, 0x55, 0x21, 0x0A, 0x80, 0x00, 0x20, 0x90, 0x11, 0x03, 0xC0, 0x95, 0xC7, 0x27, + 0x27, 0x45, 0xC6, 0xDD, 0x21, 0x0E, 0xE0, 0x00, 0x70, 0x91, 0x91, 0x03, 0xC0, 0x06, 0x0B, 0x00, + 0x88, 0x92, 0x51, 0x03, 0xC0, 0x06, 0x0A, 0x00, 0x01, 0x08, 0x92, 0x91, 0x03, 0xC0, 0x06, 0x0A, + 0x00, 0x01, 0x08, 0x92, 0x11, 0x03, 0xC1, 0xD5, 0xC7, 0x76, 0xDC, 0x45, 0xDD, 0x5D, 0x5C, 0x57, + 0x50, 0x00, 0x87, 0x11, 0xE2, 0x03, 0xC0, 0x95, 0x04, 0x55, 0x50, 0x44, 0x89, 0x55, 0x48, 0x55, + 0x50, 0x00, 0x80, 0x88, 0x03, 0x03, 0xC0, 0x9D, 0x87, 0x75, 0x58, 0x54, 0x89, 0xD5, 0x48, 0x25, + 0x50, 0x00, 0x40, 0x7C, 0x04, 0x83, 0xC0, 0x95, 0x01, 0x54, 0x50, 0x54, 0x89, 0x55, 0x48, 0x25, + 0x50, 0x00, 0x40, 0x07, 0xF8, 0x43, 0xC0, 0x95, 0xC7, 0x54, 0x5C, 0x6D, 0xC9, 0x5D, 0xC8, 0x27, + 0x70, 0x00, 0x30, 0x00, 0x00, 0x43, 0xC0, 0x06, 0x0B, 0x00, 0x0F, 0xFF, 0xFF, 0x83, 0xC0, 0x06, + 0x0E, 0x00, 0x03, 0xC0, 0x06, 0x0E, 0x00, 0x03, 0xC0, 0x00, 0x07, 0xC7, 0xF1, 0xFC, 0x7F, 0x00, + 0x03, 0xF8, 0xFE, 0x3F, 0x8F, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0xC7, 0xF1, 0xFC, 0x7F, 0x00, + 0x03, 0xF8, 0xFE, 0x3F, 0x8F, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x05, 0x4E, 0x3B, 0x8E, 0xE3, 0x80, + 0x07, 0x1D, 0xC7, 0x71, 0xDC, 0x70, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x4E, 0x3A, 0x8E, 0xE3, 0x80, + 0x05, 0x15, 0xC7, 0x51, 0x54, 0x50, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x4A, 0x2B, 0x8A, 0xA2, 0x80, + 0x07, 0x15, 0x45, 0x71, 0x5C, 0x50, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x4A, 0x28, 0x0A, 0xA2, 0x80, + 0x00, 0x15, 0x45, 0x01, 0x40, 0x50, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x4A, 0x28, 0x0A, 0xA6, 0x80, + 0x00, 0x15, 0x4D, 0x01, 0x40, 0x50, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x4E, 0x28, 0x0E, 0xA6, 0x80, + 0x00, 0x1D, 0x4D, 0x01, 0xC0, 0x70, 0x00, 0x03, 0xC0, 0x00, 0x01, 0xC3, 0xE8, 0x0E, 0xAA, 0x9F, + 0xE1, 0xF9, 0x55, 0x1F, 0x87, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x01, 0xC3, 0xE8, 0x38, 0xAA, 0x90, + 0x23, 0xF1, 0x55, 0x3F, 0x0F, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x40, 0x28, 0x38, 0xB2, 0x9F, + 0xE7, 0x01, 0x65, 0x70, 0x1C, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x40, 0x28, 0x28, 0xB2, 0x80, + 0x05, 0x01, 0x65, 0x50, 0x14, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x40, 0x28, 0x28, 0xA2, 0x80, + 0x05, 0x01, 0x45, 0x50, 0x14, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x40, 0x28, 0x28, 0xA2, 0x80, + 0x05, 0x01, 0x45, 0x50, 0x14, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x40, 0x38, 0x28, 0xE3, 0x80, + 0x05, 0x01, 0xC7, 0x50, 0x14, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x01, 0x40, 0x38, 0x28, 0xE3, 0x80, + 0x05, 0x0D, 0xC7, 0x50, 0xD4, 0x30, 0x00, 0x03, 0xD4, 0x00, 0x07, 0xF3, 0xF0, 0x38, 0x7F, 0x00, + 0x07, 0xFC, 0xFE, 0x7F, 0xDF, 0xF0, 0x00, 0x2B, 0xC8, 0x00, 0x0F, 0xFB, 0xF0, 0x38, 0x7F, 0x00, + 0x07, 0xFC, 0xFE, 0x7F, 0xDF, 0xF0, 0x00, 0x13, 0xD4, 0x06, 0x0E, 0x00, 0x2B, 0xC0, 0x06, 0x0E, + 0x00, 0x03, 0x06, 0x20, 0xFF +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_Cable.c b/applications/plugins/wii_ec_anal/gfx/img_cc_Cable.c new file mode 100644 index 000000000..2fc6b5f23 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_Cable.c @@ -0,0 +1,17 @@ +// ####..## +// ##..#### +// ####..## +// ##..#### +// ####..## +// ##..#### +// ####..## +// ##..#### +// ####..## +// ##..#### +// ####..## + +#include "images.h" + +const image_t img_cc_Cable = { 4, 11, true, 4, 0x00, { // orig:6, comp:33.33% + 0x00, 0x05, 0xDB, 0xD0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_Joy.c b/applications/plugins/wii_ec_anal/gfx/img_cc_Joy.c new file mode 100644 index 000000000..dd189cb7e --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_Joy.c @@ -0,0 +1,25 @@ +// ................##................ +// ............##########............ +// ....############..############.... +// ....######..............######.... +// ....####..................####.... +// ....##......................##.... +// ..####......................####.. +// ..####......................####.. +// ####..........................#### +// ..####......................####.. +// ..####......................####.. +// ....##......................##.... +// ....####..................####.... +// ....######..............######.... +// ....############..############.... +// ............##########............ +// ................##................ + +#include "images.h" + +const image_t img_cc_Joy = { 17, 17, false, 37, 0, { + 0x00, 0x80, 0x01, 0xF0, 0x0F, 0xDF, 0x87, 0x01, 0xC3, 0x00, 0x61, 0x00, 0x11, 0x80, 0x0C, 0xC0, + 0x06, 0xC0, 0x01, 0xB0, 0x01, 0x98, 0x00, 0xC4, 0x00, 0x43, 0x00, 0x61, 0xC0, 0x70, 0xFD, 0xF8, + 0x07, 0xC0, 0x00, 0x80, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_Main.c b/applications/plugins/wii_ec_anal/gfx/img_cc_Main.c new file mode 100644 index 000000000..8e7bd5ed9 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_Main.c @@ -0,0 +1,92 @@ +// ..................................................##################................................................................................................##################.................................................. +// ......................................############................##............##########....................................................##########............##................############...................................... +// ..................................####............................##..........##..........##......................####......................##..........##..........##............................####.................................. +// ................................##................................##############..........####################################################..........##############................................##................................ +// ............................######................................##..........##..........##......................####......................##..........##..........##................................######............................ +// ..........................##..##....................################..........##..........##......................####......................##..........##..........################....................##..##.......................... +// ........................##....##........############............................##########....................................................##########............................############........##....##........................ +// ......................##......##########........................................................................................................................................................##########......##...................... +// ....................##..........########################################################################################################################################################################..........##.................... +// ..................##......########....................................................................................................................................................................########......##.................. +// ................##....######................................................................................................................................................................................######....##................ +// ..............##....####........................................................................................................................................................................................####....##.............. +// ............##########............................................................................................................................................................................................##########............ +// ............######......................................................................................####......####..####..####....................................................................................######............ +// ..........######......................##################................................................####..##..####..................................................................######..........................######.......... +// ..........####........................##################................................................####..##..####..####..####....................................................##########..........................####.......... +// ........####..........................####..........####................................................####..##..####..####..####..................................................####......####..........................####........ +// ......######..........................####..........####..................................................####..####....####..####................................................####..........####........................######...... +// ......####............................####....##....####........................................................................................................................####....##..##....####........................####...... +// ......##..............................####....##....####........................................................................................................................####......##......####..........................####.... +// ....####..............................####....##....####........................................................................................................................####....##..##....####..........................####.... +// ....##..................##################..........##################............................................................................................######..........####..........####..........######..............##.... +// ..####..................##################..........##################..........................................................................................##########..........####......####..........##########............####.. +// ..##....................####......................................####..........................########........########........########......................####......####..........##########..........####......####............##.. +// ..##....................####......................................####........................####....####....####....####....####....####..................####..........####..........######..........####....##....####..........##.. +// ####....................####....######..................######....####........................##........##....##........##....##........##................####....##..##....####......................####....##..##....####........#### +// ##......................####......................................####........................##........##....##........##....##........##................####....######....####......................####....######....####..........## +// ##......................####......................................####........................####....####....####....####....####....####................####........##....####......................####....##..##....####..........## +// ##......................##################..........##################..........................########........########........########....................####....##....####..........######..........####..........####............## +// ##......................##################..........##################........................................................................................####......####..........##########..........####......####..............## +// ##....................................####....##....####........................................................................................................##########..........####......####..........##########................## +// ##....................................####....##....####..........................................................................................................######..........####..##......####..........######..................## +// ##....................................####....##....####........................................................................................................................####....##........####................................## +// ##....................................####..........####........................................................................................................................####....####......####................................## +// ##....................................####..........####........................................................................................................................####....##..##....####................................## +// ####..................................##################..........................................................................................................................####....####..####................................#### +// ..##..................................##################............................................................................................................................####......####..................................##.. +// ..##..................................................................................................................................................................................##########....................................##.. +// ..####..................................................................................................................................................................................######....................................####.. +// ....##............................................................................................................................................................................................................................##.... +// ....##............................................................................................................................................................................................................................##.... +// ....####........................................................................................................................................................................................................................####.... +// ......##........................................................................................................................................................................................................................##...... +// ......####....................................................................................................................................................................................................................####...... +// ........####................................................................................................................................................................................................................####........ +// ..........####............................................................................................................................................................................................................####.......... +// ............####........................................................................................................................................................................................................####............ +// ..............####....................................................................................................................................................................................................####.............. +// ................######............................................................................................................................................................................................######................ +// ....................####........................................................................................................................................................................................####.................... +// ......................######................................................................................................................................................................................######...................... +// ..........................########....................................................................................................................................................................########.......................... +// ................................########################################################################################################################################################################................................ + +#include "images.h" + +const image_t img_cc_Main = { 116, 53, true, 542, 0x05, { // orig:769, comp:29.52% + 0x00, 0x00, 0x00, 0x7F, 0xC0, 0x05, 0x05, 0x00, 0x3F, 0xE0, 0x05, 0x04, 0x00, 0x01, 0xF8, 0x04, + 0x0F, 0x80, 0x00, 0x00, 0x1F, 0x02, 0x01, 0xF8, 0x05, 0x04, 0x00, 0x60, 0x00, 0x41, 0x04, 0x00, + 0x60, 0x02, 0x08, 0x20, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0xF0, 0x7F, 0xFF, 0xFF, + 0xE0, 0xFE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x41, 0x04, 0x00, 0x60, 0x02, 0x08, + 0x20, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x50, 0x03, 0xFC, 0x10, 0x40, 0x06, 0x00, 0x20, 0x83, 0xFC, + 0x00, 0xA0, 0x00, 0x00, 0x09, 0x0F, 0xC0, 0x00, 0xF8, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x3F, 0x09, + 0x00, 0x00, 0x01, 0x1F, 0x05, 0x09, 0x00, 0x0F, 0x88, 0x00, 0x00, 0x20, 0x05, 0x0A, 0xFF, 0xF0, + 0x40, 0x00, 0x04, 0x78, 0x05, 0x09, 0x00, 0x01, 0xE2, 0x00, 0x00, 0x9C, 0x05, 0x0A, 0x00, 0x03, + 0x90, 0x00, 0x13, 0x05, 0x0B, 0x00, 0x0C, 0x80, 0x03, 0xE0, 0x05, 0x0B, 0x00, 0x7C, 0x00, 0x38, + 0x05, 0x05, 0x00, 0xC6, 0xD8, 0x05, 0x04, 0x00, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0xF0, 0x00, 0x00, + 0x0D, 0x60, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x60, 0x01, 0xFF, 0x00, 0x00, 0x00, 0xD6, + 0xD8, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x60, 0x0C, 0x00, 0x18, 0x30, 0x00, 0x00, 0x0D, 0x6D, 0x80, + 0x00, 0x00, 0x31, 0x80, 0x03, 0x01, 0xC0, 0x01, 0x83, 0x00, 0x00, 0x00, 0x6C, 0xD8, 0x00, 0x00, + 0x06, 0x0C, 0x00, 0x38, 0x18, 0x00, 0x19, 0x30, 0x05, 0x07, 0x00, 0xCA, 0x60, 0x01, 0x81, 0x00, + 0x01, 0x93, 0x05, 0x07, 0x00, 0x0C, 0x46, 0x00, 0x0C, 0x30, 0x00, 0x19, 0x30, 0x05, 0x07, 0x00, + 0xCA, 0x60, 0x00, 0xC2, 0x00, 0xFF, 0x83, 0xFE, 0x05, 0x05, 0x00, 0x07, 0x06, 0x0C, 0x1C, 0x04, + 0x60, 0x0F, 0xF8, 0x3F, 0xE0, 0x05, 0x05, 0x00, 0xF8, 0x31, 0x83, 0xE0, 0x64, 0x00, 0xC0, 0x00, + 0x06, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x18, 0xC1, 0xF0, 0x63, 0x02, 0x40, 0x0C, 0x00, 0x00, 0x60, + 0x01, 0x99, 0x99, 0x98, 0x03, 0x06, 0x0E, 0x0C, 0x98, 0x2C, 0x00, 0xCE, 0x00, 0xE6, 0x00, 0x10, + 0x90, 0x90, 0x80, 0x65, 0x30, 0x01, 0x94, 0xC3, 0x80, 0x0C, 0x00, 0x00, 0x60, 0x01, 0x09, 0x09, + 0x08, 0x06, 0x73, 0x00, 0x19, 0xCC, 0x18, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x19, 0x99, 0x99, 0x80, + 0x61, 0x30, 0x01, 0x94, 0xC1, 0x80, 0x0F, 0xF8, 0x3F, 0xE0, 0x00, 0xF0, 0xF0, 0xF0, 0x03, 0x26, + 0x0E, 0x0C, 0x18, 0x18, 0x00, 0xFF, 0x83, 0xFE, 0x05, 0x05, 0x00, 0x18, 0xC1, 0xF0, 0x63, 0x01, + 0x80, 0x00, 0x19, 0x30, 0x05, 0x06, 0x00, 0xF8, 0x31, 0x83, 0xE0, 0x18, 0x00, 0x01, 0x93, 0x05, + 0x06, 0x00, 0x07, 0x06, 0x8C, 0x1C, 0x01, 0x80, 0x00, 0x19, 0x30, 0x05, 0x07, 0x00, 0xC8, 0x60, + 0x00, 0x18, 0x00, 0x01, 0x83, 0x05, 0x07, 0x00, 0x0C, 0xC6, 0x00, 0x01, 0x80, 0x00, 0x18, 0x30, + 0x05, 0x07, 0x00, 0xCA, 0x60, 0x00, 0x1C, 0x00, 0x01, 0xFF, 0x05, 0x07, 0x00, 0x06, 0x6C, 0x00, + 0x03, 0x40, 0x00, 0x1F, 0xF0, 0x05, 0x07, 0x00, 0x31, 0x80, 0x00, 0x24, 0x05, 0x0A, 0x00, 0x01, + 0xF0, 0x00, 0x02, 0x60, 0x05, 0x0A, 0x00, 0x0E, 0x00, 0x00, 0x62, 0x05, 0x0D, 0x00, 0x04, 0x20, + 0x05, 0x0D, 0x00, 0x43, 0x05, 0x0D, 0x00, 0x0C, 0x10, 0x05, 0x0D, 0x00, 0x81, 0x80, 0x05, 0x0C, + 0x00, 0x18, 0x0C, 0x05, 0x0C, 0x00, 0x03, 0x00, 0x60, 0x05, 0x0C, 0x00, 0x60, 0x03, 0x05, 0x0C, + 0x00, 0x0C, 0x00, 0x18, 0x05, 0x0B, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x05, 0x0B, 0x00, 0x70, 0x00, + 0x03, 0x05, 0x0B, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x05, 0x0A, 0x00, 0x03, 0x80, 0x00, 0x00, 0x78, + 0x05, 0x09, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x05, 0x0A, 0xFF, 0xF0, 0x00, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_btn_A1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_A1.c new file mode 100644 index 000000000..4d54cbf22 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_A1.c @@ -0,0 +1,13 @@ +// ############## +// ######..###### +// ####..##..#### +// ####......#### +// ####..##..#### +// ############## +// ############## + +#include "images.h" + +const image_t img_cc_btn_A1 = { 7, 7, false, 7, 0, { + 0xFF, 0xDF, 0x5E, 0x3D, 0x7F, 0xFF, 0x80 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_btn_B1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_B1.c new file mode 100644 index 000000000..89d357282 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_B1.c @@ -0,0 +1,13 @@ +// ############## +// ####..######## +// ####..######## +// ####....###### +// ####..##..#### +// ######....#### +// ############## + +#include "images.h" + +const image_t img_cc_btn_B1 = { 7, 7, false, 7, 0, { + 0xFF, 0xBF, 0x7E, 0x7D, 0x7C, 0xFF, 0x80 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_btn_X1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_X1.c new file mode 100644 index 000000000..a1e7f2876 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_X1.c @@ -0,0 +1,13 @@ +// ############## +// ############## +// ####..##..#### +// ######..###### +// ####..##..#### +// ############## +// ############## + +#include "images.h" + +const image_t img_cc_btn_X1 = { 7, 7, false, 7, 0, { + 0xFF, 0xFF, 0x5F, 0x7D, 0x7F, 0xFF, 0x80 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_btn_Y1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_Y1.c new file mode 100644 index 000000000..01f66b4c7 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_btn_Y1.c @@ -0,0 +1,13 @@ +// ############## +// ############## +// ####..##..#### +// ####......#### +// ########..#### +// ######..###### +// ############## + +#include "images.h" + +const image_t img_cc_btn_Y1 = { 7, 7, false, 7, 0, { + 0xFF, 0xFF, 0x5E, 0x3F, 0x7D, 0xFF, 0x80 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_pad_LR1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_pad_LR1.c new file mode 100644 index 000000000..698fcfdd6 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_pad_LR1.c @@ -0,0 +1,11 @@ +// ############## +// ############## +// ####......#### +// ############## +// ############## + +#include "images.h" + +const image_t img_cc_pad_LR1 = { 7, 5, false, 5, 0, { + 0xFF, 0xFF, 0x1F, 0xFF, 0xE0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_pad_UD1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_pad_UD1.c new file mode 100644 index 000000000..b7d104ee4 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_pad_UD1.c @@ -0,0 +1,13 @@ +// ########## +// ########## +// ####..#### +// ####..#### +// ####..#### +// ########## +// ########## + +#include "images.h" + +const image_t img_cc_pad_UD1 = { 5, 7, false, 5, 0, { + 0xFF, 0xF7, 0xBD, 0xFF, 0xE0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L1.c new file mode 100644 index 000000000..cf4d7159b --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L1.c @@ -0,0 +1,12 @@ +// ......##############....##....##.. +// ..####..##....##....##....##....## +// ##....##....##....##....##....##.. +// ##..##....##....##....##....##.... +// ..##....##....##....############## +// ##....##############.............. + +#include "images.h" + +const image_t img_cc_trg_L1 = { 17, 6, false, 13, 0, { + 0x1F, 0xC9, 0x34, 0x92, 0x64, 0x92, 0x54, 0x92, 0x44, 0x93, 0xFC, 0xFE, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L2.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L2.c new file mode 100644 index 000000000..9e61a64cc --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L2.c @@ -0,0 +1,12 @@ +// ......##############..##..##..##.. +// ..####..##..##..##..##..##..##..## +// ####..##..##..##..##..##..##..##.. +// ##..##..##..##..##..##..##..##..## +// ..##..##..##..##..################ +// ##..##..############.............. + +#include "images.h" + +const image_t img_cc_trg_L2 = { 17, 6, true, 12, 0x01, { // orig:13, comp:7.69% + 0x1F, 0xD5, 0x35, 0x55, 0x75, 0x01, 0x04, 0x55, 0x57, 0xFD, 0x7E, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L3.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L3.c new file mode 100644 index 000000000..1b06de5ee --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L3.c @@ -0,0 +1,12 @@ +// ......############..####..####..## +// ..######..####..####..####..####.. +// ######..####..####..####..####..## +// ####..####..####..####..####..#### +// ##..####..####..################## +// ..####..############.............. + +#include "images.h" + +const image_t img_cc_trg_L3 = { 17, 6, false, 13, 0, { + 0x1F, 0xB6, 0xBB, 0x6D, 0xBB, 0x6D, 0xBB, 0x6D, 0xBB, 0x6F, 0xFB, 0x7E, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L4.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L4.c new file mode 100644 index 000000000..12f877ab1 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_L4.c @@ -0,0 +1,12 @@ +// ......############################ +// ..################################ +// ################################## +// ################################## +// ################################## +// ####################.............. + +#include "images.h" + +const image_t img_cc_trg_L4 = { 17, 6, true, 8, 0x01, { // orig:13, comp:38.46% + 0x1F, 0xFF, 0xBF, 0x01, 0x08, 0xFF, 0xFE, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R1.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R1.c new file mode 100644 index 000000000..a196c0fe1 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R1.c @@ -0,0 +1,12 @@ +// ..##....##....##############...... +// ##....##....##....##....##..####.. +// ..##....##....##....##....##....## +// ....##....##....##....##....##..## +// ##############....##....##....##.. +// ..............##############....## + +#include "images.h" + +const image_t img_cc_trg_R1 = { 17, 6, false, 13, 0, { + 0x49, 0xFC, 0x49, 0x25, 0x92, 0x49, 0x24, 0x92, 0x5F, 0xE4, 0x90, 0x0F, 0xE4 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R2.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R2.c new file mode 100644 index 000000000..ea5458f39 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R2.c @@ -0,0 +1,12 @@ +// ..##..##..##..##############...... +// ##..##..##..##..##..##..##..####.. +// ..##..##..##..##..##..##..##..#### +// ##..##..##..##..##..##..##..##..## +// ################..##..##..##..##.. +// ..............############..##..## + +#include "images.h" + +const image_t img_cc_trg_R2 = { 17, 6, false, 13, 0, { + 0x55, 0xFC, 0x55, 0x55, 0x95, 0x55, 0x75, 0x55, 0x5F, 0xF5, 0x50, 0x0F, 0xD4 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R3.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R3.c new file mode 100644 index 000000000..94cf02bf0 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R3.c @@ -0,0 +1,12 @@ +// ##..####..####..############...... +// ..####..####..####..####..######.. +// ##..####..####..####..####..###### +// ####..####..####..####..####..#### +// ##################..####..####..## +// ..............############..####.. + +#include "images.h" + +const image_t img_cc_trg_R3 = { 17, 6, false, 13, 0, { + 0xB6, 0xFC, 0x36, 0xDB, 0xAD, 0xB6, 0xFB, 0x6D, 0xBF, 0xFB, 0x68, 0x0F, 0xD8 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R4.c b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R4.c new file mode 100644 index 000000000..c90fbe20b --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_cc_trg_R4.c @@ -0,0 +1,12 @@ +// ############################...... +// ################################.. +// ################################## +// ################################## +// ################################## +// ..............#################### + +#include "images.h" + +const image_t img_cc_trg_R4 = { 17, 6, true, 11, 0x00, { // orig:13, comp:15.38% + 0xFF, 0xFC, 0x7F, 0xFF, 0xBF, 0x00, 0x05, 0xFF, 0xF8, 0x0F, 0xFC +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_csLogo_FULL.c b/applications/plugins/wii_ec_anal/gfx/img_csLogo_FULL.c new file mode 100644 index 000000000..97f09ac17 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_csLogo_FULL.c @@ -0,0 +1,81 @@ +// ....##########################################........##..........##........##############........##############........##############........##############............................................................................................ +// ....##########################################......######......######......##############........##############........##############........##############............................................................................................ +// ############..............................######....######......######....####........######....######......######................######....######......######..............######..######..######...................................................... +// ############..............................##..##....##..##......##..##....######......######....######......######....######......######....######......##..##..............##......##........##........................................................ +// ############..............................##..##....##..##......##..##....######......##..##....##..##......##..##....######......##..##....##..##......##..##..............####....######....##........................................................ +// ####....####..............................##..##....##..##......##..##....##..##......##..##....##..##......##..##....##..##......##..##....##..##......##..##..............##..........##....##........................................................ +// ############..............................######....##..##......##..##....##..##......##..##....##..##......##..##....##..##......##..##....##..##......######..............######..######....##..##.................................................... +// ############........................................##..##......##..##....##..##......######....##..##..##..##..##....##..##......######....##..##...................................................................................................... +// ####....####........................................######......######....##..##########........##..##......##..##....##..##########........##..##........................####..######..######..##...................................................... +// ######..####........####..............................##############......##..##########........##..##......##..##....##..##########........##..##..########................##..##..##..##..##..##..##.................................................. +// ####..######........####................................####..####........##..##......######....##..##..##..##..##....##..##....######......##..##..##########..............##..######..######..######.................................................. +// ######..####................####..........................##..##..........##..##......##..##....##..##......##..##....##..##....##..##......##..##......##..##..............##......##..##..##......##.................................................. +// ####..######..............##....##........................##..##..........##..##......##..##....##..##......##..##....##..##....##..##......##..##......##..##............######....##..######......##..................................##.............. +// ######..####..............##....##........................##..##..........##..##......##..##....##..##......##..##....##..##....##..##......######......##..##........................................................................##..##............ +// ####..######................####..........................##..##..........######......######....######......######....##..##....##..##......######......##..##..................................................................######......##.......... +// ####....####..............................................######..........######......######....######......######....##..##....##..##......####........######..................................................................####....##....##........ +// ####....####..............................................######............##############........##############......######....######........##############....................................................................##....##..##....##...... +// ####....####............................................##########..........##############........##############......######......######......##############..............................................................######....##......##....##.... +// ####....####..............................................................................................................................................................................................................####........##..##..##....##.. +// ####....####..............................................................................................................................................................................................................##....##......##......##....## +// ####....####....................##############........##..........##........##############......##################......##############........##############........##############..................................######....##..........##..##....#### +// ####....####....................##############......######......######......##############......##################......##############........##############........##############..................................####....##......##......##....###### +// ####..######..................####........######....######......######....####........######....####..######..####....####....##########....##################....####........######................................##........##..##..##........######## +// ######..####..................######......##..##....##..##......##..##....######......##..##..........##..##..........######................######..##..######....######......##..##..........................######....##......##......##....########.. +// ####..######..................##..##......##..##....##..##......##..##....##..##......##..##..........##..##..........##..##................##..##..##..##..##....##..##......##..##..........................####....##..##..........##....##########.. +// ######..####..................##..##......##..##....##..##......##..##....##..##......##..##..........##..##..........##..##................##..##..##..##..##....##..##......##..##..........................##....##......##......##....############## +// ####..######..................##..##......######....##..##......##..##....##..##......######..........##..##..........##..##................##..##..##..##..##....##..##......######....................######............##..##........########....#### +// ######..####..................######................##..##......##..##....######......................##..##..........##..##....######......##..##..##..##..##....######................................####....................##....##########........ +// ####....####....................############........######......######......############..............##..##..........##..########..........##..##..##..##..##......############........................##....##..............##....##############...... +// ############........................##########........##############............##########............##..##..........##..########..........##..##..##..##..##..........##########....................##....##..##..........##....########....####...... +// ############..............................######........####..####....................######..........##..##..........##..##....######......##..##..##..##..##................######................##..##........##............##########.............. +// ####....####..................######......##..##..........##..##..........######......##..##..........##..##..........##..##................##..##......##..##....######......##..##................####............##..##....##############............ +// ############..................##..##......##..##..........##..##..........##..##......##..##..........##..##..........##..##................##..##..##..##..##....##..##......##..##................####....##........##....########....####............ +// ############..........####....##..##......##..##..........##..##..........##..##......##..##..........##..##..........##..##................##..##......##..##....##..##......##..##..................##########....##....##########.................... +// ############..........####....##..##......######..........##..##..........##..##......######..........##..##..........######................##..##......##..##....##..##......######....................######..........##############.................. +// ############..........####....######........####..........######..........######........####..........##..##..........####....##########....##..##......##..##....######........####......................####........########....####.................. +// ....######################......##############............######............##############............######............##############......######......######......##############..........................######..##########.......................... +// ....######################......##############..........##########..........##############............######............##############......######......######......##############............................##################........................ +// ................................................................................................................................................................................................................########....####........................ +// ..................................................................................................................................................................................................................####.................................. + +#include "images.h" + +const image_t img_csLogo_FULL = { 124, 40, true, 571, 0x0B, { // orig:620, comp:7.90% + 0x3F, 0xFF, 0xFE, 0x10, 0x43, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, 0x0B, 0x05, 0x00, 0x03, 0xFF, 0xFF, + 0xE3, 0x8E, 0x3F, 0x87, 0xF0, 0xFE, 0x1F, 0xC0, 0x0B, 0x05, 0x00, 0xFC, 0x00, 0x07, 0x38, 0xE6, + 0x1C, 0xE3, 0x80, 0x73, 0x8E, 0x03, 0xBB, 0x80, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x52, 0x8A, 0x71, + 0xCE, 0x39, 0xC7, 0x38, 0xA0, 0x22, 0x10, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x05, 0x28, 0xA7, 0x14, + 0xA2, 0x9C, 0x52, 0x8A, 0x03, 0x39, 0x00, 0x00, 0x00, 0x0C, 0xC0, 0x00, 0x52, 0x8A, 0x51, 0x4A, + 0x29, 0x45, 0x28, 0xA0, 0x20, 0x90, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x07, 0x28, 0xA5, 0x14, 0xA2, + 0x94, 0x52, 0x8E, 0x03, 0xB9, 0x40, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x02, 0x8A, 0x51, 0xCA, 0xA9, + 0x47, 0x28, 0x0B, 0x06, 0x00, 0xCC, 0x00, 0x00, 0x38, 0xE5, 0xF0, 0xA2, 0x97, 0xC2, 0x80, 0x06, + 0xEE, 0x80, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x01, 0xFC, 0x5F, 0x0A, 0x29, 0x7C, 0x2B, 0xC0, 0x2A, + 0xAA, 0x00, 0x00, 0x00, 0xDC, 0x30, 0x00, 0x0D, 0x85, 0x1C, 0xAA, 0x94, 0xE2, 0xBE, 0x02, 0xEE, + 0xE0, 0x00, 0x00, 0x0E, 0xC0, 0x30, 0x00, 0x50, 0x51, 0x4A, 0x29, 0x4A, 0x28, 0xA0, 0x22, 0xA2, + 0x00, 0x00, 0x00, 0xDC, 0x04, 0x80, 0x05, 0x05, 0x14, 0xA2, 0x94, 0xA2, 0x8A, 0x07, 0x2E, 0x20, + 0x00, 0x08, 0x0E, 0xC0, 0x48, 0x00, 0x50, 0x51, 0x4A, 0x29, 0x4A, 0x38, 0xA0, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xDC, 0x03, 0x00, 0x05, 0x07, 0x1C, 0xE3, 0x94, 0xA3, 0x8A, 0x0B, 0x04, 0x00, 0xE2, + 0x0C, 0xC0, 0x00, 0x00, 0x70, 0x71, 0xCE, 0x39, 0x4A, 0x30, 0xE0, 0x00, 0x00, 0x00, 0x0C, 0x90, + 0xCC, 0x00, 0x00, 0x07, 0x03, 0xF8, 0x7F, 0x1C, 0xE1, 0xFC, 0x0B, 0x04, 0x00, 0x94, 0x8C, 0xC0, + 0x00, 0x00, 0xF8, 0x3F, 0x87, 0xF1, 0xC7, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0x72, 0x24, 0xCC, 0x0B, + 0x0C, 0x00, 0x06, 0x15, 0x2C, 0xC0, 0x0B, 0x0C, 0x00, 0x48, 0x89, 0xCC, 0x00, 0xFE, 0x10, 0x43, + 0xF8, 0xFF, 0x8F, 0xE1, 0xFC, 0x3F, 0x80, 0x00, 0x39, 0x05, 0x3C, 0xC0, 0x0F, 0xE3, 0x8E, 0x3F, + 0x8F, 0xF8, 0xFE, 0x1F, 0xC3, 0xF8, 0x00, 0x03, 0x22, 0x27, 0xDC, 0x01, 0x87, 0x38, 0xE6, 0x1C, + 0xDD, 0x99, 0xF3, 0xFE, 0x61, 0xC0, 0x00, 0x21, 0x50, 0xFE, 0xC0, 0x1C, 0x52, 0x8A, 0x71, 0x41, + 0x41, 0xC0, 0x3A, 0xE7, 0x14, 0x00, 0x1C, 0x88, 0x9E, 0xDC, 0x01, 0x45, 0x28, 0xA5, 0x14, 0x14, + 0x14, 0x02, 0xAA, 0x51, 0x40, 0x01, 0x94, 0x13, 0xEE, 0xC0, 0x14, 0x52, 0x8A, 0x51, 0x41, 0x41, + 0x40, 0x2A, 0xA5, 0x14, 0x00, 0x12, 0x22, 0x7F, 0xDC, 0x01, 0x47, 0x28, 0xA5, 0x1C, 0x14, 0x14, + 0x02, 0xAA, 0x51, 0xC0, 0x0E, 0x05, 0x0F, 0x3E, 0xC0, 0x1C, 0x02, 0x8A, 0x70, 0x01, 0x41, 0x4E, + 0x2A, 0xA7, 0x00, 0x00, 0xC0, 0x09, 0xF0, 0xCC, 0x00, 0xFC, 0x38, 0xE3, 0xF0, 0x14, 0x17, 0x82, + 0xAA, 0x3F, 0x00, 0x09, 0x01, 0x3F, 0x8F, 0xC0, 0x03, 0xE1, 0xFC, 0x0F, 0x81, 0x41, 0x78, 0x2A, + 0xA0, 0xF8, 0x01, 0x28, 0x27, 0x98, 0xFC, 0x00, 0x07, 0x0D, 0x80, 0x1C, 0x14, 0x14, 0xE2, 0xAA, + 0x01, 0xC0, 0x28, 0x40, 0xF8, 0x0C, 0xC0, 0x1C, 0x50, 0x50, 0x71, 0x41, 0x41, 0x40, 0x28, 0xA7, + 0x14, 0x03, 0x02, 0x9F, 0xC0, 0xFC, 0x01, 0x45, 0x05, 0x05, 0x14, 0x14, 0x14, 0x02, 0xAA, 0x51, + 0x40, 0x32, 0x13, 0xCC, 0x0F, 0xC1, 0x94, 0x50, 0x50, 0x51, 0x41, 0x41, 0x40, 0x28, 0xA5, 0x14, + 0x01, 0xF2, 0x7C, 0x00, 0xFC, 0x19, 0x47, 0x05, 0x05, 0x1C, 0x14, 0x1C, 0x02, 0x8A, 0x51, 0xC0, + 0x0E, 0x0F, 0xE0, 0x0F, 0xC1, 0x9C, 0x30, 0x70, 0x70, 0xC1, 0x41, 0x9F, 0x28, 0xA7, 0x0C, 0x00, + 0x61, 0xE6, 0x00, 0x3F, 0xF8, 0xFE, 0x07, 0x03, 0xF8, 0x1C, 0x0F, 0xE3, 0x8E, 0x3F, 0x80, 0x03, + 0xBE, 0x00, 0x03, 0xFF, 0x8F, 0xE0, 0xF8, 0x3F, 0x81, 0xC0, 0xFE, 0x38, 0xE3, 0xF8, 0x00, 0x1F, + 0xF0, 0x0B, 0x0E, 0x00, 0xF3, 0x0B, 0x0E, 0x00, 0x06, 0x00, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_csLogo_Small.c b/applications/plugins/wii_ec_anal/gfx/img_csLogo_Small.c new file mode 100644 index 000000000..5cd2f613f --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_csLogo_Small.c @@ -0,0 +1,18 @@ +// ################## +// ################## +// ####..........#### +// ####..........#### +// ####..##.......... +// ####......######## +// ####......##....## +// ####......##...... +// ####......######## +// ####............## +// ########..##....## +// ########..######## + +#include "images.h" + +const image_t img_csLogo_Small = { 9, 12, false, 14, 0, { + 0xFF, 0xFF, 0xF0, 0x78, 0x3D, 0x06, 0x3F, 0x13, 0x88, 0xC7, 0xE0, 0x7D, 0x3E, 0xF0 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_ecp_SCL.c b/applications/plugins/wii_ec_anal/gfx/img_ecp_SCL.c new file mode 100644 index 000000000..533b79c7b --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_ecp_SCL.c @@ -0,0 +1,13 @@ +// ....##############......######## +// ....##############......######## +// ....####......####......####.... +// ....####......####......####.... +// ....####......####......####.... +// ########......##############.... +// ########......##############.... + +#include "images.h" + +const image_t img_ecp_SCL = { 16, 7, false, 14, 0, { + 0x3F, 0x8F, 0x3F, 0x8F, 0x31, 0x8C, 0x31, 0x8C, 0x31, 0x8C, 0xF1, 0xFC, 0xF1, 0xFC +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_ecp_SDA.c b/applications/plugins/wii_ec_anal/gfx/img_ecp_SDA.c new file mode 100644 index 000000000..7384fc87c --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_ecp_SDA.c @@ -0,0 +1,19 @@ +// ......##.......................... +// ....####.......................... +// ..####............................ +// ######################............ +// ######################....##...... +// ..####....................####.... +// ....####....................####.. +// ......##....###################### +// ............###################### +// ............................####.. +// ..........................####.... +// ..........................##...... + +#include "images.h" + +const image_t img_ecp_SDA = { 17, 12, false, 26, 0, { + 0x10, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1F, 0xFC, 0x0F, 0xFE, 0x43, 0x00, 0x30, 0xC0, 0x0C, 0x27, + 0xFF, 0x03, 0xFF, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x80 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_ecp_port.c b/applications/plugins/wii_ec_anal/gfx/img_ecp_port.c new file mode 100644 index 000000000..942f0c593 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_ecp_port.c @@ -0,0 +1,66 @@ +// ....................##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..## +// ..................##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##.. +// ................##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..## +// ..............##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##.. +// ............##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..## +// ..........##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##.. +// ........##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..##..## +// ......######################################################################################################################..##..##..##.. +// ......########################################################################################################################..##..##..## +// ......####..............................................................................................................####..##..##..##.. +// ......####..............................................................................................................######..##..##..## +// ......####..............................................................................................................####..##..##..##.. +// ......####..............................................................................................................######..##..##..## +// ......####..............................................................................................................####..##..##..##.. +// ......####........##############################################################################################........######..##..##..## +// ......####........##############################################################################################........####..##..##..##.. +// ......####........####........####..........####........####..........####........####..........####........####........######..##..##..## +// ......####........####........####..........####........####..........####........####..........####........####........####..##..##..##.. +// ......####........####........##################........##################........##################........####........######..##..##..## +// ......####........####........##################........##################........##################........####........####..##..##..##.. +// ......####........####......................................................................................####........######..##..##..## +// ..########........####......................................................................................####........####..##########.. +// ##########........####......................................................................................####........################## +// ##########........####......................................................................................####........####..##########.. +// ..########........####......................................................................................####........################## +// ......####........####........##################..................................##################........####........####..##..##..##.. +// ......####........####........##################..................................##################........####........######..##..##..## +// ......####........####........####..........####........##################........####..........####........####........####..##..##..##.. +// ......####........####........####..........####........##..............##........####..........####........####........######..##..##..## +// ......####........##############################################################################################........####..##..##..##.. +// ......####........##############################################################################################........######..##..##..## +// ......####..............................................................................................................####..##..##..##.. +// ......####..............................................................................................................######..##..##..## +// ......####..............................................................................................................####..##..##..##.. +// ......####....................................######################################....................................######..##..##..## +// ......####....................................######################################....................................####..##..##..##.. +// ......####....................................####..##..##..##..................####....................................######..##..##.... +// ......####....................................######..##..##....................####....................................####..##..##...... +// ......####....................................####..##..##......................####....................................######..##........ +// ......####....................................######..##........................####....................................####..##.......... +// ......############################################..##..........................##############################################............ +// ......##############################################............................############################################.............. + +#include "images.h" + +const image_t img_ecp_port = { 69, 42, true, 290, 0x04, { // orig:363, comp:20.11% + 0x00, 0x2A, 0x04, 0x06, 0xAA, 0xA8, 0x02, 0x04, 0x07, 0xAA, 0x80, 0x2A, 0x04, 0x07, 0xAA, 0x02, + 0x04, 0x07, 0xAA, 0xA0, 0x2A, 0x04, 0x07, 0xAA, 0x82, 0x04, 0x07, 0xAA, 0xA8, 0x2A, 0x04, 0x07, + 0xAA, 0xA3, 0x04, 0x07, 0xFF, 0xAA, 0x1F, 0x04, 0x06, 0xFF, 0xFE, 0xA8, 0xC0, 0x04, 0x06, 0x00, + 0x6A, 0x86, 0x04, 0x06, 0x00, 0x03, 0xAA, 0x30, 0x04, 0x06, 0x00, 0x1A, 0xA1, 0x80, 0x04, 0x06, + 0x00, 0xEA, 0x8C, 0x04, 0x06, 0x00, 0x06, 0xA8, 0x61, 0x04, 0x05, 0xFF, 0xFC, 0x3A, 0xA3, 0x0F, + 0x04, 0x05, 0xFF, 0xE1, 0xAA, 0x18, 0x61, 0x83, 0x0C, 0x18, 0x60, 0xC3, 0x0E, 0xA8, 0xC3, 0x0C, + 0x18, 0x60, 0xC3, 0x06, 0x18, 0x6A, 0x86, 0x18, 0x7F, 0xC3, 0xFE, 0x1F, 0xF0, 0xC3, 0xAA, 0x30, + 0xC3, 0xFE, 0x1F, 0xF0, 0xFF, 0x86, 0x1A, 0xA1, 0x86, 0x04, 0x05, 0x00, 0x30, 0xEA, 0xBC, 0x30, + 0x04, 0x04, 0x00, 0x01, 0x86, 0xFB, 0xE1, 0x80, 0x04, 0x04, 0x00, 0x0C, 0x3F, 0xFF, 0x0C, 0x04, + 0x05, 0x00, 0x61, 0xBE, 0x78, 0x60, 0x04, 0x04, 0x00, 0x03, 0x0F, 0xF8, 0xC3, 0x0F, 0xF8, 0x00, + 0x03, 0xFE, 0x18, 0x6A, 0x86, 0x18, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0xC3, 0xAA, 0x30, 0xC3, 0x06, + 0x1F, 0xF0, 0xC1, 0x86, 0x1A, 0xA1, 0x86, 0x18, 0x30, 0x80, 0x86, 0x0C, 0x30, 0xEA, 0x8C, 0x3F, + 0x04, 0x05, 0xFF, 0x86, 0xA8, 0x61, 0x04, 0x05, 0xFF, 0xFC, 0x3A, 0xA3, 0x04, 0x06, 0x00, 0x01, + 0xAA, 0x18, 0x04, 0x06, 0x00, 0x0E, 0xA8, 0xC0, 0x04, 0x06, 0x00, 0x6A, 0x86, 0x00, 0x00, 0x7F, + 0xFF, 0xF0, 0x00, 0x03, 0xAA, 0x30, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x1A, 0xA1, 0x80, 0x00, + 0x1A, 0xA0, 0x0C, 0x00, 0x00, 0xEA, 0x0C, 0x00, 0x00, 0xEA, 0x00, 0x60, 0x00, 0x06, 0xA0, 0x60, + 0x00, 0x06, 0xA0, 0x03, 0x00, 0x00, 0x3A, 0x03, 0x00, 0x00, 0x3A, 0x00, 0x18, 0x00, 0x01, 0xA0, + 0x1F, 0xFF, 0xFF, 0xA0, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, + 0xE0, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_Back.c b/applications/plugins/wii_ec_anal/gfx/img_key_Back.c new file mode 100644 index 000000000..d13bcf7f2 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_Back.c @@ -0,0 +1,15 @@ +// ..##############.. +// ################## +// ######..########## +// ####........###### +// ######..####..#### +// ############..#### +// ########....###### +// ################## +// ....############.. + +#include "images.h" + +const image_t img_key_Back = { 9, 9, false, 11, 0, { + 0x7F, 0x7F, 0xFB, 0xF8, 0x7E, 0xDF, 0xEF, 0xCF, 0xFF, 0x3F, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_D.c b/applications/plugins/wii_ec_anal/gfx/img_key_D.c new file mode 100644 index 000000000..8d182427c --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_D.c @@ -0,0 +1,14 @@ +// ..##############.. +// ################## +// ################## +// ####..........#### +// ######......###### +// ########..######## +// ################## +// ..##############.. + +#include "images.h" + +const image_t img_key_D = { 9, 8, false, 9, 0, { + 0x7F, 0x7F, 0xFF, 0xF8, 0x3E, 0x3F, 0xBF, 0xFE, 0xFE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_L.c b/applications/plugins/wii_ec_anal/gfx/img_key_L.c new file mode 100644 index 000000000..1fc5556b1 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_L.c @@ -0,0 +1,15 @@ +// ..############.. +// ################ +// ########..###### +// ######....###### +// ####......###### +// ######....###### +// ########..###### +// ################ +// ..############.. + +#include "images.h" + +const image_t img_key_L = { 8, 9, false, 9, 0, { + 0x7E, 0xFF, 0xF7, 0xE7, 0xC7, 0xE7, 0xF7, 0xFF, 0x7E +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_OK.c b/applications/plugins/wii_ec_anal/gfx/img_key_OK.c new file mode 100644 index 000000000..ef64128f8 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_OK.c @@ -0,0 +1,15 @@ +// ..##############.. +// ################## +// ######......###### +// ####..........#### +// ####..........#### +// ####..........#### +// ######......###### +// ################## +// ....############.. + +#include "images.h" + +const image_t img_key_OK = { 9, 9, false, 11, 0, { + 0x7F, 0x7F, 0xF8, 0xF8, 0x3C, 0x1E, 0x0F, 0x8F, 0xFF, 0x3F, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_OKi.c b/applications/plugins/wii_ec_anal/gfx/img_key_OKi.c new file mode 100644 index 000000000..595f2f431 --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_OKi.c @@ -0,0 +1,15 @@ +// ..##############.. +// ####..........#### +// ##....######....## +// ##..##########..## +// ##..##########..## +// ##..##########..## +// ##....######....## +// ####..........#### +// ..##############.. + +#include "images.h" + +const image_t img_key_OKi = { 9, 9, false, 11, 0, { + 0x7F, 0x60, 0xE7, 0x37, 0xDB, 0xED, 0xF6, 0x73, 0x83, 0x7F, 0x00 +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_R.c b/applications/plugins/wii_ec_anal/gfx/img_key_R.c new file mode 100644 index 000000000..87cc385bc --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_R.c @@ -0,0 +1,15 @@ +// ..############.. +// ################ +// ######..######## +// ######....###### +// ######......#### +// ######....###### +// ######..######## +// ################ +// ..############.. + +#include "images.h" + +const image_t img_key_R = { 8, 9, false, 9, 0, { + 0x7E, 0xFF, 0xEF, 0xE7, 0xE3, 0xE7, 0xEF, 0xFF, 0x7E +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_U.c b/applications/plugins/wii_ec_anal/gfx/img_key_U.c new file mode 100644 index 000000000..aca5bb62a --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_U.c @@ -0,0 +1,14 @@ +// ..##############.. +// ################## +// ########..######## +// ######......###### +// ####..........#### +// ################## +// ################## +// ..##############.. + +#include "images.h" + +const image_t img_key_U = { 9, 8, false, 9, 0, { + 0x7F, 0x7F, 0xFD, 0xFC, 0x7C, 0x1F, 0xFF, 0xFE, 0xFE +}}; diff --git a/applications/plugins/wii_ec_anal/gfx/img_key_Ui.c b/applications/plugins/wii_ec_anal/gfx/img_key_Ui.c new file mode 100644 index 000000000..b740780ad --- /dev/null +++ b/applications/plugins/wii_ec_anal/gfx/img_key_Ui.c @@ -0,0 +1,14 @@ +// ..##############.. +// ####..........#### +// ##......##......## +// ##....######....## +// ##..##########..## +// ##..............## +// ####..........#### +// ..##############.. + +#include "images.h" + +const image_t img_key_Ui = { 9, 8, false, 9, 0, { + 0x7F, 0x60, 0xE2, 0x33, 0x9B, 0xEC, 0x07, 0x06, 0xFE +}}; diff --git a/applications/plugins/wii_ec_anal/i2c_workaround.h b/applications/plugins/wii_ec_anal/i2c_workaround.h new file mode 100644 index 000000000..de1dbba54 --- /dev/null +++ b/applications/plugins/wii_ec_anal/i2c_workaround.h @@ -0,0 +1,119 @@ +/* + As of the date of releasing this code, there is (seemingly) a bug in the FZ i2c library code + It is described here: https://github.com/flipperdevices/flipperzero-firmware/issues/1670 + + This is a short-term workaround so I can keep developing while we get to the bottom of the issue + + FYI. *something* in the following code is the fix + +void furi_hal_i2c_acquire (FuriHalI2cBusHandle* handle) +{ + // 1. Disable the power/backlight (it uses i2c) + furi_hal_power_insomnia_enter(); + // 2. Lock bus access + handle->bus->callback(handle->bus, FuriHalI2cBusEventLock); + // 3. Ensuree that no active handle set + furi_check(handle->bus->current_handle == NULL); + // 4. Set current handle + handle->bus->current_handle = handle; + // 5. Activate bus + handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate); + // 6. Activate handle + handle->callback(handle, FuriHalI2cBusHandleEventActivate); +} + +void furi_hal_i2c_release (FuriHalI2cBusHandle* handle) +{ + // Ensure that current handle is our handle + furi_check(handle->bus->current_handle == handle); + // 6. Deactivate handle + handle->callback(handle, FuriHalI2cBusHandleEventDeactivate); + // 5. Deactivate bus + handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate); + // 3,4. Reset current handle + handle->bus->current_handle = NULL; + // 2. Unlock bus + handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock); + // 1. Re-enable the power system + furi_hal_power_insomnia_exit(); +} + +*/ + +#ifndef I2C_WORKAROUND_H_ +#define I2C_WORKAROUND_H_ + +#include + +#define ENABLE_WORKAROUND 1 + +#if ENABLE_WORKAROUND == 1 + //+============================================================================ ======================================== + static inline + bool furi_hal_Wi2c_is_device_ready (FuriHalI2cBusHandle* const bus, const uint8_t addr, const uint32_t tmo) + { + furi_hal_i2c_acquire(bus); + bool rv = furi_hal_i2c_is_device_ready(bus, addr, tmo); + furi_hal_i2c_release(bus); + return rv; + } + + //+============================================================================ + static inline + bool furi_hal_Wi2c_tx ( FuriHalI2cBusHandle* const bus, const uint8_t addr, + const void* buf, const size_t len, const uint32_t tmo ) + { + furi_hal_i2c_acquire(bus); + bool rv = furi_hal_i2c_tx(bus, addr, buf, len, tmo); + furi_hal_i2c_release(bus); + return rv; + } + + //+============================================================================ + static inline + bool furi_hal_Wi2c_rx ( FuriHalI2cBusHandle* const bus, const uint8_t addr, + void* buf, const size_t len, const uint32_t tmo ) + { + furi_hal_i2c_acquire(bus); + bool rv = furi_hal_i2c_rx(bus, addr, buf, len, tmo); + furi_hal_i2c_release(bus); + return rv; + } + + //+============================================================================ + static inline + bool furi_hal_Wi2c_trx ( FuriHalI2cBusHandle* const bus, const uint8_t addr, + const void* tx, const size_t txlen, + void* rx, const size_t rxlen, const uint32_t tmo ) + { + bool rv = furi_hal_Wi2c_tx(bus, addr, tx, txlen, tmo); + if (rv) rv = furi_hal_Wi2c_rx(bus, addr, rx, rxlen, tmo); + return rv; + } + + //----------------------------------------------------------------------------- ---------------------------------------- +# define furi_hal_i2c_is_device_ready(...) furi_hal_Wi2c_is_device_ready(__VA_ARGS__) +# define furi_hal_i2c_tx(...) furi_hal_Wi2c_tx(__VA_ARGS__) +# define furi_hal_i2c_rx(...) furi_hal_Wi2c_rx(__VA_ARGS__) +# define furi_hal_i2c_trx(...) furi_hal_Wi2c_trx(__VA_ARGS__) + +#endif //ENABLE_WORKAROUND + +//+============================================================================ ======================================== +// Some devices take a moment to respond to read requests +// The puts a delay between the address being set and the data being read +// +static inline +bool furi_hal_i2c_trxd ( FuriHalI2cBusHandle* const bus, const uint8_t addr, + const void* tx, const size_t txlen, + void* rx, const size_t rxlen, const uint32_t tmo, const uint32_t us ) +{ + bool rv = furi_hal_i2c_tx(bus, addr, tx, txlen, tmo); + if (rv) { + furi_delay_us(us); + rv = furi_hal_i2c_rx(bus, addr, rx, rxlen, tmo); + } + return rv; +} + +#endif //I2C_WORKAROUND_H_ diff --git a/applications/plugins/wii_ec_anal/info.sh b/applications/plugins/wii_ec_anal/info.sh new file mode 100644 index 000000000..e009eb118 --- /dev/null +++ b/applications/plugins/wii_ec_anal/info.sh @@ -0,0 +1,11 @@ +echo "MARKED AS TODO" +echo "==============" +grep //! *.c *.h + +echo -e "\nSUPPORTED CONTROLLERS" +echo "=====================" +grep '\[PID_.*{ {' wii_ec.c | head -n -3 | sed 's/\s*\(.*\)/\1/' + +echo -e "\nLOGGING" +echo "=======" +grep LOG_LEVEL *.h | grep -v '#if ' diff --git a/applications/plugins/wii_ec_anal/notes.txt b/applications/plugins/wii_ec_anal/notes.txt new file mode 100644 index 000000000..61b6e29af --- /dev/null +++ b/applications/plugins/wii_ec_anal/notes.txt @@ -0,0 +1,87 @@ +//+============================================================================ ======================================== +// Select font +// A full list of u8g2 fonts can be found here: +// https://github.com/olikraus/u8g2/wiki/fntlistall +// ...and here are the ones available in FZ (currently: all of them): +// grep -P '.*u8g2.*\[[0-9]*\]' lib/u8g2/u8g2_fonts.c | sed 's/.*\(u8g2_.*\)\[.*/\1/' +// +#if 0 //! Extra fonts is just too memory hungry +#include +void setFont (Canvas* const canvas, const uint8_t* font) +{ + u8g2_SetFontMode(&canvas->fb, 1); // no idea - but canvas.c does it + u8g2_SetFont(&canvas->fb, font); +} +#endif + +litui : @BlueChip for posterity, the function to break at is flipper_application_spawn. At that point, you can set new breakpoints in your fap code and continue. + +/* + +This is wrong on quite a few levels! +https://training.ti.com/introduction-i2c-reserved-addresses + +void doit (void) +{ + furi_hal_i2c_acquire(&furi_hal_i2c_handle_external); + printf("Scanning external i2c on PC0(SCL)/PC1(SDA)\r\n" + "Clock: 100khz, 7bit address\r\n" + "\r\n"); + printf(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n"); + printf("--+--------------------------------\r\n"); + for(uint8_t row = 0; row < 0x8; row++) { + printf("%x | ", row); + for(uint8_t column = 0; column <= 0xF; column++) { + bool ret = furi_hal_i2c_is_device_ready( + &furi_hal_i2c_handle_external, ((row << 4) + column) << 1, 2); + printf("%c ", ret ? '#' : '-'); + } + printf("\r\n"); + } + furi_hal_i2c_release(&furi_hal_i2c_handle_external); +} +*/ + + +region locking : firmware/targets/f7/furi_hal/furi_hal_region.c + + +# if 0 //! scrolling works beautifully, but the LCD refresh can't keep up :( + // Waveform + if (cnt) { // start + for (int a = ACC_1; a < ACC_N; a++) { + canvas_draw_dot(canvas, x,y[a]+v[a][idx]); + for (int i = 1; i < aw -cnt; i++) { + canvas_draw_line(canvas, x+i,y[a]+v[a][i-1] , x+i,y[a]+v[a][i]); + } + } + } else { // scroll + for (int a = ACC_1; a < ACC_N; a++) { + for (int i = 0; i < aw; i++) { + int off = (idx +i) %aw; + int prev = off ? off-1 : aw-1; + canvas_draw_line(canvas, x+i,y[a]+v[a][prev] , x+i,y[a]+v[a][off]); + } + } + } + +# else + int end = idx ? idx : aw; + for (int a = ACC_1; a < ACC_N; a++) { + canvas_draw_dot(canvas, x,y[a]+v[a][idx]); + if (state->apause) { + for (int i = 1; i < end; i++) + canvas_draw_line(canvas, x+i,y[a]+v[a][i-1] , x+i,y[a]+v[a][i]); + } else { + for (int i = 1; i < end; i++) + canvas_draw_line(canvas, x+i,y[a]+v[a][i-1] , x+i,y[a]+v[a][i]); + for (int i = end+10; i < aw -cnt; i++) + canvas_draw_line(canvas, x+i,y[a]+v[a][i-1] , x+i,y[a]+v[a][i]); + } + } + + // Wipe bar + if (end < aw) canvas_draw_line(canvas, x+end,y[0], x+end,y[2]+ah-1); + if (++end < aw) canvas_draw_line(canvas, x+end,y[0], x+end,y[2]+ah-1); + if (++end < aw) canvas_draw_line(canvas, x+end,y[0], x+end,y[2]+ah-1); +# endif diff --git a/applications/plugins/wii_ec_anal/wii_anal.c b/applications/plugins/wii_ec_anal/wii_anal.c new file mode 100644 index 000000000..fdf718b63 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal.c @@ -0,0 +1,540 @@ +//----------------------------------------------------------------------------- ---------------------------------------- +// Includes +// + +// System libs +#include // malloc +#include // uint32_t +#include // __VA_ARGS__ +#include +#include + +// FlipperZero libs +#include // Core API +#include // GUI (screen/keyboard) API +#include // GUI Input extensions +#include + +// Do this first! +#define ERR_C_ // Do this in precisely ONE file +#include "err.h" // Error numbers & messages + +#include "bc_logging.h" + +// Local headers +#include "wii_anal.h" // Various enums and struct declarations +#include "wii_i2c.h" // Wii i2c functions +#include "wii_ec.h" // Wii Extension Controller functions (eg. draw) +#include "wii_anal_keys.h" // key mappings +#include "gfx/images.h" // Images +#include "wii_anal_lcd.h" // Drawing functions +#include "wii_anal_ec.h" // Wii controller events + +#include "wii_anal_ver.h" // Version number + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// OOOOO // SSSSS CCCCC AAA L L BBBB AAA CCCC K K SSSSS +// O O /// S C A A L L B B A A C K K S +// O O /// SSSSS C AAAAA L L BBBB AAAAA C KKK SSSSS +// O O /// S C A A L L B B A A C K K S +// OOOOO // SSSSS CCCCC A A LLLLL LLLLL BBBB A A CCCC K K SSSSS +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//+============================================================================ ======================================== +// OS Callback : Timer tick +// We register this function to be called when the OS signals a timer 'tick' event +// +static +void cbTimer (FuriMessageQueue* queue) +{ + ENTER; + furi_assert(queue); + + eventMsg_t message = {.id = EVID_TICK}; + furi_message_queue_put(queue, &message, 0); + + LEAVE; + return; +} + +//+============================================================================ ======================================== +// OS Callback : Keypress +// We register this function to be called when the OS detects a keypress +// +static +void cbInput (InputEvent* event, FuriMessageQueue* queue) +{ + ENTER; + furi_assert(queue); + furi_assert(event); + + // Put an "input" event message on the message queue + eventMsg_t message = {.id = EVID_KEY, .input = *event}; + furi_message_queue_put(queue, &message, FuriWaitForever); + + LEAVE; + return; +} + +//+============================================================================ +// Show version number +// +static +void showVer (Canvas* const canvas) +{ + show(canvas, 0,59, &img_3x5_v, SHOW_SET_BLK); + show(canvas, 4,59, VER_MAJ, SHOW_SET_BLK); + canvas_draw_frame(canvas, 8,62, 2,2); + show(canvas, 11,59, VER_MIN, SHOW_SET_BLK); +} + +//+============================================================================ +// OS Callback : Draw request +// We register this function to be called when the OS requests that the screen is redrawn +// +// We actually instruct the OS to perform this request, after we update the interface +// I guess it's possible that this instruction may able be issued by other threads !? +// +static +void cbDraw (Canvas* const canvas, void* ctx) +{ + ENTER; + furi_assert(canvas); + furi_assert(ctx); + + state_t* state = NULL; + + // Try to acquire the mutex for the plugin state variables, timeout = 25mS + if ( !(state = (state_t*)acquire_mutex((ValueMutex*)ctx, 25)) ) return ; + + switch (state->scene) { + //--------------------------------------------------------------------- + case SCENE_SPLASH: + show(canvas, 2,0, &img_csLogo_FULL, SHOW_SET_BLK); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64,43, AlignCenter, AlignTop, "Wii Extension Controller"); + canvas_draw_str_aligned(canvas, 64,55, AlignCenter, AlignTop, "Protocol Analyser"); + + showVer(canvas); + + break; + + //--------------------------------------------------------------------- + case SCENE_RIP: + show(canvas, 0,0, &img_RIP, SHOW_SET_BLK); + break; + + //--------------------------------------------------------------------- + case SCENE_WAIT: +# define xo 2 + + show(canvas, 3+xo,10, &img_ecp_port, SHOW_SET_BLK); + + BOX_TL(22+xo, 6, 82+xo,23); // 3v3 + BOX_TL(48+xo,21, 82+xo,23); // C1 + BOX_BL(22+xo,41, 82+xo,58); // C0 + BOX_BL(48+xo,41, 82+xo,44); // Gnd + + show(canvas, 90+xo, 3, &img_6x8_3, SHOW_SET_BLK); // 3v3 + show(canvas, 97+xo, 3, &img_6x8_v, SHOW_SET_BLK); + show(canvas, 104+xo, 3, &img_6x8_3, SHOW_SET_BLK); + + show(canvas, 90+xo,18, &img_6x8_C, SHOW_SET_BLK); // C1 <-> + show(canvas, 98+xo,18, &img_6x8_1, SHOW_SET_BLK); + show(canvas, 107+xo,16, &img_ecp_SDA, SHOW_SET_BLK); + + show(canvas, 90+xo,40, &img_6x8_G, SHOW_SET_BLK); // Gnd + show(canvas, 97+xo,40, &img_6x8_n, SHOW_SET_BLK); + show(canvas, 104+xo,40, &img_6x8_d, SHOW_SET_BLK); + + show(canvas, 90+xo,54, &img_6x8_C, SHOW_SET_BLK); // C0 _-_- + show(canvas, 98+xo,54, &img_6x8_0, SHOW_SET_BLK); + show(canvas, 108+xo,54, &img_ecp_SCL, SHOW_SET_BLK); + + show(canvas, 0,0, &img_csLogo_Small, SHOW_SET_BLK); + showVer(canvas); + +# undef xo + break; + + //--------------------------------------------------------------------- + case SCENE_DEBUG: + canvas_set_font(canvas, FontSecondary); + + show(canvas, 0,0, &img_key_U, SHOW_SET_BLK); + canvas_draw_str_aligned(canvas, 11, 0, AlignLeft, AlignTop, "Initialise Perhipheral"); + + show(canvas, 0,11, &img_key_OK, SHOW_SET_BLK); + canvas_draw_str_aligned(canvas, 11,11, AlignLeft, AlignTop, "Read values [see log]"); + + show(canvas, 0,23, &img_key_D, SHOW_SET_BLK); + canvas_draw_str_aligned(canvas, 11,22, AlignLeft, AlignTop, "Restart Scanner"); + + show(canvas, 0,33, &img_key_Back, SHOW_SET_BLK); + canvas_draw_str_aligned(canvas, 11,33, AlignLeft, AlignTop, "Exit"); + + break ; + + //--------------------------------------------------------------------- + default: + if (state->ec.pidx >= PID_ERROR) { + ERROR("%s : bad PID = %d", __func__, state->ec.pidx); + } else { + if ((state->scene == SCENE_DUMP) || !ecId[state->ec.pidx].show) + ecId[PID_UNKNOWN].show(canvas, state); + else + ecId[state->ec.pidx].show(canvas, state); + } + break; + } + + // Release the mutex + release_mutex((ValueMutex*)ctx, state); + + LEAVE; + return; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// SSSSS TTTTT AAA TTTTT EEEEE V V AAA RRRR IIIII AAA BBBB L EEEEE SSSSS +// S T A A T E V V A A R R I A A B B L E S +// SSSSS T AAAAA T EEE V V AAAAA RRRR I AAAAA BBBB L EEE SSSSS +// S T A A T E V V A A R R I A A B B L E S +// SSSSS T A A T EEEEE V A A R R IIIII A A BBBB LLLLL EEEEE SSSSS +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//+============================================================================ ======================================== +// Initialise plugin state variables +// +static inline +bool stateInit (state_t* const state) +{ + ENTER; + furi_assert(state); + + bool rv = true; // assume success + + // Enable the main loop + state->run = true; + + // Timer + state->timerEn = false; + state->timer = NULL; + state->timerHz = furi_kernel_get_tick_frequency(); + state->fps = 30; + + // Scene + state->scene = SCENE_SPLASH; + state->scenePrev = SCENE_NONE; + state->scenePegg = SCENE_NONE; + + state->hold = 0; // show hold meters (-1=lowest, 0=current, +1=highest} + state->calib = CAL_TRACK; + state->pause = false; // animation running + state->apause = false; // auto-pause animation + + // Notifications + state->notify = NULL; + + // Perhipheral + state->ec.init = false; + state->ec.pidx = PID_UNKNOWN; + state->ec.sid = ecId[state->ec.pidx].name; + + // Controller data + memset(state->ec.pid, 0xC5, PID_LEN); // Cyborg 5ystems + memset(state->ec.calF, 0xC5, CAL_LEN); + memset(state->ec.joy, 0xC5, JOY_LEN); + + // Encryption details + state->ec.encrypt = false; + memset(state->ec.encKey, 0x00, ENC_LEN); + + // Seed the PRNG + // CYCCNT --> lib/STM32CubeWB/Drivers/CMSIS/Include/core_cm7.h +// srand(DWT->CYCCNT); + + LEAVE; + return rv; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// MM MM AAA IIIII N N +// M M M A A I NN N +// M M M AAAAA I N N N +// M M A A I N NN +// M M A A IIIII N N +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//+============================================================================ ======================================== +// Enable/Disable scanning +// +void timerEn (state_t* state, bool on) +{ + ENTER; + furi_assert(state); + + // ENable scanning + if (on) { + if (state->timerEn) { + WARN(wii_errs[WARN_SCAN_START]); + } else { + // Set the timer to fire at 'fps' times/second + if (furi_timer_start(state->timer, state->timerHz/state->fps) == FuriStatusOk) { + state->timerEn = true; + INFO("%s : monitor started", __func__); + } else { + ERROR(wii_errs[ERR_TIMER_START]); + } + } + + // DISable scanning + } else { + if (!state->timerEn) { + WARN(wii_errs[WARN_SCAN_STOP]); + } else { + // Stop the timer + if (furi_timer_stop(state->timer) == FuriStatusOk) { + state->timerEn = false; + INFO("%s : monitor stopped", __func__); + } else { + ERROR(wii_errs[ERR_TIMER_STOP]); + } + } + } + + LEAVE; + return; +} + +//+============================================================================ ======================================== +// Plugin entry point +// +int32_t wii_ec_anal (void) +{ + ENTER; + + // ===== Variables ===== + err_t error = 0; // assume success + Gui* gui = NULL; + ViewPort* vpp = NULL; + state_t* state = NULL; + ValueMutex mutex = {0}; + FuriMessageQueue* queue = NULL; + const uint32_t queueSz = 20; // maximum messages in queue + uint32_t tmo = (3.5f *1000); // timeout splash screen after N seconds + + // The queue will contain plugin event-messages + // --> local + eventMsg_t msg = {0}; + + INFO("BEGIN"); + + // ===== Message queue ===== + // 1. Create a message queue (for up to 8 (keyboard) event messages) + if ( !(queue = furi_message_queue_alloc(queueSz, sizeof(msg))) ) { + ERROR(wii_errs[(error = ERR_MALLOC_QUEUE)]); + goto bail; + } + + // ===== Create GUI Interface ===== + // 2. Create a GUI interface + if ( !(gui = furi_record_open("gui")) ) { + ERROR(wii_errs[(error = ERR_NO_GUI)]); + goto bail; + } + + // ===== Plugin state variables ===== + // 3. Allocate space on the heap for the plugin state variables + if ( !(state = malloc(sizeof(state_t))) ) { + ERROR(wii_errs[(error = ERR_MALLOC_STATE)]); + goto bail; + } + // 4. Initialise the plugin state variables + if (!stateInit(state)) { + // error message(s) is/are output by stateInit() + error = 15; + goto bail; + } + // 5. Create a mutex for (reading/writing) the plugin state variables + if (!init_mutex(&mutex, state, sizeof(state))) { + ERROR(wii_errs[(error = ERR_NO_MUTEX)]); + goto bail; + } + + // ===== Viewport ===== + // 6. Allocate space on the heap for the viewport + if ( !(vpp = view_port_alloc()) ) { + ERROR(wii_errs[(error = ERR_MALLOC_VIEW)]); + goto bail; + } + // 7a. Register a callback for input events + view_port_input_callback_set(vpp, cbInput, queue); + // 7b. Register a callback for draw events + view_port_draw_callback_set(vpp, cbDraw, &mutex); + + // ===== Start GUI Interface ===== + // 8. Attach the viewport to the GUI + gui_add_view_port(gui, vpp, GuiLayerFullscreen); + + // ===== Timer ===== + // 9. Allocate a timer + if ( !(state->timer = furi_timer_alloc(cbTimer, FuriTimerTypePeriodic, queue)) ) { + ERROR(wii_errs[(error = ERR_NO_TIMER)]); + goto bail; + } + + // === System Notifications === + // 10. Acquire a handle for the system notification queue + if ( !(state->notify = furi_record_open(RECORD_NOTIFICATION)) ) { + ERROR(wii_errs[(error = ERR_NO_NOTIFY)]); + goto bail; + } + patBacklight(state); // Turn on the backlight [qv. remote FAP launch] + + INFO("INITIALISED"); + + // ==================== Main event loop ==================== + + if (state->run) do { + bool redraw = false; + FuriStatus status = FuriStatusErrorTimeout; + + // Wait for a message +// while ((status = furi_message_queue_get(queue, &msg, tmo)) == FuriStatusErrorTimeout) ; + status = furi_message_queue_get(queue, &msg, tmo); + + // Clear splash screen + if ( (state->scene == SCENE_SPLASH) && (state->scenePrev == SCENE_NONE) && // Initial splash + ( (status == FuriStatusErrorTimeout) || // timeout + ((msg.id == EVID_KEY) && (msg.input.type == InputTypeShort)) ) // or key-short + ) { + tmo = 60 *1000; // increase message-wait timeout to 60secs + timerEn(state, true); // start scanning the i2c bus + status = FuriStatusOk; // pass status check + msg.id = EVID_NONE; // valid msg ID + sceneSet(state, SCENE_WAIT); // move to wait screen + } + + // Check for queue errors + if (status != FuriStatusOk) { + switch (status) { + case FuriStatusErrorTimeout: DEBUG(wii_errs[DEBUG_QUEUE_TIMEOUT]); continue ; + case FuriStatusError: ERROR(wii_errs[(error = ERR_QUEUE_RTOS)]); goto bail ; + case FuriStatusErrorResource: ERROR(wii_errs[(error = ERR_QUEUE_RESOURCE)]); goto bail ; + case FuriStatusErrorParameter: ERROR(wii_errs[(error = ERR_QUEUE_BADPRM)]); goto bail ; + case FuriStatusErrorNoMemory: ERROR(wii_errs[(error = ERR_QUEUE_NOMEM)]); goto bail ; + case FuriStatusErrorISR: ERROR(wii_errs[(error = ERR_QUEUE_ISR)]); goto bail ; + default: ERROR(wii_errs[(error = ERR_QUEUE_UNK)]); goto bail ; + } + } + // Read successful + + // *** Try to lock the plugin state variables *** + if ( !(state = (state_t*)acquire_mutex_block(&mutex)) ) { + ERROR(wii_errs[(error = ERR_MUTEX_BLOCK)]); + goto bail; + } + + // *** Handle events *** + switch (msg.id) { + //--------------------------------------------- + case EVID_TICK: // Timer events + //! I would prefer to have ecPoll() called by cbTimer() + //! ...but how does cbTimer() get the required access to the state variables? Namely: 'state->ec' + //! So, for now, the timer pushes a message to call ecPoll() + //! which, in turn, will push WIIEC event meesages! + ecPoll(&state->ec, queue); + break; + + //--------------------------------------------- + case EVID_WIIEC: // WiiMote Perhipheral + if (evWiiEC(&msg, state)) redraw = true ; + break; + + //--------------------------------------------- + case EVID_KEY: // Key events + patBacklight(state); + if (evKey(&msg, state)) redraw = true; + break; + + //--------------------------------------------- + case EVID_NONE: + break; + + //--------------------------------------------- + default: // Unknown event + WARN("Unknown message.ID [%d]", msg.id); + break; + } + + // *** Update the GUI screen via the viewport *** + if (redraw) view_port_update(vpp) ; + + // *** Try to release the plugin state variables *** + if ( !release_mutex(&mutex, state) ) { + ERROR(wii_errs[(error = ERR_MUTEX_RELEASE)]); + goto bail; + } + } while (state->run); + + // ===== Game Over ===== + INFO("USER EXIT"); + +bail: + // 10. Release system notification queue + if (state->notify) { + furi_record_close(RECORD_NOTIFICATION); + state->notify = NULL; + } + + // 9. Stop the timer + if (state->timer) { + (void)furi_timer_stop(state->timer); + furi_timer_free(state->timer); + state->timer = NULL; + state->timerEn = false; + } + + // 8. Detach the viewport + gui_remove_view_port(gui, vpp); + + // 7. No need to unreqgister the callbacks + // ...they will go when the viewport is destroyed + + // 6. Destroy the viewport + if (vpp) { + view_port_enabled_set(vpp, false); + view_port_free(vpp); + vpp = NULL; + } + + // 5. Free the mutex + if (mutex.mutex) { + delete_mutex(&mutex); + mutex.mutex = NULL; + } + + // 4. Free up state pointer(s) + // none + + // 3. Free the plugin state variables + if (state) { + free(state); + state = NULL; + } + + // 2. Close the GUI + furi_record_close("gui"); + + // 1. Destroy the message queue + if (queue) { + furi_message_queue_free(queue); + queue = NULL; + } + + INFO("CLEAN EXIT ... Exit code: %d", error); + LEAVE; + return (int32_t)error; +} diff --git a/applications/plugins/wii_ec_anal/wii_anal.h b/applications/plugins/wii_ec_anal/wii_anal.h new file mode 100644 index 000000000..ac7ffddb1 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal.h @@ -0,0 +1,97 @@ +#ifndef WII_ANAL_H_ +#define WII_ANAL_H_ + +#include // Core API +#include // GUI Input extensions +#include + +//----------------------------------------------------------------------------- ---------------------------------------- +// GUI scenes +// +typedef + enum scene { + SCENE_NONE = 0, + SCENE_SPLASH = 1, + SCENE_RIP = 2, + SCENE_WAIT = 3, + SCENE_DEBUG = 4, + SCENE_DUMP = 5, + SCENE_CLASSIC = 6, + SCENE_CLASSIC_N = 7, + SCENE_NUNCHUCK = 8, + SCENE_NUNCHUCK_ACC = 9, + } +scene_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +#include "wii_i2c.h" +#include "wii_ec.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +// A list of event IDs handled by this plugin +// +typedef + enum eventID { + EVID_NONE, + EVID_UNKNOWN, + + // A full list of events can be found with: `grep -r --color "void.*set_.*_callback" applications/gui/*` + // ...A free gift to you from the makers of well written code that conforms to a good coding standard + EVID_KEY, // keypad + EVID_TICK, // tick + EVID_WIIEC, // wii extension controller + } +eventID_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +// An item in the event message-queue +// +typedef + struct eventMsg { + eventID_t id; + union { + InputEvent input; // --> applications/input/input.h + wiiEcEvent_t wiiEc; // --> local + }; + } +eventMsg_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +// State variables for this plugin +// An instance of this is allocated on the heap, and the pointer is passed back to the OS +// Access to this memory is controlled by mutex +// +typedef + struct state { + bool run; // true : plugin is running + + bool timerEn; // controller scanning enabled + FuriTimer* timer; // the timer + uint32_t timerHz; // system ticks per second + int fps; // poll/refresh [frames]-per-second + + int cnvW; // canvas width + int cnvH; // canvas height + scene_t scene; // current scene + scene_t scenePrev; // previous scene + scene_t scenePegg; // previous scene for easter eggs + int flash; // flash counter (flashing icons) + + int hold; // hold type: {-1=tough-peak, 0=none, +1=peak-hold} + ecCalib_t calib; // Software calibration mode + + bool pause; // Accelerometer animation pause + bool apause; // Accelerometer animation auto-pause + + NotificationApp* notify; // OS nitifcation queue (for patting the backlight watchdog timer) + + wiiEC_t ec; // Extension Controller details + } +state_t; + +//============================================================================= ======================================== +// Function prototypes +// +void timerEn (state_t* state, bool on) ; + +#endif //WII_ANAL_H_ diff --git a/applications/plugins/wii_ec_anal/wii_anal_ec.c b/applications/plugins/wii_ec_anal/wii_anal_ec.c new file mode 100644 index 000000000..94f021289 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_ec.c @@ -0,0 +1,85 @@ +#include +#include + +#include "wii_anal.h" +#include "wii_anal_lcd.h" +#include "wii_anal_keys.h" + +//+============================================================================ ======================================== +// Handle Wii Extension Controller events +// +bool evWiiEC (const eventMsg_t* const msg, state_t* const state) +{ + bool redraw = false; + +# if LOG_LEVEL >= 4 + { + const char* s = NULL; + switch (msg->wiiEc.type) { + case WIIEC_NONE: s = "Error"; break ; + case WIIEC_CONN: s = "Connect"; break ; + case WIIEC_DISCONN: s = "Disconnect"; break ; + case WIIEC_PRESS: s = "Press"; break ; + case WIIEC_RELEASE: s = "Release"; break ; + case WIIEC_ANALOG: s = "Analog"; break ; + case WIIEC_ACCEL: s = "Accel"; break ; + default: s = "Bug"; break ; + } + INFO("WIIP : %s '%c' = %d", s, (isprint((int)msg->wiiEc.in) ? msg->wiiEc.in : '_'), msg->wiiEc.val); + if ((msg->wiiEc.type == WIIEC_CONN) || (msg->wiiEc.type == WIIEC_DISCONN)) + INFO("...%d=\"%s\"", msg->wiiEc.val, ecId[msg->wiiEc.val].name); + } +# endif + + switch (msg->wiiEc.type) { + case WIIEC_CONN: + patBacklight(state); + state->hold = 0; + state->calib = CAL_TRACK; + sceneSet(state, ecId[msg->wiiEc.val].scene); + redraw = true ; + break; + + case WIIEC_DISCONN: + patBacklight(state); + sceneSet(state, SCENE_WAIT); + redraw = true; + break; + + case WIIEC_PRESS: + if (state->scene == SCENE_NUNCHUCK_ACC) switch (msg->wiiEc.in) { + case 'z': // un-pause + state->pause = !state->pause; + break; + case 'c': // toggle auto-pause + state->pause = false; + state->apause = !state->apause; + break; + default: break ; + } + +#if 1 //! factory calibration method not known for classic triggers - this will set the digital switch point + if (state->ec.pidx == PID_CLASSIC) { + if (msg->wiiEc.in == 'l') state->ec.calS.classic[2].trgZL = msg->wiiEc.val ; + if (msg->wiiEc.in == 'r') state->ec.calS.classic[2].trgZR = msg->wiiEc.val ; + } +#endif + __attribute__ ((fallthrough)); + + case WIIEC_RELEASE: + patBacklight(state); + redraw = true; + break; + + case WIIEC_ANALOG: + case WIIEC_ACCEL: + ecCalibrate(&state->ec, state->calib); + redraw = true; + break; + + default: + break; + } + + return redraw; +} diff --git a/applications/plugins/wii_ec_anal/wii_anal_ec.h b/applications/plugins/wii_ec_anal/wii_anal_ec.h new file mode 100644 index 000000000..886b60281 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_ec.h @@ -0,0 +1,14 @@ +#ifndef WII_ANAL_EC_H_ +#define WII_ANAL_EC_H_ + +#include + +//============================================================================= ======================================== +// Function prototypes +// +typedef struct eventMsg eventMsg_t ; +typedef struct state state_t ; + +bool evWiiEC (const eventMsg_t* const msg, state_t* const state) ; + +#endif //WII_ANAL_EC_H_ diff --git a/applications/plugins/wii_ec_anal/wii_anal_keys.c b/applications/plugins/wii_ec_anal/wii_anal_keys.c new file mode 100644 index 000000000..bcdcf5a62 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_keys.c @@ -0,0 +1,295 @@ +#include + +#include "bc_logging.h" + +#include "wii_anal.h" + +//+============================================================================ ======================================== +// Stop Calibration mode +// +static +void calStop (state_t* const state) +{ + state->hold = 0; // stop calibration mode + state->calib &= ~(CAL_RANGE | CAL_NOTJOY); // ... +} + +//+============================================================================ ======================================== +// Change to another scene +// +void sceneSet (state_t* const state, const scene_t scene) +{ + calStop(state); // Stop software calibration + state->scenePrev = state->scene; // Remember where we came from + state->scene = scene; // Go to new scene + INFO("Scene : %d -> %d", state->scenePrev, state->scene); +} + +//+============================================================================ ======================================== +// Change to an easter egg scene +// +static +void sceneSetEgg (state_t* const state, const scene_t scene) +{ + calStop(state); // Stop software calibration + state->scenePegg = state->scene; // Remember where we came from + state->scene = scene; // Go to new scene + INFO("Scene* : %d => %d", state->scenePegg, state->scene); +} + +//+============================================================================ ======================================== +// Several EC screens have 'peak-hold' and 'calibration' features +// Enabling peak-hold on screen with no peak meters will have no effect +// So, to avoid code duplication... +// +bool key_calib (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + switch (msg->input.type) { + case InputTypeShort: //# input.key) { + case InputKeyUp: //# hold = (state->hold == +1) ? 0 : +1 ; // toggle peak hold + used = true; + break; + + case InputKeyDown: //# hold = (state->hold == -1) ? 0 : -1 ; // toggle trough hold + used = true; + break; + + case InputKeyOk: //# calib & CAL_RANGE) calStop(state) ; // STOP softare calibration + else ecCalibrate(&state->ec, CAL_CENTRE) ; // perform centre calibration + used = true; + break; + + default: break ; + } + break; + + case InputTypeLong: //# >! After INPUT_LONG_PRESS interval, asynch to InputTypeRelease + switch (msg->input.key) { + case InputKeyOk: //# >O [ LONG-OK ] + ecCalibrate(&state->ec, CAL_RESET | CAL_CENTRE); // START software calibration + state->hold = 0; + state->calib |= CAL_RANGE; + state->flash = 8; // start with flash ON + used = true; + break; + + default: break ; + } + break; + + default: break ; + } + + return used; +} + +//+============================================================================ ======================================== +// WAIT screen +// +static inline +bool wait_key (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + if (msg->input.type == InputTypeShort) { + switch (msg->input.key) { + case InputKeyLeft: //# run = false; + used = true; + break; + + default: break ; + } + } + + return used; +} + +//+============================================================================ ======================================== +// DEBUG screen +// +static inline +bool debug_key (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + switch (msg->input.type) { + case InputTypeShort: //# input.key) { + case InputKeyUp: { //# ec, NULL); // Initialise the controller //! NULL = no encryption + (void)init; // in case INFO is optimised out + INFO("%s : %s", __func__, (init ? "init OK" : "init fail")); + used = true; + break; + } + + case InputKeyOk: //# ec) == 0) { // Read the controller + INFO( "%s : joy: {%02X,%02X,%02X,%02X,%02X,%02X}", __func__, + state->ec.joy[0], state->ec.joy[1], state->ec.joy[2], + state->ec.joy[3], state->ec.joy[4], state->ec.joy[5] ); + } + used = true; + break; + + case InputKeyDown: //# scenePrev); + used = true; + break; + + case InputKeyBack: //# run = false; + used = true; + break; + + default: break ; //# input.key == InputKeyBack) && (state->scenePrev == SCENE_NONE)) state->run = false ; + + // ANY-other-KEY press + if (msg->input.type == InputTypeShort) { + timerEn(state, true); // Restart the timer + state->scene = state->scenePegg; + } + + return true; +} + + +//+============================================================================ ======================================== +// "_pre" allows the plugin to use the key before the active scene gets a chance +// +static inline +bool key_pre (const eventMsg_t* const msg, state_t* const state) +{ + (void)msg; + (void)state; + + return false; +} + +//+============================================================================ ======================================== +// "_post" allows the plugin to use a key if it was not used by the active scene +// +static inline +bool key_post (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + if (msg->input.key == InputKeyBack) { + if (msg->input.type == InputTypeShort) { //# ec.init = false; // reset/disconnect the controller + sceneSet(state, SCENE_WAIT); + used = true; + + } else if (msg->input.type == InputTypeLong) { //# >B [LONG-BACK] + state->run = false; // Signal the plugin to exit + used = true; + } + } + + // Easter eggs + switch (state->scene) { + case SCENE_SPLASH: // Scenes that do NOT offer Easter eggs + case SCENE_RIP: + case SCENE_DEBUG: + break; + default: + if (msg->input.type == InputTypeLong) { + switch (msg->input.key) { + case InputKeyDown: //# >D [LONG-DOWN] + timerEn(state, false); // Stop the timer + sceneSetEgg(state, SCENE_DEBUG); + used = true; + break; + + case InputKeyLeft: //# >L [ LONG-LEFT ] + timerEn(state, false); // Stop the timer + sceneSetEgg(state, SCENE_SPLASH); + used = true; + break; + + case InputKeyUp: //# >U [ LONG-UP ] + timerEn(state, false); // Stop the timer + sceneSetEgg(state, SCENE_RIP); + used = true; + break; + + default: break ; + } + } + break; + } + + return used; +} + +//+============================================================================ ======================================== +// Handle a key press event +// +bool evKey (const eventMsg_t* const msg, state_t* const state) +{ + furi_assert(msg); + furi_assert(state); + + bool used = key_pre(msg, state); + + if (!used) switch (state->scene) { + case SCENE_SPLASH: //... + case SCENE_RIP: used = splash_key(msg, state); break ; + + case SCENE_WAIT: used = wait_key(msg, state); break ; + case SCENE_DEBUG: used = debug_key(msg, state); break ; + + default: + if (state->ec.pidx >= PID_ERROR) { + ERROR("%s : bad PID = %d", __func__, state->ec.pidx); + } else { + if ((state->scene == SCENE_DUMP) || !ecId[state->ec.pidx].keys) + ecId[PID_UNKNOWN].keys(msg, state); + else + ecId[state->ec.pidx].keys(msg, state); + } + break; + + case SCENE_NONE: break; + } + + if (!used) used = key_post(msg, state) ; + + return used; +} + diff --git a/applications/plugins/wii_ec_anal/wii_anal_keys.h b/applications/plugins/wii_ec_anal/wii_anal_keys.h new file mode 100644 index 000000000..0ebbd5e8e --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_keys.h @@ -0,0 +1,16 @@ +#ifndef WII_ANAL_KEYS_H_ +#define WII_ANAL_KEYS_H_ + +//============================================================================= ======================================== +// Function prototypes +// +#include // bool +typedef struct eventMsg eventMsg_t ; +typedef struct state state_t ; +typedef enum scene scene_t ; + +void sceneSet (state_t* const state, const scene_t scene) ; +bool key_calib (const eventMsg_t* const msg, state_t* const state) ; +bool evKey (const eventMsg_t* const msg, state_t* const state) ; + +#endif //WII_ANAL_KEYS_H_ diff --git a/applications/plugins/wii_ec_anal/wii_anal_lcd.c b/applications/plugins/wii_ec_anal/wii_anal_lcd.c new file mode 100644 index 000000000..d031bc120 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_lcd.c @@ -0,0 +1,223 @@ +#include "wii_anal.h" +#include "gfx/images.h" // Images + +//----------------------------------------------------------------------------- ---------------------------------------- +// A couple of monospaced hex fonts +// +const image_t* img_6x8[16] = { + &img_6x8_0, &img_6x8_1, &img_6x8_2, &img_6x8_3, &img_6x8_4, &img_6x8_5, &img_6x8_6, &img_6x8_7, + &img_6x8_8, &img_6x8_9, &img_6x8_A, &img_6x8_B, &img_6x8_C, &img_6x8_D, &img_6x8_E, &img_6x8_F, +}; + +const image_t* img_5x7[16] = { + &img_5x7_0, &img_5x7_1, &img_5x7_2, &img_5x7_3, &img_5x7_4, &img_5x7_5, &img_5x7_6, &img_5x7_7, + &img_5x7_8, &img_5x7_9, &img_5x7_A, &img_5x7_B, &img_5x7_C, &img_5x7_D, &img_5x7_E, &img_5x7_F, +}; + +//+============================================================================ ======================================== +// void backlightOn (void) +// { +// // Acquire a handle for the system notification queue +// // Do this ONCE ... at plugin startup +// NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); +// +// // Pat the backlight watchdog +// // Send the (predefined) message sequence {backlight_on, end} +// // --> applications/notification/*.c +// notification_message(notifications, &sequence_display_backlight_on); +// +// // Release the handle for the system notification queue +// // Do this ONCE ... at plugin quit +// furi_record_close(RECORD_NOTIFICATION); +// } +void patBacklight (state_t* state) +{ + notification_message(state->notify, &sequence_display_backlight_on); +} + +//============================================================================= ======================================== +// Show a hex number in an inverted box (for ananlogue readings) +// +void showHex ( Canvas* const canvas, uint8_t x, uint8_t y, + const uint32_t val, const uint8_t cnt, const int b ) +{ + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, x++,y++, 1 +(cnt *(6 +1)), 10); + + // thicken border + if (b == 2) canvas_draw_frame(canvas, x-2,y-2, 1 +(cnt *(6 +1))+2, 10+2); + + for (int i = (cnt -1) *4; i >= 0; i -= 4, x += 6+1) + show(canvas, x,y, img_6x8[(val >>i) &0xF], SHOW_SET_WHT) ; +} + +//============================================================================= ======================================== +// Show the up/down "peak hold" controls in the bottom right +// +void showPeakHold (state_t* const state, Canvas* const canvas, const int hold) +{ + switch (hold) { + case 0: + show(canvas, 119,51, &img_key_U, SHOW_CLR_BLK); + show(canvas, 119,56, &img_key_D, SHOW_CLR_BLK); + break; + case +1: + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 120,52, 7,6); + show(canvas, 119,51, &img_key_U, SHOW_CLR_WHT); + show(canvas, 119,56, &img_key_D, SHOW_CLR_BLK); + break; + case -1: + show(canvas, 119,51, &img_key_U, SHOW_CLR_BLK); + canvas_draw_box(canvas, 120,57, 7,6); + show(canvas, 119,56, &img_key_D, SHOW_CLR_WHT); + break; + default: + break; + } + canvas_set_color(canvas, ColorBlack); + canvas_draw_frame(canvas, 119,51, 9,13); + + // calibration indicator + show( canvas, 108,55, + ((state->calib & CAL_RANGE) && (++state->flash &8)) ? &img_key_OKi : &img_key_OK, + SHOW_SET_BLK ); +} + +//============================================================================= ======================================== +// This code performs a FULL calibration on the device EVERY time it draws a joystick +//...This is NOT a good way forward for anything other than a test tool. +// +// Realistically you would do all the maths when the controller is connected +// or, if you prefer (and it IS a good thing), have a "calibrate controller" menu option +// ...and then just use a lookup table, or trivial formual +// +// THIS algorithm chops the joystick in to one of 9 zones +// Eg. {FullLeft, Left3, Left2, Left1, Middle, Right1, Right2, Right3, FullRight} +// FullLeft and FullRight have a deadzone of N [qv. xDead] ..a total of N+1 positions +// Middle has a deadzone of N EACH WAY ...a total of 2N+1 positions +// +// If the remaining range does not divide evenly in to three zones, +// the first remainder is added to zone3, +// and the second remainder (if there is one) is added to zone2 +// ...giving finer control near the centre of the joystick +// +// The value of the deadzone is based on the number of bits in the +// joystcik {x,y} values - the larger the range, the larger the deadzone. +// +// 03 15 29 +// |<<| Calibration points |==| |>>| +// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F +// |---| |________________________| |------| |______________________________| |---| +// |r=2| | range = 9 | | r=3 | | range = 11 | |r=2| +// Zones: |-4 | |-3 |-2 |-1 | |0 | |+1 |+2 |+3 | |+4 | +// +// This is not "the right way to do it" ...this is "one way to do it" +// Consider you application, and what the user is trying to achieve +// Aim a gun - probably need to be more accurate +// Turn and object - this is probably good enough +// Start slowly & pick up speed - how about a log or sine curve? +// +void showJoy ( Canvas* const canvas, const uint8_t x, const uint8_t y, // x,y is the CENTRE of the Joystick + const uint8_t xMin, const uint8_t xMid, const uint8_t xMax, + const uint8_t yMin, const uint8_t yMid, const uint8_t yMax, + const uint8_t xPos, const uint8_t yPos, const uint8_t bits ) +{ + int xOff = 0; // final offset of joystick hat image + int yOff = 0; + + int xDead = (bits < 7) ? (1<<0) : (1<<3); // dead zone (centre & limits) + int yDead = xDead; + + // This code is NOT optimised ...and it's still barely readable! + if ((xPos >= (xMid -xDead)) && (xPos <= (xMid +xDead))) xOff = 0 ; // centre [most likely] + else if (xPos <= (xMin +xDead)) xOff = -4 ; // full left + else if (xPos >= (xMax -xDead)) xOff = +4 ; // full right + else if (xPos < (xMid -xDead)) { // part left + // very much hard-coded for 3 interim positions + int lo = (xMin +xDead) +1; // lowest position + int hi = (xMid -xDead) -1; // highest position + + // this is the only duplicated bit of code + int range = (hi -lo) +1; // range covered + int div = range /3; // each division (base amount, eg. 17/3==5) + int rem = range -(div *3); // remainder (ie. range%3) + +// int hi1 = hi; // lowest value for zone #-1 +// int lo1 = hi1 -div +1; // highest value for zone #-1 +// int hi2 = lo1 -1; // lowest value for zone #-2 +// int lo2 = hi2 -div +1 -(rem==2); // highest value for zone #-2 expand out remainder +// int hi3 = lo2 -1; // lowest value for zone #-3 +// int lo3 = hi3 -div +1 -(rem>=1); // highest value for zone #-3 expand out remainder + + int lo1 = hi -div +1; // (in brevity) + int hi3 = hi -div -div -(rem==2); // ... + + if (xPos <= hi3) xOff = -3 ; // zone #-3 + else if (xPos >= lo1) xOff = -1 ; // zone #-1 + else xOff = -2 ; // zone #-2 + + } else /*if (xPos > (xMid +xDead))*/ { // part right + // very much hard-coded for 3 interim positions + int lo = (xMid +xDead) +1; // lowest position + int hi = (xMax -xDead) -1; // highest position + + int range = (hi -lo) +1; // range covered + int div = range /3; // each division (base amount, eg. 17/3==5) + int rem = range -(div *3); // remainder (ie. range%3) + +// int lo1 = lo; // lowest value for zone #+1 +// int hi1 = lo +div -1; // highest value for zone #+1 +// int lo2 = hi1 +1; // lowest value for zone #+2 +// int hi2 = lo2 +div -1 +(rem==2); // highest value for zone #+2 expand out remainder +// int lo3 = hi2 +1; // lowest value for zone #+3 +// int hi3 = lo3 +div -1 +(rem>=1); // highest value for zone #+3 expand out remainder + + int hi1 = lo +div -1; // (in brevity) + int lo3 = lo +div +div +(rem==2); // ... + + if (xPos <= hi1) xOff = 1 ; // zone #1 + else if (xPos >= lo3) xOff = 3 ; // zone #3 + else xOff = 2 ; // zone #2 + } + + // All this to print a 3x3 square (in the right place) - LOL! + if ((yPos >= (yMid -yDead)) && (yPos <= (yMid +yDead))) yOff = 0 ; // centre [most likely] + else if (yPos <= (yMin +yDead)) yOff = +4 ; // full down + else if (yPos >= (yMax -yDead)) yOff = -4 ; // full up + else if (yPos < (yMid -yDead)) { // part down + int lo = (yMin +yDead) +1; // lowest position + int hi = (yMid -yDead) -1; // highest position + + int range = (hi -lo) +1; // range covered + int div = range /3; // each division (base amount, eg. 17/3==5) + int rem = range -(div *3); // remainder (ie. range%3) + + int lo1 = hi -div +1; // (in brevity) + int hi3 = hi -div -div -(rem==2); // ... + + if (yPos <= hi3) yOff = +3 ; // zone #3 + else if (yPos >= lo1) yOff = +1 ; // zone #1 + else yOff = +2 ; // zone #2 + + } else /*if (yPos > (yMid +yDead))*/ { // part up + int lo = (yMid +yDead) +1; // lowest position + int hi = (yMax -yDead) -1; // highest position + + int range = (hi -lo) +1; // range covered + int div = range /3; // each division (base amount, eg. 17/3==5) + int rem = range -(div *3); // remainder (ie. range%3) + + int hi1 = lo +div -1; // (in brevity) + int lo3 = lo +div +div +(rem==2); // ... + + if (yPos <= hi1) yOff = -1 ; // zone #-1 + else if (yPos >= lo3) yOff = -3 ; // zone #-3 + else yOff = -2 ; // zone #-2 + } + + show(canvas, x-(img_cc_Joy.w/2),y-(img_cc_Joy.h/2), &img_cc_Joy, SHOW_SET_BLK); + + // All ^that^ for v-this-v - LOL!! + canvas_draw_box(canvas, (x-1)+xOff,(y-1)+yOff, 3,3); +} diff --git a/applications/plugins/wii_ec_anal/wii_anal_lcd.h b/applications/plugins/wii_ec_anal/wii_anal_lcd.h new file mode 100644 index 000000000..5258c4de1 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_lcd.h @@ -0,0 +1,43 @@ +#ifndef WII_ANAL_LCD_H_ +#define WII_ANAL_LCD_H_ + +//----------------------------------------------------------------------------- ---------------------------------------- +// A couple of monospaced hex fonts +// +#include "gfx/images.h" + +extern const image_t* img_6x8[]; +extern const image_t* img_5x7[]; + +//============================================================================= ======================================== +// macros to draw only two sides of a box +// these are used for drawing the wires on the WAIT screen +// +#define BOX_TL(x1,y1,x2,y2) do { \ + canvas_draw_frame(canvas, x1,y1, x2-x1+1,2); \ + canvas_draw_frame(canvas, x1,y1+2, 2,y2-y1+1-2); \ +}while(0) + +#define BOX_BL(x1,y1,x2,y2) do { \ + canvas_draw_frame(canvas, x1,y2-1, x2-x1+1,2); \ + canvas_draw_frame(canvas, x1,y1, 2,y2-y1+1-2); \ +}while(0) + + +//============================================================================= ======================================== +// Function prototypes +// +void patBacklight (state_t* state) ; + +void showHex ( Canvas* const canvas, uint8_t x, uint8_t y, + const uint32_t val, const uint8_t cnt, const int b ) ; + +void showPeakHold (state_t* const state, Canvas* const canvas, const int hold) ; + +void showJoy ( Canvas* const canvas, const uint8_t x, const uint8_t y, // x,y is the CENTRE of the Joystick + const uint8_t xMin, const uint8_t xMid, const uint8_t xMax, + const uint8_t yMin, const uint8_t yMid, const uint8_t yMax, + const uint8_t xPos, const uint8_t yPos, const uint8_t bits ) ; + + +#endif //WII_ANAL_LCD_H_ diff --git a/applications/plugins/wii_ec_anal/wii_anal_ver.h b/applications/plugins/wii_ec_anal/wii_anal_ver.h new file mode 100644 index 000000000..88ed17d19 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_anal_ver.h @@ -0,0 +1,9 @@ +#ifndef WII_ANAL_VER_H_ +#define WII_ANAL_VER_H_ + +#include "gfx/images.h" + +#define VER_MAJ &img_3x5_1 +#define VER_MIN &img_3x5_0 + +#endif //WII_ANAL_VER_H_ diff --git a/applications/plugins/wii_ec_anal/wii_ec.c b/applications/plugins/wii_ec_anal/wii_ec.c new file mode 100644 index 000000000..87b4edcfb --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec.c @@ -0,0 +1,214 @@ +#include +#include // Core API + +#include "wii_anal.h" +#include "wii_i2c.h" +#include "wii_ec.h" +#include "bc_logging.h" + +#include "gfx/images.h" // Images +#include "wii_anal_lcd.h" // Drawing functions +#include "wii_anal_keys.h" // key mappings + +//----------------------------------------------------------------------------- ---------------------------------------- +// List of known perhipherals +// +// More perhipheral ID codes here: https://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way +// +const ecId_t ecId[PID_CNT] = { + [PID_UNKNOWN ] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "Unknown Perhipheral", SCENE_DUMP, + NULL, NULL, NULL, NULL, ec_show, ec_key}, + + // If you're wise, ONLY edit this bit + [PID_NUNCHUCK ] = { {0x00, 0x00, 0xA4, 0x20, 0x00, 0x00}, "Nunchuck", SCENE_NUNCHUCK, + NULL, nunchuck_decode, nunchuck_msg, nunchuck_calib, nunchuck_show, nunchuck_key }, + + [PID_CLASSIC ] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x01}, "Classic Controller", SCENE_CLASSIC, + NULL, classic_decode, classic_msg, classic_calib, classic_show, classic_key }, + + [PID_BALANCE ] = { {0x00, 0x00, 0xA4, 0x20, 0x04, 0x02}, "Balance Board", SCENE_DUMP, + NULL, NULL, NULL, NULL, NULL, NULL }, + + [PID_GH_GUITAR ] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x03}, "Guitar Hero Guitar", SCENE_DUMP, + NULL, NULL, NULL, NULL, NULL, NULL }, + + [PID_GH_DRUMS ] = { {0x01, 0x00, 0xA4, 0x20, 0x01, 0x03}, "Guitar Hero World Tour Drums", SCENE_DUMP, + NULL, NULL, NULL, NULL, NULL, NULL }, + + [PID_TURNTABLE ] = { {0x03, 0x00, 0xA4, 0x20, 0x01, 0x03}, "DJ Hero Turntable", SCENE_DUMP, + NULL, NULL, NULL, NULL, NULL, NULL }, + + [PID_TAIKO_DRUMS] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x11}, "Taiko Drum Controller)", SCENE_DUMP, + NULL, NULL, NULL, NULL, NULL, NULL }, // Taiko no Tatsujin TaTaCon (Drum controller) + + [PID_UDRAW ] = { {0xFF, 0x00, 0xA4, 0x20, 0x00, 0x13}, "uDraw Tablet", SCENE_DUMP, + udraw_init, NULL, NULL, NULL, NULL, NULL }, //! same as drawsome? + // ----- + + [PID_ERROR ] = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, "Read Error", SCENE_NONE, + NULL, NULL, NULL, NULL, NULL, NULL }, + + [PID_NULL ] = { {0}, NULL, SCENE_NONE, NULL, NULL, NULL, NULL, NULL, NULL } // last entry +}; + +//+============================================================================ ======================================== +void ecDecode (wiiEC_t* pec) +{ + if (ecId[pec->pidx].decode) ecId[pec->pidx].decode(pec) ; +} + +//+============================================================================ ======================================== +void ecCalibrate (wiiEC_t* const pec, ecCalib_t c) +{ + if (ecId[pec->pidx].calib) ecId[pec->pidx].calib(pec, c) ; +} + +//+============================================================================ ======================================== +void ecPoll (wiiEC_t* const pec, FuriMessageQueue* const queue) +{ + ENTER; + furi_assert(queue); + + if (!pec->init) { + // Attempt to initialise + if (ecInit(pec, NULL)) { //! need a way to auto-start with encryption enabled + eventMsg_t msg = { + .id = EVID_WIIEC, + .wiiEc = { + .type = WIIEC_CONN, + .in = '<', + .val = pec->pidx + } + }; + furi_message_queue_put(queue, &msg, 0); + } + + } else { + // Attempt to read + switch (ecRead(pec)) { + case 2: { // device gone + eventMsg_t msg = { + .id = EVID_WIIEC, + .wiiEc = { + .type = WIIEC_DISCONN, + .in = '>', + .val = pec->pidx + } + }; + furi_message_queue_put(queue, &msg, 0); + break; + } + + case 0: { // read OK + void (*fn)(wiiEC_t*, FuriMessageQueue*) = ecId[pec->pidx].check; + if (fn) fn(pec, queue); + break; + } + + case 3: // read fail + // this is probably temporary just ignore it + break; + + default: // bug: unknown + case 1: // bug: not initialised - should never happen + ERROR("%s : read bug", __func__); + break; + } + } + + LEAVE; + return; +} + +//+============================================================================ ======================================== +// This is the screen drawn for an unknown controller +// It is also available by pressing LEFT (at least once) on a "known controller" screen +// +void ec_show (Canvas* const canvas, state_t* const state) +{ + wiiEC_t* pec = &state->ec; + int h = 11; // line height + int x = 1; // (initial) offset for bits + int y = -h; // previous y value + int yb = 0; // y for bit patterns + int c2 = 17; // column 2 + + // Headings + canvas_set_font(canvas, FontSecondary); + canvas_set_color(canvas, ColorBlack); + + canvas_draw_str_aligned(canvas, 0 ,0, AlignLeft, AlignTop, "SID:"); + canvas_draw_str_aligned(canvas, c2,0, AlignLeft, AlignTop, pec->sid); + + canvas_draw_str_aligned(canvas, 0 ,11, AlignLeft, AlignTop, "PID:"); + canvas_draw_str_aligned(canvas, 0 ,22, AlignLeft, AlignTop, "Cal:"); + + // PID + x = c2; + for (int i = 0; i < 6; i++) { + show(canvas, x,11, img_5x7[pec->pid[i]>>4], SHOW_SET_BLK); + x += 5+1; + show(canvas, x,11, img_5x7[pec->pid[i]&0xF], SHOW_SET_BLK); + x += 5+1+2; + } + + // Calibrations data + y = 11; + for (int j = 0; j <= 8; j += 8) { + x = c2; + y += 11; + for (int i = 0; i < 8; i++) { + show(canvas, x,y, img_5x7[pec->calF[i+j]>>4], SHOW_SET_BLK); + x += 5+1; + show(canvas, x,y, img_5x7[pec->calF[i+j]&0xF], SHOW_SET_BLK); + x += 5+1+2; + } + } + + // Reading + x = 1; + y++; + yb = (y+=h) +h +2; + + canvas_draw_line(canvas, x,y-1, x,yb+4); + x += 2; + + for (int i = 0; i < JOY_LEN; i++) { + show(canvas, x+ 1,y, img_6x8[pec->joy[i]>>4], SHOW_SET_BLK); + show(canvas, x+11,y, img_6x8[pec->joy[i]&0xF], SHOW_SET_BLK); + + // bits + for (int m = 0x80; m; m >>= 1) { + x += 2 * !!(m & 0x08) ; // nybble step + canvas_draw_box(canvas, x,yb +(2*!(pec->joy[i] & m)), 2,2) ; + x += 2; // bit step + } + + // byte step + x += 1; + canvas_draw_line(canvas, x,y-1, x,yb+4); + x += 2; + } + + // Scene navigation + if (state->scenePrev != SCENE_WAIT) + show(canvas, 120,0, &img_key_R, SHOW_SET_BLK); +} + +//+============================================================================ ======================================== +// The DUMP screen is +// +bool ec_key (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + if (state->scenePrev != SCENE_WAIT) { + //# input.type == InputTypeShort) && (msg->input.key == InputKeyRight)) { + sceneSet(state, state->scenePrev); + used = true; + } + } + + return used; +} diff --git a/applications/plugins/wii_ec_anal/wii_ec.h b/applications/plugins/wii_ec_anal/wii_ec.h new file mode 100644 index 000000000..60f7c7b23 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec.h @@ -0,0 +1,175 @@ +#ifndef WII_EC_H_ +#define WII_EC_H_ + +#include + +#include + +#include "wii_ec_nunchuck.h" +#include "wii_ec_classic.h" +#include "wii_ec_udraw.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +// Crypto key (PSK), base register : {0x40..0x4F}[2][8] +#define ENC_LEN (2*8) + +// Controller State data, base register : {0x00..0x05}[6] +#define JOY_LEN (6) + +// Calibration data, base register : {0x20..0x2F}[16] +#define CAL_LEN (16) + +// Controller ID, base register : {0xFA..0xFF}[6] +#define PID_LEN (6) + +//----------------------------------------------------------------------------- ---------------------------------------- +// Perhipheral specific parameters union +// +typedef + union ecDec { + ecDecNunchuck_t nunchuck; + ecDecClassic_t classic; + } +ecDec_t; + +//----------------------------------------------------------------------------- +typedef + union ecCal { + // 0=lowest seen ; 1=min ; 2=mid ; 3=max ; 4=highest seen + ecCalNunchuck_t nunchuck[5]; + ecCalClassic_t classic[5]; + } +ecCal_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +// Wii Extension Controller events +// +typedef + enum wiiEcEventType { + WIIEC_NONE, + WIIEC_CONN, // Connect + WIIEC_DISCONN, // Disconnect + WIIEC_PRESS, // Press button + WIIEC_RELEASE, // Release button + WIIEC_ANALOG, // Analogue change (Joystick/Trigger) + WIIEC_ACCEL, // Accelerometer change + } +wiiEcEventType_t; + +//----------------------------------------------------------------------------- +typedef + struct wiiEcEvent { + wiiEcEventType_t type; // event type + char in; // input (see device specific options) + uint32_t val; // new value - meaningless for digital button presses + } +wiiEcEvent_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +// Known perhipheral types +// +typedef + enum ecPid { + PID_UNKNOWN = 0, + PID_FIRST = 1, + PID_NUNCHUCK = PID_FIRST, + + // If you're wise, ONLY edit this section + PID_CLASSIC, + PID_BALANCE, + PID_GH_GUITAR, + PID_GH_DRUMS, + PID_TURNTABLE, + PID_TAIKO_DRUMS, + PID_UDRAW, //! same as drawsome? + // ----- + + PID_ERROR, + PID_NULL, + PID_CNT, + } +ecPid_t; + +//----------------------------------------------------------------------------- +// Calibration strategies +// +typedef + enum ecCalib { + CAL_FACTORY = 0x01, // (re)set to factory defaults + CAL_TRACK = 0x02, // track maximum and minimum values seen + CAL_RESET = 0x04, // initialise ready for software calibration + CAL_RANGE = 0x08, // perform software calibration step + CAL_CENTRE = 0x10, // reset centre point of joystick + CAL_NOTJOY = 0x20, // do NOT calibrate the joystick + } +ecCalib_t; + +//----------------------------------------------------------------------------- +// ecId table entry +// +typedef + struct ecId { + uint8_t id[6]; // 6 byte ID string returned by Extension Controller + char* name; // Friendly name + scene_t scene; // Default scene + bool (*init)(wiiEC_t*); // Additional initialisation code + void (*decode)(wiiEC_t*); // Decode function + void (*check)(wiiEC_t*, FuriMessageQueue*); // check (for action) function + void (*calib)(wiiEC_t*, ecCalib_t); // calibrate analogue controllers [SOFTWARE] + void (*show)(Canvas* const, state_t* const); // Draw scene + bool (*keys)(const eventMsg_t* const, state_t* const); // Interpret keys + } +ecId_t; + +//----------------------------------------------------------------------------- +// List of known perhipherals +// +// More perhipheral ID codes here: https://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way +// +extern const ecId_t ecId[PID_CNT] ; + +//----------------------------------------------------------------------------- ---------------------------------------- +// Data pertaining to a single Perhipheral instance +// +typedef + struct wiiEC { + // Perhipheral state + bool init; // Initialised? + + uint8_t pid[PID_LEN]; // PID string - eg. {0x00, 0x00, 0xA4, 0x20, 0x00, 0x00} + ecPid_t pidx; // Index in to ecId table + const char* sid; // just for convenience + + bool encrypt; // encryption enabled? + uint8_t encKey[ENC_LEN]; // encryption key + + uint8_t calF[CAL_LEN]; // factory calibration data (not software) + uint8_t joy[JOY_LEN]; // Perhipheral raw data + + ecDec_t dec[2]; // device specific decode (two, so we can spot changes) + int decN; // which decode set is most recent {0, 1} + ecCal_t calS; // software calibration data + } +wiiEC_t; + +//----------------------------------------------------------------------------- ---------------------------------------- +// Function prototypes +// +// top level calls will work out which sub-function to call +// top level check() function will handle connect/disconnect messages +// + +#include // Canvas +typedef struct wiiEC wiiEC_t ; +typedef enum ecCalib ecCalib_t ; +typedef struct state state_t ; +typedef struct eventMsg eventMsg_t ; + +void ecDecode (wiiEC_t* const pec) ; +void ecPoll (wiiEC_t* const pec, FuriMessageQueue* const queue) ; +void ecCalibrate (wiiEC_t* const pec, ecCalib_t c) ; + +void ec_show ( Canvas* const canvas, state_t* const state) ; +bool ec_key (const eventMsg_t* const msg, state_t* const state) ; + +#endif //WII_EC_H_ diff --git a/applications/plugins/wii_ec_anal/wii_ec_classic.c b/applications/plugins/wii_ec_anal/wii_ec_classic.c new file mode 100644 index 000000000..91393ba07 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec_classic.c @@ -0,0 +1,398 @@ +#include +#include // Core API + +#include "wii_anal.h" +#include "wii_ec.h" +#include "bc_logging.h" + +//#include "gfx/images.h" // Images +#include "wii_anal_lcd.h" // Drawing functions +#include "wii_anal_keys.h" // key mappings + +// ** If you want to see what this source code looks like with all the MACROs expanded +// ** grep -v '#include ' wii_i2c_classic.c | gcc -E -o /dev/stdout -xc - +# include "wii_ec_macros.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +// Classic Controller ... Classic Controller Pro is electronically the same +// +// ANA{l} ANA{r} +// BTN{l} BTN{L} BTN{R} BTN{r} +// ,--------. ,-, ,-, .--------, +// .----------------------------------------------------------. +// | | +// | BTN{W} BTN{x} | +// | BTN{A} BTN{D} BTN{-} BTN{h} BTN{+} BTN{y} BTN{a} | +// | BTN{S} BTN{b} | +// | | +// | ANA{y} ANA{Y} | +// | ANA{x} ANA{X} | +// | | +// `----------------------------------------------------------' + +//+============================================================================ ======================================== +// https://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller +// I think a LOT of drugs went in to "designing" this layout +// ...And yes, the left-joystick has an extra 'bit' of precision! +// ...Also: trgZ{L|R} WILL continue to increase after btnZ{L|R} has gone active +// +void classic_decode (wiiEC_t* const pec) +{ + ecDecClassic_t* p = &pec->dec[(pec->decN = !pec->decN)].classic; + uint8_t* joy = pec->joy; + + p->trgZL = ((joy[2] >>2) &0x18) | ((joy[3] >>5) &0x07); // {5} + p->btnZL = !(joy[4] & 0x20); // !{1} + + p->trgZR = joy[3] & 0x1F; // {5} + p->btnZR = !(joy[4] & 0x02); // !{1} + + p->btnL = !(joy[5] & 0x80); // !{1} + p->btnR = !(joy[5] & 0x04); // !{1} + + p->padU = !(joy[5] & 0x01); // !{1} + p->padD = !(joy[4] & 0x40); // !{1} + p->padL = !(joy[5] & 0x02); // !{1} + p->padR = !(joy[4] & 0x80); // !{1} + + p->btnM = !(joy[4] & 0x10); // !{1} + p->btnH = !(joy[4] & 0x08); // !{1} + p->btnP = !(joy[4] & 0x04); // !{1} + + p->btnX = !(joy[5] & 0x08); // !{1} + p->btnY = !(joy[5] & 0x20); // !{1} + + p->btnA = !(joy[5] & 0x10); // !{1} + p->btnB = !(joy[5] & 0x40); // !{1} + + p->joyLX = joy[0] & 0x3F; // {6} + p->joyLY = joy[1] & 0x3F; // {6} + + p->joyRX = ((joy[0] >>3) &0x18) | ((joy[1] >>5) &0x06) | ((joy[2] >>7) &0x01); // {5} + p->joyRY = joy[2] & 0x1F; // {5} + + DEBUG( ">%d> ZL{%02X}%c, L:%c, R:%c, ZR{%02X}%c", pec->decN, + p->trgZL, (p->btnZL ? '#' : '.'), + (p->btnL ? '#' : '.'), + (p->btnR ? '#' : '.'), + p->trgZR, (p->btnZR ? '#' : '.') + ); + DEBUG( ">%d> D:{%c,%c,%c,%c}, H:{%c,%c,%c}, B:{%c,%c,%c,%c}", pec->decN, + (p->padU ? 'U' : '.'), (p->padD ? 'D' : '.'), (p->padL ? 'L' : '.'), (p->padR ? 'R' : '.'), + (p->btnM ? '-' : '.'), (p->btnH ? 'H' : '.'), (p->btnP ? '+' : '.'), + (p->btnX ? 'X' : '.'), (p->btnY ? 'Y' : '.'), (p->btnA ? 'A' : '.'), (p->btnB ? 'B' : '.') + ); + DEBUG( ">%d> JoyL{x:%02X, y:%02X}, JoyR{x:%02X, y:%02X}", pec->decN, + p->joyLX, p->joyLY, p->joyRX, p->joyRY + ); +} + +//+============================================================================ ======================================== +// Give each button a unique character identifier +// +void classic_msg (wiiEC_t* const pec, FuriMessageQueue* const queue) +{ + ecDecClassic_t* new = &pec->dec[pec->decN].classic; + ecDecClassic_t* old = &pec->dec[!pec->decN].classic; + + eventMsg_t msg = { + .id = EVID_WIIEC, + .wiiEc = { + .type = WIIEC_NONE, + .in = ' ', + .val = 0, + } + }; + + ANALOG(trgZL, 'l'); // FIVE bit value + ANABTN(btnZL, trgZL, 'l'); + + BUTTON(btnL, 'L'); + BUTTON(btnR, 'R'); + + ANALOG(trgZR, 'r'); // FIVE bit value + ANABTN(btnZR, trgZR, 'r'); + + BUTTON(padU, 'W'); + BUTTON(padL, 'A'); + BUTTON(padD, 'S'); + BUTTON(padR, 'D'); + + BUTTON(btnM, '-'); + BUTTON(btnH, 'h'); + BUTTON(btnP, '+'); + + BUTTON(btnX, 'x'); + BUTTON(btnY, 'y'); + BUTTON(btnA, 'a'); + BUTTON(btnB, 'b'); + + ANALOG(joyLX, 'x'); // SIX bit values + ANALOG(joyLY, 'y'); + + ANALOG(joyRX, 'X'); // FIVE bit values + ANALOG(joyRY, 'Y'); +} + +//+============================================================================ ======================================== +// https://web.archive.org/web/20090415045219/http://www.wiili.org/index.php/Wiimote/Extension_Controllers/Classic_Controller#Calibration_data +// +// Calibration data +// 0..2 left analog stick X axis {maximum, minimum, center} ... JoyL is 6bits, so >>2 to compare to readings +// 3..5 left analog stick Y axis {maximum, minimum, center} ... JoyL is 6bits, so >>2 to compare to readings +// 6..8 right analog stick X axis {maximum, minimum, center} ... JoyR is 5bits, so >>3 to compare to readings +// 9..11 right analog stick Y axis {maximum, minimum, center} ... JoyR is 5bits, so >>3 to compare to readings +// 12..15 somehow describe the shoulder {5bit} button values!? +// +void classic_calib (wiiEC_t* const pec, ecCalib_t c) +{ + ecDecClassic_t* src = &pec->dec[pec->decN].classic; // from input + ecCalClassic_t* dst = pec->calS.classic; // to calibration data + + if (c & CAL_RESET) { // initialise ready for software calibration + // LO is set to the MAXIMUM value (so it can be reduced) + // HI is set to ZERO (so it can be increased) + RESET_LO_HI(trgZL, 5); // 5bit value + RESET_LO_HI(trgZR, 5); // 5bit value + + RESET_LO_MID_HI(joyLX, 6); // 6bit value + RESET_LO_MID_HI(joyLY, 6); // 6bit value + + RESET_LO_MID_HI(joyRX, 5); // 5bit value + RESET_LO_MID_HI(joyRY, 5); // 5bit value + } + if (c & CAL_FACTORY) { // (re)set to factory defaults +//! strategy for factory calibration for classic controller [pro] triggers is (currently) unknown +//! FACTORY_LO( trgZL, pec->calF[12..15]); +//! FACTORY_MID(trgZL, pec->calF[12..15]); +//! FACTORY_HI( trgZL, pec->calF[12..15]); + +//! FACTORY_LO( trgZR, pec->calF[12..15]); +//! FACTORY_MID(trgZR, pec->calF[12..15]); +//! FACTORY_HI( trgZR, pec->calF[12..15]); + +#if 1 + FACTORY_LO(trgZL, 0x03); + FACTORY_LO(trgZR, 0x03); + + FACTORY_MID(trgZL, 0x1B); //! these will be set every time the digital switch changes to ON + FACTORY_MID(trgZR, 0x1B); +#endif + + FACTORY_LO( joyLX, pec->calF[ 1] >>2); + FACTORY_MID(joyLX, pec->calF[ 2] >>2); + FACTORY_HI( joyLX, pec->calF[ 0] >>2); + + FACTORY_LO( joyLY, pec->calF[ 4] >>2); + FACTORY_MID(joyLY, pec->calF[ 5] >>2); + FACTORY_HI( joyLY, pec->calF[ 3] >>2); + + FACTORY_LO( joyRX, pec->calF[ 7] >>3); + FACTORY_MID(joyRX, pec->calF[ 8] >>3); + FACTORY_HI( joyRX, pec->calF[ 6] >>3); + + FACTORY_LO( joyRY, pec->calF[10] >>3); + FACTORY_MID(joyRY, pec->calF[11] >>3); + FACTORY_HI( joyRY, pec->calF[ 9] >>3); + } + if (c & CAL_TRACK) { // track maximum and minimum values seen + TRACK_LO_HI(trgZL); + TRACK_LO_HI(trgZR); + + TRACK_LO_HI(joyLX); + TRACK_LO_HI(joyLY); + + TRACK_LO_HI(joyRX); + TRACK_LO_HI(joyRY); + } + if (c & CAL_RANGE) { // perform software calibration step + RANGE_LO_HI(trgZL); + RANGE_LO_HI(trgZR); + + RANGE_LO_HI(joyLX); + RANGE_LO_HI(joyLY); + + RANGE_LO_HI(joyRX); + RANGE_LO_HI(joyRY); + } + if (c & CAL_CENTRE) { // reset centre point of joystick + CENTRE(joyLX); + CENTRE(joyLY); + + CENTRE(joyRX); + CENTRE(joyRY); + } +} + +//+============================================================================ ======================================== +// bits that are common to both screens +// +static +void classic_show_ (Canvas* const canvas, state_t* const state) +{ + ecDecClassic_t* d = &state->ec.dec[state->ec.decN].classic; + ecCalClassic_t* js = state->ec.calS.classic; + + static const int dead = 1; // trigger deadzone + const image_t* img = NULL; // trigger image + + show(canvas, 6, 0, &img_cc_Main , SHOW_SET_BLK); + show(canvas, 62,53, &img_cc_Cable, SHOW_SET_BLK); + + // classic triggers + if (d->trgZL >= js[2].trgZL ) img = &img_cc_trg_L4; + else if (d->trgZL <= js[1].trgZL +dead) img = NULL; + else { + // copied from the joystick calibration code + int lo = js[1].trgZL +dead +1; + int hi = js[2].trgZL -1; + int range = hi -lo +1; + int div = range /3; // each division (base amount, eg. 17/3==5) + int rem = range -(div *3); // remainder (ie. range%3) + int hi1 = lo +div -1; // (in brevity) + int lo3 = lo +div +div +(rem==2); // ... + + if (d->trgZL <= hi1) img = &img_cc_trg_L1 ; // zone #1 + else if (d->trgZL >= lo3) img = &img_cc_trg_L3 ; // zone #3 + else img = &img_cc_trg_L2 ; // zone #2 + } + if (img) show(canvas, 22,1, img, SHOW_SET_BLK) ; + + if (d->trgZR >= js[2].trgZR ) img = &img_cc_trg_R4; + else if (d->trgZR <= js[1].trgZR +dead) img = NULL; + else { + // copied from the joystick calibration code + int lo = js[1].trgZR +dead +1; + int hi = js[2].trgZR -1; + int range = hi -lo +1; + int div = range /3; // each division (base amount, eg. 17/3==5) + int rem = range -(div *3); // remainder (ie. range%3) + int hi1 = lo +div -1; // (in brevity) + int lo3 = lo +div +div +(rem==2); // ... + + if (d->trgZR <= hi1) img = &img_cc_trg_R1 ; // zone #1 + else if (d->trgZR >= lo3) img = &img_cc_trg_R3 ; // zone #3 + else img = &img_cc_trg_R2 ; // zone #2 + } + if (img) show(canvas, 89,1, img, SHOW_SET_BLK) ; + + if (d->padU ) show(canvas, 27,16, &img_cc_pad_UD1, SHOW_ALL) ; + if (d->padL ) show(canvas, 20,23, &img_cc_pad_LR1, SHOW_ALL) ; + if (d->padD ) show(canvas, 27,28, &img_cc_pad_UD1, SHOW_ALL) ; + if (d->padR ) show(canvas, 32,23, &img_cc_pad_LR1, SHOW_ALL) ; + + if (d->btnX ) show(canvas, 96,16, &img_cc_btn_X1, SHOW_ALL) ; + if (d->btnY ) show(canvas, 85,23, &img_cc_btn_Y1, SHOW_ALL) ; + if (d->btnA ) show(canvas, 107,23, &img_cc_btn_A1, SHOW_ALL) ; + if (d->btnB ) show(canvas, 96,30, &img_cc_btn_B1, SHOW_ALL) ; + + canvas_set_color(canvas, ColorBlack); + if (d->btnL ) canvas_draw_box(canvas, 46,2, 5,4) ; + if (d->btnR ) canvas_draw_box(canvas, 77,2, 5,4) ; + + if (d->btnM ) canvas_draw_box(canvas, 54,24, 4,4) ; + if (d->btnH ) canvas_draw_box(canvas, 62,24, 4,4) ; + if (d->btnP ) canvas_draw_box(canvas, 70,24, 4,4) ; + + // Show joysticks + showJoy(canvas, 48,42, js[1].joyLX,js[2].joyLX, js[3].joyLX, + js[1].joyLY,js[2].joyLY, js[3].joyLY, d->joyLX,d->joyLY, 6); + showJoy(canvas, 78,42, js[1].joyRX,js[2].joyRX, js[3].joyRX, + js[1].joyRY,js[2].joyRY, js[3].joyRY, d->joyRX,d->joyRY, 5); + + show(canvas, 0,55, &img_key_L, SHOW_SET_BLK); +} + +//+============================================================================ ======================================== +static +void classic_showN (Canvas* const canvas, state_t* const state) +{ + ecCalClassic_t* c = (state->hold) ? &state->ec.calS.classic[(state->hold < 0) ? 0 : 4] + : (ecCalClassic_t*)(&state->ec.dec[state->ec.decN].classic) ; //! danger + + classic_show_(canvas, state); + + showHex(canvas, 0, 0, c->trgZL, 2,1); // 5bits + showHex(canvas, 113, 0, c->trgZR, 2,1); // 5bits + + showHex(canvas, 24,41, c->joyLX, 2,1); // 6bits + showHex(canvas, 41,54, c->joyLY, 2,1); // 6bits + + showHex(canvas, 88,41, c->joyRX, 2,1); // 5bits + showHex(canvas, 71,54, c->joyRY, 2,1); // 5bits + + showPeakHold(state, canvas, state->hold); // peak keys +} + +//+============================================================================ ======================================== +void classic_show (Canvas* const canvas, state_t* const state) +{ + // Classic controllers have TWO scenes + if (state->scene == SCENE_CLASSIC_N) return classic_showN(canvas, state) ; + + // Default scene + classic_show_(canvas, state); + show(canvas, 9,55, &img_key_R, SHOW_SET_BLK); + + show( canvas, 119,55, + ((state->calib & CAL_RANGE) && (++state->flash &8)) ? &img_key_OKi : &img_key_OK, + SHOW_SET_BLK ); +} + +//+============================================================================ ======================================== +static +bool classic_keyN (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + if ((msg->input.type == InputTypeShort) && (msg->input.key == InputKeyLeft)) { + sceneSet(state, SCENE_CLASSIC); + used = true; + } + + // Calibration keys + if (!used) used = key_calib(msg, state) ; + + return used; +} + +//+============================================================================ ======================================== +bool classic_key (const eventMsg_t* const msg, state_t* const state) +{ + // Classic controllers have TWO scenes + if (state->scene == SCENE_CLASSIC_N) return classic_keyN(msg, state) ; + + // Default scene + int used = false; // assume key is NOT-handled + + switch (msg->input.type) { + case InputTypeShort: //# input.key) { + case InputKeyUp: //# +#include + +//----------------------------------------------------------------------------- ---------------------------------------- +// Classic Controller ... Classic Controller Pro is electronically the same +// +// ANA{l} ANA{r} +// BTN{l} BTN{L} BTN{R} BTN{r} +// ,--------. ,-, ,-, .--------, +// .----------------------------------------------------------. +// | | +// | BTN{W} BTN{x} | +// | BTN{A} BTN{D} BTN{-} BTN{h} BTN{+} BTN{y} BTN{a} | +// | BTN{S} BTN{b} | +// | | +// | ANA{y} ANA{Y} | +// | ANA{x} ANA{X} | +// | | +// `----------------------------------------------------------' +// + +//----------------------------------------------------------------------------- ---------------------------------------- +// Controllers which have calibration must have their calibratable controls here +//! Is there a better way to get the start of the decode struct to match the calibration struct ? +#define CLASSIC_ANALOGUE \ + uint8_t trgZL, trgZR; /* ANA{l, l} lowercase=trigger 5bit values {5} */ \ + uint8_t joyLX, joyLY; /* ANA{x, y} left=lowercase 6bit values {6}<-- */ \ + uint8_t joyRX, joyRY; /* ANA{X, Y} 5bit values {5} */ + +//----------------------------------------------------------------------------- +// Calibratable controls +// +typedef + struct ecCalClassic + { + CLASSIC_ANALOGUE + } +ecCalClassic_t; + +//----------------------------------------------------------------------------- +// All controls +// +typedef + struct ecDecClassic + { + CLASSIC_ANALOGUE // MUST be first + + // Digital controls + bool btnZL, btnZR; // BTN{l, l} + + bool btnL, btnR; // BTN{L, R} upperrcase=shoulder + + bool padU, padL, padD, padR; // BTN{W, A, S, D} + + bool btnM, btnH, btnP; // BTN{-, h, +} + + bool btnX, btnY; // BTN{x, y} + bool btnA, btnB; // BTN{a, b} + + } +ecDecClassic_t; + +#undef CLASSIC_ANALOGUE + +//============================================================================= ======================================== +// Function prototypes +// +#include // Canvas +typedef struct wiiEC wiiEC_t ; +typedef enum ecCalib ecCalib_t ; +typedef struct state state_t ; +typedef struct eventMsg eventMsg_t ; + +void classic_decode (wiiEC_t* const pec) ; +void classic_msg (wiiEC_t* const pec, FuriMessageQueue* const queue) ; +void classic_calib (wiiEC_t* const pec, ecCalib_t c) ; + +void classic_show (Canvas* const canvas, state_t* const state) ; +bool classic_key (const eventMsg_t* const msg, state_t* const state) ; + +#endif //WII_EC_CLASSIC_H_ diff --git a/applications/plugins/wii_ec_anal/wii_ec_macros.h b/applications/plugins/wii_ec_anal/wii_ec_macros.h new file mode 100644 index 000000000..33daf944d --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec_macros.h @@ -0,0 +1,84 @@ +#ifndef WII_EC_MACROS_H_ +#define WII_EC_MACROS_H_ + +//----------------------------------------------------------------------------- ---------------------------------------- +// CHECK MACROS +// +// I don't generally like this style of coding - it just (generally) makes things nightmarish to debug +// However, on this occasion I think it's a good choice (to make adding controllers LESS bug-prone) +// + +//if (furi_message_queue_get_count(queue) > 18) WARN("queue high %d", furi_message_queue_get_count(queue)); +#define MSGQ(lbl) do { \ + msg.wiiEc.in = lbl; \ + furi_message_queue_put(queue, &msg, 0); \ +}while(0) + + +// A 'standard' "button" is an independent SPST switch +// Eg. Nunchuck 'Z' button +// The "value" will always be 0 +#define BUTTON(btn,lbl) do { \ + if (new->btn != old->btn) { \ + msg.wiiEc.type = (new->btn) ? WIIEC_PRESS : WIIEC_RELEASE; \ + msg.wiiEc.val = 0; \ + MSGQ(lbl); \ + } \ +}while(0) + +// An "analogue button" is an SPST coupled with an ananlogue 'switch' +// Eg. The "bottom out" switches on the triggers of the classic controller +// The "value" will be the value of the associated analogue controller +#define ANABTN(btn,ana,lbl) do { \ + if (new->btn != old->btn) { \ + msg.wiiEc.type = (new->btn) ? WIIEC_PRESS : WIIEC_RELEASE; \ + msg.wiiEc.val = new->ana; \ + MSGQ(lbl); \ + } \ +}while(0) + +#define ANALOG(ana,lbl) do { \ + if (new->ana != old->ana) { \ + msg.wiiEc.type = WIIEC_ANALOG; \ + msg.wiiEc.val = new->ana; \ + MSGQ(lbl); \ + } \ +}while(0) + +#define ACCEL(acc,lbl) do { \ + if (new->acc != old->acc) { \ + msg.wiiEc.type = WIIEC_ACCEL; \ + msg.wiiEc.val = new->acc; \ + MSGQ(lbl); \ + } \ +}while(0) + +//----------------------------------------------------------------------------- ---------------------------------------- +// CALIBRATION MACROS +// +// Again ...I totally agree with anyone who says "MACRO coding" is (gernally) a poor choice of programming style +// But something about this code is making it soooo appealing +// +// ... v=variable, n=number +// +#define FACTORY_LO(v,n) do{ (dst[1]. v) = n; }while(0) +#define FACTORY_MID(v,n) do{ (dst[2]. v) = n; }while(0) +#define FACTORY_HI(v,n) do{ (dst[3]. v) = n; }while(0) + +#define TRACK_LO(v) do{ if ((src-> v) < (dst[0]. v)) (dst[0]. v) = (src-> v); }while(0) +#define TRACK_HI(v) do{ if ((src-> v) > (dst[4]. v)) (dst[4]. v) = (src-> v); }while(0) +#define TRACK_LO_HI(v) do{ TRACK_LO(v); TRACK_HI(v); }while(0) + +#define RESET_LO(v,b) do{ (dst[0]. v) = (dst[1]. v) = ((1<<(b))-1); }while(0) +#define RESET_HI(v) do{ (dst[4]. v) = (dst[3]. v) = 0; }while(0) +#define RESET_MID(v) do{ (dst[2]. v) = (src-> v); }while(0) +#define RESET_LO_HI(v,b) do{ RESET_LO(v,b); RESET_HI(v); }while(0) +#define RESET_LO_MID_HI(v,b) do{ RESET_LO(v,b); RESET_MID(v); RESET_HI(v); }while(0) + +#define RANGE_LO(v) do{ if ((src-> v) < (dst[1]. v)) (dst[1]. v) = (src-> v); }while(0) +#define RANGE_HI(v) do{ if ((src-> v) > (dst[3]. v)) (dst[3]. v) = (src-> v); }while(0) +#define RANGE_LO_HI(v) do{ RANGE_LO(v); RANGE_HI(v); }while(0) + +#define CENTRE(v) do{ (dst[2]. v) = (src-> v); } while(0) + +#endif //WII_EC_MACROS_H_ diff --git a/applications/plugins/wii_ec_anal/wii_ec_nunchuck.c b/applications/plugins/wii_ec_anal/wii_ec_nunchuck.c new file mode 100644 index 000000000..81c32a243 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec_nunchuck.c @@ -0,0 +1,459 @@ +#include +#include // Core API + +#include "wii_anal.h" +#include "wii_i2c.h" +#include "bc_logging.h" + +#include "gfx/images.h" // Images +#include "wii_anal_lcd.h" // Drawing functions +#include "wii_anal_keys.h" // key mappings + +// ** If you want to see what this source code looks like with all the MACROs expanded +// ** grep -v '#include ' wii_ec_nunchuck.c | gcc -E -o /dev/stdout -xc - +# include "wii_ec_macros.h" + +//+============================================================================ ======================================== +// Standard Nunchuck : 2 buttons, 1 analogue joystick, 1 3-axis accelerometer +// +void nunchuck_decode (wiiEC_t* const pec) +{ + ecDecNunchuck_t* p = &pec->dec[(pec->decN = !pec->decN)].nunchuck; + uint8_t* joy = pec->joy; + + p->btnC = !(joy[5] & 0x02); // !{1} + p->btnZ = !(joy[5] & 0x01); // !{1} + + p->joyX = joy[0]; // {8} + p->joyY = joy[1]; // {8} + + p->accX = ((uint16_t)joy[2] << 2) | ((joy[5] >>2) & 0x03); // {10} + p->accY = ((uint16_t)joy[3] << 2) | ((joy[5] >>4) & 0x03); // {10} + p->accZ = ((uint16_t)joy[4] << 2) | ((joy[5] >>6) & 0x03); // {10} + + DEBUG(">%d> C:%c, Z:%c, Joy{x:%02X, y:%02X}, Acc{x:%03X, y:%03X, z:%03X}", pec->decN, + (p->btnC ? '#' : '.'), (p->btnZ ? '#' : '.'), + p->joyX, p->joyY, p->accX, p->accY, p->accZ + ); +} + +//+============================================================================ ======================================== +// Give each button a unique character identifier +// +void nunchuck_msg (wiiEC_t* const pec, FuriMessageQueue* const queue) +{ + ecDecNunchuck_t* new = &pec->dec[pec->decN].nunchuck; + ecDecNunchuck_t* old = &pec->dec[!pec->decN].nunchuck; + + eventMsg_t msg = { + .id = EVID_WIIEC, + .wiiEc = { + .type = WIIEC_NONE, + .in = ' ', + .val = 0, + } + }; + + BUTTON(btnC, 'c'); + BUTTON(btnZ, 'z'); + + ANALOG(joyX, 'x'); + ANALOG(joyY, 'y'); + + ACCEL(accX, 'x'); + ACCEL(accY, 'y'); + ACCEL(accZ, 'z'); +} + +//+============================================================================ ======================================== +// https://www.hackster.io/infusion/using-a-wii-nunchuk-with-arduino-597254#toc-5--read-actual-calibration-data-from-the-device-14 +// +void nunchuck_calib (wiiEC_t* const pec, ecCalib_t c) +{ + ecDecNunchuck_t* src = &pec->dec[pec->decN].nunchuck; // from input + ecCalNunchuck_t* dst = pec->calS.nunchuck; // to calibration data + + if (c & CAL_RESET) { // initialise ready for software calibration + // LO is set to the MAXIMUM value (so it can be reduced) + // HI is set to ZERO (so it can be increased) + RESET_LO_HI(accX, 10); // 10bit value + RESET_LO_HI(accY, 10); // 10bit value + RESET_LO_HI(accZ, 10); // 10bit value + + RESET_LO_HI(joyX, 8); // 8bit value + RESET_LO_HI(joyY, 8); // 8bit value + } + if (c & CAL_FACTORY) { // (re)set to factory defaults + //! "[4] LSB of Zero value of X,Y,Z axes" ...helpful! + //! ...Well, my test nunchuck has bits set in the bottom 6 bits, so let's guess ;) + + // No value available - annecdotal tests suggest 8 is reasonable + FACTORY_LO( accX, 8); + FACTORY_LO( accY, 8); + FACTORY_LO( accZ, 8); + + // @ 0G + FACTORY_MID( accX, ((pec->calF[0] <<2) | ((pec->calF[3] >>4) &0x3)) ) ; + FACTORY_MID( accY, ((pec->calF[1] <<2) | ((pec->calF[3] >>2) &0x3)) ) ; + FACTORY_MID( accZ, ((pec->calF[2] <<2) | ((pec->calF[3] ) &0x3)) ) ; + + // @ 1G + FACTORY_HI( accX, ((pec->calF[4] <<2) | ((pec->calF[7] >>4) &0x3)) ) ; + FACTORY_HI( accY, ((pec->calF[5] <<2) | ((pec->calF[7] >>2) &0x3)) ) ; + FACTORY_HI( accZ, ((pec->calF[6] <<2) | ((pec->calF[7] ) &0x3)) ) ; + + // Joysticks + FACTORY_LO( joyX, pec->calF[ 9] ) ; + FACTORY_MID(joyX, pec->calF[10] ) ; + FACTORY_HI( joyX, pec->calF[ 8] ) ; + + FACTORY_LO( joyY, pec->calF[12] ) ; + FACTORY_MID(joyY, pec->calF[13] ) ; + FACTORY_HI( joyY, pec->calF[11] ) ; + } + if (c & CAL_TRACK) { // track maximum and minimum values seen + TRACK_LO_HI(accX); + TRACK_LO_HI(accY); + TRACK_LO_HI(accZ); + + TRACK_LO_HI(joyX); + TRACK_LO_HI(joyY); + } + if (c & CAL_RANGE) { // perform software calibration step + RANGE_LO_HI(accX); + RANGE_LO_HI(accY); + RANGE_LO_HI(accZ); + + if (!(c & CAL_NOTJOY)) { // double negative! + RANGE_LO_HI(joyX); + RANGE_LO_HI(joyY); + } + } + if (c & CAL_CENTRE) { // reset centre point of joystick + CENTRE(accX); + CENTRE(accY); + CENTRE(accZ); + + CENTRE(joyX); + CENTRE(joyY); + } +} + +//============================================================================= ======================================== +// Accelerometer screen ...might this be useful for other controllers? +// +// https://bootlin.com/labs/doc/nunchuk.pdf +// X : Move Left/Right : -left / +right +// Y : Move Fwd/Bkwd : -fwd / +bkwd +// Z : Move Down/Up : -down / +up +// +// Movement in the direction of an axis changes that axis reading +// Twisting/tilting around an axis changes the other two readings +// +// EG. Move left will effect X ; turn left will effect Y & Z +// +#define aw 110 // axis width +#define ah 15 // height {0......7......14} +#define am 7 // midpoint { 7 } +#define ar 7 // range {1234567 1234567} + +enum { + ACC_X = 0, + ACC_Y = 1, + ACC_Z = 2, + ACC_CNT = 3, + ACC_1 = ACC_X, // first + ACC_N = ACC_Z, // last +}; + +//+============================================================================ +static +void nunchuck_showAcc (Canvas* const canvas, state_t* const state) +{ + ecDecNunchuck_t* d = &state->ec.dec[state->ec.decN].nunchuck; + ecCalNunchuck_t* lo = &state->ec.calS.nunchuck[1]; + ecCalNunchuck_t* mid = &state->ec.calS.nunchuck[2]; + ecCalNunchuck_t* hi = &state->ec.calS.nunchuck[3]; + + int y[ACC_CNT] = {0, 0+(ah+4), 0+((ah+4)*2)}; + int x = 10; + + static uint16_t v[ACC_CNT][aw] = {0}; +// static uint16_t tv[ACC_CNT][aw] = {0}; + + static uint16_t idx = 0; + static uint16_t cnt = aw -1; + + // Only record when scanner NOT-paused + if (!state->pause) { + uint16_t dead = (1<<5); + + // Find axes y-offsets + for (int a = ACC_1; a <= ACC_N; a++) { + uint16_t* dp = NULL; // data value (current reading) + uint16_t* lp = NULL; // lo value + uint16_t* mp = NULL; // mid value + uint16_t* hp = NULL; // hi value + uint16_t* vp = NULL; // value (result) + + switch (a) { + case ACC_X: + dp = & d->accX; // data (input) + lp = & lo->accX; // low \. + mp = &mid->accX; // mid > calibration + hp = & hi->accX; // high / + vp = &v[ ACC_X][idx]; // value (where to store the result) + break; + case ACC_Y: + dp = & d->accY; + lp = & lo->accY; + mp = &mid->accY; + hp = & hi->accY; + vp = &v[ ACC_Y][idx]; + break; + case ACC_Z: + dp = & d->accZ; + lp = & lo->accZ; + mp = &mid->accZ; + hp = & hi->accZ; + vp = &v[ ACC_Z][idx]; + break; + default: break ; + } + + // Again - qv. the joysick calibration: + // This is not the "right way" to do this, it is just "one way" to do it + // ...mid point and extreme zones have a deadzone + // ...the rest is evenly divided by the amount of space on the graph + if ((*dp >= (*mp -dead)) && (*dp <= (*mp +dead))) *vp = ar ; + else if (*dp >= (*hp -dead)) *vp = ah-1 ; + else if (*dp <= (*lp +dead)) *vp = 0 ; + else if (*dp < *mp) { + uint16_t min = ((*lp +dead) +1); + uint16_t max = ((*mp -dead) -1); + float range = (max -min) +1; + float m = range /(ar-1); // 6 evenly(/fairly) divided zones + *vp = ((int)((*dp -min) /m)) +1; + + } else {//if (*dp > *mp) + uint16_t min = ((*mp +dead) +1); + uint16_t max = ((*hp -dead) -1); + float range = (max -min) +1; + float m = range /(ar-1); // 6 evenly(/fairly) divided zones + *vp = ((int)((*dp -min) /m)) +1 +ar; + } + } + +//! If we decide to offer "export to CSV" +//! I suggest we keep a second array of true-values, rather than do all the maths every time +//! Also - the data will need to me moved to the 'state' table - so a.n.other function can save it off +// tv[ACC_X][idx] = d->accX; +// tv[ACC_Y][idx] = d->accY; +// tv[ACC_Z][idx] = d->accZ; + + // Prepare for the next datapoint + if (++idx >= aw) idx = 0 ; + if (cnt) cnt-- ; + } + + // Auto-pause + if (state->apause && !idx) state->pause = true ; + + // *** Draw axes *** + show(canvas, 0,y[ACC_X] +((ah -img_6x8_X.h) /2), &img_6x8_X, SHOW_SET_BLK); + show(canvas, 0,y[ACC_Y] +((ah -img_6x8_Y.h) /2), &img_6x8_Y, SHOW_SET_BLK); + show(canvas, 0,y[ACC_Z] +((ah -img_6x8_Z.h) /2), &img_6x8_Z, SHOW_SET_BLK); + + canvas_set_color(canvas, ColorBlack); + for (int a = ACC_1; a <= ACC_N; a++) { + canvas_draw_line(canvas, x-1,y[a] , x -1,y[a]+ah); + canvas_draw_line(canvas, x ,y[a]+ah, x+aw-1,y[a]+ah); + + // Mid & Peak lines + for (int i = 1; i < aw; i += 3) { + canvas_draw_dot(canvas, x+i,y[a]); + canvas_draw_dot(canvas, x+i,y[a] +(ah /2)); + } + } + + // Data (wiper display - see notes.txt for scrolling algorithm) + int end = idx ? idx : aw; + for (int a = ACC_1; a <= ACC_N; a++) { + canvas_draw_dot(canvas, x,y[a]+v[a][idx]); + for (int i = 1; i < end; i++) + canvas_draw_line(canvas, x+i,y[a]+v[a][i-1] , x+i,y[a]+v[a][i]); + if (!state->apause) + for (int i = end+10; i < aw -cnt; i++) + canvas_draw_line(canvas, x+i,y[a]+v[a][i-1] , x+i,y[a]+v[a][i]); + } + // Wipe bar + if (end < aw) canvas_draw_line(canvas, x+end,y[0], x+end,y[2]+ah-1); + if (++end < aw) canvas_draw_line(canvas, x+end,y[0], x+end,y[2]+ah-1); + if (++end < aw) canvas_draw_line(canvas, x+end,y[0], x+end,y[2]+ah-1); + + // *** Mode buttons *** + show(canvas, 0,55, &img_key_L, SHOW_SET_BLK); // mode key + + if ((state->calib & CAL_RANGE) || state->pause) state->flash++ ; + + // -pause- ...yeah, this got a little out of hand! LOL! + if (state->pause || state->apause) { + if (state->pause && state->apause && !idx) { + if (state->flash &8) { + show(canvas, 108,56, &img_key_U, SHOW_SET_BLK); + } else { + show(canvas, 108,56, &img_key_Ui, SHOW_SET_BLK); + canvas_draw_line(canvas, x+aw,y[0], x+aw,y[2]+ah-1); + } + } else { + show(canvas, 108,56, &img_key_Ui, SHOW_SET_BLK); + } + } else { + show(canvas, 108,56, &img_key_U, SHOW_SET_BLK); // pause + } + + // -calibration- + if (state->calib & CAL_RANGE) { + show(canvas, 119,55, (state->flash &8) ? &img_key_OKi : &img_key_OK, SHOW_SET_BLK); + } else { + show(canvas, 119,55, &img_key_OK, SHOW_SET_BLK); + } +} + +# undef aw +# undef ah +# undef am +# undef ar + +//+============================================================================ ======================================== +// Default nunchuck screen +// +void nunchuck_show (Canvas* const canvas, state_t* const state) +{ + // Nunchucks have TWO scenes + if (state->scene == SCENE_NUNCHUCK_ACC) return nunchuck_showAcc(canvas, state) ; + + // Default scene + ecDecNunchuck_t* d = &state->ec.dec[state->ec.decN].nunchuck; + ecCalNunchuck_t* c = (state->hold) ? &state->ec.calS.nunchuck[(state->hold < 0) ? 0 : 4] + : (ecCalNunchuck_t*)d ; //! danger will robinson! + ecCalNunchuck_t* js = state->ec.calS.nunchuck; + + // X, Y, Z + show(canvas, 42,0, &img_6x8_X, SHOW_SET_BLK); + show(canvas, 73,0, &img_6x8_Y, SHOW_SET_BLK); + show(canvas, 104,0, &img_6x8_Z, SHOW_SET_BLK); + + canvas_draw_str_aligned(canvas, 0,14, AlignLeft, AlignTop, "Accel"); + canvas_draw_str_aligned(canvas, 0,28, AlignLeft, AlignTop, "Joy"); + + // accel values + showHex(canvas, 34,12, c->accX, 3,2); + showHex(canvas, 65,12, c->accY, 3,2); + showHex(canvas, 96,12, c->accZ, 3,2); + // Joy values + showHex(canvas, 38,27, c->joyX, 2,2); + showHex(canvas, 69,27, c->joyY, 2,2); + + showJoy(canvas, 103,32, js[1].joyX, js[2].joyX, js[3].joyX, + js[1].joyY, js[2].joyY, js[3].joyY, d->joyX,d->joyY, 8); + + // buttons + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned(canvas, 0,44, AlignLeft, AlignTop, "Button"); + + if (!d->btnC) { + canvas_draw_rframe(canvas, 36,42, 18,12, 6); + show(canvas, 42,44, &img_6x8_C, SHOW_SET_BLK); + } else { + canvas_draw_rbox(canvas, 36,42, 18,12, 6); + show(canvas, 42,44, &img_6x8_C, SHOW_SET_WHT); + canvas_set_color(canvas, ColorBlack); + } + + if (!d->btnZ) { + canvas_draw_rframe(canvas, 64,40, 24,16, 2); + show(canvas, 73,44, &img_6x8_Z, SHOW_SET_BLK); + } else { + canvas_draw_rbox(canvas, 64,40, 24,16, 2); + show(canvas, 73,44, &img_6x8_Z, SHOW_SET_WHT); + } + + // Navigation + showPeakHold(state, canvas, state->hold); // peak keys + show(canvas, 0,55, &img_key_L, SHOW_SET_BLK); // mode keys + show(canvas, 9,55, &img_key_R, SHOW_SET_BLK); +} + +//+============================================================================ ======================================== +static +bool nunchuck_keyAcc (const eventMsg_t* const msg, state_t* const state) +{ + int used = false; // assume key is NOT-handled + + switch (msg->input.type) { + case InputTypeShort: //# input.key) { + case InputKeyDown: //# pause) state->pause = false ; // Paused? Restart + else state->apause = !state->apause ; // No? toggle auto-pause + used = true; + break; + + case InputKeyLeft: //# calib &= ~CAL_NOTJOY; // DO calibrate joystick in NUNCHUCK mode + used = true; + break; + + default: break ; //# scene == SCENE_NUNCHUCK_ACC) return nunchuck_keyAcc(msg, state) ; + + // Default scene + int used = false; // assume key is NOT-handled + + switch (msg->input.type) { + case InputTypeShort: //# input.key) { + case InputKeyLeft: //# calib |= CAL_NOTJOY; // do NOT calibrate joystick in _ACC mode + used = true; + break; + default: break ; //# +#include + +//----------------------------------------------------------------------------- +// Controllers which have calibration must have their calibratable controls here +//! Is there a better way to get the start of the decode struct to match the calibration struct ? +#define NUNCHUCK_ANALOGUE \ + uint8_t joyX, joyY; \ + uint16_t accX, accY, accZ; + +//----------------------------------------------------------------------------- +// Calibratable controls +// +typedef + struct ecCalNunchuck { + NUNCHUCK_ANALOGUE + } +ecCalNunchuck_t; + +//----------------------------------------------------------------------------- +// All controls +// +typedef + struct ecDecNunchuck { + NUNCHUCK_ANALOGUE // MUST be first + + // Digital controls + bool btnC, btnZ; // BTN{c, z} + } +ecDecNunchuck_t; + +#undef NUNCHUCK_ANALOGUE + +//============================================================================= +// Function prototypes +// +#include // Canvas +typedef struct wiiEC wiiEC_t ; +typedef enum ecCalib ecCalib_t ; +typedef struct state state_t ; +typedef struct eventMsg eventMsg_t ; + +void nunchuck_decode (wiiEC_t* const pec) ; +void nunchuck_msg (wiiEC_t* const pec, FuriMessageQueue* const queue) ; +void nunchuck_calib (wiiEC_t* const pec, ecCalib_t c) ; + +void nunchuck_show (Canvas* const canvas, state_t* const state) ; +bool nunchuck_key (const eventMsg_t* const msg, state_t* const state) ; + +#endif //WII_EC_NUNCHUCK_H_ diff --git a/applications/plugins/wii_ec_anal/wii_ec_udraw.c b/applications/plugins/wii_ec_anal/wii_ec_udraw.c new file mode 100644 index 000000000..babbc92ab --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec_udraw.c @@ -0,0 +1,145 @@ +//! udraw support is NOT written - this is just notes about the init function +#include +#include // Core API + +#include "wii_anal.h" +#include "wii_ec.h" +#include "bc_logging.h" + +#include "i2c_workaround.h" //! temporary workaround for a bug in furi i2c [see header] + +// ** If you want to see what this source code looks like with all the MACROs expanded +// ** grep -v '#include ' wii_ec_udraw.c | gcc -E -o /dev/stdout -xc - +# include "wii_ec_macros.h" + +//+============================================================================ ======================================== +// https://github.com/madhephaestus/WiiChuck/blob/master/src/Drawsome.cpp#L3 +// Gratuitously stolen ... never tested (don't own one) - just bought one on ebay +// although it seems like the UK version is a "uDraw" and MIGHT contain a different chipset :/ +// +// read 6 bytes starting from 0x20 +// read 6 bytes starting from 0x28 +// read 6 bytes starting from 0x30 +// read 6 bytes starting from 0x38 +// read 6 bytes starting from 0x00 (#1) +// read 6 bytes starting from 0x00 (#2) +// write 1 byte [0x01] to 0xFB +// read 6 bytes starting from 0x00 (#3) +// read 6 bytes starting from 0x00 (#4) +// +bool udraw_init (wiiEC_t* const pec) +{ + ENTER; + bool rv = true; + +(void)pec; +/* +//! this is the Drawsome code, NOT the uDraw code !! + static const uint8_t reg[9] = {0x20, 0x28, 0x30, 0x38, 0x00, 0x00, 0xFB, 0x00, 0x00}; // 0..8 + const uint8_t* p = reg; + uint8_t buf[6] = {0}; + + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 0 + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 1 + furi_delay_ms(100); + + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 2 + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 3 + furi_delay_ms(100); + + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 4 + furi_delay_ms(100); + + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 5 + furi_delay_ms(100); + + buf[0] = *p++; + buf[1] = 0x01; + if (!furi_hal_i2c_tx(bus,addr, buf,2, timeout)) goto fail ; // 6 + + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 7 + furi_delay_ms(100); + + if (!furi_hal_i2c_trxd(bus,addr, p++,1, buf,sizeof(buf), timeout,300)) goto fail ; // 8 + furi_delay_ms(100); + + TRACE("%s : OK #%d", __func__, (p-reg)); + goto done; + +fail: + ERROR("%s : fail #%d", __func__, (p -reg) -1); + rv = false; + +done: +*/ + LEAVE; + return rv; +} + +//+============================================================================ ======================================== +bool udraw_key (const eventMsg_t* const msg, state_t* const state) +{ +(void)state; + bool run = true; + + switch (msg->input.type) { + case InputTypeShort: //# input.key) { + case InputKeyUp: //# ! After INPUT_LONG_PRESS interval, asynch to InputTypeRelease + switch (msg->input.key) { + case InputKeyUp: //# >U [ LONG-UP ] + case InputKeyDown: //# >D [ LONG-DOWN ] + case InputKeyLeft: //# >L [ LONG-LEFT ] + case InputKeyRight: //# >R [ LONG-RIGHT ] + case InputKeyOk: //# >O [ LONG-OK ] + case InputKeyBack: //# >B [ LONG-BACK ] + default: break ; //# >? + } + break; + case InputTypePress: //# +! After debounce + switch (msg->input.key) { + case InputKeyUp: //# +U [ SHORT-UP ] + case InputKeyDown: //# +D [ SHORT-DOWN ] + case InputKeyLeft: //# +L [ SHORT-LEFT ] + case InputKeyRight: //# +R [ SHORT-RIGHT ] + case InputKeyOk: //# +O [ SHORT-OK ] + case InputKeyBack: //# +B [ SHORT-BACK ] + default: break ; //# +? + } + break; + case InputTypeRepeat: //# *! With INPUT_REPEATE_PRESS period after InputTypeLong event + switch (msg->input.key) { + case InputKeyUp: //# *U [ REPEAT-UP ] + case InputKeyDown: //# *D [ REPEAT-DOWN ] + case InputKeyLeft: //# *L [ REPEAT-LEFT ] + case InputKeyRight: //# *R [ REPEAT-RIGHT ] + case InputKeyOk: //# *O [ REPEAT-OK ] + case InputKeyBack: //# *B [ REPEAT-BACK ] + default: break ; //# *? + } + break; + case InputTypeRelease: //# -! After debounce + switch (msg->input.key) { + case InputKeyUp: //# -U [ RELEASE-UP ] + case InputKeyDown: //# -D [ RELEASE-DOWN ] + case InputKeyLeft: //# -L [ RELEASE-LEFT ] + case InputKeyRight: //# -R [ RELEASE-RIGHT ] + case InputKeyOk: //# -O [ RELEASE-OK ] + case InputKeyBack: //# -B [ RELEASE-BACK ] + default: break ; //# -? + } + break; + default: return true ; + } + + return run; +} diff --git a/applications/plugins/wii_ec_anal/wii_ec_udraw.h b/applications/plugins/wii_ec_anal/wii_ec_udraw.h new file mode 100644 index 000000000..1721894e5 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_ec_udraw.h @@ -0,0 +1,18 @@ +#ifndef WII_EC_UDRAW_H_ +#define WII_EC_UDRAW_H_ + +#include +#include + +//============================================================================= ======================================= +// Function prototypes +// +typedef struct wiiEC wiiEC_t ; +typedef enum ecCalib ecCalib_t ; +typedef struct eventMsg eventMsg_t ; +typedef struct state state_t ; + +bool udraw_init (wiiEC_t* const pec) ; +bool udraw_key (const eventMsg_t* const msg, state_t* const state) ; + +#endif //WII_EC_UDRAW_H_ diff --git a/applications/plugins/wii_ec_anal/wii_i2c.c b/applications/plugins/wii_ec_anal/wii_i2c.c new file mode 100644 index 000000000..90fe22163 --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_i2c.c @@ -0,0 +1,309 @@ +//----------------------------------------------------------------------------- ---------------------------------------- +// Biblio: [standing on the shoulders of giants] +// https://bootlin.com/labs/doc/nunchuk.pdf +// https://www.hackster.io/infusion/using-a-wii-nunchuk-with-arduino-597254#toc-i2c-protocol-9 +// https://web.archive.org/web/20220000000000*/https://www.hackster.io/infusion/using-a-wii-nunchuk-with-arduino-597254 +// https://github.com/madhephaestus/WiiChuck/blob/master/src/Accessory.cpp#L14 +// https://wiibrew.org/wiki/Wiimote/Extension_Controllers +// https://www.best-microcontroller-projects.com/i2c-tutorial.html +// +// WiiMote Extension Controller: +// Bus Address : 0x52 +// Register autoincrements after each (byte is) read +// 0x00..0x05 ( 6 bytes) ... [r] Controller Data +// 0x20..0x2F (16 bytes) ... [r] Calibration Data +// 0x30..0x3F (16 bytes) ... [r] (A copy of the) Calibration Data +// 0x40..0x4F (16 bytes) ... [w] Encryption key(s) +// 0xFA..0xFF ( 6 bytes) ... [r] Perhipheral ID + +//----------------------------------------------------------------------------- ---------------------------------------- +#include +#include +#include + +#include +#include +#include + +#include "i2c_workaround.h" //! temporary workaround for a bug in furi i2c [see header] + +#include "wii_anal.h" +#include "wii_i2c.h" +#include "wii_ec.h" + +#include "bc_logging.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +// Wii Extension Controller i2c Bus address +static const uint8_t ec_i2cAddr = 0x52; + +// Initialise for UNencrypted comms +static const uint8_t regInit1 = 0xF0; +static const uint8_t regInit2 = 0xFB; +static const uint8_t cmdInit1[] = {regInit1, 0x55}; +static const uint8_t cmdInit2[] = {regInit2, 0x00}; + +// Initialise for ENcrypted comms +static const uint8_t regInitEnc = 0x40; +static const uint8_t cmdInitEnc[] = {regInitEnc, 0x00}; + +// Crypto key (PSK), base register : {0x40..0x4F}[2][8] +static const uint8_t regEnc = 0x40; // ENC_LEN + +// Controller State data, base register : {0x00..0x05}[6] +static const uint8_t regJoy = 0x00; // JOY_LEN + +// Calibration data, base register : {0x20..0x2F}[16] +static const uint8_t regCal = 0x20; // CAL_LEN + +// Controller ID, base register : {0xFA..0xFF}[6] +static const uint8_t regPid = 0xFA; // PID_LEN + +//+============================================================================ ======================================== +// Hexdump a buffer to the logfile +// +#if LOG_LEVEL >= 4 // INFO + +static +void dump (const uint8_t* buf, const unsigned int len, const char* id) +{ + // snprintf() would be useful! + char s[128] = {0}; + char* p = NULL; + + strcpy(s, id); + p = s +strlen(s); + *p++ = ':'; + *p++ = ' '; + *p++ = '{'; + + for (unsigned int i = 0; i < len; i++) { + uint8_t hi = (buf[i] &0xF0) >>4; + uint8_t lo = (buf[i] &0x0F); + + hi = hi + ((hi > 9) ? ('A' -10) : '0'); + lo = lo + ((lo > 9) ? ('A' -10) : '0'); + + *p++ = (char)hi; + *p++ = (char)lo; + *p++ = ','; + } + *p = '\0'; + *--p = '}'; + INFO(s); +} + +#else +# define dump(...) +#endif + +//+============================================================================ ======================================== +// +//! -W-A-R-N-I-N-G- : THIS ENCRYPTION CODE SHOULD NEVER BE REQUIRED ... AS SUCH, I'VE NEVER TESTED IT +// +static +void decrypt (uint8_t* buf, const uint8_t* encKey, const uint8_t reg, unsigned int len) +{ +#if 1 // Use standard algorithm + // decrypted_byte = (encrypted_byte XOR encKey[1][address%8]) + encKey[2][address%8] + for (uint8_t* p = buf; p < buf+len; p++) + *p = (*p ^ encKey[(reg +(p -buf)) %8]) + encKey[8 +((reg +(p -buf)) %8)]; + +#else //! This is (I think) a shortcut for an all-zero key [not tested] + (void)encKey; + (void)reg; + for (uint8_t* p = buf; p < buf+len; p++) + *p = (*p ^ 0x17) + 0x17; +#endif +} + +//+============================================================================ ======================================== +// Read the Extension Controller state +// ...and decode it in to something sane +// +// Returns: {0:OK, >0:Error} +// +int ecRead (wiiEC_t* pec) +{ + ENTER; + int rv = 0; // assume success + + if (!pec->init) { + WARN("%s : device not initialised", __func__); + rv = 1; + goto bail; + } + + if (!furi_hal_i2c_is_device_ready(i2cBus,i2cAddr, i2cTimeout)) { + INFO("%s : device disconnected", __func__); + pec->init = false; + rv = 2; + goto bail; + } + + if (!furi_hal_i2c_trxd(i2cBus,i2cAddr, ®Joy,1, pec->joy,JOY_LEN, i2cTimeout,i2cReadWait)) { + ERROR("%s : trxd fail", __func__); + rv = 3; + goto bail; + } + + if (pec->encrypt) decrypt(pec->joy, pec->encKey, regJoy, JOY_LEN) ; + + // Decode the readings (according to Controller type) + ecDecode(pec); + +bail: + LEAVE; + return rv; +} + +//+============================================================================ ======================================== +// Initialise an Extension Controller +// +//! To disable encryption, pass a NULL encryption key <-- this is currently ALWAYS the case +// +bool ecInit (wiiEC_t* pec, const uint8_t* encKey) +{ + ENTER; + + bool rv = false; // assume failure + +#if 0 //! i2c workaround + //! I think this is done during OS startup - long before the plugin starts + furi_hal_i2c_init(); +#endif + +#if 0 //! i2c workaround + // May become relevant when the i2c issues are resolved + // Take control of the i2c bus [which returns void !?] + // --> firmware/targets/f7/furi_hal/furi_hal_i2c.c + furi_hal_i2c_acquire(i2cBus); +#endif + + pec->init = false; // assume failure + + // === See if the device is alive === + if (!furi_hal_i2c_is_device_ready(i2cBus,i2cAddr, i2cTimeout)) { + TRACE("%s : waiting for device", __func__); + goto bail; + } + INFO("%s : device connected", __func__); + + // === Initialise the device === + pec->init = false; // This goes true AFTER the (optional) controller-specific init code + + // === Start the Extension Controller === + if (encKey) { //! start in encrypted mode + + //! todo - should this happen here, or AFTER we've got the ID ? + + } else { + + if ( !furi_hal_i2c_tx(i2cBus,i2cAddr, cmdInit1,sizeof(cmdInit1), i2cTimeout) ) { + ERROR("%s : init fail (dec1)", __func__); + goto bail; + } + TRACE("%s : init OK1", __func__); + + if ( !furi_hal_i2c_tx(i2cBus,i2cAddr, cmdInit2,sizeof(cmdInit2), i2cTimeout) ) { + ERROR("%s : init fail (dec2)", __func__); + goto bail; + } + TRACE("%s : init OK2", __func__); + } + + // === Retrieve the Extension Controller ID === + if (!furi_hal_i2c_trx(i2cBus,i2cAddr, ®Pid,1, pec->pid,PID_LEN, i2cTimeout)) { + ERROR("%s : T(R)x fail (pid)", __func__); + goto bail; + } + if (pec->encrypt) decrypt(pec->joy, pec->encKey, regJoy, JOY_LEN); + dump(pec->pid, PID_LEN, "pid"); // debug INFO + + // Find the StringID in the lookup table + for (pec->pidx = PID_FIRST; pec->pidx < PID_ERROR; pec->pidx++) + if (memcmp(pec->pid, ecId[pec->pidx].id, PID_LEN) == 0) break ; + if (pec->pidx == PID_ERROR) pec->pidx = PID_UNKNOWN ; + pec->sid = ecId[pec->pidx].name; + INFO("sid: %s", pec->sid); + + // === (optionally) Enable encryption === + if (!encKey) { + pec->encrypt = false; + + } else { // Controller WILL encrypt ALL tranmissions +//! this encryption code fails - should it be done earlier? +//! as it is probably never of any use, I'm kinda loathed to spend time on it +//! https://github.com/madhephaestus/WiiChuck/blob/master/src/Accessory.cpp#L138 + uint8_t encTx[1+ENC_LEN] = {0}; + uint8_t* ep = encTx; + + pec->encrypt = true; + + // ** Start the Controller in ENcrytped mode + if ( !furi_hal_i2c_tx(i2cBus,i2cAddr, cmdInitEnc,sizeof(cmdInitEnc), i2cTimeout) ) { + ERROR("%s : init fail (enc)", __func__); + goto bail; + } + + // Copy the (symmetric) encryption key to the controller state table + if (pec->encKey != encKey) + memcpy(pec->encKey, encKey, ENC_LEN); + + // Build the encryption key packet + *ep++ = regEnc; + memcpy(ep, pec->encKey, ENC_LEN); + + // ** Send encryption key (PSK) + if ( !furi_hal_i2c_tx(i2cBus,i2cAddr, encTx,(1+ENC_LEN), i2cTimeout) ) { + ERROR("%s : key fail", __func__); + goto bail; + } + + TRACE("%s : init OK (enc)", __func__); + } + + // === Some devices [eg. Drawsome/uDraw] require additional init code === + if ( ecId[pec->init].init && (ecId[pec->init].init(pec) == false) ) goto bail ; + pec->init = true; + + // === Read calibration data === + if (!furi_hal_i2c_trx(i2cBus,i2cAddr, ®Cal,1, pec->calF,CAL_LEN, i2cTimeout)) { + ERROR("%s : trx fail (cal)", __func__); + goto bail; + } + if (pec->encrypt) decrypt(pec->joy, pec->encKey, regJoy, JOY_LEN); + dump(pec->calF, CAL_LEN, "cal"); + + ecCalibrate(pec, CAL_RESET | CAL_FACTORY); // Load factory default calibration + + // === Initialise decode buffers === + pec->decN = 0; // read in to decode[1] (yes, N=0 -> read in to dec[1]) + switch (ecRead(pec)) { + case 0: // read OK + memcpy(&pec->dec[0], &pec->dec[1], sizeof(pec->dec[0])); + dump(pec->joy, JOY_LEN, "joy"); + break; + + default: // bug: unknown + case 1: // bug: not initialised - should never happen + ERROR("%s : read bug", __func__); + break; + + case 2: // device gone + case 3: // read fail + // Logging done by ecRead() + pec->init = false; + goto bail; + } + + rv = true; // yay :) + +bail: +#if 0 //! i2c workaround + furi_hal_i2c_release(i2cBus); +#endif + + LEAVE; + return rv; +} diff --git a/applications/plugins/wii_ec_anal/wii_i2c.h b/applications/plugins/wii_ec_anal/wii_i2c.h new file mode 100644 index 000000000..18cb5ee9b --- /dev/null +++ b/applications/plugins/wii_ec_anal/wii_i2c.h @@ -0,0 +1,42 @@ +#ifndef WII_I2C_H_ +#define WII_I2C_H_ + +#include + +//#include "wii_ec.h" + +//----------------------------------------------------------------------------- ---------------------------------------- +// i2c bus details +// +// https://www.best-microcontroller-projects.com/i2c-tutorial.html +// https://web.archive.org/web/20220000000000*/https://www.best-microcontroller-projects.com/i2c-tutorial.html +// https://training.ti.com/introduction-i2c-reserved-addresses +// +// After the (special) START "bit"... +// the first 8bits (byte) of i2c data are the 7bit i2c Address, +// FOLLOWED by 1bit to signify a READ or WRITE {0=write, 1=read} +// The data is transmitted BIG-Endian, IE. MSb first [human readable] +// So the address actually lives in the TOP (MSb's) of the first "byte", (with bit0 being used as the read/write flag) +// +// The read() and write() functions on the FZ will set the LSb appropriately, +// BUT they do NOT shift the address left to make room for it! +// So the address you give to read/write() MUST be given as (7bitAddress << 1) +// +// When we read: After we send the read command, we wait for i2cReadWait uS before reading the data +// + +// firmware/targets/f7/furi_hal/furi_hal_i2c_types.h +#define i2cBus (&furi_hal_i2c_handle_external) // FZ external i2c bus +#define i2cAddr (ec_i2cAddr << 1) +#define i2cTimeout (3) // in mS +#define i2cReadWait (300) //! 300uS: how low can we take this? + +//----------------------------------------------------------------------------- ---------------------------------------- +// public functions +// +typedef struct wiiEC wiiEC_t ; + +bool ecInit (wiiEC_t* const pec, const uint8_t* encKey) ; +int ecRead (wiiEC_t* const pec) ; + +#endif //WII_I2C_H_