📜 ⬆️ ⬇️

The option of organizing software version control for devices with multiple network devices on board

I want to share some ideas about the organization of repositories in the version control system. For definiteness: we use Mercurial, but this is not so important.

In a nutshell about the task. Several projects are underway at the same time. Projects are devices with digital devices on board (dozens of devices) that are networked. We are talking about onboard device software that needs to be tracked using a version control system.

There are onboard devices, the same for different devices, and there are specific ones. Devices can be programmed by different developers, and some of the devices program counterparties. The brands of processors (controllers) onboard devices vary. Different devices can use the same libraries: drivers, mathematics, etc.
')
Developers spend a lot of time on business trips (on tests), where they quickly need to change the code and exchange updates over the Internet.

Now it is surprising that such work was carried out without a version control system. Perhaps this was possible because there were not so many projects, but only two developers. But things can't continue like this anymore.

We have formed the concept of version control and slowly begin refactoring projects in line with this concept. While we are at the beginning of the road, we like the solutions we find, but perhaps we don’t see all the pitfalls and can pay for it in the future. We hope that the recommendations of the readers will help to correct the errors before we go very far.


So, about the very concept of control. For us, it is important to use a distributed version control system (see frequent and long trips above). For several reasons, the choice fell on Mercurial, although Guit would probably have descended.

The storage is used not one, but their whole set (tree, structure). Storages are interconnected and distributed to folders in a specific order. Further such set of storages will be called a tree of storages.

One repository tree is hosted on the server. His clones are on local PC developers. The developer clones the local tree or its individual branches as he wants.

The storage tree template is as follows:

Repositories | +–.CrossplatformLib1 | +–.CrossplatformLib2 | +–... | +–Platform1 | | | +–.Platform1Lib1 | | | +–.Platform1Lib2 | | | +–... | +–Platform2 | | | +–.Platform2Lib1 | | | +–.Platform2Lib2 | | | +–... | +–... | +–Devices | | | +–.Device1 | | | +–.Device2 | | | +–... | +–Vehicles | +–Vehicle1 | +–Vehicle2 | +–... 

Dot stores are marked with a dot at the beginning of the name, for example .Device1. Names without dots are regular folders, for example, Devices.

At the root of the tree (at the root of the Repositories folder) are located the .CrossplatformLibX storages containing cross-platform libraries, for example, mathematics, algorithms, etc.

At the same level are the PlatformX folders, with the .PlatformXLibY repositories, containing libraries specific to PlatformX. For example, network drivers under Windows.

In the top-level folder of Devices, there are .DeviceX software storage for onboard devices that can be used on different devices.

The last top-level folder is Vehicles. It contains projects for different vehicles VehicleX.

In turn, the design of a specific VehicleX device may be a repository or a set of repositories. Now it is not so important, and later will be considered in more detail.


This structure demonstrates the location of the repositories relative to each other. Now let's look at how the stores themselves are organized.

Sub-storage mechanism is essentially used (as I understand it, there are such possibilities in all modern version control systems).

Consider for example some device Devices \ .DeviceX. For example, device X uses the cross-platform library Y and the library N specialized for platform Z. Then, at the level of the Devices \ .DeviceX folder, clones of the .CrossplatformLibY and PlatformZ \ .PlatformZLibN storages are created:

 Repositories | +–Devices | +–.DeviceX | +–.CrossplatformLibY | +–.PlatformZLibN | +–DeviceXSpecificFolder1 | +–... 

Along with the sub-storage .CrossplatformLibY and .PlatformZLibN, the folder contains device-specific X source code files in the folders DeviceXSpecificFolderM, etc.

Compiler settings files use relative paths, and these files themselves are tracked by the version control system. If you need to transfer the .DeviceX project to another computer, for example, copy it to a laptop and take it with you on a business trip, then it will be enough to copy only the .DeviceX folder - it contains all the information you need to compile. At the same time, it is not necessary to keep the path to the copied .DeviceX folder unchanged.


Now back to the draft VehicleX device, which includes a variety of network devices .DeviceY. In the simplest case, all the onboard devices are slave subscribers in the network, and one of them is the master. Let's call him Master. The lead subscriber is the center of system integration - it knows the formats of all messages, sends requests, receives replies, etc. The corresponding .VehicleX repository can have the following structure:

 Repositories | +–Vehicles | +–.VehicleX | +–.DeviceY | +–.DeviceZ | +–DeviceM | +–... | +–Master 

Network devices can be both universal (used on different devices) and specific. In the first case, the corresponding backup (let it be .DeviceY) is a clone of the Devices \ .DeviceY repository. In the second case, the device project can be monitored as a separate depository (.DeviceZ), or it can be organized as a separate subfolder of the .VehicleX storage (for example, this isVehicleX \ DeviceM). The option with a depository is more convenient because it is easier to isolate it from the project (by cloning).

The question arises. Do we need to store in the .VehicleX storage all source codes of universal devices .DeviceY? In fact, to develop a Master Master, it suffices to know only the interfaces of universal devices, in the simplest case - the formats of their messages. These formats are generally stable and rarely change. At the same time, the implementation of devices undergoes changes regularly, at least in the early stages of development, it changes significantly more often than the interface.

Why establish strong links between .VehicleX and .DeviceY projects? Why should the system integrator (Master developer) understand and synchronize these projects when changing some internal details of the implementation of network devices?

This problem is overcome if you synchronize not the projects of the devices entirely, but only their interfaces. One of the interface tracking options might be this. Select the interface files of the .DeviceY device into a separate .Interface sub-storage:

 Repositories | +–Devices | +–.DeviceY | +–.Interface | | + +- device_y.h | +–Source | +–... 

The store .Interface can often consist of a single header file device_y.h, so be it!

Now, in the storage of the .VehicleX device, you can not track the entire .DeviceY project, but only its .DeviceY \ .Interface interface, which is less cumbersome and more stable. His clone can be placed in the .VehicleX \ Devices \ .DeviceY dungeon:

 Repositories | +–Vehicles | +–.VehicleX | +–Devices | | + +-.DeviceY | | + +-... | +–... | +–Master 

In the folder .VehicleX \ Devices you can put interfaces and other network devices. In order not to prescribe the paths to each sub-storage of the network device interface .VehicleX \ Devices \ .DeviceY in the settings of the Master compiler, you can place the device_y.h files with the redirection #include ”. \. DeviceY \ device_y.h” in the folderVehicleX \ Devices. Then, for the Master compiler, it will be enough to register only the path .. \ Devices.

Considered reception with interfaces is especially convenient when contractors are developing network devices. In this case, the source code of the device may not be available, but the interface files must be consistent, for example, at the stage of the formation of the technical specifications.

That's all in general terms. But here not all questions are presented. For example, we have not yet decided how to control versions of executable files (binaries). I really do not want to put them under the control of the version system so that the repositories do not swell. And given that each project consists of a set of executable files - I foresee a “nightmare dll”.

Source: https://habr.com/ru/post/177635/


All Articles