ReservedField/evic-sdk

Support for eVic VT/Cuboid

Opened this issue · 22 comments

Is there any chance that the sdk would ever support other Joyetech mods? I understand that it depends on the hardware and pinouts, but after atomizer support is added maybe other mods could be taken into consideration?

Long post ahead, beware. Many people asked this so I'll try to be clear. I would be extremely happy to get more devices supported. Let's break it down in steps.

First, can we get code execution on the eVic-VT and Cuboid? They have upgradable firmware, so yes, we can upload code. On-chip encryption would be a showbreaker, but AFAIK it's not used by Joyetech (IIRC eVic-VT firmware has been decrypted, so I expect Cuboid to be the same). As far as I know, I am the only one to have ever achieved code execution on a Joyetech product, but I'm pretty confident I can get it on any mod (as long as it has upgradable firmware that we can encrypt/decrypt).

Second, what would the implications for the SDK be? Well, if you have looked at the code you can see that the interface to the programmer is actually very abstracted from the hardware (best example is the display driver, that has three abstraction layers). So it'd be possible to have an API that is mostly the same across all products. Of course there'll be differences, for example in display size/capabilities and buttons, but the rest can be abstracted from the programmer. Abstraction is the whole point of writing an SDK in the first place. This is looking good :)

So what is stopping me? Well... I don't have the devices in hand. I absolutely cannot develop software on a device which is not in my possession, especially if it's embedded and I have to reverse engineer it. You can't debug the code in any other way. To get the first hello world working, I probably flashed 20-30 times before I got it right. If I get stuck with non-working code (initially, you're basically coding blind since there's no interface other than display and USB) and I have the device, I can crack it open, find some unused pins, hook up a logic analyzer and use them for debugging. Or I can hook up the manufacturer debugging tool, if I have it. This freedom is essential.

So what we need is good reverse engineers that can work on the other hardwares. But reversing is not enough, they also need to write the code and test it on their devices. I've been looking, but I can't find anyone (maybe I'm looking in the wrong places). So either someone like this pops up, or I'd have to buy the hardware. Which doesn't really make sense to me, since I'm perfectly fine with my VTC Mini and the other mods don't appeal much to me.

TL;DR: I don't own the hardware so I can't code on it.

By the way, I think evic-sdk should work as-is on the Presa 75W (but nobody tested it, so it's just a hunch) since it has nearly the same exact board as the VTC Mini and the hardware version -> display type mappings match. Reuleaux RX200 is also doable, its firmware has been decrypted a while ago. IIRC same CPU is used, just a different display (also it's I2C, not SPI as in the VTC Mini).

Finally, there has been little activity in the past week: I'm pulling through exams at uni, so I have very little time until early February. Then until March I'll be working hard on this sdk as I have no classes to attend. I have to fix a few things around the code, but most importantly I have to add atomizer control.

@Ban3 What do you think about this? Other than the VTC Mini, Presa and Reuleaux do you know more that use the same encryption scheme? Do you own other Joyetech hardware?

Ban3 commented

@ReservedField put it very well. Most importantly:

TL;DR: I don't own the hardware so I can't code on it.

I have nothing against supporting those devices in the SDK, but I only own an Evic. Trying to reverse a device you don't have access to is insanity, IMHO. Somebody who owns the device needs to step up and write the device specific parts.

So what we need is good reverse engineers that can work on the other hardwares. But reversing is not enough, they also need to write the code and test it on their devices. I've been looking, but I can't find anyone (maybe I'm looking in the wrong places).

I wonder what happened to kfazz & others who were working on this pretty early on.

By the way, I think evic-sdk should work as-is on the Presa 75W (but nobody tested it, so it's just a hunch) since it has nearly the same exact board as the VTC Mini and the hardware version -> display type mappings match.

Same hardware, but the hardware versions don't completely match on Type A devices. Evic-SDK should still work, though.

What do you think about this? Other than the VTC Mini, Presa and Reuleaux do you know more that use the same encryption scheme? Do you own other Joyetech hardware?

All of the Wiscmec devices with upgradable firmware, including the vaporflask ones, are based on the same board and firmware with the same encryption. They probably have some kind of internal SDK to port it to other devices.

I wonder what happened to kfazz & others who were working on this pretty early on.

Maybe they lost interest after they reversed most of it? I know from experience that reversing and reimplementing are two very distinct processes. I love that kfazz made the reverse public, even if it's 1.30. I have my own 2.00 reverse (I use the Hex-Rays Decompiler a lot, while kfazz's reverse is pure asm) but I often refer to his to see if he had already found something I was looking for. Offsets are different, but most instructions are the same. A few days ago gxcreator posted a bitmap extraction script on Reddit, so I figured out he was still working on it and wrote to him to ask a few things about resistance reading and atomizer control, but he hasn't replied yet.

Same hardware, but the hardware versions don't completely match on Type A devices. Evic-SDK should still work, though.

I thought that the HW version change on eVic was just to prevent the Presa FW from defaulting to SSD1306 on newer SSD1327 eVics, since the Presa has less hardware versions. So the ones that are in both do not match exactly? Good to know. Anyway, it's a trivial problem to solve, no need to do it at runtime, we just add a Makefile option to select the device since we have to change the verifications strings as well anyway. (ok, given the verification method we could actually have a firmware that verifies both for eVic and Presa, but the point is that a HW -> display mapping is not an issue)

They probably have some kind of internal SDK to port it to other devices.

Sometimes I wonder if Joyetech knows about our SDK and what they think about it, eheh. At least ours is not a mess of copypasted Nuvoton example code :P (not looking down on you, Joyetech. Just sayin')

That's a lot of awesome work you are doing there guys. I understand the abstraction layers of the sdk, that's why I asked if you consider doing it in future.

Is posting reverse-engineered code prohibited by joyetech licenses? If not, I'd love to take a peek at the code, I have decent experience with x86 assembly and as far as I know arm is simmilar in many ways, maybe I could contribute a bit if my current knowedgle allows me to.

Also, I'm following the project since first post on reddit, already asked some people what would they like to see in custom rom and what annoys them in official one. I have written down some ideas and I'm only waiting for atomizer support to begin working on the project :)

Is posting reverse-engineered code prohibited by joyetech licenses?

I'm afraid it is. Kfazz posted his, I don't really feel comfortable posting mine, but my email is on my public profile so hit me up.

I have written down some ideas and I'm only waiting for atomizer support to begin working on the project :)

That's great! I kept thinking "will there be someone that actually uses evic-sdk to write a CFW?".

I've set up environment and build bot on my vps machine, ready to start coding. Just need the atomizer support and I'll be good to go.

@Ban3 I checked latest eVic 3.00 against latest Presa 3.00. Max hw version is from the bytes following device ID, SSD1327 versions are from disasm.

eVic 3.00:
Maximum HW version: 1.11
SSD1327 versions: 1.02, 1.03, 1.06, 1.08, 1.09, 1.11

Presa 3.00:
Maximum HW version: 1.03
SSD1327 versions: 1.02, 1.03

Of course evic-sdk mappings are the same as eVic 3.00. As you can see, the only mappings that we care about for Presa are 1.02, 1.03 -> SSD1327, which match the OFW/evic-sdk ones. So mapping will work as-is on the Presa (actually, eVic FW should also work on it - anybody tried?).

Ban3 commented

@ReservedField Ah, sorry, I was a bit unclear. That was what I meant by not matching as there are fewer versions of Presa devices. SDK supports them all so it's not a issue.

This is slightly offtopic for this issue but could you point me in the direction where the mapping is made in the official image? I think I was looking around for it at some point but didn't see it. Might come useful for python-evic purposes.

In 3.00, it's done in the subroutine at 0x1408, which does dataflash reading. The "is SSD1327" flag is the byte at 0x20000032, hardware version is the dword at 0x20000254. The actual flag store happens at 0x153C, looking up from it you can see the comparisons.
For other versions and Presa it's similiar, you can get it in many ways: you could look for display routines, see the address that is checked for display type and xref from it, or even simpler just look for the hardware versions hex values and find the comparisons.

mpaw commented

That's great! I kept thinking "will there be someone that actually uses evic-sdk to write a CFW?"

Most definitely. I just found this project today and can't wait to start once the sdk is more mature.

I've got all examples of the SDK running on my couple of days old Cuboid.
The only thing that does not fully work, is the Atomizer example. No power output.
Already just disassembled my Cuboid to check the disassembling prozess. Will have to buy new very small (needle like) contact cables for my multimeter. Maybe then I will be able to identify the right MCU pins.
Buttons etc. working fine. Battery charge level and charging flag working fine.

I had to make a small change in the SDK source to get AROM accepted by the Cuboid and experienced a very strange behaviour with some examples.
For example the helloworld first did not show any text.
Funny thing is, that if I define a variable buf char[100] and do a siprintf into it (even if not using it anywhere else - just avoid compiler optimizing that buf away), the example just starts to do what is expected. Seems to me, like there is some minimum amount of code required to generate a working AROM. As said, strange, but did not dig into it so far.
Same true for some other examples (bigger code ones directly worked, smaller code sizes not).
Maybe that problem description already makes someone having some idea where the problem my come from... otherwise, first not important, later I will nail that problem - that's for sure ;)

@chaosman123 That's amazing!
When I first started working on the atomizer my first approach was the same as yours - hook up a logic analyzer (we're talking 150kHz PWM, a multimeter is useless in this case) and look at the signals. I quickly figured out that attaching probes to a 0.5mm pitch IC without spending a fortune wasn't gonna happen, so I just reversed the OFW.
On the eVic, the signal are apparently routed in a inner layer, so you either hook up your probes to the IC (very, very hard) or to the switches under the heatsink (easier, but requires removing the heatsink). I don't know how the Cuboid is internally, though.

You are hitting issue #16. I changed the build process to partially link CRT0 (it was getting hard to manage otherwise) and that broke something. I'm still trying to figure out what...

Care to share the change you had to make to get the APROM accepted? Are you referring to the verification string for the official updater or something else?

mpaw commented

I had the same experience. Hello world does not work, button example does.

In the startup.s line 6 I had to put:
.ascii "E060" @ Device (Cuboid) E052 eVic VTC Mini
So, changed E052 to E060. After that change my Cuboid accepted the AROMs. (not telling wrong hardware anymore)
It would be good to make the HW detection part of the AROM build process - or, at least add some parameter to it, so the build can be done for a defined HW to later run on.
Automatic detection would require the Mod to be connected and online while building, So, I'd prefer some compile option/flag for target HW definition instead.

I don't have any logic analizer (anymore). Sold mind a couple of years ago.
Let's see, how far I get without scope and logic analyzer.
If it requires one, I will just buy one - just takes more time ;)
Took me yesterday about 4 hours to get there. Time... give me more time...

Following way helloworld will work; ;)
You can try to not use buf. Tried it on a different example...

#include <stdio.h>
#include <M451Series.h>
#include <Display.h>
#include <Font.h>
#include <TimerUtils.h>

int main() {
        char buf[100];

        Display_Clear();
        // Blit text
        //Display_PutText(8, 56, "Hello,\nWorld.", FONT_DEJAVU_8PT);
        siprintf(buf, "Hello,\nWorld.");
        Display_PutText(0, 0, buf, FONT_DEJAVU_8PT);

        // Update display
        Display_Update();
}

Yeah, it's just the same old issue #16. Easy workaround would be updating all samples to use siprintf, but it doesn't feel right since it used to work before that partial linking commit.

@chaosman123 Yeah, I imagined you changed the verification string. It will actually work with python-evic (disabling APROM verification) without changing it. I'll check the official Cuboid updater for the position limits, but they should be fine. Of course we'll have to add a compile-time flag to choose the device.

cmock commented

OK, so now we have the SDK running on the VTC and the Presa; however, it seems the shunts are not the same (OFW sees coil at 0.90 while SDK says 1.09).

So it's about time to introduce some #ifdefs for hardware support, methinks. @ReservedField , I'd be willing to send you a pull request, but I think the "infrastructure" part of this would better be designed by you...

@cmok Just checked a Presa binary, looks like shunt is 100 for all hardware versions. Try replacing the switch-case in Atomizer_Init with Atomizer_shuntRes = 100 and see if it's better. Presa hardware only goes up to 1.02, so SDK will choose 115 or 125, resulting in 15% or 25% error, which agrees with your measurement.

In the last days I worked on Cuboid firmware because I'm designing the porting support (along with preparing finals and working on thread-safety... wonder why I'm not committing? :P). I have a good idea of the differences between devices, but I'm analyzing them in detail to work out the best infrastructure to do this. Right now what I'd like to do is to make device-specific header files which #define all the features, drivers, constants etc. used by that device. Some things (like shunt) may require code instead of simple #defines, but I'll put that in the header as inline. Each device also has a Makefile include.

I want to make it pretty modular: as an example, take display. eVic and Cuboid use SSD1306/1327 on SPI, while RX200 uses the same controllers but on I2C (IIRC). I'd make the display drivers handle the protocol but not the bus, then I'd make a bus driver for SPI and for I2C. There won't be much extra code, mostly refactoring and adding I2C of course. Also display can handle some common GPIOs, like reset. Each driver has a pointer table to access its functions. In the device header file there are functions, called at initialization, that return the right function table for drivers for that specific hardware version (since we can't know at compile time). Right now we're doing an if() on the display type in Display_SSD.c to choose between the two SSD drivers, while with the new method we would cache the table pointer instead of the display type. Likewise, display driver would ask for the bus driver. Performance is exactly the same, since in both cases a single load is done (well, new method also saves a comparison), and it's much simpler to extend. The device-specific makefile include only compiles the needed drivers.

The device header would also specify thing like display width, height, etc. Also, for example, a device with two or more batteries would do extra #defines, so the battery code can conditionally compile only the needed code via #ifdefs.

I think it's better that what we have, and just plugging #ifdefs everywhere will quickly become an unmaintainable mess. Anyway, those are some early ideas. Any improvement is very welcome.

(I'm going to set whoever tells me I should use C++ virtual functions on fire)

So it looks like this is turning into a general "how are other mods supported" thread so if this is the wrong place to ask this just let me know. I've played with the examples for the evic mini and would like to help contribute or at least hack on things. I have a new rx200s and I'm wondering what the gating factors are to me being able to work on it.

Do we need to get a firmware update from wismec to even begin? The screen is new on the 200s so obviously that would be a big part of adding support. Would it help to tare down my mod and see what I can find about it?

Also if the only thing stopping (other than time available) is getting some of you guys mods I would be willing to fund a few purchases.

cmok commented

@cstcyr @ReservedField , I think you like to talk to @cmock not me @cmok here.

@cstcyr Sorry for the massive delay. I'm done with the darn finals and getting back to SDK development.

I have a new rx200s and I'm wondering what the gating factors are to me being able to work on it.

We need to build the porting infrastructure. I have ideas on how to do that, but I can't start right away because I want to finish up the threading stuff first (i.e. making the SDK thread-safe, since threads are working). Since porting will imply a good amount of refactoring, merging threads into the refactored tree would be a major pain. That's why I want to do it first. (Yeah, threads are actually useful: complex firmware like VaporWare would benefit a lot from them)

Do we need to get a firmware update from wismec to even begin? The screen is new on the 200s so obviously that would be a big part of adding support. Would it help to tare down my mod and see what I can find about it?

A firmware update is most likely needed, to know what kind of hardware we're dealing with. I've found that understanding hardware by reversing the firmware is a lot quicker and easier than digging into the PCB. Even attaching a logic analyzer is painful... Mod teardown wouldn't tell us very much. As an example, we could see that channel X is used for reading atomizer voltage by following traces. Then we'd need high-res pictures to understand the chain (e.g. the ratio of the voltage divider used). Consider doing that for everything, on a multilayer board... it takes a lot of time and is error-prone. If we have a firmware, we can just see all those things at a glance.

You also have to consider that if there's no firmware update you have nothing to fall back on. Once you flash a CFW, you're stuck with it until an update comes out. Might not be the best choice for a device you actually want to use now.

Anyway, if you join ##evic-modding on Freenode we can talk more about this. Also, if you have experience with reversing, I wrote some pretty good IDA scripts that make reversing those firmwares much, much easier.

Some value similiar to shuntRes is set to 105 in Cuboid OFW
This is how the current is calculated:
word_200000CC = ((unsigned int)(25600 * v1) >> 12) / (unsigned __int8)byte_20000033;
word_200000CC is used when displaying the current value on main screen, byte_20000033 is set to 105 during device initialization.
v1 is ACD_Read(2)