Categories

[Little Brosers] Indeed, dealing with flash is lightning fast

Hello everyone !

 

Don’t ask me how, my brain seems to have enough battery life to keep writing posts here.

Let’s get to it, shall we?

 

First: The flash

Last week I left you with a code very approximative trying to stimulate the flash.

One week later, we fully control it. I just needed more of those sweet full sleeping night (and some ROSE Guru’s advice). After reading even more the datasheet and insulting my computer for no reason, I got it to work as expected. We can now, read/write in a page any amount of data up to a page size (528 bytes). Also, I tested the “super-duper amazing ultra low power mode” of the flash. Just kidding, just note that we are able to put the flash in its deepest power mode and wake it.

 

Second: We gotta make it fit in 64 ko

 

Indeed, our NRF52832 can only provide 64 ko of RAM. This few kilobytes are supposed to hold our Merkle tree and the slots. (c.f. older posts if you don’t know what ‘slots’ refers to). And let’s not forget all the crypto code as well as the RAM that BLE needs.

 

So, with Guillaume, we tried to reduce the size of our structures as much as we could. Choosing space-saving over run-time optimization. For instance, the width of a node’s children can be deduced from its ‘start’ and ‘end’ fields. Same for its depth in the tree. So yes, we reduced the size of our structures by removing as much ‘not so essential” fields as possible (which was previously stored in each node).

Also, we dramatically reduced the size and count of the messages that will be stored in a drop. Being optimistic, I would say that we could fit 1000 messages in a drop. We’ll see. The ideal would be to use a NRF52840 (which has way more RAM), but this SoC was not available to buy when we started the project, and still isn’t, I think.

 

Third: the diff

Ok, the rest of the week was dedicated to the diff. I you forgot what ‘diff’ means in our super fancy vocabulary, it means “comparing two Merkle trees and determining which messages those trees need to send to each other in order to be identical”.

This has been done in python by Guillaume at the beginning of the project. The thing is, he had not the RAM limitation that I encounter now with the Drop’s CPU. So with Guillaume we worked on translating his diff algorithm to C. I Started by implementing in C the stack he was using in python. Saturday, I spent the day connecting the diff code to the C++ simulation. And dude, that’s so satisfying. I can launch as many drops as I want now and ask them to launch a diff with another one. All of this being done in separated threads. Since I use UDP for emulating BLE communication, we can even launch one drop per terminal. It even should work for computers in the same local network.

 

Oh yes, and the best part is, I tried to keep the diff hardware independent. Indeed, at first we thought we would have to code a diff in Java for the Android part in addition of the C one. Mostly because of the difference between Drops and Android phones about BLE, events and interrupts. But since we now master the JNI and the Android NDK , my fellow mates only need to provide two C function pointers, one for sending, one for receiving. Those function need to be blocking, and write to/read from a byte array for which I will provide a size, that’s all. There is also a void* in the function signature, if the language which uses the diff needs to pass something to its send/recv functions. (I do for C++ simulation)

And finally, because unitary testing is always around the corner, we started today testing each part of the diff algorithm with Criterion. The diff is not fully functional yet, but it shouldn’t be long.

 

What’s next…?

Basically everything. I mean, there is only 4 days left. I still need to write code for the merge (not very complicated I think, the diff does all the handwork), the date shift, the flash monitor to know which page of the flash is dead or not and the battery monitor.

 

That is my program for the following days.

 

Have fun guys !

 

Antony

 

[Little Brosers] PCB, Images, hash digests and flash memory

Hello everyone,

 

This week, and particulary this week-end have been quite intense. Let’s sum it up.

PCB : First hands-on and testing

We received our PCBs this week ! It was awesome to see it, like, for real, not only on my screen. We spent a day testing each component and all went beautifully well. We had a software issue with the external flash’s pins but somme google research solved it. We forgot to configure the pin used for SPI’s CS, which is used for NFC by default. We juste had to declare a preprocessor constant to remove the NFC from this pin.

 

Some pics :

 

Banana for scale

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

In case you wonder, our drop’s PCB roll very well and resists to battery pole inversion 🙂

Docker images

Finally, after weeks of procrastination about Docker, I finally took the time to make a precisely adapted image for each jobs of our CI. “Took the time” means 1 full night and one full day but at least we now have beautiful lightweight alpine/arch docker images for our jobs. Tests run way faster than before !

 

Hash digests

So, for the last weeks, I have been in charge of our merkle tree and for simplicity, I never implemented messages hash. I always used the first byte of the message’s payload to run our sub-sorting, first one being timestamp. Also I never took care of computing the nodes’s hash of our merkle tree. This was just not usefull for what I had to do.

However the project is progressing and we came to the point where we needed those hash digests. Thus during friday, I sat at a table with Chris and we reviewed together the hash code for the drop. At the end of the day, we ended up with the exact same code for computing code from simulation or from the drops. We just made sure to redirect the “#include”s to the appropriate header files.

This is going to be merged into master branch pretty soon.

 

External flash memory

Ok, this time, it’s simple : my whole week-end was dedicated to the external flash memory. Saturday I started from master with what Xavier had already written for it and started to build basic functions like a get_status() function allowing main() to read the status register of the flash and I spent the rest of the day reading the datasheet. Today was all about writing a full Little Brosers message to the flash. Knowing that a flash page is 528 bytes, we decided that our messaged would be 528 bytes long for the maximum length. The external flash memory has 8192 pages.

So to make a quick summuray of what I have learned:

The flash has two SRAM buffer of 528 bytes buffer. They are used to optimize writing and reading operation. In our case it is very usefull.

Indeed, the nrf52 SPI driver only allows SPI transfers up to 255 bytes(i.e. 251 bytes of payload, 4 bytes being used by the flash commandID and page/word address). We won’t be able to fill a full page with only one transfert, even if the flash allows it, the nrf doesn’t. I mean, we could force the sending of more than 255 bytes using nrf52’s SPI driver but it would require a heavy structure using nrf52’s timers and PPIs to make it possible. We don’t have time for such a complex thing. Instead, we chose the following procedure to write a msg in the page i using buffer1:

-> transform the message_t C struct into a byte array of size 528
-> write msg[0] to msg[250] in buffer1[0] for 251 bytes
-> write msg[251] to msg[501] in buffer1[251] for 251 bytes
-> write msg[502] to msg[527] in buffer1[501] for 26 bytes
-> push whole buffer1 to page i

 

The procedure for reading is quite similar except that we do not use the buffers. Indeed, we use the low power continuous array read on the page i three times (0->250, 251->501, 502->527).

 

It is 22h36 and for now, it “seems” that writing works fine, not so sure about reading. I’ll stop here for today, we’ll see tomorrow with a full night of recover. I’ll have to show it to my coworkers and see if they have any idea how to debug this part. I have to admit that it is not very easy since we still not fully master the NRF_LOG macro which is supposed to replace the usual printf() of the libc. It very often doesn’t actually print the characters I asked for; skipping some of them if the number of characters is too high. Even if I raise the RTT buffer size.

So for now, flash support is not reliable.

 

See you

 

Antony Lopez

[Little Brosers] Memory management issues

OK, first, happy new year ! Hope you all had great holida… come on, it’s ROSE’s logbook 😉

So for the last two weeks, I kept working one our lovely merkle tree and all the code it implies.

Interactivity

Indeed, first week was about adding interactivity to the simulation. Thus I added a shell to our simulation program as well as a thread per Device. “Device” is a c++ class wrapping the Little Brosers API which is supposed to emulate a running drop/phone.

Also I added basic C++ TCP server/client to the drops. Allowing them to communicate whenever main’s thread asks them to interact with each other. For now they are only able to ping the other. But I will use this communication channel to implement the diff-like. Indeed, until now, all the code I wrote could be tested without the presence of another Device. All was creating a merkle tree and adding messages to it. No interaction.

In total this interactivity implies 2 threads per Device(one for its “main” thread, another one for the tcp) and one for the main().

Rolling memory

So, while my merkle tree building process was believed to be fully terminated, I noticed yersterday a BIG issue. First some context:

In Guillaume’s Python script, the messages where dynamically allocated whenever it was necessary. Embedded C code does not allow this.

Also, in python, the messages were directly accessible. In our drops, the will be stored in the external flash memory.

Thus, I had to creat a C structure called a “slot pool” :

#define LB_NB_MAX_MSGS 50

typedef struct lb_bucket_slot lb_bucket_slot;
struct lb_bucket_slot {
    lb_bucket_slot *p_previous;
    lb_bucket_slot *p_next;
    message_t *p_msg;
    uint32_t timestamp;
    uint8_t p_hash[MESSAGE_SIGNATURE_SIZE];
};


typedef struct {
    // The + 1 is used to ease the memory management when all slots are full
    lb_bucket_slot slots[LB_NB_MAX_MSGS + 1];
    lb_bucket_slot *begin_busy;
    lb_bucket_slot *begin_free;
    size_t nb_free;
} lb_slot_pool;

As you ca see, a slot_pool is a big array of slots. A slot is a simple structure meant to represent in RAM one particular message stored in the external flash, with a copy of the message’s time stamp and signature for ease-of-use reasons.

So this pool has a limited capacity. Its capacity will eventually be the number of messages we can fit in our external memory. But for now, during simulation, we can choose any size. Here it is 50.

The thing is, what to do when we run out of free slots? Well, we are supposed to free the one referring to the oldest message. This feature was badly implemented by…. me. So i spent the whole day of yesterday re-thinking the management of this pool. And during the process, re-writing the merkle tree build process.

 

Now everything works fine. The slot pool size can be from 1 to +infinite. And whenever a pool of messages is submitted to this merkle tree, it will only keep the newest it can store.

I reviewed the entire code with Guillaume today and we found some edge-cases in the merkle tree build process that wear treated before yesterday (with the bad memory implementation) but not today. However, those cases are easy to solve with the new memory model. In this specific case, I clearly saw that a CI with unitary tests would have noticed me that the merkle tree build process of my new memory management forgot some edge cases that the previous model took care of.So now and more than ever, we realy need to write tests for this whole merkle tree thing. Don’t worry, Guillaume should be on it as I am writing this post.

 

See you next week !

 

Antony Lopez

[Little Brosers] Decorating my very own Christmas Merkle tree

Ho Ho Ho !

Guess who’s putting messages instead of presents at the foot of it’s Christmas Merkle tree ?

Ok so last week I wrote you a whole essai about how I planned to manage messages relatively to the drop’s Merkle tree, and how to build this tree.

Here is a simplistic summary:

Merkle tree ? Again?

Yes, this week I kept on testing my Merkle tree build process. I also tested the function allowing to insert new messages in a tree already containing messages. It may not seem that complicated, but I had to make sure to take into account every single case of insertion and not break my structure. And believe me, there is quite a lot. Don’t forget we have two sorting levels.

There is still no unitary test. But fear not, it’s coming soon ! With Guillaume, we agreed that he should be in charge of reviewing my code and writing the tests for it (see? I told you 😉 )

The reason for that is the following: Guillaume wrote the prototype python code for the Merkle tree and for our diff-like algorithm for comparing trees of two drops. We will see if I respected his vision of the whole process.

 

What’s comming for me?

Next step is writing the diff-like algorithm in C. However to write and test this, I am using a C++ simulation environment emulating the existence of two drops and their interaction. It kept me busy for the last three days, I am still building it before diving into the diff-like algorithm.

For now the drops C++ objects share the same thread. I’m thinking about giving each “virtual” drop its own.

 

That’s all for me,

 

Merry Christmas !

 

Antony Lopez

[Little Brosers] From Python to C

Soooooo… No joke this week, I’m almost gonna write an essai this time.

 

First step: Allocating memory for our Merkle tree

So, the first issue about implementing our Merkle tree structure using C is memory allocation.

A simple way would be to use recursive build function for each node and malloc() each of them. But, let’s remember that we will use this code on an embedded system. Dynamic allocation is not allowed.

So the first struggle was to find out how to staticaly allocate the space needed for our Merkle tree.

 

First I need to refresh your memory. Our Merkle tree is 4-ary balanced-ish. That is to say, each child of a node represents the time frame of the node divided by four. But this balanced time distribution rule is broken for the 4 first children of the tree, a.k.a. the root’s children. Those nodes have a an arbitrary part of the root’s time frame. This choice has been made because we think a lot of messages will be recent. Thus, the very last 24 hours will be more likely to contain messages than the last week.

To know when do we stop to split a node’s time frame, we have a constant in the code called BUCKET_SIZE. It gives the minimum time frame a node can represent. Thus, in this case, if the time frame width of a node divided by the number of children (4 here) is greater than BUCKET_SIZE, we split it. Otherwise, this node becomes a leaf.

Here is a basic representation:

So how do we statically allocate such a structure?

Several solutions were examined and to be short, the chosen one is the magic “python generated C header”.

In other terms, a python script included in our Makefile is called whenever the file containing our Merkle tree’s constants is modified and re-write a second header which only contains the size of our sub trees. This way we only have to include this generated header in our merkle_tree.c file and we know at compilation time the size needed for each subtree.

Oh and the sub trees are stored in C arrays.

 

Second step: Building the Merkle tree

Ok, now we know we have all the memory pre-allocated. The thing is…. we only have four dumb arrays. We need to turn this into a tree structure.

See below, we have 4 arrays of ‘node’ C structs and one node C stuct:

The sub trees are stored in their array in a Breadth First Search manner. The sizes of the arrays have been “#define” declared by the python script in a header.

The image above is a simplified representation of the sub trees and arrows are missing. Actually, There is also pointers to parent node.The job in this part has been to make sure each node C struct of the arrays is filled correctly and that each of its pointers is set.

For the curious ones, here is the content of a node C struct (for now):

struct node_t {
    uint64_t start;
    uint64_t end;
    uint32_t child_width;
    node_t *p_parent;
    node_t *p_children[LB_MT_NB_CHILDREN];
    uint16_t depth;
    uint16_t child_id;
    uint16_t array_id;

    slot_t *p_slots;
    uint8_t p_hash[SHA256_BLOCK_SIZE];
};

 

 

Third step: Attaching messages to leafs

We have now a Merkle tree structure we can explore without knowing it’s an array and just using the provided pointers in each node.

The next step is to find out which message has to be attached to which leaf. Also, the actual messages will be stored in external flash so we can’t “put” the message in the leaf structure. We will instead use structures called ‘slot’. Each slot can only correspond to one message and will have an integer which will correspond to the address of its message in the external flash. The only thing we will copy from the message is its time stamp, for convenience. This is what it looks like :

struct slot_t {
    slot_t *p_previous;
    slot_t *p_next;
    uint32_t msg_addr;
    uint32_t timestamp;
};

So each leaf will be able to have what we call a bucket, a.k.a. a linked list of slot_t C structs.

By the way, the slots are stored in a global array of slot_t. The array’s size is the max number of messages we can store in the external flash. We also have three global variables in the program of type slot_t* named begin_busyend_busy and begin_free. We will see that our array of slots can be seen as a pool of slots.

At startup, none of slots are used. Thus, we will attach the slots all together. Then will assign begin_free to the first slot of the array. Making begin_free the head of a linked list of ready-to-use slots.

During the tree building process, a slot will be detached from this linked list each time a message is being attached to a leaf’s bucket. The begin_busy and end_busy pointers will be set latter.

At the end of this process, each message will be attached to its slot. This slot will be placed in a leaf’s bucket following those rules:

  • When there is only one message belonging to a leaf’s time frame, the bucket of this leaf will be of size 1 and will contain this messages’s slot.
  • If several messages with different time stamps all belong to the same leaf, they will be attached to this leaf’s bucket. The bucket’s order will be based on the slots time stamps.
  • Finally, if several messages with the same time stamp all belong to the same leaf, the will be attached to this leaf’s bucket. We will not be able to order them by time stamp since their are equal. We will us their SHA256 instead.

Fourth step: Building our linked list of time-ordered messages

 

So now, we have a Merkle tree with (small) linked lists attached to its leafs. The only thing to do next is to attache all those linked lists together to have a long one. The begining and ending of this long list will be stored in the begin_busy and end_busy pointers. This long linked list will be used to travel across the messages list in an time ordered manner. Being able to doing so will be very useful because it allows us to not order the messages in the external flash.

 

What to do next ?

 

So yeah, it has been quit challenging to find an efficiente way to store and build this Merkle tree in C. I now understand why python is such an easy-to-prototype language.

 

Even if i have a some messages pools for which the tree building process succeed, I know for sure that it is not over yet. I found particular message pool which make crash my building process. So i might spend the following week fixing it.

 

By the way, there is still no automatic test using criterion in my code. I plan on adding some as soon as possible. For now I only use my eyes to read the text-representation of my tree and printf() error reporting in order to detect errors.

 

See you next week !

 

Antony Lopez

[Little Brosers] Tree best reasons to start working on our C library

Guess what, I spent less time finding this posts’s title joke than last week. I’m getting good at it !

 

Reason one: No-More-Windows

Let’s just say that designing our PCB using Windows 10 on my MacBook Pro (late 2011) was not the best time effective part of ROSE. More seriously, our PCB’s design is now over. I spent some time this week tweaking last details: adding the VIAs all over the board and designing the antenna to SoC track adapting its impedance to get the most out of our tiny little baby 2.4GHz antenna.

Oh and, I forgot to mention the number one killer feature of this board : There will be the following text engraved in it: “Little Brosers ROSE 2018”. Wow. So fancy. Much professional.

Reason two: Winter is coming, the end of ROSE too

My dear fellows know as much as me how reassuring the countdown of this blog’s welcome page is. Or is it?

Regarding our project, we were building tiny parts of the project until now and some start to interact. (mostly Android and nrf52 bluetooth stack for now)

Our merkle tree implementation and the “diff-like” algorithm written in python by Guillaume are functional but need to be translated to some more optimized C code. This is what I started to do this week and what will fill the next ones.

There is some big issues about how we will allocate the memory for the merkle tree and how we will link it to the messages stored in the external flash. For now, we need to validate the diff-like algorithm in order to test it with the bluetooth stack.Thus, we will simply dynamically allocate the merkle tree. This is still a big chunk of work to do. Of course we will switch to a static allocation later in the project.

Reason tree: Credibility

I just needed three elements to make my joke.

See you next week !

Antony Lopez

[Little Brosers] Grounded in a tear drop shape

Ok so… Apart from spending 10 minutes to find a joke for this post’s title, I have well progressed on my Little Brosers tasks.

 

As I said in my previous post, this week as been all about PCBs. First some practice on the PCB design software and those 3 last days were dedicated to the drops’s schematic and PCB.

I’m happy to present you the very first version of our drop’s PCB :

 

To be honest, this is not fully ready yet. On tomorrow class I’ll improve the ground plan exclusion to shape it as a “U” letter.

Also I have to add some fixation holes and two targets for the component placing machine.

The round shape is mostly aesthetic. Since our product is called a “dead drop”, it seemed logical to make round.  It also reduces the size of the PCB since our biggest component is the round shaped battery holder. You can’t see it on the preview image but it is basically the same size than the PCB.

 

Cheers

Antony Lopez

[Little Brosers] Stepping into the PCB’s design

Hello every one!

 

Ok, first things first : yes, my week in Madrid was great. Thanks for asking.

You need to see the Royal Palace if you ever go there, it’s beautiful. Seriously.

Let’s get back to our dear dead drops. I had no chance to publish any post last week but still, there is always something happening in the ROSE’s projects!

 

Updates on PSSC

We began this week with a meeting about PSSCs. To be honest, some of our early PSSC were late on schedule and others had not much time left before its deadline. Thus, the first days of the week were dedicated to put the finished ones in “Wait for validation” state and actually finish the others. We had a code review session as well as an android app test among the team’s member’s phones. The goal was to make sure the ongoing notification (the ones you can’t dismiss by swiping) generated by our app could not be dismissed on any of our phones.

We now wait for the ROSES’s guru’s validation.

 

Lucky me!

Ok, so this week I wanted to start our PCB. The thing is… there is not su much to wire, and that’s great!

 

Indeed, our drops will only contain a battery holder, a flash memory, a JTAG connector, a SoC , a quartz and some passive components. We don’t even need to bother about the battery recharging system because… we don’t need one. Remember! Our goal is to be able to hide our Drops in a hard to reach stash, we don’t care about recharging the battery.

Moreover, our dear Nordic engineers have put into their info center a typical NRF52832 schematic for us. I started from it to design our PCB.

Also, by default I chose the DC/DC power mode for the SoC. We’ll discuss it in our next group meeting, but it is very likely the power mode we will use considering its lower consumption compared to LDO power mode.

About our flash memory, we made the simple choice to take the same than the previous Dead Drops-like project (ROSE 2014). Of course, the idea is not to copy their work but reading theirs posts about this particular flash and their PCB helped me determine how we will wire it for our NRF52. In their logbook posts they also explained the few trubles they had with this flash memory. It’s a work we will not have to waist time on. Thanks’ fellows!

 

I guess that is all for this week.

 

See you next week!

 

Antony Lopez

[Little Brosers] Finalize the Makefile and setup the CI

Hello there!

 

Guess what ? This week i’m writing my article from Madrid ! So let’s sum up what happened this week int the Little Brosers project, or at least, what I worked on.

Makefile

This week was all about designing a compilation environment. First we started from the Nordic’s SDK examples. It gave us a functional Makefile compatible with the design we had in mind.

First idea was to put all make targets (devkit targets, c++ simulation target, custom Little Brosers PCB targets),  in one Makefile. However, it seemed simpler and cleaner to have a Makefile per platform. Thus we now have two Makefiles. One for building a .elf for the DevKit and another one for the C++ simulation.

Those two pick code from three folders:

  • hw : All code here is hardware dependent
  • core : All code here is hardware independent. It’s basically merging Merkle trees algorithms and cryptographic code. No main.c/.cpp should exist here.
  • sim : All code here is used to test the core folder C code. It allows us to get ride of BLE communication constraints to test algorithms.

The C++ simulation Makefile also comes with the linter related targets designed by me and Guillaume Lagrange.
Those are used by ourselves (programmers) before pushing our code and also by the CI to test the code style.

I worked a lot on the C++ Makefile to allow it manage automatically dependencies and put all the .o and .d files in a “build” sub folder. The objective was to never create any file in the src/ folder of the project. Indeed, we have to keep in mind that other Makefile will read files in the src/ folder.

 

Continuous Integration

This week was also about setting up the continuous integration using GitLab and Docker. This job has been shared between all group members. I took care of the CI artifacts and C/C++ compilation stages. Other group members took care of CI for python, linter and Android mobile app.

See you next week from home this time 🙂

Antony Lopez

 

[Little Brosers] Narrowing the components list and pushing my first commit !

SoC final choice

After more digging into SDK features, we finally chose the NRF52832 from Nordic as our SoC thanks to Nordic’s great SDK.

Why this choice ? I’m glad you asked!

Comparing NXP, Cypress and Nordic SDKs, I came to the conclusion that our development process would be simplified the most using Nordic’s SDK. Not only the C libraries from Nordic such as the nRF5 SDK v14.1.0 are impressively well documented but we will also be helped by the Nordic Android BLE SDK and user guide for the mobile app we plan to develop.

Other tools may be considered. For example, Nordic provide the Power Profiler Kit allowing developers to estimate the current consumption of the SoC during our code execution from 1µA to 70mA with a resolution of 0.2µA.

Also, Nordic’s SoC come with OTA firmware update feature. Allowing us to easily setup the firmware update process though BLE.

Choosing the Flash memory

We had less specific needs for the flash memory.

To estimate the needed size, I used the following values:

  • A message with payload +  Little Brosers’s overhead should take less than 400 bytes
  • A drop should be able to store around 9000 messages
  • A worst case scenario 4-ary Merkle tree with this configuration should have a size of 300kB with 128 bits long hashs
  • The total of those estimation gave us a size of around 4MB

Of course those estimations are not precise but 9000 messages is quite a big number and we’ll allow us to store less messages on a drop if needed.

I also knew that a easy to solder package like SOIC-8 would be way more convenient during the soldering process of our PCBs.

In the end I had 5 flash models packaged in a SOIC-8 with similar features and I selected one of average price, well balanced set of feature and allowing several power modes to adapt its consumption. This is the AT45DB321E from Adesto Technologies.

Pushing my first commit

Indeed, for the drops firmware we plan to separate the C source code supposed to be used in the drops and the C++ source code only executed one our PCs to perform quick simulations. This structure should allow us to develop the hardware independent C code for the drops and test it using C++ ease of use. Those simulations will allow us to perform Merkle tree merges without the whole BLE communication process. We will emulate it with C++ objects.

So, i spoke about my first commit… and what a commit !

Indeed, we decided to start from a Nordic’s SDK’s example four our Makefile structure. Thus, I had to put the whole Nordic SDK in the repository (~120MB).

In the following weeks, I’ll work on editing the Nordic’s Makefile to include our C++ simulation environnement.

Eventually, we would like to have a Makefile from which we could run the following kind of targets:

  • make sim : build a x86 binary including hardware independent C code and the C++ simulation code
  • make devkit : build an ARM binary for the NRF52 DevKit including hardware independent C code, SDK and DevKit specific code
  • make firmware : build an ARM binary for the drops including hardware independent C code, BLE code, SDK and Drops specific code
  • make clean : well… clean the project
  • make flashdv : flash the DevKit with its dedicated binary
  • make flashd : flash a Drop with its dedicated binary

See you next week !!

Antony Lopez