[Q] choose array-elements with certain probability - General Questions and Answers

hello,
I'm writing a Android App (java) - but I guess this question is pretty general, and isn't java-specific:
so I have an Array of Elements
and I let a random-number-generator pick one array-element randomly and hand it to me.
now I've also built in a "score"-field into each array Element
so what I want to do now, is that the random-number-generator takes the array's "score" in consideration, and gives me the array-elements with the higher/lower scores with a higher/lower probability
I dont want it to ALWAYS/NEVER give me the elements with the highest/lowest score - just with a higher/lower probability
I hope I could describe my problem in a proper way....
does anybody know how to achieve this?
(as I said, i use java, but i guess code in any language - or even pseudo-code would help me out)

*bump*
anybody?

Try this, it's in C# but it's pretty close to Java.
You cannot directly weight the random function so you have to use a different method.
By applying a weight to each item in the array, then using a random function to select using the weighting values, the results of the selection can be swayed.
The weighting values are relative to each other.
Using the values in the code, 'B' should turn up about three times more often than 'A'
The only object that may need some explanation is Random:
http://msdn.microsoft.com/en-us/library/system.random(v=VS.80).aspx
Code:
using System;
namespace RandomWeighting
{
class Program
{
static void Main(string[] args)
{
char[] Select = new char[10] {'A','B','C','D','E','F','G','H','I','J'};
int[] Weight = new int[10] {10,30,25,60,20,70,10,80,20,30};
int[] WeightSum = new int[10];
int i,j,k;
Random Rnd = new Random();
WeightSum[0]=Weight[0];
for (i = 1; i < 10; i++)
WeightSum[i] = WeightSum[i - 1] + Weight[i];
for (j = 0; j < 70; j++)
{
k = Rnd.Next(WeightSum[9]);
for (i = 0; k > WeightSum[i]; i++) ;
Console.Write(Select[i]);
}
Console.WriteLine();
}
}
}
Output:
Code:
HEFIBHHCCFBCAEFFDHACHBEJHHFDFIDFEDFFCHHDJBIDJEHHFHCJJJBHJGBDDGFDDFHHHB
Note the low density of A and G as opposed to H
It is just a sample at random, but 2 'A's and 7 'B's roughly matches the conjecture above, but over a million selections, the distribution is as follows:
Code:
A 30664
B 84187
C 70648
D 168481
E 56529
F 197311
G 28145
H 225764
I 56613
J 81658
If your code changes values in the Weight array then the WeightSum array must be recalculated.

wow, thats a lot!
The only thing I dont understand about the code is this line:
k = Rnd.Next(WeightSum[9]);
for (i = 0; k > WeightSum; i++) ;
what exactly happens here?
what kind of a for-loop is this?
why is there no body?
and strangely, while debugging this line, i noticed that the value of i jumps to some random number in this line - and I have no idea why and how
------
by the way: I've already tried it out, it works pretty good.
although I noticed that the first element always gets picked ALOT, no matter how low the weight.
I think thats a flaw in the algorithm

After the following code:
Code:
for (i = 1; i < 10; i++)
WeightSum[i] = WeightSum[i - 1] + Weight[i];
The WeightSum array contains the following values:
Code:
[0] 10
[1] 40
[2] 65
[3] 125
[4] 145
[5] 215
[6] 225
[7] 305
[8] 325
[9] 355
The Random.Next() function that takes a single integer as an argument is defined as:
-------- Courtesy of MS VS .NET Help ------
public virtual int Next(int maxValue)
Parameters maxValue Type: System.Int32
The exclusive upper bound of the random number to be generated. maxValue must be greater than or equal to zero.
Return Value Type: System.Int32
A 32-bit signed integer greater than or equal to zero, and less than maxValue; that is, the range of return values ordinarily includes zero but not maxValue. However, if maxValue equals zero, maxValue is returned.
-------------- End of Help ----------------
So, we are asking for a random value between 0 and 354,(element WeightSum[9] above). The following code then finds which is the lowest element of WeightSum which holds a value greater than the one we have been given. When this happens 'i' contains the index to use for the selection.
Code:
for (i = 0; k > WeightSum[i]; i++);
The standard construction of a for loop in C is
for(One or more initialisation statements; Do_While_True Condition; One or more iteration statements)
{
loop processing code;
}
If there is nothing to do in the loop body, you don't need it, and you can replace it with the ';' at the end of the for statement. In effect, it is identical to the following code:-
Code:
i=0;
while(k > WeightSum[i])
{
i++;
}
As regards the first element being picked more than the others, have a look at the distribution table in post #3. It is what you would expect for the values given. I assume the difference is either the Random function in Java or some different implementation between C# and Java.
You may have to change some of the code slightly, i.e. change the for() loop to the while() loop above and step though it in the Java debugger to get to the root of the problem.
You can't debug a for loop followed by an immediate ';' The entire for loop is executed to completion when you use debug and try and step through it. To debug it place a dummy statement in the for loop. A breakpoint may now be set on this line.
Code:
int i,z;
for (i = 0; k > WeightSum[i]; i++)
{
z=0;
}

ActionScript and Javascript versions ...
Thanks for the great write-up! In case anyone is interested, I've adapted this into a javascript and ActionScript class. If anyone is interested, I've attached the code. For a more in-depth post, check out blog.teamthinklabs.com.
Cheers!
Kipp Ashford
Art Director
Seven2 Interactive

Related

Application crashes when trying to get a list of loaded modules

I have been looking into the C-Sharp__DLLImport project here:
http://forum.xda-developers.com/showthread.php?t=1006331&highlight=dllimport
I am trying to modify the FileSystem project to be able to get a list of the modules that are loaded for each process.
Code:
STDMETHODIMP CFileSystemIO::GetModulesForProcess(DWORD dwPID, BSTR* result)
{
// Get the process snapshot
HANDLE hModuleSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
// Initialize the module entry structure
MODULEENTRY32 moduleEntry = { 0 };
moduleEntry.dwSize = sizeof( moduleEntry );
// Get the first module info
BOOL Return = FALSE;
Return = Module32First( hModuleSnapshot, &moduleEntry);
// Getting process info failed.
if( !Return )
{
CloseHandle( hModuleSnapshot );
return S_FALSE;
}
int x = 1;
CString modList(TEXT(""));
do
{
modList.AppendFormat(TEXT("%d-%d-%d-%d-%d-%d-%s-%s\n"),
moduleEntry.dwSize,
moduleEntry.th32ProcessID,
moduleEntry.GlblcntUsage,
moduleEntry.ProccntUsage,
moduleEntry.modBaseAddr,
moduleEntry.modBaseSize,
moduleEntry.szModule,
moduleEntry.szExePath);
}
while( Module32Next( hModuleSnapshot, &moduleEntry ));
// Close the handle
CloseHandle( hModuleSnapshot );
// set the result
*result = (modList.AllocSysString());
return S_OK;
}
The code is based off a similar function that is already in the project (the CFileSystemIO::MessageBoxRunningProc function which works fine).
By putting some MessageBoxes in there for debugging, I can confirm that the Module32First and Module32Next methods are working correctly. When it gets to the line:
*result = (modList.AllocSysString());
The application crashes. I put a try/catch around there and it didn't trigger a CMemoryException or any other exception.
Any idea why this method would be causing the app to crash?
As an update to this, I was able to figure out the problem. I was unaware of this, but closing the handle generated in the method to get the process messes up the generation of the modules. I didn't think this would be the case since when you generate the handle it also takes a pid. I ended up combining the 2 methods.
The final project uses com interop to call the native methods and it builds a tasklist with all the corresponding modules as subclasses. You can find out which libraries and interfaces are in use by which applications, and where those dll files are located on your phone. If anyone wants to see it, I can post it at some point. It's not a very elegant looking interface, but it gets the job done.

Enable GPU 5th Step?

I was looking around in the gpu driver files and I noticed that there was a hidden 5th 533MHz OC in there. I tried to enable it by copying in the "asv_3d_volt_9_prime" table in for the "non-prime" table. I made sure to remove the -1 in the non prime's table so it wouldn't think the extra voltages for 533MHz was out of bounds. I made sure to comment out these crippling lines:
Code:
/*if ((samsung_rev() < EXYNOS4412_REV_2_0) && (maliDvfsStatus.currentStep == 3))
{
level=get_mali_dvfs_status();
}*/ //a crippling check for "prime" note 2?
I also (after looking at siyah's kernel) copied in the entries for the step4 sysfs variables into mali_kernel_linux.c but my cell phone seems to be bent on not giving me this 5th step.
Sorry again for asking a question that's probably obvious to elite developers. Oh and thank you for answering my question on adding frequencies to the cpu. I now have my own (not copy and pasted :cyclops: ) lines in there to give me 2OC frequency and 1 underclock frequency.
Where's that code snippet from? Anyway it's not related to the limiting if the 5th step.
Code:
static mali_bool mali_dvfs_table_update(void)
{
unsigned int i;
unsigned int step_num = MALI_DVFS_STEPS;
//if (samsung_rev() < EXYNOS4412_REV_2_0)
//step_num = MALI_DVFS_STEPS - 1;
Just comment out those two lines in the DVFS decision making and it should scale up to 5 steps.
AndreiLux said:
Where's that code snippet from? Anyway it's not related to the limiting if the 5th step.
Code:
static mali_bool mali_dvfs_table_update(void)
{
unsigned int i;
unsigned int step_num = MALI_DVFS_STEPS;
//if (samsung_rev() < EXYNOS4412_REV_2_0)
//step_num = MALI_DVFS_STEPS - 1;
Just comment out those two lines in the DVFS decision making and it should scale up to 5 steps.
Click to expand...
Click to collapse
I tried that already. It didn't work. The code snippet I pasted comes from the same file.

Big Bang steering wheel interface support page

Support Page for the Big Bang Steering Wheel Interface
The purpose of this page is to provide support and answers to questions for the Big Bang Steering Wheel interface until our Wiki and support site at UnderGroundElectronics.net is finished.
We are discussing the Big Bang Steering Wheel interface project on Kickstarter.
A Quick Description: The Big Bang is a interface between the car and your tablet. Our goal is to enable you to install your tablet in your car with OEM like integration. We had to start somewhere and we are planning other items for the future but this critical first step we felt was the most nessasary thing for a every day user experiance.
We know that there are a lot of people and threads on installing tablets in cars. We've seen various methods to achieve this solution but no one has made a item for this specific purpose. Even if your car does not have steering wheel controls, this device allows for the waking and sleeping of the tablet while still allowing it to charge constantly.
This device is fairly simple in operation, however the automobiles they go in are not so simple. There are lot of things that can cause problems and we hope to address them here (until we can get our site up, and maybe even after since XDA is a go to place for trouble shooting problems with our tablets and phones).
Lets Start with a basic description of operation
Most autos that have steering wheel controls use a single wire behind the head unit. This wire is typically one of three types: Resistive Negative, Resistive Positive, and Digital. A few Autos use independent wires, one example is Harley Davison. Each button is independent and thus must use resisters to combine the buttons to a single wire.
Currently the Big Bang is made to work on Negative and positive resistive Autos. Data type is expected to be developed by the time we ship.
Finding the wire in your auto:
At the steering column is the best way. But BE WARNED, there is danger probing around with the electrical system of any car that has airbags. You should disconnect the battery and let the car sit at least 30 minutes before doing anything with the wiring in a car with air bags. (Yes we realize that this is very cautious stand but we don't want people getting hurt. If you are un-experienced with Automotive electrical or unsure of what you are doing you probably should consult you local Car Stereo Shop. At the very least use sites like "the 12volt .com" or ask for assistance here. AND NEVER EVER USE A TEST LIGHT, Voltmeters only here.
We can't stress this enough. The data systems and air bag systems in modern cars are very sensitive and can be damaged or set off with just static electricity. We can not be held responsible for what you are doing, we are simply trying to guide you. In my case I have years of car audio experience. I still run into things in new cars that I've never seen before and I've seen plenty of cars damaged by people cutting the wire that was the right color or "injecting voltage" to test something.
Moving forward:
Negative systems:
Typically a Negative system is one that the control wire will go negative from a resting position that is positive. In the case of most Honda's it rests at 5V and goes negative with each button. If you have a stock navigation system (In the case of the Honda. Others may be different) some buttons may be dedicated to the Nav Brain. That unit needs to be removed with the head unit to function properly and has special "reverse wiring" to provide all buttons functions.
Positive systems
Positive systems work just like negative systems but instead rest at or near ground (zero voltage). The voltage at the wire will go positive when a button is pressed.
Programming the Big Bang
Our site will cover most of this but at present the Big Bang is programmed via a PC. We do hope to one day be able to program it from the tablet, allowing one to tweak the controls after install and to improve installation experience. We will provide more detailed instructions closer to launch day but the short of it is you will download a program, modify it to fit your car/application then run it to program the Big Bang.
Connecting the Big Bang
We recommend using the Big Bang with a USB Hub that is powered. We have found some 12V to 5V dc to dc Converters we will link below as well as the USB hubs we recommend. The Big Bang will connect to the USB hub and the USB hub will plug into the tablet or phone. The big bang will have two wires that need to be connected. The Big Bang is powered from the USB power, so it and the tablet are always receiving power. It will have two wires to be connected. The white wire is the control wire and needs to be attached to the steering wheel control wire. The Red one is the ACC[essory] or IGN[ition] wire and needs to be tapped to it as a reference for the cars voltage. This wire should be fused as there is always a potential for shorting. It may be redundant but we still recommend fusing this wire independent of others, or using the same fuse used for the USB 12v to 5v converter.
Problems we've seen in our testing
First and worst problem I've experienced is cheap USB OTG cables. Some are very finicky about the position the sit in to make contact. It could be that they are old and worn out too. We plan to explain a "best methods" guide but best I can say is get decent quality USB OTG adapters for this use.
The second issue I've seen is random reboots. My n7 experiences these only when I'm using it in the car. I'm running Paranoid Android, and I don't believe it is the issue. I believe it is due to the faulty USB cable described above.
Other then that, we've experienced few issues but we are still in somewhat early testing phase.
I'll update this post with Q and A's as they come in. When asking questions about your installation it would be helpful for you to be as thorough as possible. Let us know if you are an experienced car audio person or not. Also make model and year of car may be important.
Until now this has been our idea for our car, we now open it to you. We can't promises anything but if you have suggestions, tell us. We may include the feature. We are working on other products as well to enable people to install their tablet and have it operate as normal as possible.
Tested Devices:
We've tested it on these devices so far but you can help. Get a USB OTG cable for your tablet, then plug in a USB keyboard or mouse and see if it functions. post your results and we'll add it to the list.
Confirmed working:
N10
N7
Galaxy Note2
Galaxy S3
Know to NOT work:
N4
Post #2
So we have run into a problem with the USB OnTheGo mode and charging. The Big Bang requires the tablet to be in USB OTG to receive control inputs. While in USB OTG mode the tablet is not charging. We have found there is another mode, Rid_a mode. By enabling this Rid_a mode the tablet will do both USB OTG and charge. We have it working on some Samsung's, we now need to figure out the nexus line.
It is possible that this is something coded into the kernel so we are looking into that. Right now the two default options, if we can't work it out, are:
A) A source built kernel with this one thing enabled.
B) a much more complicated setup that would auto switch between host and client mode from the ignition control. This we feel is less desirable based off the fact that if one is driving long distances the tablet could die out.
Post #3
Ok, I know I’m a bad person, I have left you hanging for ages. Well, it was not without feeling bad, and it was not on purpose, I’ve just been busy trying to pay bills.
So I suppose I’ll start with an overview. So our prototype is a DigiSpark. You can get one for like $9.99 or less. They are neat little devices. If your cool you can follow this little how to to use the Atiny85 http://youtu.be/30rPt802n1k, Which is where we were going with our own custom board. You might need to understand a little about voltage, voltage dividers and such. I will try to help, but I can’t climb in your car and measure the voltage or resistance for you so you’ll need to know how to use a DVOM and some pretty basic electronics.
Ok so probably the most common steering wheel interface type is a negative type, but there is other types. So for the standard type, I’ll try to diagram This is pure example.
Code:
(-gnd)----|---/\/\/\/\/\-----(s1)--------|
| 12k R1 |
|---/\/\/\/\/\-----(s2)--------|
| 8k R2 |
|---/\/\/\/\/\----(s3)---------|
| 5k R3 |
|---/\/\/\/\/\----(s4)---------|
| 2.4k R4 |
|---/\/\/\/\/\----(s5)---------|
| 1k R5 |
|---/\/\/\/\/\----(s6)---------|
450 R6 |
|---------/\/\/\/\/\---- (+12v (vcc) )
| 1k Rb
|
\ /
\/
MPU pin ?
So basically the way this works is on the steering wheel side the wire is grounded. In my honda there is actually both wire sides, the positive and negative or common resistor/common Switch sides. Since I pulled all of the stock Nav Electronics out, I had to ground the one side and put the 12v through the other. You can find a lot of this info out from PIE, PAC and peripheral websites (They make steering wheel interfaces and they should have some info in the installation manual PDF on what your car will be).
This may not be new to you, but for others: The Math is
R1+Rb
--------- * V (probably 12v, 14.4v running)
R1*Rb
So for each switch we’ll have a voltage, or more specifically a voltage range. I had a bit of a solution for the range part but for most applications having a range will be acceptable. In my case the range was +(-) 0.5v.
This should give you approximately something like S1= 11v to 12v, S2= 8v to 9v, etc
So the problem is we can only use a 0v to 5v range. So either we must adjust Rb or use another solution, such as an OP Amp to reduce the voltages. However it should be enough to adjust the resistance of Rb.
So we are going to use the A/D input pin of the ATtiny85 (digispark). We’ll convert that to a digital number and then compare it to some reference values. We’ll just consider the MSB Most significant bits and ignore the last few. This gives us some range to tolerate voltage fluctuations due to the cars electrical system.
That basically explains the car interface. We can do all kinds of neat stuff. We have a few useable pins so we can add pins for ACC, or door triggers, etc.
Now we need to consider the USB interface. The Digispark makes this easy. It is built on a board that has a USB interface built in. If you are using the ATtiny85 on a DIY you’ll need to make up a USB cable for this part. We’re going to make the steering wheel control look like a USB keyboard or Audio control to the tablet.
For the USB part I found a neat description on XDA in a reply on a post that inspired the basic workings. Understanding the USB ASCii code is important here. Android uses many standard ones. It’s a complicated code as it is meant to be able to grow and handle all kinds of different possible things.
The Main uses I found were in the Standard keyboard codes and in the Audio control codes.
We use the Digispark hex program that comes in the digispark start up guide, keyboard.h . We pass the code calls to keyboard.h and it does the rest, except we need to add our specific functions to keyboard.h.
We’ll modify keyboard.h and write our sketch and program the Arduino/Digispark/ATtiny85. It will loop through reading the A/D and comparing to the pre-determined reference values. When it matches we’ll output a USB code to do something on the tablet.
This is where the problem came in. Of all things I didn’t expect to have a issue charging while acting as a usb host to, effectively, a keyboard. As of USB standard 1.1 using a certain resistance between the two data pins will put it in different modes. Unfortunately what I found was on some Samsung devices this value put it in a different mode, and yet a mode that gave us USB host, didn’t allow for charging. On the Nexus devices I couldn’t find a way at all, without requiring a different kernel to be installed. This left two main choices. A) charge when the car is off only. Which is unacceptable in my opinion. A long drive would kill even a Nexus7 and then you’re stuck with nothing. B) Require an aftermarket kernel/ROM installed. Well we realized guiding one to remove the deck and do some major work to put a tablet in the dash ment they were serious, it didn’t seem fair to expect them to also root/hack the OS on said device. Sure I suppose we could have made it such but it didn’t fit our goal. There is a third option I just now thought of. One could add a circuit that triggered the Host mode change only when the buttons are pressed. This can be as simple as causing a closed/open connection between data+ and data- . This could cause some missed keystrokes but if planned right, it might be a viable solution.
Sketch Code:
Code:
#include "DigiKeyboard.h"
/*
Basic Steering wheel to Tablet (or any computer) controls. Posted here are the basics from a honda ridgeline '07. The steering wheel wire is Green with red stripe, pin 3
The Brown wire, pin 11, Needs to be connected to ground (the buttons are resisters accross those two). This is only Vol+,Vol-, Mode, Ch+, Ch-. I will search for Back and Talk later.
The Resistance Values read from it was: Rest=9.9k, Mode=3.73k, Ch+= 1.69k, Ch-= 780, Vol+=356.8, Vol-=101.4. Using a 1k pull up to the 5V USB lead seems like a good value and will yeild
a large variance in voltage output. The outputs should be Rest=4.5454v, Mode=3.94v, Ch+=3.146v, Ch-=2.19v, Vol+=1.314v, Vol-=.4603v. These can be converted to a 10bit value and are about
Rest=931.4, Mode=807.4, Ch+=644.6, Ch-=448.8, Vol+=269.26, Vol-=94.3. This variance is more then 100 dec thus to allow a wide tolarance we will drop the last four bits and
test only the four MSB. I.E. if analogRead(0)==11010000 then Ch+. The LSB will need to be striped away due to them not being exactly the same otherwise.
Grey wire, at steering coulumb is the Talk and Back button. It works with The Same brown wire as with the volume. 9.99k at rest, Talk= 2.238K, Back= .64k. Used with a 1K resister, They are
Rest=4.5454v, Talk=3.455v, Back=1.95v.
## DISCOVERY, analogRead is a DEC value and is difficult to convert. was going to read value then roll value right and then compare. This would have given a range:
// audioState = audioState >> 7;
// navState = navState >> 7;
##Delay output can act as a Remote turn on for Amplifire.
*/
/* Rest= 931 = 1110100011 = 0x3A3
// Mode=807 = 1100100111 = 0x327
// Ch+=644 = 1010000100 = 0x284
// Ch-=449 = 0111000001 = 0x1C1
// Vol+=269 = 0100001101 = 0x10D
// Vol-=94 = 0001011110 = 0x5E
//
// Rest= 931 = 1110100011 = 0x3A3
// Talk= 708 = 1011000100 = 0x2C4
// Back= 399.6= 0110010000 = 0x190
*/
//const int audioCtrl = 5; //pin 5, analog Read 0
//const int navCtrl = 2; //pin 2, analog Read 1
const int ledPin = 1;
int audioState = 1023; //B1110100011; //Variable to store button Value
int navState = 1023; //B1110100011; //Variable to store button Value
int twiceSel = 0; //Variable for checking for double press of vol- and of back
int storeState = 0; //Store the current state for double press check.
void setup() {
pinMode(ledPin, OUTPUT); // Turn on onboard LED when button is pressed
// pinMode(audioCtrl, INPUT); //P0 is volume up
// digitalWrite(volUp, HIGH); //set the pull up resister
// pinMode(navCtrl, INPUT); //P2 is Volume down
// digitalWrite(volDown, HIGH); //set the pull up resister
}
void loop() {
DigiKeyboard.update();
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
audioState = analogRead(1); //read value at audio control pin2, write it to audioState for further processing
navState = analogRead(0); //Read the value of navagation Control pin5, write it to navagationState for further processing.
// Rest= 931 = 1110100011 = 0x3A3 = 111
// Mode=807 = 1100100111 = 0x327 = 110 >675 <850
// Ch+=644 = 1010000100 = 0x284 = 101 >550 <675
// Ch-=449 = 0111000001 = 0x1C1 = 011 >300 < 500
// Vol+=269 = 0100001101 = 0x10D = 010 >120 < 300
// Vol-=94 = 0001011110 = 0x5E = 000 >50 <110
//
// Rest= 931 = 1110100011 = 0x3A3 = 111
// Talk= 708 = 1011000100 = 0x2C4 = 101 >650 <750
// Back= 399.6= 0110010000 = 0x190 = 011 >350 <450
// TODO:
//Need debounce, or slowdown, or delay. Currently it cycles too fast.
// Add double press Vol- triggers mute
// Add double press Back triggers Home
//Fix the "/" causing search to display "//
// Use Dpad instead of arrow (probably a function of the Keypad arrows)
if (audioState >675 && audioState < 850 ) { //Mode inbetween 675 and 850
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_ENTER); //tell computer Select
digitalWrite(ledPin,LOW);
delay (200); //200ms Delay
}
else if (audioState >550 && audioState < 675) { //Ch+ >550 < 675
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_ARROW_RIGHT); //tell computer Right Arrow
digitalWrite(ledPin,LOW);
delay (200); //200ms Delay
}
else if (audioState >300 && audioState < 500) { //Ch- >300 < 500
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_ARROW_LEFT); //tell computer Left Arrow
digitalWrite(ledPin,LOW);
delay (200); //200ms Delay
}
else if (audioState >120 && audioState < 300) { //Vol+ >120 <300
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_VOL_UP); //tell computer Volume Up
digitalWrite(ledPin,LOW);
delay (200); //200ms Delay
}
else if (audioState >50 && audioState < 110) { //Vol- >50 < 110
delay (200);
for(int x =0; x < 5; x++) {
audioState = analogRead(1); //read button again
if(audioState >50 && audioState < 110){
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_VOL_DOWN); //tell computer Select
digitalWrite(ledPin,LOW);
//if statement test for 5cycle if button pressed again, if not changes vol- if so mutes
}
else if (navState >675 && navState < 850) { //Talk >650<750
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_SEARCH); //tell computer Select
digitalWrite(ledPin,LOW);
delay (200); //200ms Delay
}
else if (navState >350 && navState < 450) { //Back >350 <450
//if statement test for 5cycle if button pressed again, if not back, if so home
// storeState = 0; //Clear storeage
// twiceSel = 0;
// storeState = navState; // back was pressed, we need to store it's current state.
// navState = 0;
delay (200);
for (int x=0; x < 5; x++){ // Test 5 times
navState = analogRead(0); //Read the value of navagation Control pin5, write it to navagationState for further processing
if (navState >350 && navState < 450) { //Back >350 <450
// twiceSel = 1; //pressed twice
//Something different
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_HOME); //tell computer Select
digitalWrite(ledPin,LOW);
}
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_ESC); //tell computer Select
digitalWrite(ledPin,LOW);
}
}
}
/*
OLD code left for Refrence
buttonState = digitalRead(volUp);
if (buttonState == LOW) {
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_VOL_UP); //tell computer to turn the volume down
}
else{
digitalWrite(ledPin, LOW);
}
buttonState = digitalRead(volDown);
if (buttonState == LOW) {
digitalWrite(ledPin, HIGH);
DigiKeyboard.sendKeyStroke(0); //this is generally not necessary but with some older systems it seems to prevent missing the first character after a delay
DigiKeyboard.sendKeyStroke(KEY_VOL_DOWN); //tell computer to turn the volume down
}
else{
digitalWrite(ledPin, LOW);
}
*/
Keyboard.h Code:
Code:
/*
* Based on Obdev's AVRUSB code and under the same license.
*
* TODO: Make a proper file header. :)
* Modified for Digispark by Digistump
*/
#ifndef __DigiKeyboard_h__
#define __DigiKeyboard_h__
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <string.h>
#include "usbdrv.h"
// TODO: Work around Arduino 12 issues better.
//#include <WConstants.h>
//#undef int()
typedef uint8_t byte;
#define BUFFER_SIZE 2 // Minimum of 2: 1 for modifiers + 1 for keystroke
static uchar idleRate; // in 4 ms units
/* We use a simplifed keyboard report descriptor which does not support the
* boot protocol. We don't allow setting status LEDs and but we do allow
* simultaneous key presses.
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
* which can be downloaded from http://www.usb.org/developers/hidpage/.
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
* for the second INPUT item.
*/
PROGMEM char usbHidReportDescriptor[39] = { //USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
0x05, 0x01, // 0x05, 0x01 USAGE_PAGE (Generic Desktop)
0x09, 0x01, // 0x09, 0x06 USAGE (Keyboard)
0xa1, 0x01, // 0xa1, 0x01 COLLECTION (Application)
0x25, 0x01,
0x15, 0x00,
0x75, 0x01,
0x95, 0x05, // REPORT_COUNT (5)
0x09, 0xb5, // USAGE (Scan Next Track)
0x09, 0xb6, // USAGE (Scan Previous Track)
0x09, 0xb7, // USAGE (Stop)
0x09, 0xcd, // USAGE (Play/Pause)
0x09, 0xe2, // USAGE (Mute)
0x81, 0x06, // INPUT (Data,Var,Rel) - relative inputs
// -------------------- volume up/down bits
0x95, 0x02, // REPORT_COUNT (2)
0x09, 0xe9, // USAGE (Volume Up)
0x09, 0xea, // USAGE (Volume Down)
0x81, 0x02, // INPUT (Data,Var,Abs) - absolute inputs
// -------------------- padding bit
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
//0x05, 0x07, // 0x05, 0x07 USAGE_PAGE (Keyboard) change to 0x0c for consumer device.
//0x19, 0xe0, // 0x19, 0xe0 USAGE_MINIMUM (Keyboard LeftControl)
//0x29, 0xe7, // 0x29, 0xe7 USAGE_MAXIMUM (Keyboard Right GUI)
//0x15, 0x00, // 0x15, 0x00 LOGICAL_MINIMUM (0)
//0x25, 0x01, // 0x25, 0x01 LOGICAL_MAXIMUM (1)
//0x75, 0x01, // 0x75, 0x01 REPORT_SIZE (1)
//0x95, 0x08, // 0x95, 0x08 REPORT_COUNT (8)
//0x81, 0x02, // 0x81, 0x02 INPUT (Data,Var,Abs)
//0x95, 0x01, // 0x95, 0x01 REPORT_COUNT (simultaneous keystrokes)
//0x75, 0x08, // 0x75, 0x08 REPORT_SIZE (8)
//0x25, 0xE7, // 0x25, 0xE7 LOGICAL_MAXIMUM (130) 0x65 originally
//0x19, 0x00, // 0x19, 0x00 USAGE_MINIMUM (Reserved (no event indicated))
//0x29, 0xE7, // 0x29, 0xE7 USAGE_MAXIMUM (Keyboard Application) 0x65 originally
//0x81, 0x00, // 0x81, 0x00 INPUT (Data,Ary,Abs)
0xc0 // 0xc0 END_COLLECTION
};
/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
* 10 Keyboard/Keypad Page for more codes.
*/
/*
#define MOD_CONTROL_LEFT (1<<0)
#define MOD_SHIFT_LEFT (1<<1)
#define MOD_ALT_LEFT (1<<2)
#define MOD_GUI_LEFT (1<<3)
#define MOD_CONTROL_RIGHT (1<<4)
#define MOD_SHIFT_RIGHT (1<<5)
#define MOD_ALT_RIGHT (1<<6)
#define MOD_GUI_RIGHT (1<<7)
//#define KEY_ARROW_UP 0x52 //Added 2-5-2013 JWA
//#define KEY_ARROW_DOWN 0x51 //Added 2-5-2013 JWA
*/
//Tested with Logitech keyboard on N7. Right Meta key (MOD_GUI_RIGHT) plus F1 = home. Right Meta plus F3= search. Home = Internet home, Search = Windows search Application specific according to Logitech page.
#define KEY_HOME 157 //Added 2-7-2013 JWA according to android doc 3, According to other doc 165
#define KEY_MUTE 0xE9 //Added 2-7-2013 JWA keypad 3 and Page down according to android doc 91/127
#define KEY_SEARCH 127 //Added 2-6-2013 JWA according to android doc 84
#define KEY_ESC 41 //Added 2-6-2013 JWA KEboard ID ESC = 41
// /system/usr/keylayout/geniric.kl
// 172=Home
// 217= Search - 127
// 213== Music
// 140== Calculator
// 158 = Back - 1
// 102=power Confirmed hid usage ID
// 101=menu confirmed
#define KEY_ARROW_LEFT 0x50 // Android dock d-pad left = 105
#define KEY_ARROW_RIGHT 0x4F //Added 2-5-2013 JWA Andorid dock D-pad right=106
#define KEY_ENTER 40 //mode long press could do recent apps key 187
#define KEY_VOL_UP 128 //Added 2-5-2013 JWA 0x80 Andoid dock volume up=115 vdown= 114
#define KEY_VOL_DOWN 129//Added 2-5-2013 JWA 0x81
class DigiKeyboardDevice {
public:
DigiKeyboardDevice () {
TIMSK &= !(1<TOIE0);
cli();
usbDeviceDisconnect();
_delay_ms(250);
usbDeviceConnect();
usbInit();
sei();
// TODO: Remove the next two lines once we fix
// missing first keystroke bug properly.
memset(reportBuffer, 0, sizeof(reportBuffer));
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
void update() {
usbPoll();
}
void sendKeyStroke(byte keyStroke) {
sendKeyStroke(keyStroke, 0);
}
void sendKeyStroke(byte keyStroke, byte modifiers) {
while (!usbInterruptIsReady()) {
// Note: We wait until we can send keystroke
// so we know the previous keystroke was
// sent.
usbPoll();
_delay_ms(5);
}
memset(reportBuffer, 0, sizeof(reportBuffer));
reportBuffer[0] = modifiers;
reportBuffer[1] = keyStroke;
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
while (!usbInterruptIsReady()) {
// Note: We wait until we can send keystroke
// so we know the previous keystroke was
// sent.
usbPoll();
_delay_ms(5);
}
// This stops endlessly repeating keystrokes:
memset(reportBuffer, 0, sizeof(reportBuffer));
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
//private: TODO: Make friend?
uchar reportBuffer[2]; // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
};
DigiKeyboardDevice DigiKeyboard = DigiKeyboardDevice();
#ifdef __cplusplus
extern "C"{
#endif
// USB_PUBLIC uchar usbFunctionSetup
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (usbRequest_t *)((void *)data);
usbMsgPtr = DigiKeyboard.reportBuffer; //
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){
/* class request type */
if(rq->bRequest == USBRQ_HID_GET_REPORT){
/* wValue: ReportType (highbyte), ReportID (lowbyte) */
/* we only have one report type, so don't look at wValue */
// TODO: Ensure it's okay not to return anything here?
return 0;
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
// usbMsgPtr = &idleRate;
// return 1;
return 0;
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
}
}else{
/* no vendor specific requests implemented */
}
return 0;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __DigiKeyboard_h__
I had planned and some idea of how to implement things like double press vs long press vs single short press all without lots of delay. It had to do with using changes in the AD values to trigger events and use timers to allow other things to happen in the meantime. Also things such as two buttons pressed at the same time could potentially trigger an event.
Unfortunately I’ve abandoned this whole thing. Firstly I have a background in Car audio, so unlike many of you, I am used to a gaping hole in my dash. My stereo is in a state of flux while I come up with exactly what I want to do. Right now I enjoy just popping my Note2 on the dash and using it for my nav/music needs it allows me to keep my tablet in the house. I’m not saying the idea isn’t still great, nor that I don’t love it. If I was in Car Audio still, I would be using Nexus7’s in place of Alpine car stereos all day long.
Links:
http://www.Digistump.com buy your digispark here, Also the source of much of the code, software and info for making things work.
http://www.arduino.cc/ you’ll need the software, bare minimum. The Digispark page may walk you through installing it.
http://www.atmel.com/Images/Atmel-2...ller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf The chip used in this project is based on the ATtiny85. One can use an Arduino if they choose.
https://github.com/digistump/Digisp...er/libraries/DigisparkKeyboard/DigiKeyboard.h Bluebie’s Keyboard.h library.
https://github.com/Bluebie/micronucleus-t85 Bluebie’s bootloader which provides the USB funcitonality
http://www.obdev.at/products/vusb/index.html More info on using an AVR as a USB device
http://www.microchip.com/forums/m618147.aspx Use of a PIC microchip as a USB device
http://www.microchip.com/forums/m440956-print.aspx HID Audio Controler Usage table
http://www.freebsddiary.org/APC/usb_hid_usages.php USB Useage tables.
http://www.usb.org/developers/devclass_docs/Hut1_11.pdf More USB useage tables
http://forum.xda-developers.com/showthread.php?p=36930621 Tunner app for USB FM radio
https://droidperception.wordpress.com/2013/01/13/nexus-7-webcam-attached-update/ Info on using Extrernal USB Webcams
http://forum.xda-developers.com/showthread.php?t=2113259 A great thread on what can be done with a tablet in the car. He beat me to the install by just a month or two. He also was the reason I realized the limitation on the Charging while acting as a host.
Much of the code above is not my work. I made changes to it where I needed to but, specifically in the keybaord.h almost all of it is not mine. Credit goes to Bluebie and/or Digispark for the original work. If they would like me to remove the code, Please ask, I will. However since it's posted on Github I believe it's safe to post here.
I'm working on a way to adapted steering wheel controls on my mustang. But the issue is I have a base with no controls. I want swap out a premuim steering wheel to get this, but I have to have fords flash the acm for it to work. The issue is I still wont have controls for the tablet since mt car does not have bluetooth. So it will become costly. My solution is to use arduino or some other way to communicate with the factory HU. So im looking forward to this as a viable option.
Just an FYI, CM10-based kernel allows USB OTG and charging at the same time.
I've been on this hunt for a couple months now, albeit not hardcore. I have a rooted Galaxy Tab 2 7.0 that I'll be installing into an Infiniti G35. I would be more than happy to test stuff out for you if you want another guinea pig.
Pics to come
I'll post some pics from my installation so you can get an idea of what I did. Hopefully that and the code, etc will help you figure out how to do yours.
So hopefully Posting this will help some people get their own going. Here are the photos from the unit in my car.
My car has two sets of controls, first is the volume and channel buttons, second is the talk and navigate buttons. Also because I removed the complete Nav system the whole circuit was open. This gave me more options on how to do it, but I wen't with the more conventional. The Orange wire is going to ground. The Red and Yellow are each set of controls. The 1K resistors is a pull up resistor sourced from Vin on the digispark.
Hey joeavery2
thanks a lot for the hard work
If I am understanding the connections correctly, the tablet will draw the charge power from the USB Hub correct? If this is the case, is the tablet limited to 500mA charge current?
Hi guys i would ask your help. I have an Alfa Romeo Giulietta, Installed in the dash a nexus 7 2013 and I want use the steering wheel buttons. The car use the protocol is 15765-4 29bit and I have on Bluetooth obd reader. Can you please help me out? Thanks in advance.
Inviato dal mio FRD-L09 utilizzando Tapatalk

[GUIDE][TOOL][v1.2]-=Solved=-The Google Splash Sceen & Bootloader Graphics

Attempting to modify your bootloader may brick your device!!
Updated to v1.2: August 23rd, 2014
-Embedded a solid jpeg extractor in rlimager1.2.c (java is no longer needed)
-Added a zero byte function to fix the encoding of rgb0, bgr0, 0bgr, & 0rgb pixel formats​A while back I wanted to make a boot animation for my Nexus 7 2013, that utilized the Google splash screen in the first part of the bootanimation. I started searching Google and XDA, and found that it was embedded in the bootloader somewhere, but nobody had a clue how to retrieve it. I could see the battery charging icons with a hex editor and use FFmpeg to convert them from their encoded rgb24 pixel format into usable images. That was easy, but I couldn't find what I was looking for. I then figured they were in some odd pixel format, maybe even proprietary. I made loops going through every conceivable pixel format at different widths, generating 1000's of images, still nothing. The last thing I tried was making an image where every bit in the bootloader was translated into a pixel, either on or off, still nothing. I pretty much gave up, until I came across this thread. I had heard of run length encoding, but didn't know it was used in Android. I soon found that Google and some manufacturers were using it for the graphics in their bootloaders.
Hit the button below to see the splash screen for the Nexus 7 2013, this is a pixel for pixel exact image, with the Google logo and Unlock Icon in their un-encoded form as seen on the devices screen. (unfortunately the splash screen wasn't encoded as a complete image, the text was encoded one place and the lock icon in another, so I did have to use photoshop to make a 1200x1920 black background and place the Google logo and the lock icon in the right position.)
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
The complete Google splash screen in full 1200x1920 can be downloaded as an attachment at the bottom of this post. It is a PSD with a black background layer and the 518 pixel "Google" and the 72 pixel "unlock" all on separate layers.
The "Tool":
This is a Windows batch script I wrote to find images in any type of file. Included in the zip at the bottom of this post is: a modified run length encoder/decoder, rlimager1.2.c, that does the encoding/decoding and the extraction of jpegs from any type of file.
Rlimager1.2.c is based off of the original to565.c put out by the AOSP several years ago. To565 was made to convert an rgb24 image into a rgb565 run length encoded file which could then be named initlogo.rle, and packed into the boot image for a kernel splash screen. Of course having the ability to encode images in this format left users the want to decode them as well (to make sure it worked before they flashed it to their device). XDA user @zebarbu in this thread, made a program to decode rgb565 rle as well. I must credit both of these authors, as rlimager1.2.c is based off of both these programs.:good: I have added additional decoding/encoding of some newer formats; as mentioned below; as well as a jpeg extractor and a function to write 0's where ffmpeg will put 1's in the case of certain pixel formats.
The executable rlimager1.2.exe was compiled with mingw32-gcc 4.8.1 on a 64-bit Intel running Windows 7, and has been tested on Windows 7 Home Premium and Windows 8. The batch script, RUN_length_imager_v1.2.bat, will not work with obsolete versions of Windows. The source file for rlimager1.2.exe and RUN_length_imager_v1.2 batch script are available in the second post, as well as in the `src\` folder of the download. FFmpeg is also in the download, and the source can be found here, while the included pre-compiled version was downloaded at Zeranoe.
Googles ADB is also included in the download, which is located at the bottom of this post.
"Run_length_imager_v1.2.zip", should be unzipped into a new directory.
Click the button below for instructions on how to use rlimager1.2 by itself. Rlimager1.2 is a standalone command line program.
Usage:
rlimager1.2.exe ([-e] [2-4] | [-d] [2-4] [-m] [max run] [-o] [offset]) < input_file > output_file
Mandatory, one or the other
-d (2-4)Run Length Decode input_file from 2, 3, or 4 byte color pattern
-e (2-4) Run Length Encode input_file to 2, 3, or 4 byte color pattern
-j (output root name) Extract Jpegs from file. Output name can include a full path.
-z (skip) -o (offset) Zero every (skip) bytes, starting with (offset)
Optional for [-d] decoding only:
-m (max run) Maximum pixel run to decode. Default is 0, which defaults to the maximum allowable for each color pattern
-o (offset) Offset (in bytes) to start decoding. Default is 0
Examples:
rlimager1.2 -d 4 -m 8064 < "C:\example_file.rle" > "C:\output\rle_decoded\example_file.rgb0"
rlimager1.2 -j root_name < "C:\users\downloads\system.img"
Notice with the jpeg extractor example above you have to use: < "inputfile"
rlimager1.2 -z 8 -o 5 -i "C:\output\example_file.rle" -e 4 < "C:\example_file.rgb0" > "C:\output\example_file.rle"
The above example run length encodes the input file, then takes the output file and zeros every eighth byte starting at 5
You can also zero byte any file without doing it all on one line, like:
rlimager1.2 -z 5 -o 8 -i "C:\file_to_be_zeroed_every_5th_byte_strarting_with_the_8th.raw"​
To load a file into RUN_length_imager_v1.2.bat, you have two options:
-Drag and drop the file you wish to use onto the "RUN_length_imager_v1.2.bat" file.
-Run the program and choose option 4 at the menu. This will pull whichever partition you choose, from your device to your computer.
Note:
The second method requires you to have your ADB drivers for your device installed on your computer. You must also have busybox installed on your device. If for some reason ADB will not start and you end up with a blank partition list, simply close the program and open it back up and it should work. If it still doesn't work your ADB is probably not functioning correctly.​
First and foremost before you get too much into searching for run length encoded images, you should check for jpegs first, especially if you have a Samsung device. It is really fast, and all you have to do is drag the file onto the RUN_length_imager_v1.2.bat file and select option 8 at the main menu. In five seconds or less, if there are jpegs in the file, you will have all of them in their entirety.
What is run length encoding?
RLE is a method of encoding an image with the intentions of having a smaller filesize. If you have 1000 pixels of the exact same color, you can save memory, by instead of encoding (R,G,B) 1000 times; you can add a count before the pixel description, 1000 (R,G,B). This works real efficiently for images that have lots of pixel runs, but an image where every pixel is different actually will take more memory than your conventional method of storage.
The Run Length Patterns:
I have found three different run length patterns so far. The first is the original one mentioned up above, rgb565, or as I call it 2 byte. This format can be used to encode any pixel format that uses two bytes per pixel. It works like this, the first 2 bytes is the count and the next 2 bytes is the color. The M8 uses this encoding for its bootloader graphics.
Note:
When I say "can be used to encode any pixel format that uses two bytes per pixel", I really mean pixel formats with sequential pixels. Some pixel formats use the YUV colorspace. Not all formats stored in the YUV colorspace store the pixels sequentially. For instance some YUV pixel formats will take 6 bytes of data for 4 pixels, but the first 3 bytes are not just for the first 2 pixels.
In the RGB colorspace there are BAYER pixel formats which don't encode sequential pixels either, the colors are split onto different lines in this method. Neither of the previous examples are candidates for this type of run length encoding.​
The Nexus 5 and 4 use this next one, what I call 3 byte, because it can be used to encode any pixel format that uses...3 bytes per pixel. This encoding uses a 1 byte count and 3 byte color. This is easily the slowest method, for obvious reasons.
The last one, up to this point, is what I will reference as 4 byte. It works with four byte per pixel pixel formats, and uses 4 bytes for the count and 4 bytes for color. Both Nexus 7's use this format.
There may be more patterns, but it is hard to find partition dumps to download off the internet. I have found several though, and found run length encoded images in almost all of them. If anyone wants to upload a bootloader, I will gratefully add it to my collection and see what is in it.
This program will take any file, and decode it using whatever pixel format you choose, and if you have run length decoding turned on it will automatically associate the proper run length method to make a usable image, if there is one. Another important thing when dealing with raw image files, besides the pixel format, is the line length (width). This width is encoded in regular image files like bmp, jpg, and pngs. But raw images are nothing but pixel data. To get the correct image, if there is one, you have to specify when to go to the next line. I have built loops into the windows script that will let you specify multiple pixel formats to run, with an embedded loop that goes through all of the different widths you choose.
You may want to load a whole bootloader file to see if there are any images in it. To do so just drag and drop the file onto "RUN_length_imager.bat" Since the file contains different types of code and possibly images, you will want to set the maximum pixel count down to around 1000. This will limit the maximum number of a pixel run. This is necessary because not all of the data going through the decoder is meant to be run length decoded obviously, so FF FF FF FF 01 01 0A F0 in a 4 byte rle scheme will decode to over 16 gigabytes if you don't have your maximum pixel run set down to halt this.
Note:
You can stop the program at any time. I designed the program to save your settings before running and after changing anything. So if you accidentally don't set your max run and it seems like it is taking forever, and you are watching the output file size growing and growing, you can simply x out of it, or close it. Restart it and adjust whatever you have to.​Another variable is the byte offset. Since the very first count byte has to go into the decoder as the very first count byte, you may have to offset the whole file up to a certain number of bytes as specified below.
For 4 byte rle patterns offsets to be tried are 0,1,2,3,4,5,6,7.
For 3 byte rle patterns offsets to be tried are 0,1,2,3
For 2 byte rle patterns offsets to be tried are 0,1,2,3​
The last variable is the width. Hitting 2 in the program will allow you to set a range, or specific widths. Example: My Nexus 7 2013 bootloader has the Google logo as a 518 pixel wide image, the android as 712, the buttons as 1090, and some other things at 600 and 960. I would enter:
Code:
518 712 1090 600 960
You simply separate the different widths with spaces. You can't mess up, you can put whatever width (in any order) you want to in and it will make an image.
The second method is an exploratory method, where you enter the starting width, skips, ending width. All separated by commas.
Example:
Code:
712, 1, 1200
This will run through every width, incrementing by 1, from 712 pixels to 1200 pixels.
Note:
The height is automatically calculated based on the width, filesize, bytes per pixel. This happens at the core of the loops.​Click the button below to see what the entire Nexus 5 bootloader screen looks like when the bootloader "file" is loaded with these settings used: pixel format rgb24, max run 1080, offset 0, line length 1080. The image is really big, because the whole file is run length decoded.
After you click the button, scroll down and you will see the bootloader screen towards the bottom of the image.
This is the Nexus 4, whole bootloader, pixel format rgb24, max run 1080, offset 0, line length 720
After you click the button, scroll down and you will see the bootloader screen towards the bottom of the image.
You've Identified there are images, but how do you extract just the images?
You need a good hex editor, don't worry though because you don't have to look at any hex. I prefer 010 Editor by SweetScape Software. You get a free 30 day trial. Download it. Load your bootloader file into it by right clicking on the file and selecting "010 editor". If you don't have your bootloader file you can use option 4 in RUN_length_imager.bat and pull the partition from your device. If you don't know what partition you are looking for or how to do it manually, here is an excellent guide. If you use my script, the partition will be saved in the "__partitions__" folder.
Go up to View:
Set Left Area to Char
Set Right Area to Binary
Change Line Width to Custom Width
Choose a value where the characters on your left pane almost fill up your screen so that when you start scrolling over, your right pane (binary) is right there. The right binary pane is a lot wider, that's why I prefer it on the right. Also choose a width that is evenly divisible by 8, I set mine at 224, using a small 1366x768 laptop.​
A real handy shortcut in 010 editor is Ctrl + and Ctrl - to enlarge or shrink the font.​The 4 byte run length encoding is the easiest to identify because there is 4 bytes for the count, and the biggest number you can store into a 4 byte address is over 4 billion. The 3rd and 4th bytes are usually nothing but zeros. The only 4 byte pixel format I've seen used so far is, bgr0, which also has the fourth byte as nothing but 8 zeros. Here is what a typical looking 4 byte rle image looks like.
Notice how the count value, mostly, show up as just four periods ....
Sometimes the first byte (period) will be a different character representing a higher value for a run of same colored pixels. Also notice that there is a lot of black and white (gray) shades in the color values. All colors on a grey scale, represented in rgb, are equal values. A value of 255,255,255 is white 200,200,200 is a light shade of grey, and 0,0,0 is black. The rgb values will always be identical to be an exact shade of grey. This image is part of the Google logo which is mostly black and white.
Any area that you highlight in the "char" pane will also be highlighted in the "binary" pane when you scroll over, you'll find this extremely handy. These 8 bytes is one complete encoded run, which represents 15 pixels pure white. You can see exactly how the four count bytes sit beside the bgr0 color bytes. Byte 1 is 00001111, binarys equivalent to decimal 15. Bytes 2, 3, and 4 are 0; then the color bytes 5, 6, 7, 8. Blue is represented with the 5th byte, green the 6th, red the 7th, and the 8th byte is not used in this pixel format. Don't get confused about the pixel format, because this method of encoding will cover all 4 byte per pixel formats, some could use the 4th color byte (or alpha), and the order they're in is not that important right now. Unless you know exactly what you are looking for, like the infamous green android laying on its back, you may be trying to pay more attention to the green column when trying to find where the image starts or stops.
(This is the binary copy of the android image you see if you have a Nexus 7 2013)
(from Nexus 7 2013 bootloader)
This part can be kind of tricky, I actually surprised myself at how good I was at "getting lucky" and finding the correct beginning and ending of an image in the bootloader files. So that probably means that it really isn't that hard, it is just not something you encounter every day. Being aware of how your image should be encoded helps a lot. If you know there are 100's of black pixels at the start and/or end of an image, keep that in your mind when looking at the characters.
An image will never start or end with the count byte(s) as 00000000!!! But, often times they DO start or end after some zeros, or before some zeros at the end. Take for example: This is the beginning of one of the lock images. (notice how it is right after the text ANDROID BOOT, hmm)
(Keep in mind that this is a 4 byte pattern run length encoding, which actually will consume 8 bytes total per run. Four bytes for the count and four bytes for the color. The other two patterns look as you would think: 3 byte .### 2 byte ..##)
Notice how the count bytes before what I have highlighted in blue is all zeros. So you won't start there, move right and see what that is. And that is your image start, it is a run of 28 solid black pixels (0,0,0,0) Once you have identified the start, and hopefully selected it as I have in the screenshot, write down the number after "Start:" Which is 3097596.
This is the end of the lock. Notice the characters all of the sudden changing, this is an indication of a color change. I visually scanned line by line and found this spot that separated all the ÿÿÿ and ÀÀÀ's up above to the newer assortment of characters like ## and 33Ì
Now you need to isolate just that image. With those last 8 bytes selected, go up to Edit - Select Range, and down at the bottom of the screen, enter in the start byte you wrote down earlier. Hit enter and the encoded image will be selected. Copy this by hitting Ctrl-C or going up to Edit - Copy.
Go to File - New - New Hex File
Hit Ctrl-V to paste, or go to Edit - Paste
Now save that file somewhere, and drag and drop it onto "RUN_length_imager.bat"
I already knew the width of the image before writing this, but here is the output with the Line length set at 60,1,80 and pixel format bgr0
Notes:
You can also encode jpg, bmp, and png files into whatever 2, 3 or 4 byte pixel format you choose. The run length encoding will be automatically adjusted according to which pixel format you choose. When encoding images into the pixel format rgb0, bgr0, 0rgb ...
Any of those 4 byte formats. FFmpeg will put 11111111 in place of the zero in the zero byte position. I'm not sure why it doesn't put 00000000 like it should, but I know how to fix it, but it involves another option, and I haven't gotten to it yet. If you were to try writing this to your device, I have no idea how Android would treat this 11111111 in the null spot, because as far as I know rgb0 (and cousins) is a made up definition by the writers of FFmpeg to describe rgb24 as rgb32 with 8 bits per color, and 8 padding bits.
Nexus 5 & 4 use the pixel format rgb24. The whole bootloader screen is encoded in one pass, as opposed to drawing several images at different spots on the screen.
The Nexus 7 1 & 2 use the pixel format bgr0. It's kind of ironic that at first when I was looking for the Google logo, I thought it was entirely made up of black and white pixels and stored in an 1 = white 0 = black, binary format (that would account for no one being able to find it, unless you do like I did and use the monow or monob pixel format in FFmpeg), but in actuality the format that it is stored in can potentially contain billions of colors. (4 byte color)
The Nexus 7 2013 Unlock Icon has an extra white pixel at the bottom right that you can clearly see on the device, now that I told you it's there. Does it mean something, or is it just poor editing by the people at Google?
The Nexus 7 2013 has the Google logo encoded in 3 different places in the Bootloader. They are binary copies of each other, so that leads me to believe that the reason for this is to discourage people from trying to edit the images. Maybe you'd brick if you just changed one and not all three? I don't know, but can't think of any other reason why they would do this. There is also two unlock icons, not counting the big one on the bootloader screen that asks you if you're sure you want to unlock it.
The Nexus 7 2013 has the only bootloader, that I've encountered, that not only stores images in a 4 byte run length manner, but there are also non-encoded 3 byte rgb24 images for the battery icon, and charging icons. Even the older Nexus 7 has all of the images run length encoded.
Samsung bootloaders use jpegs, although I did find the Linux penguin, non-encoded in the Note 3. I also found the "font mask" that uses bits to make some different fonts stored as bit masks. You can see it, using the monow or monob pixel format and setting your width at 16 32.
The HTC M8 uses the pixel format rgb565. The only device I own is the second generation Nexus 7, and it is the only one where I have been through the bootloader with a purpose. Since I don't own a M8 I really kind of just glanced at it in the hex editor and found the exclamation triangle, the htc silver logo, and the android laying on its back; all run length encoded. It also has the bit mask font embedded in it for the text, as I mentioned about the Note 3.​I take no responsibility to any damage that is done to your device or computer with this program.
The source file and batch script can be found in the following post AND in the download!
Download Run Length Imager v1.2​
Changelog:
Current version 1.2
-Embedded a solid jpeg extractor (java is no longer needed)
-Added a zero byte function to fix the encoding of rgb0, bgr0, 0bgr, & 0rgb pixel formats
-Added and Output folder to contain made images
-Several other code modifications
v1.1
-Added a java jpeg extractor
-Click the button below to view the additional credits related to version 1.1
The java jpegextractor.java I found here! It was written back in 2002 by Marco Schmidt. I have slightly modified it by putting in a polarity counter that takes care of embedded jpegs, that otherwise will destroy the jpeg extraction process.
v1.0
-initial upload
More images:
Nexus 5
HTC M8
2013 Nexus 7 where you can see all three logos
RUN_length_imager_v1.2.bat
Code:
@echo off
setlocal enabledelayedexpansion
color 0b
set "vers=1.2"
title Run Length Imager v%vers%
set "device_dir=sdcard"
set "partitionfind=mmc"
set autozero=sure
set outfiletype=png
set autoopen=sure
set "outfilefolder=output"
set "loglevel=-loglevel debug"
set "hidebanner=-hide_banner"
set "adblog=>>"%~dp0sys\adb_log.txt" 2>&1"
set "ffmlog=>>"%~dp0sys\ffmpeg_log.txt" 2>&1"
IF "%~1"=="-d" (
set ffmlog=
set adblog=
set "loglevel=-loglevel debug"
set hidebanner=
mode con:cols=1000 lines=4000
color 07
shift
)
cd /d "%~dp0"
if not exist "%~dp0%outfilefolder%\" mkdir "%~dp0%outfilefolder%"
if exist "%~dp0sys\adb_log.txt" del /q "%~dp0sys\adb_log.txt"
if exist "%~dp0sys\ffmpeg_log.txt" del /q "%~dp0sys\ffmpeg_log.txt"
if exist "%~dp0sys\rli_log.txt" del /q "%~dp0sys\rli_log.txt"
if exist "%~dp0sys\needfiles" del /q "%~dp0sys\needfiles"
if not exist "%~dp0bin\ffmpeg.exe" echo.FFMPEG Program "%~dp0bin\ffmpeg.exe">>"%~dp0sys\needfiles"
if not exist "%~dp0bin\rlimager1.2.exe" echo.rlimager1.2.exe "%~dp0bin\rlimager1.2.exe">>"%~dp0sys\needfiles"
if exist "%~dp0sys\needfiles" goto :help
if not exist "%~dp0sys\definitions" call :make_definitions_file
if "[%~1]" neq "[]" if exist "%~1" echo.%1>"%~dp0sys\last_file"
if exist "%~dp0sys\settings" (call :load_settings) else (
set "maxcount=0"
set "offset=0"
set /a "bpp=4"
set "pixel_format=bgr0"
set "line_length=50,1,180"
set "rldecode_on=1"
call :save_settings
)
if exist "%~dp0sys\last_file" call :load_last_file
goto :menu
:help
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
echo.The following necessary file^(s^) are not found in their proper location:
echo.&echo.
type "%~dp0sys\needfiles"
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
pause>nul
goto :egress
:make_definitions_file
cls&echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
if not exist "%~dp0sys\" mkdir "%~dp0sys"
echo.Building FFmpeg Pixel Format List..
echo.This should only take a minute...&echo.
if exist "%~dp0sys\definitions" del /q "%~dp0sys\definitions"
echo.rgb565 2 >>"%~dp0sys\definitions"
echo.bgr565 2 >>"%~dp0sys\definitions"
for /f "skip=1 tokens=2" %%p in ('bin\ffmpeg -pix_fmts 2^>^&1^|findstr /rxic:"^I.*"') do (
%ffmlog%"%~dp0bin\ffmpeg.exe" -f rawvideo -s 1x1 -pix_fmt rgba -i "%~dp0sys\getres" -f rawvideo -s 1x1 -pix_fmt %%p -y "%~dp0sys\%%p"
for %%? in ("%~dp0sys\%%p") do if not "%%~z?"=="0" set /a bval=%%~z?/3&echo.%%~n? !bval!>>"%~dp0sys\definitions"
del /q "%~dp0sys\%%p"
)
echo.Finished!&call :load_settings
goto :eof
:make_images
call :drawhead
call :drawsettings
if defined list (set "for_type=for /l") else (set "for_type=for")
for %%p in (%pixel_format%) do (
call :setbpp %%p
if "!rldecode_on!"=="1" (
set "out_file=decoded_raw_!bpp!_byte_%in_filename%"
set "out_path=%~dp0%outfilefolder%\%in_filename%_max_%maxcount%_offset_%offset%"
if not exist "!out_path!\" mkdir "!out_path!"
if not exist "!out_path!\!out_file!" (echo.Decoding !bpp! byte rle)&("%~dp0bin\rlimager1.2.exe" -d !bpp! -m %maxcount% -o %offset% < %file% > "!out_path!\!out_file!")||(call :rli_help&goto :menu)
for %%? in ("!out_path!\!out_file!") do set /a "out_filesize=%%~z?"
if not exist "!out_path!\%%p\" mkdir "!out_path!\%%p"
if defined autoopen start "" "!out_path!\%%p\"
%for_type% %%R in (%line_length%) do (
set /a height=!out_filesize!/%%R/!bpp!
echo.Using ffmpeg to generate %%Rx!height! image from %%p pixel format.
if !height! NEQ 0 %ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -f rawvideo -vcodec rawvideo -pix_fmt %%p -s %%Rx!height! -i "!out_path!\!out_file!" -vframes 1 -y "!out_path!\%%p\%%Rx!height!.%outfiletype%"
)
) else (
set "out_path=%~dp0%outfilefolder%\%in_filename%_no_rldecode\%%p"
if not exist "!out_path!\" mkdir "!out_path!"
if defined autoopen start "" "!out_path!\"
%for_type% %%R in (%line_length%) do (
set /a height=!in_filesize!/%%R/!bpp!
if /i "%%p"=="monow" set /a height*=8
if /i "%%p"=="monob" set /a height*=8
echo.Using ffmpeg to generate %%Rx!height! image from %%p pixel format.
if !height! NEQ 0 %ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -f rawvideo -vcodec rawvideo -pix_fmt %%p -s %%Rx!height! -i %file% -vframes 1 -y "!out_path!\%%Rx!height!.%outfiletype%"
)
)
if "!auto_turn_back_on!"=="1" (set "rldecode_on=1"&set auto_turn_back_on=)
)
goto :eof
:rle_image
set "out_path=%outfilefolder%\Run Length Encoded_%in_filename%"
for %%p in (%pixel_format%) do (
call :setbpp %%p
if "%%p"=="rgb0" (set "zoffset=8"&set "zero=8")
if "%%p"=="0rgb" (set "zoffset=5"&set "zero=8")
if "%%p"=="bgr0" (set "zoffset=8"&set "zero=8")
if "%%p"=="0bgr" (set "zoffset=5"&set "zero=8")
set "out_file=encoded_raw_!bpp!_byte_%in_filename%"
if not exist "%~dp0!out_path!\" mkdir "%~dp0!out_path!\"
%ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -i %file% -f rawvideo -vcodec rawvideo -pix_fmt %%p -y "%~dp0!out_path!\raw_%%p"
if defined autozero (echo.Encoding !bpp! byte rle&"%~dp0bin\rlimager1.2.exe" -z 8 -o !zoffset! -i "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format" -e !bpp! < "%~dp0!out_path!\raw_%%p" > "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format"||(call :rli_help&goto :menu)
) else (echo.Encoding !bpp! byte rle&"%~dp0bin\rlimager1.2.exe" -e !bpp! < "%~dp0!out_path!\raw_%%p" > "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format"||(call :rli_help&goto :menu))
set zoffset=&set zero=
)
if defined autoopen start "" "%~dp0!out_path!\"
goto :eof
:rli_help
echo.There was a problem encoding^/decoding the file:&echo.%file%
echo.Bpp is: %bpp%&echo.Pixel format is: %pixel_format%&echo.Offset is: %offset%
echo.Max run is: %maxcount%&echo.Width is: %line_length%&echo.Working file name is: %in_filename%&echo.&pause >nul
goto :eof
:load_last_file
set "encode="
set /p file=<"%~dp0sys\last_file"
for %%? in (%file%) do set /a "in_filesize=%%~z?" &set "in_filename=%%~n?" &set "ext=%%~x?"
if [%ext%]==[] goto :eof
if "%ext%"==".jpg" set "encode=true"
if "%ext%"==".png" set "encode=true"
if "%ext%"==".bmp" set "encode=true"
if "%ext%"==".jpeg" set "encode=true"
goto :eof
:load_settings
<"%~dp0sys\settings" (
set /p pixel_format=
set /p bpp=
set /p offset=
set /p maxcount=
set /p line_length=
set /p rldecode_on=
)
set /a bpp
echo.%line_length%|findstr ".*,.*,"&&set "list=1"||set list=
goto :eof
:save_settings
>"%~dp0sys\settings" (
echo.%pixel_format%
echo.%bpp%
echo.%offset%
echo.%maxcount%
echo.%line_length%
echo.%rldecode_on%
)
goto :eof
:menu
set auto_turn_back_on=&call :load_last_file&call :drawhead&call :drawsettings
echo.&echo.&echo.1 - Make Image(s)
echo.&echo.2 - Change Output Line Length ^(width^)
echo.&echo.3 - Change Pixel Format
echo.&echo.4 - Use ADB To List/Pull A Partition
echo.&if defined rldecode_on (echo.5 - Turn Off Run Length Decoding) else (echo.5 - Turn On Run Length Decoding)
echo.&if defined rldecode_on (echo.6 - Change Offset) else (echo. - - Change Offset ^(run length decoding is off^))
echo.&if defined rldecode_on (echo.7 - Change Max Run Length) else (echo. - - Change Max Run Length ^(run length decoding is off^))
echo.&if defined encode (echo.8 - Encode image) else (echo.8 - Extract Jpgs From File)
echo.&echo.9 - Exit&echo.
choice /n /m "Select A Menu Number:" /C:123456789
if errorlevel 1 set k=1
if errorlevel 2 set k=2
if errorlevel 3 set k=3
if errorlevel 4 set k=4
if errorlevel 5 set k=5
if errorlevel 6 set k=6
if errorlevel 7 set k=7
if errorlevel 8 set k=8
if errorlevel 9 set k=9
if %k%==1 call :make_images
if %k%==8 if "%encode%"=="true" (call :rle_image) else (call :jextract %file%)
if %k%==4 call :getpartitions
if %k%==3 call :change_pf
if %k%==2 call :change_line_length
if %k%==5 call :rle_toggle
if %k%==6 if defined rldecode_on call :change_offset
if %k%==7 if defined rldecode_on call :change_max_run
if %k%==9 goto :egress
goto :menu
:jextract
call :drawhead&call :drawsettings
set "out_path=%~dp0%outfilefolder%\%in_filename%_extracted_jpgs"
if not exist "%out_path%\" mkdir "%out_path%"
echo.&echo.Working...
"%~dp0bin\rlimager1.2.exe" -o %offset% -j "%out_path%\%in_filename%" <%file%
if defined autoopen start "" "%out_path%\"
echo.&echo.&echo Press any key to continue to the main menu..
pause>nul
goto :eof
:change_max_run
call :drawhead&call :drawsettings
echo.over 4 billion times. With a 3 Bpp rle pattern the highest value 0xFF will repeat the
echo.pixel 255 times maximum. And with a 2 Bpp rle pattern the value 0xFFFF will repeat
echo.a pixel 65535 times.&echo.
echo.When searching this way you need to set the max pixel run count to around ~1000-2000 to avoid
echo.unusable image files that can take forever to generate.&echo.
echo.Just press enter for a default value of 0 which will let the decoding process run its
echo.natural course.&echo.
set /p maxcount=Max pixel run:||set "maxcount=0"
call :save_settings
goto :eof
:change_offset
call :drawhead&call :drawsettings
echo.Enter the byte offset for the file.&echo.
echo.This should always be 0 when dealing with pure rle image files.
echo.The reason it is in here is because if you load an entire file with data/images all
echo.mixed together; the start of the Pixel count read for an image might just not be in
echo.the right spot, and the count will be read as color data instead of count data, resulting
echo.in really long^/short runs and no image. If using a whole partition^/file and a standard
echo.0 as the offset at several resolutions isn't generating the image you are looking for,
echo.taking the offset up, 1 by 1 until you get to 7 for 4 Bpp raw files, or an offset of
echo.3 for 2 ^& 3 Bpp raw files. It is advised to set your max pixel run count to ^~1000-2000
echo.when searching through complete files/partitions like this.&echo.
echo.This is the same thing as deleting "x" bytes from the beginning of the file.&echo.
echo.If you are using an image that starts with the count byte^(s^) at byte 1 in the file, then
echo.you don't have to worry about it.&echo.
echo.Just press enter for the default offset of 0.&echo.
set /p offset=Offset:||set "offset=0"
call :save_settings
goto :eof
:egress
"%~dp0bin\adb.exe" kill-server>nul 2>&1
endlocal&exit
goto :eof
:rle_toggle
if defined rldecode_on (set rldecode_on=) else (set "rldecode_on=1")
call :save_settings
goto :eof
:change_pf
:keepitinthecall
call :drawhead
call :drawsettings
echo.Enter the pixel format to use. The run length decoder will automatically adjust format accordingly.
echo.You may enter multiple pixel formats, but of course if will take longer and produce double the
echo.images if you enter two, or triple if you choose three. If you enter multiple pixel formats
echo.seperate them with a space or a comma. The bytes per pixel number seen at the top of the screen
echo.will only reflect the correct value when one pixel format is chosen, this however will have
echo.no bearing when you go to make images as the bpp is determined before each set of images is made.&echo.
echo.Note that any pixel format over 4 bytes per pixel will probably never be used in Android, for the
echo.purpose of displaying a static image at least.
echo.Threre is no run length decoding of those pixel formats over 4 bytes per pixel as of right now.&echo.
echo.The ones listed below, grouped by their bytes per pixel, are some of the more common pixel formats.
echo.Hit enter to see all input formats available with your FFmpeg build.
echo.&echo.Enter pixel formats in LOWER CASE ONLY.&echo.
echo.Enter "build" if you have updated your ffmpeg, and would like to update the pixel formats also.&echo.
echo.Enter "show" to show available pixel formats with your ffmpeg build.
echo.Common 2 Bpp android pixel formats ^[rgb565le, bgr565le^]
echo.Common 3 Bpp android pixel formats ^[rgb24, bgr24^]
echo.Common 4 Bpp android pixel formats ^[rgb0, 0rgb, 0bgr, bgr0, rgba, argb, abgr, bgra^]&echo.
set "old=%pixel_format%"
set /p pixel_format=Pixel format^(s^):||goto :eof
if /i "%pixel_format%"=="build" (set "pixel_format=%old%"&call :make_definitions_file&goto :keepitinthecall)
if /i "%pixel_format%"=="show" (set "pixel_format=%old%"&call :show_pixel_formats&goto :keepitinthecall)
call :setbpp %pixel_format%
call :save_settings
goto :eof
:setbpp
for /f "tokens=1,2" %%a in ('type "%~dp0sys\definitions"') do if /i "%~1"=="%%a" set /a "bpp=%%b"
if %bpp% GEQ 5 if defined rldecode_on (set "auto_turn_back_on=1"&set rldecode_on=)
if %bpp% EQU 1 if defined rldecode_on (set "auto_turn_back_on=1"&set rldecode_on=)
call :save_settings
goto :eof
:show_pixel_formats
cls&echo.Input pixel formats supported with your FFmpeg build:
for /f "skip=1 tokens=2,4" %%A in ('bin\ffmpeg -pix_fmts 2^>^&1^|FINDSTR /rxic:"^I.*"') DO echo.%%A--- %%B ^<^<^<BITS per pixel
echo.&echo.Press enter to continue...
pause>nul
goto :eof
:drawsettings
echo.Working Name: %in_filename%&echo.File Name: %file%&echo.Size: %in_filesize% bytes
echo.__________________________________&echo.______________________________________&echo.
echo.Pixel Format: %pixel_format%&echo.Line Length: %line_length%
if defined rldecode_on (
echo.Rle Format: %bpp% byte pp&echo.Max Run Length: %maxcount% pixels
echo.Offset: %offset%) else (echo.&echo.Run Length Decoding Is Turned Off.&echo.)
echo.______________________________________&echo.
goto :eof
:change_line_length
call :drawhead&call :drawsettings
echo.Enter the line length ^(width^) that you want to use. You can enter several, SEPERATED BY SPACES;
echo.or you can use a range SEPERATED BY COMMAS, in this format: start resolution, skips, ending resolution.&echo.
echo.Example: If you want to use the widths of 150 25 3000 400 98 16. You would enter in any order:
echo.150 25 3000 400 16 98&echo.
echo.Example: If you want a line length starting at 100 pixels going to 1200 pixels, while skipping to every
echo.10th pixel. You would enter:
echo.100,10,1200&echo.
set /p "line_length=Line length:"
echo.%line_length%|findstr ".*,.*,.*"&&set "list=1"||set list=
call :save_settings
goto :eof
:drawhead
cls&echo.&echo.___________________________________-_-
echo.__________________________________&echo.&echo.Run Length Imager: v%vers% by makers_mark
echo.__________________________________&echo.______________________________________&echo.
goto :eof
:getpartitions
if not exist "%~dp0partitions\" mkdir "%~dp0partitions"
call :drawhead&set /a index=1
"%~dp0bin\adb.exe" -d start-server
if %ERRORLEVEL% GTR 0 call :adb_error&goto :eof
for /f "skip=1 tokens=3,4" %%s in ('bin\adb.exe -d shell cat /proc/partitions^|findstr /rxic:".*%partitionfind%.*"') do (
if not "%%s"=="" (call set /a "_size[!index!]=%%s"&&call set "_partition[!index!]=%%t") else (set /a index=1)
call set /a index+=1
)
if %ERRORLEVEL% GTR 0 call :adb_error&goto :eof
set /a index-=1
echo. Partition Size&echo.
for /l %%c in (1,1,%index%) do (
if %%c LSS 10 (echo. %%c. !_partition[%%c]! !_size[%%c]!) else (
echo.%%c. !_partition[%%c]! !_size[%%c]!)
)
echo.&echo.If you want to pull one of these partitions from your device, enter the number
echo.to the left of it and press enter. Just press enter to go back to the Main Menu&echo.
set /p _pick=:||goto :eof
2>nul set /a _pick=%_pick%/1 || GOTO :eof
IF %_pick% LSS 1 GOTO :eof
if %_pick% GTR %index% goto :eof
cls&echo.&echo.&echo.WARNING: WARNING: WARNING: WARNING: WARNING:&echo.WARNING: WARNING: WARNING: WARNING: WARNING:
echo.WARNING: WARNING: WARNING: WARNING: WARNING:&echo.WARNING: WARNING: WARNING: WARNING: WARNING:&echo.&echo.&echo.&echo.&echo.
echo.Issuing this command:&echo.
call echo.bin^\adb.exe -d shell dd if^=^/dev^/block^/%%_partition[!_pick!]%% of^=^/%device_dir%^/%%_partition[!_pick!]%%
echo.&echo.PLEASE READ THIS TWICE....&echo.
echo.DD is a VERY powerful tool, and if the output directory^/file; listed after ^"of^=^" is not the
echo.name of the partition you chose to pull, DO NOT CONTINUE. If you are not sure what you are doing;
echo.what this command is, or what you are even looking at. DO NOT CONTINUE.&echo.
set "guess=%random%"
echo.Enter this number to continue: %guess%
echo.&set /p answer=:||goto :eof
if not "%guess%"=="%answer%" goto :eof
echo.&echo.Copying data into a file on your device...
call echo."%~dp0bin\adb.exe" -d shell "dd if=/dev/block/%%_partition[!_pick!]%% of=/%device_dir%/%%_partition[!_pick!]%%"|cmd /v:on%adblog%&&echo.&&echo.Copying file from your device to your computer...&&call echo."%~dp0bin\adb.exe" -d pull "/%device_dir%/%%_partition[!_pick!]%%" "%~dp0partitions\%%_partition[!_pick!]%%"|cmd /v:on%adblog%&&echo.&&echo.Deleting the file from your device...&&call echo."%~dp0bin\adb.exe" -d shell rm "/%device_dir%/%%_partition[!_pick!]%%"|cmd /v:on%adblog%
call echo."%~dp0partitions\%%_partition[!_pick!]%%">"%~dp0sys\last_file"
echo.&echo.&echo.Finished. The partition has been loaded and is saved as:&echo.&call echo."%~dp0partitions\%%_partition[!_pick!]%%"&echo.&echo.Press any key to continue.
call :save_settings
pause>nul
goto :eof
:adb_error
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
echo. ADB is not connected, working properly, or you have
echo. more than one device connected.
echo. Try "Safely Removing" your device from your computer.
echo. Then unplug your usb cable, and reinsert it.
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
pause>nul
goto :eof
rlimager1.2.c
C:
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
& NOTICE:
& May 5th, 2014
&
& makers_mark @ xda-developers.com
& http://forum.xda-developers.com/showthread.php?t=2764354
&
& Original source:
& https://android.googlesource.com/platform/build/+/b6c1cf6de79035f58b512f4400db458c8401379a/tools/rgb2565/to565.c
& Based off of the original to565.c program to convert raw rgb888 r=8 g=8 b=8 images
& to, 2 byte count, 2 byte color run length encoded rgb565 r=5 g=6 b=5 files.
& Mainly, if not always to my knowledge, used for creating initlogo.rle files for kernel splash
& screens.
&
& Added decoding of 2, 3, and 4 byte rgb(x) patterns
& Added encoding of 3 and 4 byte rgb(x) patterns
& Added byte offsets and maximum pixel runs for decoding files not totally
& encoded in a run length manner
& Version 1.2 added:
& Jpeg extractor, to pull jpegs from any file or drive/device image
& A zero byte writer, to undo what ffmpeg does to rgb0, 0rgb, bgr0, and 0bgr pixel formats
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
unsigned int _CRT_fmode = _O_BINARY;
static char fileName[1024];
void zeroBytes(long long, long, char *);
void jpegExtract(char *, unsigned long long);
void headerToFooter(int);
int getFilename(char *);
void decode_rgb16_rle(unsigned int, unsigned long long int);
void decode_rgb24_rle(unsigned int, unsigned long long int);
void decode_rgbx32_rle(unsigned long int, unsigned long long int);
void encode_rgb16_rle(void);
void encode_rgb24_rle(void);
void encode_rgbx32_rle(void);
void zeroBytes(long long offset, long z, char *inputFile)
{
int readByte;
FILE *zeroStream;
FILE *inStream;
long long int cursorPosition;
char outputFile[1024];
sprintf(outputFile, "%s.zero", inputFile);
if ((inStream = fopen(inputFile, "rb")) == NULL){
fclose(inStream);
return;
}
if ((zeroStream = fopen(outputFile, "wb")) == NULL){
fclose(inStream);
fclose(zeroStream);
return;
}
fprintf(stderr,"\nZeroing every %ld bytes starting at %lld", z, offset);
fprintf(stderr,"\nInput file: %s", inputFile);
while ((readByte = fgetc(inStream)) != EOF){
cursorPosition = ftell(inStream);
if (((cursorPosition - offset) % z) == 0 && cursorPosition >= offset){
fputc(0,zeroStream);
}else{
fputc(readByte,zeroStream);
}
}
fclose(inStream);
fclose(zeroStream);
}
void jpegExtract(char outname[1024], unsigned long long o)
{
int readByte;
FILE *fileStream;
unsigned int header;
if (o != 0){
fseek(stdin, o, SEEK_SET);
}
while ((readByte = fgetc(stdin)) != EOF){
if (readByte == 0xff){
readByte = fgetc(stdin);
if (readByte == 0xd8){
readByte = fgetc(stdin);
if (readByte == 0xff){
readByte = fgetc(stdin);
if (readByte == 0xe0 || readByte == 0xe1){
header = 0x00ffd8ff | (readByte << 24);
if (!getFilename(outname)){
if ((fileStream = fopen(fileName, "wb")) == NULL){
fclose(fileStream);
return;
}
int streamNumber = fileno(fileStream);
fprintf(stderr, "\n%s", fileName);
write(streamNumber, &header, 4);
headerToFooter(streamNumber);
close(streamNumber);
continue;
}else{
break;
}
}
}
}
}
}
fclose(stdin);
}
void headerToFooter(int streamNumber)
{
short notFinished = 1;
int polarity = 1;
int readByte;
while((readByte = fgetc(stdin)) != EOF){
if (readByte == 0xff){
readByte = fgetc(stdin);
if (readByte == EOF){
readByte = 0xff;
write(streamNumber, &readByte, 1);
break;
}else if (readByte == 0xd8){
polarity += 1;
readByte = 0xd8ff;
write(streamNumber, &readByte, 2);
}else if (readByte == 0xd9){
polarity -= 1;
readByte = 0xd9ff;
write(streamNumber, &readByte, 2);
if (polarity == 0){
break;
}
}else{
readByte = 0x00ff | (readByte << 8);
write(streamNumber, &readByte, 2);
}
}else{
write(streamNumber, &readByte, 1);
}
}
}
int getFilename(char outputbase[1024])
{
unsigned int counter;
FILE *stream;
for (counter = 1; counter <= 99999; counter++){
sprintf(fileName, "%s_%05d.jpg", outputbase, counter);
if ((stream = fopen(fileName, "r+")) != NULL){
fclose(stream);
continue;
} else {
fclose(stream);
return(0);
}
}
fclose(stream);
return(1);
}
void decode_rgb16_rle(unsigned int m, unsigned long long int o)
{
unsigned short data[2], repeats;
if (o != 0){
fseek(stdin, o, SEEK_SET);
}
while(read(0,data,4) == 4){
if (data[0] > m){
continue;
}
for (repeats = 0; repeats < data[0]; repeats++){
write(1, &data[1], 2);
}
}
}
void decode_rgb24_rle(unsigned int m, unsigned long long int o)
{
unsigned char repeats, data[4];
unsigned long color;
if (o != 0){
fseek(stdin, o, SEEK_SET);
}
while(read(0, data, 4) == 4){
if (data[0] > m){
continue;
}
color = ((data[1]) | (data[2] << 8) | (data[3]) << 16);
for (repeats = 0;repeats < data[0]; repeats++){
write(1, &color, 3);
}
}
}
void decode_rgbx32_rle(unsigned long int m, unsigned long long int o)
{
unsigned long repeats;
unsigned long data[2];
if (o != 0){
fseek(stdin, o, SEEK_SET);
}
while(read(0, data, 8) == 8){
if (data[0] > m){
continue;
}
for (repeats = 0; repeats < data[0]; repeats++){
write(1, &data[1], 4);
}
}
}
void encode_rgbx32_rle(void)
{
unsigned long color, last, count;
count = 0;
while(read(0, &color, 4) == 4){
if (count){
if ((color == last) && (count != 0xFFFFFFFF)){
count++;
continue;
} else {
write(1, &count, 4);
write(1, &last, 4);
}
}
last = color;
count = 1;
}
if (count){
write(1, &count, 4);
write(1, &last, 4);
}
}
void encode_rgb16_rle(void)
{
unsigned short int last, color, count;
count = 0;
while(read(0, &color, 2) == 2){
if (count){
if ((color == last) && (count != 0xFFFF)){
count++;
continue;
} else {
write(1, &count, 2);
write(1, &last, 2);
}
}
last = color;
count = 1;
}
if (count){
write(1, &count, 2);
write(1, &last, 2);
}
}
void encode_rgb24_rle(void)
{
unsigned char count;
unsigned long int last, color;
count = 0;
while(read(0, &color, 3) == 3){
if (count){
if ((color == last) && (count != 0xFF)){
count++;
continue;
} else {
write(1, &count, 1);
write(1, &last, 3);
}
}
last = color;
count = 1;
}
if (count){
write(1, &count, 1);
write(1, &last, 3);
}
}
int usage(void){
fprintf(stderr, "\n\n\nUsage:\n\nrlimager.exe ([-e] [2-4] | [-d] [2-4] [-m] [max run] [-o] [offset]) < input_file > output_file\n\n");
fprintf(stderr, "Mandatory, one or the other\n\n");
fprintf(stderr, "-d (2-4) Run Length Decode input_file from 2, 3, or 4 byte color pattern\n");
fprintf(stderr, "-e (2-4) Run Length Encode input_file to 2, 3, or 4 byte color pattern\n");
fprintf(stderr, "-j (output root name) Extract Jpegs from file. Output name can include a full path.\n");
fprintf(stderr, "-z (skip) -o (offset) Zero every (skip) bytes, starting with (offset)\n\n");
fprintf(stderr, "Optional for [-d] decoding only:\n\n");
fprintf(stderr, "-m (max run) Maximum pixel run to decode. Default is 0, which defaults to the maximum allowable for each color pattern\n");
fprintf(stderr, "-o (offset) Offset (in bytes) to start decoding. Default is 0\n");
fprintf(stderr, "\n\nExamples:\n\nrlimager1.2 -d 4 -m 8064 < \"C:\\example_file.rle\" > \"C:\\output\\rle_decoded\\example_file.rgb0\"\n");
fprintf(stderr, "rlimager1.2 -j root_name < \"C:\\users\\downloads\\system.img\"\n\n");
fprintf(stderr, "Notice with the jpeg extractor example above you have to use: < \"inputfile\"\n\n");
fprintf(stderr, "rlimager1.2 -z 8 -o 5 -i \"C:\\output\\example_file.rle\" -e 4 < \"C:\\example_file.rgb0\" > \"C:\\output\\example_file.rle\"\n\n");
fprintf(stderr, "The above example rle encodes the input file, then takes the output file and zeros every eighth byte starting at 5\n");
fprintf(stderr, "You can also zero byte any file without doing it all on one line, like:\n\n");
fprintf(stderr, "rlimager1.2 -z 5 -o 8 -i \"C:\\file_to_be_zeroed_every_5th_byte_strarting_with_the_8th.raw\"\n");
return(1);
}
int main(int argc, char **argv)
{
unsigned int decode_opt = 0, encode_opt = 0;
unsigned long long int maxrun = 0;
long long int offset = 0;
long zeroByte = 0;
short jflag = 0;
char *d_string, *e_string, *m_string, *o_string, *j_string, *z_string, *inputFile;
int c;
while ((c = getopt (argc, argv, "i:z:j:m:o:e:d:")) != -1)
switch(c)
{
case 'i':
inputFile = optarg;
break;
case 'z':
z_string = optarg;
zeroByte = atol(z_string);
break;
case 'j':
jflag = 1;
j_string = optarg;
break;
case 'm':
m_string = optarg;
maxrun = atoll(m_string);
break;
case 'o':
o_string = optarg;
offset = atoll(o_string);
break;
case 'e':
e_string = optarg;
encode_opt = atoi(e_string);
break;
case 'd':
d_string = optarg;
decode_opt = atoi(d_string);
break;
}
if ((encode_opt > 1) && (encode_opt < 5)){
if (maxrun != 0 || decode_opt != 0){
usage();
return(1);
}
if (encode_opt == 2){
encode_rgb16_rle();
return(0);
}
if (encode_opt == 3){
encode_rgb24_rle();
}
if (encode_opt == 4){
encode_rgbx32_rle();
}
if (zeroByte){
zeroBytes(offset, zeroByte, inputFile);
}
return(0);
} else if (zeroByte){
zeroBytes(offset, zeroByte, inputFile);
return(0);
} else if ((decode_opt > 1) && (decode_opt < 5)){
if (encode_opt != 0){
usage();
return(1);
}
if (decode_opt == 2){
if (maxrun == 0){
maxrun = 0xFFFF;
}
fprintf(stderr, "Maximum pixel run set at %d\n",maxrun);
decode_rgb16_rle(maxrun, offset);
return(0);
}
if (decode_opt == 3){
if (maxrun == 0){
maxrun = 0xFF;
}
fprintf(stderr, "Maximum pixel run set at %d\n",maxrun);
decode_rgb24_rle(maxrun, offset);
return(0);
}
if (decode_opt == 4){
if (maxrun == 0){
maxrun = 0xFFFFFFFF;
}
fprintf(stderr, "Maximun pixel run set at %lld\n",maxrun);
decode_rgbx32_rle(maxrun, offset);
return(0);
}
return(0);
} else if (jflag){
jpegExtract(j_string, offset);
} else usage();
return(1);
}
@makers_mark
Very nice work! This is actually more interesting than it seem. It's also a way to inspect binary code in unknown blobs. Another thing to notice is that you can probably automate the correct image size, for images that you know contain vertical lines. If you look at the padlock image sequence, you see that the images contain parts that are "sloping" either upward or downward, this can be used to look for the correct direction to increment/decrement the size counter.
So if you remember your basic math for the slope of a line:
m = Δy/Δx = (y2 - y1)/(x2 - x1)
you can plug some pixel values in and get the slope, and subsequently the direction for the counter.
Obviously the most difficult part will be to detect what is a "line" when there are other pixels there.
E:V:A said:
@makers_mark
Very nice work! This is actually more interesting than it seem. It's also a way to inspect binary code in unknown blobs. Another thing to notice is that you can probably automate the correct image size, for images that you know contain vertical lines. If you look at the padlock image sequence, you see that the images contain parts that are "sloping" either upward or downward, this can be used to look for the correct direction to increment/decrement the size counter.
So if you remember your basic math for the slope of a line:
m = Δy/Δx = (y2 - y1)/(x2 - x1)
you can plug some pixel values in and get the slope, and subsequently the direction for the counter.
Obviously the most difficult part will be to detect what is a "line" when there are other pixels there.
Click to expand...
Click to collapse
Thank you, you can imagine my excitement the first time I had the logo I was looking for come across my screen
I was trying to think of a way to automatically choose "the right image", but cognitive dissonance kicked in and I figured that people would rather see lots of images. Kind of kidding, but I wanted it to work for almost all images, and my expectations kept leading me back to nothing.
Here is something, i forgot to mention, I found this is in the n72013 4.02 bootloader that I don't ever remember seeing on the device. It is the ASUS logo, with their slogan underneath it. But it is not all there, I've checked and checked and this is how it is in the hex editor too. It is located at the very bottom, right about the last Google logo, width is 600.
^^ And as you see above, the sloping lines is probably the remainder of the "missing" pieces. For some reason the image has been split and pieces moved around, just like for any other file. This is probably because you have extracted this as a blob from memory or EMMC in which case these pieces may have been shuffled around by internal MMC wear leveling. But the way these pieces are linked together should be via inodes and you'll need some better tools to read these. (It should be some kind of address immediately following an incomplete image.) Another possibility could be that the screen driver FW like to read images in pieces...
E:V:A said:
^^ And as you see above, the sloping lines is probably the remainder of the "missing" pieces. For some reason the image has been split and pieces moved around, just like for any other file. This is probably because you have extracted this as a blob from memory or EMMC in which case these pieces may have been shuffled around by internal MMC wear leveling. But the way these pieces are linked together should be via inodes and you'll need some better tools to read these. (It should be some kind of address immediately following an incomplete image.) Another possibility could be that the screen driver FW like to read images in pieces...
Click to expand...
Click to collapse
I was thinking that this data was from the factory download, but I just checked and you are indeed right. It is not in the bootloader.img from google, but only on my mmcblk0p12. As for the white lines surrounding it, the bottom lines are the Google logo (at 518 pixels) and the upper white areas are the up/down arrows and the second unlock icon. Your point was still well received! And thanks for your insight:good:
Here is the same image (I cropped out the upper irrelevant stuff, but the same data) at 518 width.
If you haven't read it yet, try a search for ARM_ELF.pdf
If the partition you're reading (like a boot.img) is an ELF file it will give you the offsets for the start of files (that's how I found my systems initial splash image) and the byte size for that file and any other files in that partition ie. Boot code, splash screen, text data.
Throw a boot.img/recovery.img into a hex editor (I use HxD) and alter the displayed byte count from standard 8/16/32 etc to 320 (or your screens pixel width) and scroll through and you'll see the data layout roughly of your splash screen (really basic way to find it)
Bashing away at my HTC Desire C
Antagonist42 said:
If you haven't read it yet, try a search for ARM_ELF.pdf
If the partition you're reading (like a boot.img) is an ELF file it will give you the offsets for the start of files (that's how I found my systems initial splash image) and the byte size for that file and any other files in that partition ie. Boot code, splash screen, text data.
Throw a boot.img/recovery.img into a hex editor (I use HxD) and alter the displayed byte count from standard 8/16/32 etc to 320 (or your screens pixel width) and scroll through and you'll see the data layout roughly of your splash screen (really basic way to find it)
Bashing away at my HTC Desire C
Click to expand...
Click to collapse
If only it would of been that easy...
But, if you are dealing with a non-rle images, you absolutely can see it's "likeness" in a hex editor with your width set correctly. An image that is run length encoded bears no resemblance to anything, except some of them do look like random waves, but that's another story.
Those images were the first things I noticed in my N7 bootloader, not what I wanted though. But since the non-rle images were in a rgb24 pixel format, with 3 bytes per pixel, my battery charging icon that is 340 pixels wide could only be seen correctly (in a hex editor) at 340*3=1020 for the width. That's one of the things I like about 010 editor, I think Hxd will only go up to 512 for the width, 010 editor goes up to 1024.
Ah yes, I'd forgotten about .rle :banghead: can't see it but can find it.
You will find the address of them in the ELF data, especially the splash and battery charge on power up, it's in (I think, off top of my head) hboot, if you know the partitions offsets from 0x00000000 (or you have a full nand dump) there's pointers to them
Bashing away at my HTC Desire C
Antagonist42 said:
Ah yes, I'd forgotten about .rle :banghead: can't see it but can find it.
You will find the address of them in the ELF data, especially the splash and battery charge on power up, it's in (I think, off top of my head) hboot, if you know the partitions offsets from 0x00000000 (or you have a full nand dump) there's pointers to them
Bashing away at my HTC Desire C
Click to expand...
Click to collapse
You must be referring to the kernel, I am talking about the bootloader in the OP. There is no elf header/data in the bootloader, they are typically proprietary and written in machine code &| assembly language.
You've spiked my curiosity now, especially as I've not been able to work at my PC in a while
Is now off to see where it's pointed at from....
Bashing away at my HTC Desire C
@makers_mark So I was sitting in the bar the other day...and suddenly realized where you got that name from.
Antagonist42 said:
You've spiked my curiosity now, especially as I've not been able to work at my PC in a while
Is now off to see where it's pointed at from....
Bashing away at my HTC Desire C
Click to expand...
Click to collapse
Here is the mmcblk0p12 from the Nexus 7 2013 and the whole bootloader.img from the factory download. I don't know if it would help you, I imagine you have a device to check, but I have the logo locations already if it would help you out any.
There are 4 locations of the image (the splashscreen isn't drawn all at once, it places the logo and the lock from different places in the bootloader) in the partition mmcblk0p12 they are all 43768 bytes long:
307760 o----c 351528
2390104 o----c 2433872
3075424 o----c 3119192
3166732 o----c 3210500​
In the factory image there are three locations, they are:
1183172 o----c 1226940
3265516 o----c 3309284
3950836 o----c 3994604​
 @E:V:A
If you were at a bar and you figured out where I got my name from, you'd have to be right!
Came across this, simply because it's for LCD screens but explains the different encoding methods
http://www.demmel.com/download/ilcd/2d_rle_appnote.pdf
Bashing away at my HTC Desire C
Antagonist42 said:
Came across this, simply because it's for LCD screens but explains the different encoding methods
http://www.demmel.com/download/ilcd/2d_rle_appnote.pdf
Bashing away at my HTC Desire C
Click to expand...
Click to collapse
The possibilities are endless when it comes to run length encoding. The three different methods that I've found probably aren't the only ones being used. Most people probably confuse rle with the old microsoft file format, but actually rle these days is a method of encoding. So, if you want to have 3 bytes for the count and 3 bytes for the color, you can do it. But if you notice, all three of the methods are 4 or 8 byte reads. No 3, 6, 10.... I wrote an arbitrary decoder for rlimager, but took it out because I don't see them ever using rle that doesn't add up to 4 or 8. Like 2 bytes count 3 bytes color, would be a more efficient way to encode 3 byte color, as opposed to 1 byte count 3 byte color (like they use). But it would be horribly slow. Here is the arbitrary decoder:
Code:
void arbitrary(int bytesofcount, int bytesofcolor)
{
unsigned int i, j, k, totalperpixel = bytesofcount+bytesofcolor;
unsigned long times, count, counttotal;
unsigned char color, instream[totalperpixel];
unsigned char colorbyte[bytesofcolor];
while(read(0,instream,totalperpixel)){
for (i = 0; i<bytesofcount; i++){
count = instream[i];
if (i > 0) {
counttotal = (count << 8) | counttotal;
} else {
counttotal = count;
}
}
for (j=0; j<bytesofcolor;j++){
color = instream[j+i];
colorbyte[j] = color;
}
for (times=0;times< counttotal;times++) {
for (k=0;k<bytesofcolor;k++){
write(1, &colorbyte[k], 1);
}
}
count=0;
}
}
But in the end, there are countless ways to run length encode an image. I've seen vertical encodings, diagonal, and horizontal. I've just simply found 3 used to encode images in some bootloaders...
Just flicked through a power point doc on image encoding including rle for tv transmission, it can be done with the bitmap fields as well!!
With any luck they'll keep it simple
Thought the LCD doc may come in handy as just for the screen being lcd, I don't think I've come across anything on screen images and encoding in Qualcomm docs so it's probably down to manufacturer how they do it (samsung and LG may use same as used on their TV's they make )
Bashing away at my HTC Desire C
Antagonist42 said:
Just flicked through a power point doc on image encoding including rle for tv transmission, it can be done with the bitmap fields as well!!
With any luck they'll keep it simple
Thought the LCD doc may come in handy as just for the screen being lcd, I don't think I've come across anything on screen images and encoding in Qualcomm docs so it's probably down to manufacturer how they do it (samsung and LG may use same as used on their TV's they make )
Bashing away at my HTC Desire C
Click to expand...
Click to collapse
I think they'll keep it simple, as they have for this reason: The images that are run length encoded in android, usually so far, are meant to be decoded and displayed instantaneously. If you go to a more complex algorithm to encode images in a run length fashion it is only practical for storage! I went back and forth about whether to write this guide for weeks before ever releasing any of this information, because I feared they would change it up to something that would be almost impossible to figure out, barring a leak. Then I came to the realization that they are pressed for speed on boot, and I don't think they want to make it any more complex, and if they do, oh well the game is on again.
I think that is part of the reason that the nexus 5 and 4 which use the 1 byte count 3 byte color, encode the whole bootloader screen in one pass. Because that method of decoding is easily the slowest, so instead of decoding the android at specified location, then the text, then the buttons..... They just draw the whole screen. I really think they're trying to save as much time as possible when it comes to these decoding algorithms.
Not just that but more complexity would mean a decoder, screen drivers (possibly) memory space to decompress & read it from....probably more trouble than it's worth to go hi-tech just for (basically) a splash screen in general but definitely would be worth (in my eyes) having a GUI you could run it through and alter the bit fields (sad oldie stuck on windows and no time to really get into linux :what: ).
Bashing away at my HTC Desire C
Antagonist42 said:
Not just that but more complexity would mean a decoder, screen drivers (possibly) memory space to decompress & read it from....probably more trouble than it's worth to go hi-tech just for (basically) a splash screen in general but definitely would be worth (in my eyes) having a GUI you could run it through and alter the bit fields (sad oldie stuck on windows and no time to really get into linux :what: ).
Bashing away at my HTC Desire C
Click to expand...
Click to collapse
True! :good:
The following images were all extracted using option 8 - Extract Jpgs From File
AT&T Note 3
Crespo i9020

Software Development Developing an OBD2/Canbus data logger

So I wanted to implement something like TeslaMate for my UIS7862. The idea being to be able to visualize trips, and various vehicle stats from Grafana (and maybe a live location tracker).
My original plan was to use TorquePro to log vehicle stats + GPS location, and then to send those logs to a listening webserver for storage in Prometheus and display via Grafana. I found an Automate script to hook this into HomeAssistant here: here. However, I wanted a few additional items:
I don't have a SIM card in my radio and do not normally have it connected to my phone as a hotspot, so internet connection is intermittent and I didn't want to lose data
I wanted to be able to upload to different IP addresses depending on whether I'm connected to the home network (i.e. at home) or otspot (i.e I'm driving)
I wanted to be able to store stats from the media canbus (like fuel level) that don't seem to be available on OBD-II (at least I haven't found them for my GTI)
I wanted to learn Kotlin and write a 'real' Android app
I was successful in writing an app that would send all unsent Torque data to my home server once it connects via wifi (basically reproducing Rob's Automate script), but getting the canbus data out of the radio required more work.
I decompiled 190000000_com.syu.canbus.apk and set about learning how it worked, and trying to connect my own app.
What I found so far:
Unlike the MKC/D units which appear to communicate with the canbus module via a serial port, the FYT radios seem to use I2C
The com.syu.ms.apk is responsible for the hardware communication
the com.syu.canbus.apk connects to the com.syu.ms.toolkit Intent to access hardware data.
This Service provides a getRemoteModule() procedure which seems to provide 4 different interfaces:
0: the 'Main' interface
4: the Sound interface
7: the Canbus interface
14: the 'CanUp' interface (no idea what this is)
each interface (IRemoteModule) provides 4 commands: cmd, get, register, unregister
The 'register' command registers a callback to a specific ID. That callback will be called when the value at the ID changes.
For instance, on my GTI, ID '6' of the canbus module is the fuel-level. I can register a callback at ID=6, and that callback will be called whenever the value changes
I haven't spent time to look at the other modules, nor what the 'get' or 'cmd' functions do
With the above, I now have a rudimentay application that will fetch the Fuel level from the radio (via the Canbox). My plan is to incorporate this with the OBDII capture to create a composte data-set to upload to my prometheus database. Interestingly, the com.syu.ms.toolbox only responds back to me if I use the 'com.syu.ipc.[IModuleCallback|IRemoteModule|IRemoteToolkit' descriptor.
I will make everything above available on GitHub once I've cleaned it up a bit. It should be possible to extract any canbus data the radio has (along with other internal state depending on what the other modules expose). However, what I've learned is that every CanBox has a different interface and presents diferent data, so the effort to make a generic interface would be very high and beyond the scope of what I plan to do. There are about 2500 unique CanBoxes listed in FinalCanbus. I see about 600 unique classes implementing these modules, each of which implements a different set of registerable IDs.
I plan to add an interface to register any ID if you know what you are looking for to my app. I think @surfer63 could do the same to FytHwOneKey if they were so inclined, but without a table of which features are available it would only likely benefit programmers.
I'll update this post with a GitHub link once available, but I thought there might be some interest in the canbus analysis stuff.
Here is the GitHub repository for the Canbus access library: https://github.com/AxesOfEvil/FYTCanbusMonitor
The CanBox ID is specified by ID=1000.
The low 16 bits appear to specify the canbox type, and the upper 16bits seem to represent the car make/model. This mapping happens in syu.ms.module.canbus.HandlerCanbus with the name mapping in module.canbus.FinalCanbus
Here is an example of the IDs for (some) Reise RZS CanBox to give an idea of what type of data is available:
Code:
U_CUR_OIL_EXPEND 0
U_MISC_BEGIN 0
U_LOW_OIL_WARN 1
U_LOW_BATTERY_WARN 2
U_LIFE_BELT_WARN 3
U_CLEAN_FLUIT_WARN 4
U_HANDLE_BRAKE_WARN 5
U_RESIDUAL_OIL 6
U_BATTERY_VOLTAGE 7
U_DRIVE_MILE 8
U_PARK 9
U_RADAR_MUTE 10
U_CUR_SPEED 11
U_ENGINE_SPEED 12
U_OUT_TEMP 13
U_AIR_BEGIN 14
U_AIR_POWER 14
U_MISC_END 14
U_AIR_BIG_WIND_LIGHT 15
U_AIR_LITTLE_WIND_LIGHT 16
U_AIR_AC 17
U_AIR_MAX 18
U_AIR_CYCLE 19
U_AIR_DUAL 20
U_AIR_REAR 21
U_AIR_BLOW_UP 22
U_AIR_BLOW_BODY 23
U_AIR_SHOW 24
U_AIR_BLOW_FOOT 25
U_AIR_WIND_LEVEL 26
U_AIR_TEMP_LEFT 27
U_AIR_TEMP_RIGHT 28
U_AIR_AQS 29
U_AIR_SEAT_HEAT_LEFT 30
U_AIR_REAR_LOCK 31
U_AIR_AC_MAX 32
U_AIR_SEAT_HEAT_RIGHT 33
U_AIR_TEMP_OUT 34
U_AIR_AUTO 35
U_AIR_END 36
U_DOOR_BEGIN 37
U_DOOR_ENGINE 37
U_DOOR_FL 38
U_DOOR_FR 39
U_DOOR_RL 40
U_DOOR_RR 41
U_DOOR_BACK 42
U_DOOR_END 43
U_AIR_FRONT 44
U_AIR_BLOW_MODE 45
U_CNT_MAX 46
AxesofEvil said:
I plan to add an interface to register any ID if you know what you are looking for to my app. I think @surfer63 could do the same to FytHwOneKey if they were so inclined, but without a table of which features are available it would only likely benefit programmers.
Click to expand...
Click to collapse
Nice work you are doing here.
But I do not know what you mean with above statement.
For further reading: lbdroid did some reverse engineering in 2006.
You might take a look at some of his repos: https://github.com/lbdroid/MCUd
In that github/readme are 5 other repos. They are outdated, but might still give you some clues.
surfer63 said:
Nice work you are doing here.
But I do not know what you mean with above statement.
For further reading: lbdroid did some reverse engineering in 2006.
You might take a look at some of his repos: https://github.com/lbdroid/MCUd
In that github/readme are 5 other repos. They are outdated, but might still give you some clues.
Click to expand...
Click to collapse
Sorry, maybe that was inappropriate. I guess I was thinking about ways to give users access to the canbox data since Tasker doesn't seem able to hook into services this way. One use case would be direct access to steering wheel buttons from the canbox (my understanding is that in some cases FwHwOneKey can't handle canbus related buttons...maybe I'm wrong). Or, perhaps there isn't really any use at all for this info to trigger user applications.
I know there was a request to access Canbox data for widgets (for instance to be able to display the outside temperature on a custom screen). This method should be able to support something like that, but I have no idea if there is an existing app that could make use of it. Maybe I could write a proxy that would turn service updates into system broadcast events? Just spitballing here.
Wow, it’s really communicate with canbus from user apps?
May be there is way to read can data, like we can see in develop mode
Sdese2000 said:
Wow, it’s really communicate with canbus from user apps?
May be there is way to read can data, like we can see in develop mode
Click to expand...
Click to collapse
To be clear, I only have access to whatever the canbox has already decoded (and the radio has accepted), at least on my vehicle, thee is a lot more CAN traffic that is ignored. What CAN data do you see in develop mode? I am not aware of this.
AxesofEvil said:
Sorry, maybe that was inappropriate. I guess I was thinking about ways to give users access to the canbox data since Tasker doesn't seem able to hook into services this way. One use case would be direct access to steering wheel buttons from the canbox (my understanding is that in some cases FwHwOneKey can't handle canbus related buttons...maybe I'm wrong). Or, perhaps there isn't really any use at all for this info to trigger user applications.
Click to expand...
Click to collapse
Not inappropiate at all. I just didn't get what you meant.
And yes: The BT like commands are still a big misunderstanding (for me that is). I think that could very well be a combi of activity, canbus and "something else"
But as my unit doesn't have buttons anymore, and neither my previous one, I don't spend time on my own app anymore.
AxesofEvil said:
To be clear, I only have access to whatever the canbox has already decoded (and the radio has accepted), at least on my vehicle, thee is a lot more CAN traffic that is ignored. What CAN data do you see in develop mode? I am not aware of this.
Click to expand...
Click to collapse
In Head Unit settings there is trigger, if turn on it, can logs will appear on the screen.
If found some code in com/syu/util/DebugViev.jave that provide it
Spoiler
package com.syu.util;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.p000v4.internal.view.SupportMenu;
import android.view.View;
import android.view.WindowManager;
import java.util.Locale;
public class DebugView extends View {
private int CELL_HEIGHT = 35;
int[] COLOR = {SupportMenu.CATEGORY_MASK, -1, -16711936, -256, -16776961};
private final int MAX = 16;
private final int TEXT_SIZE = 23;
/* access modifiers changed from: private */
public int[] mColors = new int[16];
/* access modifiers changed from: private */
public int mCount;
private boolean mDbg = false;
/* access modifiers changed from: private */
public int mLastIndex;
private WindowManager.LayoutParams mLp = ToolkitApp.buildOverlayLayoutParams(-1, -1);
/* access modifiers changed from: private */
public int mMsgCnt;
/* access modifiers changed from: private */
public String[] mMsgs = new String[16];
private Paint mPaint = new Paint();
public DebugView(Context context) {
super(context);
init();
}
private void init() {
this.mPaint.setAntiAlias(true);
this.mPaint.setTextSize(23.0f);
this.mPaint.setColor(-1);
}
public void setDbg(boolean flag) {
this.mDbg = flag;
}
public boolean isDbg() {
return this.mDbg;
}
public WindowManager.LayoutParams getWindowLayoutParams() {
return this.mLp;
}
public void msg(String msg) {
if (this.mDbg && msg != null) {
HandlerUI.getInstance().post(new MessageHelper(msg));
}
}
public void msg2(String msg) {
if (this.mDbg && msg != null) {
HandlerUI.getInstance().post(new MessageHelper(msg));
}
}
public void msgHex(String str, byte[] data, int start, int length) {
if (this.mDbg && data != null) {
if (data.length - start < length) {
length = data.length - start;
}
String msg = String.valueOf(str) + " * ";
for (int i = 0; i < length; i++) {
String c = Integer.toHexString(data[start + i] & 255).toUpperCase(Locale.CHINA);
if (c.length() < 2) {
c = "0" + c;
}
msg = String.valueOf(msg) + c + " ";
}
HandlerUI.getInstance().post(new MessageHelper(msg));
}
}
public void msgHex(String str, int[] data, int start, int length) {
if (this.mDbg && data != null) {
if (data.length - start < length) {
length = data.length - start;
}
String msg = String.valueOf(str) + " * ";
for (int i = 0; i < length; i++) {
String c = Integer.toHexString(data[start + i] & 255).toUpperCase(Locale.CHINA);
if (c.length() < 2) {
c = "0" + c;
}
msg = String.valueOf(msg) + c + " ";
}
HandlerUI.getInstance().post(new MessageHelper(msg));
}
}
private class MessageHelper implements Runnable {
private String mMessage;
public MessageHelper(String msg) {
this.mMessage = msg;
}
public void run() {
DebugView debugView = DebugView.this;
debugView.mLastIndex = debugView.mLastIndex + 1;
DebugView debugView2 = DebugView.this;
debugView2.mCount = debugView2.mCount + 1;
if (DebugView.this.mLastIndex > 15) {
DebugView.this.mLastIndex = 0;
}
if (DebugView.this.mCount > 16) {
DebugView.this.mCount = 16;
}
DebugView debugView3 = DebugView.this;
debugView3.mMsgCnt = debugView3.mMsgCnt + 1;
DebugView.this.mMsgs[DebugView.this.mLastIndex] = String.format("%06d @ %s", new Object[]{Integer.valueOf(DebugView.this.mMsgCnt), this.mMessage});
DebugView.this.mColors[DebugView.this.mLastIndex] = DebugView.this.COLOR[DebugView.this.mLastIndex % DebugView.this.COLOR.length];
DebugView.this.invalidate();
}
}
/* access modifiers changed from: protected */
public void onDraw(Canvas canvas) {
if (this.mCount != 0) {
int count = this.mCount;
int firstIndex = (this.mLastIndex - count) + 1;
if (firstIndex < 0) {
firstIndex += 16;
}
if (firstIndex + count > 16) {
int rightCount = 16 - firstIndex;
int leftCount = count - rightCount;
for (int i = 0; i < rightCount; i++) {
int index = firstIndex + i;
this.mPaint.setColor(this.mColors[index]);
canvas.drawText(this.mMsgs[index], (float) 5, (float) ((i + 1) * this.CELL_HEIGHT), this.mPaint);
}
for (int i2 = 0; i2 < leftCount; i2++) {
this.mPaint.setColor(this.mColors[i2]);
canvas.drawText(this.mMsgs[i2], (float) 5, (float) ((rightCount + i2 + 1) * this.CELL_HEIGHT), this.mPaint);
}
return;
}
for (int i3 = 0; i3 < count; i3++) {
int index2 = firstIndex + i3;
this.mPaint.setColor(this.mColors[index2]);
canvas.drawText(this.mMsgs[index2], (float) 5, (float) ((i3 + 1) * this.CELL_HEIGHT), this.mPaint);
}
}
}
}
I have updated the OP with a link to the GitHub library (here). The library is not really meant to be used standalone, but instead to be incorporated into other projects. I haven't posted the code for the logger as there is still quite a bit more to do on that side.
The library repo does include an example application which will simply log every message received to the screen/logfile (in /Downloads). It is very inefficient since it just blindly asks for every possible ID regardless of whether it is actually available for a given CanBox or not, but is meant to give a quick idea of what data is available and a short example of how to use the library. The latest compiled APK can be found here: https://github.com/AxesOfEvil/FYTCanbusMonitor/releases
I found this interesting tidbit today:
It seems to be that arbitrary commands can be sent to the canbus through the radio via sys.ms by calling ToolkitDev.writeMcu(0xE3, PID, data-len, data0, data1, ...) (where data can be 1-8 bytes).
Edit: ToolkitDev.writeMcu(0xE3, ...) seems to write commands to the canbox module. As I don't have the source for teh module, I'm not sure how it handles these commands, but they don't g out verbatim on the canbus itself.
There is also ToolkitDev.writeCanbusDirect, but this may send commands via an OBDII dongle...Edit: this seems to just directly send raw commands to the CanBox. It is similar to the above but requires manually calculating the entire packet (including checksum)
I have not found a way to pass arbitrary data from an external app through an intent to allow other apps to send arbitrary canbus commands, but with a hacked syu.ms, it probably means I can eliminate the DynAudio AMP control box I had to make to get my audio working. And that with more hacking, it may be possible to send GPS directions and music info to the HUD.
AxesofEvil said:
The CanBox ID is specified by ID=1000.
The low 16 bits appear to specify the canbox type, and the upper 16bits seem to represent the car make/model. This mapping happens in syu.ms.module.canbus.HandlerCanbus with the name mapping in module.canbus.FinalCanbus
Here is an example of the IDs for (some) Reise RZS CanBox to give an idea of what type of data is available:
Code:
U_CUR_OIL_EXPEND 0
U_MISC_BEGIN 0
U_LOW_OIL_WARN 1
U_LOW_BATTERY_WARN 2
U_LIFE_BELT_WARN 3
U_CLEAN_FLUIT_WARN 4
U_HANDLE_BRAKE_WARN 5
U_RESIDUAL_OIL 6
U_BATTERY_VOLTAGE 7
U_DRIVE_MILE 8
U_PARK 9
U_RADAR_MUTE 10
U_CUR_SPEED 11
U_ENGINE_SPEED 12
U_OUT_TEMP 13
U_AIR_BEGIN 14
U_AIR_POWER 14
U_MISC_END 14
U_AIR_BIG_WIND_LIGHT 15
U_AIR_LITTLE_WIND_LIGHT 16
U_AIR_AC 17
U_AIR_MAX 18
U_AIR_CYCLE 19
U_AIR_DUAL 20
U_AIR_REAR 21
U_AIR_BLOW_UP 22
U_AIR_BLOW_BODY 23
U_AIR_SHOW 24
U_AIR_BLOW_FOOT 25
U_AIR_WIND_LEVEL 26
U_AIR_TEMP_LEFT 27
U_AIR_TEMP_RIGHT 28
U_AIR_AQS 29
U_AIR_SEAT_HEAT_LEFT 30
U_AIR_REAR_LOCK 31
U_AIR_AC_MAX 32
U_AIR_SEAT_HEAT_RIGHT 33
U_AIR_TEMP_OUT 34
U_AIR_AUTO 35
U_AIR_END 36
U_DOOR_BEGIN 37
U_DOOR_ENGINE 37
U_DOOR_FL 38
U_DOOR_FR 39
U_DOOR_RL 40
U_DOOR_RR 41
U_DOOR_BACK 42
U_DOOR_END 43
U_AIR_FRONT 44
U_AIR_BLOW_MODE 45
U_CNT_MAX 46
Click to expand...
Click to collapse
Where did these IDs come from? Did you find one for Illumination/Headlights?
The IDs came out of the source code for 190000000_com.syu.canbus.apk
The IDs are canbox and probably vehicle specific, so such info may be available, but you need to identify exactly what you are looking for.
Use JadX or BytecodeViewer or a similar application to analyze the apk file above, and look in app/src/main/java/module/canbus for the appropriate Canbox for your vehicle

Categories

Resources