<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.7.6(BH)" -->
<rss version="2.0">
    <channel xmlns:g="http://base.google.com/ns/1.0">
        <title>Planet Maemo: category &quot;feed:04088ede8ecf981676b12f87999d25d2&quot;</title>
        <description>Blog entries from Maemo community</description>
        <link>http://maemo.org/news/planet-maemo/</link>
        <lastBuildDate>Sun, 24 May 2026 07:50:41 +0000</lastBuildDate>
        <generator>FeedCreator 1.7.6(BH)</generator>
        <language>en</language>
        <managingEditor>planet@maemo.org</managingEditor>
        <item>
            <title>libSDL2 and VVVVVV for the Wii</title>
            <link>http://mardy.it/blog/2024/02/libsdl2-and-vvvvvv-for-the-wii.html</link>
            <description><![CDATA[
<p>Just a quick update on something that I've been working on in my free time.</p>
<p>I recently refurbished my old Nintendo Wii, and for some reason I cannot yet
explain (not even to myself) I got into homebrew programming and decided to
port libSDL (the 2.x version -- a 1.x port already existed) to it. The result
of this work is already available via the <a href="https://devkitpro.org/">devkitPro</a>
distribution, and although I'm sure there are still many bugs, it's overall
quite usable.</p>
<p>In order to prove it, I ported the game <a href="https://thelettervsixtim.es/">VVVVVV</a>
to the Wii:</p>
<iframe src="https://vk.com/video_ext.php?oid=7200355&amp;id=456239302&amp;hd=1" width="640" height="360" allow="autoplay; encrypted-media; fullscreen;
picture-in-picture;" frameborder="0" allowfullscreen></iframe>

<p>During the process I had to fix quite a few bugs in my libSDL port and in a
couple of other libraries used by VVVVVV, which will hopefully will make it
easier to port more games. There's still an issue that bothers me, where the
screen resolution seems to be not totally supported by my TV (or is it the HDMI
adaptor's fault?), resulting in a few pixels being cut at the top and at the
bottom of the screen. But unless you are a perfectionist, it's a minor issue.</p>
<p>In case you have a Wii to spare, or wouldn't mind playing on the Dolphin
emulator, <a href="https://github.com/mardy/VVVVVV/releases/tag/v2.4.1_wii1">here's the link to the VVVVVV
release</a>. Have fun! :-)</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1eec21f35e5856ac21f11ee945b171ccdc9549b549b&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1eec21f35e5856ac21f11ee945b171ccdc9549b549b/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1eec21f35e5856ac21f11ee945b171ccdc9549b549b&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1eec21f35e5856ac21f11ee945b171ccdc9549b549b/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Fri, 02 Feb 2024 17:50:44 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1eec21f35e5856ac21f11ee945b171ccdc9549b549b</guid>
        </item>
        <item>
            <title>Will the internet forget russophobia?</title>
            <link>http://mardy.it/blog/2023/06/will-the-internet-forget-russophobia.html</link>
            <description><![CDATA[
<p>I've often wondering what will happen when this horrific war in Europe will
finally be over. I won't be discussing politics here, but what is mostly
interesting to me is how (and if) all the companies who made high proclaims
about not doing business with Russia will justify their getting back into the
Russian market. They will probably count on the fact that the war will be long,
and that people will forget what these companies' stance was. After all, the
world has forget about all the companies who collaborated with the Nazi regime,
so we can expect the same to happen with this war.</p>
<p>But I don't think that's right: if you made a mistake, you should be held
accountable for it. You might be wondering what is the “mistake” I'm talking
about: that's <strong>russophobia</strong>, indeed. To put it simply, and make a concrete
example: if The Qt Company stops doing business with Russian companies and
blocks its downloads page to Russian IP addresses because of the war, <em>without
being forced by the government to do so</em>, but does not take similar measures
against other countries who wage wars which have caused way more deaths and
displacement of individuals, well, that's what I call “russophobia”. Of course,
I'm aware that there's way more than that, and that the hatred for all what is
Russian (including culture and sport competitions) is an even bigger issue, but
in this blog post I'm especially focused on the IT world, so please forgive my
semi-intentional narrow-mindness on this topic.</p>
<p>Now, I'm fully aware that we live in a mediatic bubble that directs our
decisions in a way that is almost automatic, and I'm sure that most people
working for companies who took russophobic decisions are not themselves
russophobic at all (and I'm not dismissing the possibility that even the very
same people who took these decisions might not be russophobic) and that these
decisions were taken on impulse, because “everyone else is doing the same” and
due to the media pressure that if you don't do that, you might get accused of
supporting the “wrong” side of the war.</p>
<p>But that's not an excuse, especially for “smart” people like IT engineers (and
I put the adjective between quotes <a href="http://mardy.it/blog/2022/11/the-idiotism-of-software-developers.html">for a
reason</a>), and especially after
the initial heat has passed and when, after more than one year of war, we
should have been exposed to different point of views and be able to evaluate
the situation more rationally. It has been therefore especially stunning for me
to learn that the Linux Kernel community, and hence The Linux Foundation, has
recently given room to russophobic behaviours, refusing a patch coming from the
Russian company Baikal (a CPU maker). For the record, the incriminated patch
was not related to supporting hardware produced by this company (not that this
would make the deed less serious, but at least one could have argued that there
could be some spot of logic in it):</p>
<div class="code"><pre class="code literal-block">From: Jakub Kicinski &lt;kuba@kernel.org&gt;
To: Serge Semin &lt;Sergey.Semin@baikalelectronics.ru&gt;
[...]

On Tue, 14 Mar 2023 01:42:24 +0300 Serge Semin wrote:
&gt; From: Serge Semin &lt;Sergey.Semin@baikalelectronics.ru&gt;

We don't feel comfortable accepting patches from or relating 
to hardware produced by your organization.

Please withhold networking contributions until further notice.
</pre></div>

<p>(<a href="https://lore.kernel.org/all/20230314103316.313e5f61@kernel.org/">here</a> the
link to the original discussion). One week later, someone denounced this as a
violation to the Code of Conduct committee (unfortunately the only link I could
find to this is coming from a <a href="https://www.opennet.ru/openforum/vsluhforumID3/129994.html#529">Russian IT
forum</a>, and any
other references seem to have been removed from DuckDuckGo and Google), only to
receive a reply that it was all fine.</p>
<p>To me this is not fine. The war will end, sooner or later, but it bothers me
that we never learn from the past and repeat the same mistakes over and over.
We apparently know a lot about propaganda, yet we fail to recognize it when it
influences our own mind and actions. My humble contribution is the creation of
a page where I list the companies who have taken russophobic actions, and, on
the opposite side, companies (like Flickr and Zorin OS) who have stood out for
positive messages and helpful actions. My hope is that some of the listed
companies will find the courage to review their actions, and either correct
their stance, or at least clarify their reasons. So, I hereby present</p>
<p style="text-align: center; font-size: 130%">
  <a href="https://github.com/mardy/russophobia">Denouncing russophobia</a>
</p>

<p>where you'll find some of the good and some of the bad companies. I'm sure I'm
missing plenty of them: I just started recollecting my memories and searching
online a couple of days ago. I created this as a GitHub project, because indeed
I'm looking forward for contributions, to help me make the lists more complete.
I need to stress that the fact that a company has announced the suspension of
its business in Russia does not automatically make it russophobic: what we need
to look at is the <em>reason</em> for that decision: companies like LEGO and Nintendo,
for example, have suspended their operations citing logistic and financial
reasons; no judgement involved.</p>
<p>Let me repeat it once more, just to make sure there are no misunderstandings:
it's perfectly fine for businesses to take a stance on politics, and sometimes
it might be even praiseworthy; but if a company is international, and does not
apply the same reasoning to other armed conflicts, or seem to care only about
certain human rights violations and not others, then it's a case of double
standards which we need to be aware of, and make the company think twice about
it. And that's also the reason why you won't find any Ukrainian company among
the “bad” ones, because in their case the reaction is perfectly understandable
and they can hardly be accused of adopting double standards (well, technically
speaking, they are adopting double standards, but when you are so directly
impacted I think it does not deserve a blame): if it's your house which burns,
you should definitely scream about it, even if you previously have been silent
about your neighbour house's burning.</p>
<p><strong>I'm especially looking forward for more “good” companies</strong>, who have shown empathy
towards the people affected by the war (and maybe even collected money to help
them) while refraining from taking the judging role and forgetting about all
the injustice and suffering that other wars have caused (including on that very
same piece of land that suddenly appeared on all newspapers' front pages on
February 24th, 2022). I hope that these companies can serve as an example of
positive action, humanity, and love.</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ee02ef5cfc281002ef11ee881095434502751a751a&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ee02ef5cfc281002ef11ee881095434502751a751a/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ee02ef5cfc281002ef11ee881095434502751a751a&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ee02ef5cfc281002ef11ee881095434502751a751a/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 04 Jun 2023 07:41:02 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ee02ef5cfc281002ef11ee881095434502751a751a</guid>
        </item>
        <item>
            <title>Back to Maemo!</title>
            <link>http://mardy.it/blog/2023/01/back-to-maemo.html</link>
            <description><![CDATA[
<p>New year, new job. After <a href="http://mardy.it/blog/2022/12/leaving-canonical-again.html">leaving
Canonical</a> I'm back to working on the same
software platform on which I started working back in 2006: <a href="http://mardy.it/blog/2023/01/maemo.org">Maemo</a>.
Well, not exactly the vanilla Maemo, but rather its evolution known as <a href="https://en.wikipedia.org/wiki/Aurora_OS_(Russian_Open_mobile_platform)">Aurora
OS</a>,
which is based on <a href="https://sailfishos.org/">Sailfish OS</a>. This means I'm
actually back to fixing the very same bugs I introduced back then when I was
working in Nokia, since a lot of the middleware has remained the same.</p>
<p>At the moment OMP (the company developing Aurora OS) is mostly (or even
<em>exclusively</em>, AFAIK) targeting business customers, meaning corporations such
as the Russian posts and the railway company, whereas the consumer market is
seen as something in the far away future. Just in case you were curious whether
there were any devices on sale with Aurora OS.</p>
<p>I should also explain why I've refused several very well paying job
opportunities from Western companies: it's actually for a reason that has been
bothering me since last March, and it's a very simple one. The fact is that
because of the sanctions against Russia I already had to change bank once (as
the one I was using fell under sanctions), and in these months I've always been
working with the fear of not being able to receive my salary, since new
sanctions are introduced every month and more and more banks are being added to
the blacklist. That's why I've restricted my job search to companies having an
official presence in Russia; and to my surprise (and from some point of view, I
could even say <em>disappointment</em>) the selection and hiring processes were so
quick that I received three concrete offers while I was still working my last
weeks at Canonical, and I joined OMP on that very Monday after my last Friday
at Canonical.</p>
<p>I mean, I could have rested a bit, at least until the Christmas holidays, but
no. ☺  Anyway, I'm so far very happy with my new job, and speaking Russian at
work is something totally new for me, both challenging and rewarding at the
same time.</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ed8f95d7356b8c8f9511eda0e433ed3b75723f723f&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ed8f95d7356b8c8f9511eda0e433ed3b75723f723f/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ed8f95d7356b8c8f9511eda0e433ed3b75723f723f&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ed8f95d7356b8c8f9511eda0e433ed3b75723f723f/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 08 Jan 2023 19:48:52 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ed8f95d7356b8c8f9511eda0e433ed3b75723f723f</guid>
        </item>
        <item>
            <title>The “idiotism” of software developers</title>
            <link>http://mardy.it/blog/2022/11/the-idiotism-of-software-developers.html</link>
            <description><![CDATA[
<p>Before you get angry at me for this title, please let me state that I count
myself in the number of the “idiots” and, secondly, that what I mean by
“idiotism” here is not to be intended as an offence, but as some traits of
mindset which are typical of very logical brains.</p>
<p>Some months ago I finished reading Dostoevskiy's “The Idiot”, a book about an
exceedingly good-hearted man, prince Lev Mishkin, whose behaviour was puzzling
the people around him so much that they thought of him as an idiot. Sure, the
fact that he was suffering from epilepsy didn't help, but it was far from being
the primary reason for their thinking, since his epileptic seizures were very
rare (if I remember correctly, only two occurred during the time of the story)
and everybody's opinion had already formed well ahead of witnessing him in such
a state.</p>
<p>He was an idiot because he was open, trustful, and especially because he could
not “read between the lines” of what was been said to him: his social conduct
was straight, and although he was following at his best the customs that he had
been taught, he was supposedly awkward and unable to perceive and parse all the
messages that are implicitly conveyed by social behaviours and human
interactions. I added the word “supposedly” because, as a matter of fact, his
behaviours were all perfectly normal for me: I only noticed their awkwardness
when it was pointed out by the other characters, at which point I couldn't help
smiling and acknowledging that, indeed, that thing he did was weird.</p>
<p>However, he was a good and caring person, and not without talents: he had an
interest in calligraphy, and everybody liked to listen to him, as his speech
was insightful and his thoughts were original. I wonder how many of my readers
can identify themselves in such a character?</p>
<p>I definitely can. I won't get into the details, but I've felt many times on me
the amused or puzzled glance of people (like that time in high school when I
could not open a door in front of dozens of people, and I heard them say “So,
that guy is the genius of mathematics?” — I'll never forget that!), often
without understanding the reason for their reactions. Still, generally people
seem to like my company and be genuinely interested in talking to me.</p>
<p>So, what's wrong with prince Lev Mishkin, me, and maybe with you too? Well, a few
things, I would say. I'm not going to claim any scientific truth on what I'm
going to say, these are just my own impressions and deductions, which seem
to be shared by other people in the interwebs too, judging from a quick search
I did; take them for what they are.</p>
<p>The first thing I notice is some common traits between us and autistic people:
we tend to work better with things, rather than with people; we can focus on
a certain thing (work, a mathematical problem, a game) and forget about the
world around us; we have our unique hobbies, like solving puzzles, arguing
about a specific and very narrow topic, learning artificial (both human and
programming) languages; it's as if we needed to build a small, better world
where we would feel safe and at ease.</p>
<p>The other thing, which I actually consider harmful and which I put efforts to
change in my own life, is the fact that it's extremely easy to get us
interested into a specific aspect of a problem, and make us forget (or just not
notice) the big picture. That small part that we are looking at is stimulating
and challenging, and we are led to think that it's core of the issue, and maybe
of all the issues that affect our world. What is often missing is the ability
to take one step back and try to look at the issue from a different angle, and
especially the ability to listen for counter arguments; I mean, we do listen to
them, but since we have, in a way, “gamified” the issue, even when we think
that we are open to listen to the other side, we are in reality trying to win
the counter-arguments, rather than genuinely trying to understand them.</p>
<p>Another thing which we have, is faith. Yes, you read it right: even though the
IT world is probably the one with the highest percentage of atheists, men
always need something to believe in. We just don't realize it, but we do hold a
blind trust in certain persons and authorities. This does not mean that this
trust lives forever and cannot be broken, but this generally does not occur
because of a conscious realization of ours. Much more often than we'd like to
admit, the reason why we lose faith in a certain person or authority is because
<em>the rest of the persons and authorities that we trust has told us so</em>. In
other words, even if there's undoubtedly a reasoning of our own, the full
realisation and conviction occurs after having collected and compared the
opinions (or statements) of those we trust. The net result is that the IT
population is the one most trustful of the mainstream media, because it's the
mainstream media who has more “voice”: that's where the most <em>reputable</em>
journalists, scientists, activists are (and “reputable” is the key word here,
since this reputation is recursively created by the mainstream media
themselves or by their sponsors).</p>
<p>I might be biased by my own experience here, but it seems to me that there
isn't a group of people more homogenous in their political (and generally,
world) views than that of IT workers. When, in 2018, I saw the leaked video of
Google's co-founder Sergei Brin and other executives' reaction at Trump's
presidential victory, what I found most surprising was not the contents of the
speech, as they were mostly mainstream opinions, but rather the fact that all
this could be said in a company meeting. Something like this, I though, could
never happen in an European company, as political matters are a conventional
tabu in the work environment. But the point is that Brin and others could say
those words only because <em>they knew</em> that the overwhelming majority of the
audience shared the same opinion. I don't think you could find the same
homogeneity of thought among shop assistants or philosophy professors.</p>
<p>Assuming that you have followed me this far into my rambling, and that you
recognize that there might be some truth in what I wrote, you might now be
wondering if there's a way to counterbalance our “idiotic” traits.
Unfortunately I don't have a full answer, as myself am only halfway there (but
maybe I'm too optimistic here? and does this road even ever end?), but there
are a few things that I think are absolutely worth trying:</p>
<ul>
<li>
<p>Talk with people. Better if face to face, or at least in a video call; just
  1-on-1, avoid groups, or you'll get on the defensive and try to defend your
  position for the sake of not losing the argument in front of an audience. But
  it's not a fight. Your goal when talking should not be that of convincing or
  getting convinced, but rather just to <em>understand</em> the other points of view.</p>
</li>
<li>
<p>Read both sides of the narrative. Try to see the other party's argument as
  they themselves present it, and not how it is presented in the media you
  usually read. Media often use this trick, to either invite “clown
  representatives” of the other point of view just to ridicule it, or they give them
  too little time, or extrapolate their answer out of context, just to make
  them appear unsensible.</p>
</li>
<li>
<p>Always assume that other people are smart, and that no one is bad.</p>
</li>
<li>
<p>Whatever the argument, try to answer the key question: “Cui bono?” (who
  profits?) to be at least aware of all the hidden interests behind this and
  that. They don't necessarily invalidate a position, but they must be
  considered.</p>
</li>
<li>
<p>Lose faith. The only faith you are allowed to keep is the faith in God (or
  Gods), if you have it: but men, theories, institutions, authorities
  (including religious ones!), these must always be assumed to be imperfect and
  not blindly trusted.  People serve their interests or can be manipulated. Try
  always to start from a clean table and an empty mind, and see if they have
  enough arguments to convince you. </p>
</li>
<li>
<p>Do never assume “They can not <em>all</em> be wrong” or “If this were wrong, at
  least some media would report it”. It just doesn't work this way, this is
  again a matter of having faith in the majority. Think of how many times in
  (recent) history you were presented an unambiguous truth, which later came
  out to be a scam (Iraq war being a famous one).</p>
</li>
<li>
<p>Defocus. You might be spending a lot of energy into something that's not
  worth it. I mean, feel free to pursue whatever hobbies you like, as long as
  they make you feel better. But if you think you have a <em>mission</em>, think twice
  about it. Think about the world you'd like to live in, and whether/how this
  mission contributes to it.<sup id="fnref:saudi"><a class="footnote-ref" href="http://mardy.it/blog/2022/11/the-idiotism-of-software-developers.html#fn:saudi">1</a></sup></p>
</li>
<li>
<p>Ask questions. Be curious. Be challenging. For any topic, there are questions
  that have not been answered in mainstream media<sup id="fnref:refugees"><a class="footnote-ref" href="http://mardy.it/blog/2022/11/the-idiotism-of-software-developers.html#fn:refugees">2</a></sup>. Find the answer,
  then find explanations, never stopping at the first satisfactory one, but
  always get at least two competing answers. From here, ask more questions,
  rinse and repeat. And at every step ask yourself this: why didn't I know
  about this? Is someone trying to hide the truth from me?</p>
</li>
<li>
<p>Aim at improving. Whenever you read something or talk to people, keep a
  humble attitude and try to be challenged. Your goal should be that every
  reading and every dialog should make you wiser, even if what you initially
  read and heard sounded like garbage. There are always reasons for all these
  thoughts you disagree with.</p>
</li>
<li>
<p>Reach out to the people nearby. Try not just to be sympathetic to the needs of
  some population living far away from you, which the media has singled out as
  being those needing your compassion, and try instead (or in addition to that)
  to be sympathetic and helpful to the people around you. To your neighbours,
  to those you see in the public transport and, first and foremost, to your
  relatives.</p>
</li>
</ul>
<p>Summing up, what I want you to realize is that we IT workers are easily
exploitable. All those thought manipulation techniques represent a problem to
everyone, but it's particularly with us that they tend to be especially
effective; as a matter of fact, I've found that awareness of how the power
controls us is higher among uneducated people, because they are more
distrustful of the media and just tend to consume less of it. We, on the other
hand, are not only well educated to respect the authority (see <a href="https://www.youtube.com/watch?v=wv6TyJ1AbRM">Noam Chomsky on
education</a>), but our logical,
detail-focused mind can be easily externally controlled by continuously
stimulating it to focus on specific things and not others.</p>
<p>How would Dostoevskiy call us?</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:saudi">
<p>I was recently surprised when I read people in a forum who were
discussing avoiding doing business with Saudi Arabia because of their human
rights record. Seriously? We are talking about a government who has indirectly
caused the death of more than 300 thousands people in Yemen, and your main
reason to criticize them is human rights? It's like asking the police to arrest
a killer because before the assassination he misgendered his victim! Yet the
elephant in the room continues to go unseen. <a class="footnote-backref" href="http://mardy.it/blog/2022/11/the-idiotism-of-software-developers.html#fnref:saudi" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:refugees">
<p>My favourite one is: which country hosts more refugees from Ukraine? <a class="footnote-backref" href="http://mardy.it/blog/2022/11/the-idiotism-of-software-developers.html#fnref:refugees" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
</ol>
</div><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ed639ae7393d3c639a11ed908a9167e270a031a031&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ed639ae7393d3c639a11ed908a9167e270a031a031/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ed639ae7393d3c639a11ed908a9167e270a031a031&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ed639ae7393d3c639a11ed908a9167e270a031a031/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Tue, 08 Nov 2022 17:11:55 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ed639ae7393d3c639a11ed908a9167e270a031a031</guid>
        </item>
        <item>
            <title>Deride, a generator of mock objects for unit testing</title>
            <link>http://mardy.it/blog/2022/11/deride-a-generator-of-mock-objects-for-unit-testing.html</link>
            <description><![CDATA[
<p>If you have been writing C++ classes for mocking out your C or C++
dependencies, you know how tedious it is. I generally write small classes with
just a handful of methods, so it's generally bearable, but when using
third-party code I'm usually not that lucky. If the dependency is a C library
this becomes especially tricky, both because they might be larger than what you
can handle, and both because the lack of an object-oriented design might not
offer you an easy solution to store the mock object data.</p>
<p>But fear no more, <a href="https://pypi.org/project/deride/">Deride</a> is here!</p>
<p>I won't spend too many words describing it, since you can read its description
from the link above, where you will also find some example code. More examples,
by the way, can be found in the <code>example/</code> folder in the <a href="https://gitlab.com/mardy/deride">code
repository</a>, where you can see how it can be
used to mock both pure C++ and <code>QObject</code>-based classes, and C libraries.</p>
<p>What is most important for me to say now, is that the project is in alpha
state, meaning that I've tried it on a handful of header files only; it's
highly likely that it will not work on many real-life scenarios, and if that
happens I warmly invite you to <a href="https://gitlab.com/mardy/deride/-/issues">inform me by filing a bug
report</a> providing the include file
that was not properly processed.</p>
<p>I leave you with a short example of a unit test, written using Deride. The
class under test is called <code>Stable</code>, and internally it uses objects of type
<code>Horse</code>, that we decided to mock. We used Deride to generate the mocked
implementation and a <code>MockHorse</code> class which can be used to control the mocked
objects. When building the test, we won't link against the original
<code>horse.cpp</code>, but we'll only use the original <code>horse.h</code>; the implementation will
be found in <code>mock_horse.cpp</code>, generated by Deride. And in the corresponding
<code>mock_horse.h</code> file we'll find the <code>MockHorse</code> class with all the
<code>on&lt;method&gt;Called()</code> hooks which we can use to install our callbacks (either to
reimplement the object behaviour, or to just be notified on when its methods
are called).</p>
<div class="code"><pre class="code literal-block"><span class="w">    </span><span class="cm">/* This MockHorse is the object created by Deride</span>
<span class="cm">     *                   |</span>
<span class="cm">     *                   |</span>
<span class="cm">     *                  \|/</span>
<span class="cm">     *                   V</span>
<span class="cm">     */</span>
<span class="w">    </span><span class="k">using</span><span class="w"> </span><span class="n">Mock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Animals</span><span class="o">::</span><span class="n">MockHorse</span><span class="p">;</span>

<span class="w">    </span><span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="w"> </span><span class="n">horseNames</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="s">"Tom"</span><span class="p">,</span>
<span class="w">        </span><span class="s">"Dick"</span><span class="p">,</span>
<span class="w">        </span><span class="s">"Harry"</span><span class="p">,</span>
<span class="w">    </span><span class="p">};</span>

<span class="w">    </span><span class="cm">/* We could use a vector, but let's be explicit */</span>
<span class="w">    </span><span class="n">Mock</span><span class="w"> </span><span class="o">*</span><span class="n">mockTom</span><span class="p">;</span>
<span class="w">    </span><span class="n">Mock</span><span class="w"> </span><span class="o">*</span><span class="n">mockDick</span><span class="p">;</span>
<span class="w">    </span><span class="n">Mock</span><span class="w"> </span><span class="o">*</span><span class="n">mockHarry</span><span class="p">;</span>

<span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">createdHorses</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w">    </span><span class="c1">// onConstructorCalled() is created by Deride and called when the mocked</span>
<span class="w">    </span><span class="c1">// Horse object is created</span>
<span class="w">    </span><span class="n">Animals</span><span class="o">::</span><span class="n">MockHorse</span><span class="o">::</span><span class="n">onConstructorCalled</span><span class="p">([</span><span class="o">&amp;</span><span class="p">](</span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="w"> </span><span class="o">&amp;</span><span class="n">name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">"Horse instantiated: "</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="w">        </span><span class="n">createdHorses</span><span class="o">++</span><span class="p">;</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">"Tom"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="n">mockTom</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Mock</span><span class="o">::</span><span class="n">latestInstance</span><span class="p">();</span>
<span class="w">        </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">"Dick"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="n">mockDick</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Mock</span><span class="o">::</span><span class="n">latestInstance</span><span class="p">();</span>
<span class="w">        </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">"Harry"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="n">mockHarry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Mock</span><span class="o">::</span><span class="n">latestInstance</span><span class="p">();</span>
<span class="w">        </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="n">assert</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span><span class="w"> </span><span class="c1">// should not be reached</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">});</span>

<span class="w">    </span><span class="n">Stable</span><span class="w"> </span><span class="n">stable</span><span class="p">;</span>
<span class="w">    </span><span class="n">stable</span><span class="p">.</span><span class="n">createHorses</span><span class="p">(</span><span class="n">horseNames</span><span class="p">);</span>
<span class="w">    </span><span class="cm">/* It's at this point that the contructor callbacks we defined above will</span>
<span class="cm">     * have been called. Let's double-check that indeed that's the case.</span>
<span class="cm">     */</span>
<span class="w">    </span><span class="n">assert</span><span class="p">(</span><span class="n">createdHorses</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">3</span><span class="p">);</span>
<span class="w">    </span><span class="n">assert</span><span class="p">(</span><span class="n">stable</span><span class="p">.</span><span class="n">count</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">3</span><span class="p">);</span>
<span class="w">    </span><span class="n">assert</span><span class="p">(</span><span class="n">mockTom</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="k">nullptr</span><span class="p">);</span>
<span class="w">    </span><span class="n">assert</span><span class="p">(</span><span class="n">mockDick</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="k">nullptr</span><span class="p">);</span>
<span class="w">    </span><span class="n">assert</span><span class="p">(</span><span class="n">mockHarry</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="k">nullptr</span><span class="p">);</span>

<span class="w">    </span><span class="cm">/* Prepare for mocking the jump; these methods are generated by Deride and</span>
<span class="cm">     * allow setting the return value for the corresponding jumpHeight() method</span>
<span class="cm">     * from the original Horse class. */</span>
<span class="w">    </span><span class="n">mockTom</span><span class="o">-&gt;</span><span class="n">setJumpHeightResult</span><span class="p">(</span><span class="mf">1.5</span><span class="p">);</span>
<span class="w">    </span><span class="n">mockDick</span><span class="o">-&gt;</span><span class="n">setJumpHeightResult</span><span class="p">(</span><span class="mf">1.7</span><span class="p">);</span>
<span class="w">    </span><span class="n">mockHarry</span><span class="o">-&gt;</span><span class="n">setJumpHeightResult</span><span class="p">(</span><span class="mf">1.3</span><span class="p">);</span>

<span class="w">    </span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="w"> </span><span class="n">highestJumper</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stable</span><span class="p">.</span><span class="n">findHighestJumper</span><span class="p">();</span>
<span class="w">    </span><span class="n">assert</span><span class="p">(</span><span class="n">highestJumper</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">"Dick"</span><span class="p">);</span>
</pre></div>

<p>In my closing words I'd like to thank the <a href="https://clang.llvm.org/">Clang
project</a>, which Deride is using to parse and interpret
the input files, and <a href="https://pypi.org/project/Jinja2/">Jinja2</a>, the templating
engine used to generate the mock code.</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ed5ce4ad84aebc5ce411eda503ab2cde12dc03dc03&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ed5ce4ad84aebc5ce411eda503ab2cde12dc03dc03/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ed5ce4ad84aebc5ce411eda503ab2cde12dc03dc03&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ed5ce4ad84aebc5ce411eda503ab2cde12dc03dc03/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sat, 05 Nov 2022 06:51:41 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ed5ce4ad84aebc5ce411eda503ab2cde12dc03dc03</guid>
        </item>
        <item>
            <title>Debugging the “Factory mode” of BQ devices in Ubuntu Touch</title>
            <link>http://mardy.it/blog/2021/12/debugging-the-factory-mode-of-bq-devices-in-ubuntu-touch.html</link>
            <description><![CDATA[
<p>As you know, I'm trying to <a href="http://mardy.it/blog/2021/12/enabling-the-fm-radio-in-ubuntu-touch.html">get the FM radio to work in Ubuntu
Touch</a>, and I basically have
it working on the Redmi Note 7 Pro. But then I remembered that the BQ Aquaris
E4.5 (which is the first commercial device officially supporting Ubuntu Touch)
also comes with an FM radio, so I decided to put some effort in getting that to
work, too. You might think it's a waste of time, but as a matter of fact this
device is built on a Mediatek SoC, and FM radio support is exposed to userspace
in a very similar way across all Mediatek devices — so this work should be
covering other devices as well.</p>
<p>It was relatively easy to get the FM radio to work on this phone: I can now
tune to a frequency and see that the RDS data is received, but I cannot get any
sound out of the speakers or headphones, which makes the whole radio experience
a bit, uhm… suboptimal, let's say.</p>
<p>The problem is not new: back in the days when Ubuntu Touch was still supported
by Canonical, <a href="http://www.lieberbiber.de/">sturmflut</a> was trying to get the FM
radio to work, and he met the same issues (see
<a href="https://lists.launchpad.net/ubuntu-phone/msg17256.html">this</a> and
<a href="https://lists.launchpad.net/ubuntu-phone/msg17340.html">this</a> messages in the
mailing list). He also spent some time investigating how the <a href="http://sturmflut.github.io/ubuntu/bq/2015/05/04/hacking-the-bq-part-2-factory-mode/">Factory
mode</a>
works (the FM radio is indeed one of the features that can be tested via the
Factory mode, and it <em>does</em> work) and he mentioned that he could get <code>gdb</code> to
attach to the factory mode program and could see the various <code>ioctl</code>s being
executed. Yesterday I tried to follow the same steps, but I failed quite soon:
I simply could not connect with <code>adb shell</code> while the device was in factory
mode, so no chances of debugging for me. ☹</p>
<p>Out of dispair, I tried just to manually run the program <code>/system/bin/factory</code>
inside a Lomiri session and, to my surprise, it overlayed its yellow “Factory
Mode” title on the screen — just to immediately quit afterwards. I tried
running it with <code>strace</code>, and noticed these lines:</p>
<div class="code"><pre class="code literal-block">open("/sys/class/BOOT/BOOT/boot/boot_mode", O_RDWR|O_LARGEFILE) = 15
read(15, "0\n", 4)                      = 2
close(15)                               = 0
writev(5, [{"\3", 1}, {"FTM\0", 4}, {"[FTM UTILS] Unsupported factory "..., 39}], 3) = 44
writev(5, [{"\6", 1}, {"NVRAM\0", 6}, {"[MAIN] Unsupported Factory mode\n"..., 33}], 3) = 40
</pre></div>

<p>Of course, the <code>/sys/class/BOOT/BOOT/boot/boot_mode</code> file is read-only, so I
couldn't just write <code>1</code> into it, but could a bind-mount work? Indeed it did!
And after a few attempts, I verified that writing a value of <code>4</code> in the
<code>boot_mode</code> file made the factory program happy. It was still unusable because
it was acting as if the volume down button was being constantly pressed, so the
cursor was always moving downwards, but killing the Lomiri session did the
trick.
In short, these are the steps you need to follow in order to run the Factory
Mode from an ordinary boot session:</p>
<div class="code"><pre class="code literal-block">sudo<span class="w"> </span>-i<span class="w">  </span><span class="c1"># become root</span>
<span class="nb">echo</span><span class="w"> </span><span class="m">4</span><span class="w"> </span>&gt;<span class="w"> </span>/tmp/trick
mount<span class="w"> </span>-o<span class="w"> </span><span class="nb">bind</span><span class="w"> </span>/tmp/trick<span class="w"> </span>/sys/class/BOOT/BOOT/boot/boot_mode
service<span class="w"> </span>lightdm<span class="w"> </span>stop<span class="w">  </span><span class="c1"># wait a few seconds until this returns</span>
<span class="nb">unset</span><span class="w"> </span>LD_PRELOAD
/system/bin/factory
</pre></div>

<p>What is more surprising, is that the FM radio test is working even in this
environment, and you can actually hear the sounds (for some reason, the FM
radio item takes about 40 seconds to initialize when run under these
conditions, but it eventually works). At this point, not only I could run <code>gdb</code>
(which I didn't), but I could even run the <code>factory</code> program under strace and
collect the logs.</p>
<p>At the moment of writing this post, I haven't yet examined the logs, so I'm not
at all sure that they'll be enough to make audio work (I suspect that the
factory mode binary might be playing some tricks that are somehow not
replicable in a proper Linux system with Pulseaudio and lots of other services
running), but I do have enough information to make at least a few attempts.</p>
<p>Stay tuned, and have a Merry Christmas!</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ec655cdd0ab210655c11ec9b631b93478a8e048e04&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ec655cdd0ab210655c11ec9b631b93478a8e048e04/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ec655cdd0ab210655c11ec9b631b93478a8e048e04&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ec655cdd0ab210655c11ec9b631b93478a8e048e04/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sat, 25 Dec 2021 07:13:54 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ec655cdd0ab210655c11ec9b631b93478a8e048e04</guid>
        </item>
        <item>
            <title>Enabling the FM radio in Ubuntu Touch</title>
            <link>http://mardy.it/blog/2021/12/enabling-the-fm-radio-in-ubuntu-touch.html</link>
            <description><![CDATA[
<p>I recently realized that my Xiaomi Redmi Note 7 Pro, on which <a href="http://mardy.it/blog/2021/01/ubuntu-touch-porting-notes-for-the-redmi-note-7-pro.html">I installed
Ubuntu Touch not so long
ago</a>, has a
working FM radio. One of the many psychological bugs of mine is the irrational
urge I feel of having my hardware, no matter whether I use it or not,
<a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8c47311d34eccedb06bc60fc9435a53bd4aff392">supported by
Linux</a>.
So, the fact that I never listen to the radio is unfortunately not a reason to
dissuade me from wasting time on getting the FM radio working in Ubuntu Touch.</p>
<p>This post is a quick summary of my investigation, which should serve as a note
keeper for when I'll actually get to implement the feature.</p>
<h4>The Android story</h4>
<p>It was a bit surprising to find out that Android does not offer an API to use
the FM radio, meaning that we cannot simply expose an API via libhybris. Every
manufacturer is therefore choosing their own API, and Android applications are
most often developed for a specific chipset family, or need to carry the code
to support all the various devices.</p>
<p>For example, I found the <a href="https://github.com/vladislav805/RFM-Radio">RFM Radio Android
application</a> which supports a few
Qualcomm Snapdragon processors, for which the FM radio functionality is exposed
by a kernel driver via the V4L API. This means that the FM radio is probably
working out of the box with <a href="https://code.qt.io/cgit/qt/qtmultimedia.git/tree/src/plugins/v4l?h=5.12">QtMultimedia's
QRadioTuner</a>.
Unfortunately the Note 7 Pro uses a newer Snapdragon, and even after some days
of investigations <a href="https://www.spinics.net/lists/linux-arm-msm/msg98952.html">I couldn't find out how the radio driver communicates to the
userspace</a>; but more
on this below. Other chipsets offer other APIs, and I was glad to find that
someone already wrote a <a href="https://github.com/Venji10/fmradio-volla">Ubuntu Touch FM radio application for the Volla
phone</a>, which has a Mediatek board.</p>
<p>Anyway, the lack of a unified FM radio API is probably the reason why most of
the so-called “FM radio” applications on Android are not really using the FM
radio but rather streaming audio from the internet.</p>
<h4>The FM radio in the Note 7 Pro</h4>
<p>Before I start talking about a phone that no one cares about, let me say that
what I'm going to write applies to several other Snapdragon chipsets and could
be relevant to other phones. For one, the Redmi Note 9 Pro uses the very same
bluetooth chipset as the Note 7 Pro (and in case you are wondering why I
mentioned bluetooth, it's because the FM radio functionality is delivered by
the same BT chip), so all what I'm going to write here is also relevant for
that phone.</p>
<p>In order to figure out how the radio worked on this device, I took the drastic
decision to reflash the stock Android (well, MIUI), started the preinstalled FM
radio application, and meanwhile looked at the logcat messages (I'm not sure if
this is needed, but before doing so I went to the “Developer options” in the
system settings and set the debugging level to the maximum). Among a lot of
noise, this showed me lines like these:</p>
<div class="code"><pre class="code literal-block">I android_hardware_fm: Opened fm_helium.so shared object library successfully
I android_hardware_fm: Obtaining handle: 'FM_HELIUM_LIB_INTERFACE' to the shared object library...
D FmReceiverJNI: init native called
D android_hardware_fm: BT soc is cherokee
I android_hardware_fm: Init native called
I android_hardware_fm: Initializing the FM HAL module &amp; registering the JNI callback functions...
D radio_helium: ++hal_init
D fm_hci  : ++fm_hci_init
I fm_hci  : hci_initialize
</pre></div>

<p>Well, even without knowing nothing about all what these lines meant, I had
something I could search the internet for. So I found <a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys">the Qualcomm FM code in
CodeAurora</a>,
and search for the code relative to my Snapdragon 675 (aka <code>sm6150</code>). I quickly
gave up on trying to make some sense out of the git tag naming in that
repository, and just tried to search for a tag which could be referring to my
device. I found one, and started browsing <a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys/tree/?h=LA.UM.7.9.r1-11400-sm6150.0">its source
tree</a>.</p>
<p>It turns out that Qualcomm provides a Java package which applications can use,
and which internally <code>dlopen()</code>s the <code>fm_helium.so</code> library, which in turn
depends on the <code>libfm_hci.so</code> library. I had a quick look at the source code of
these libraries, which are also present in the repository, but decided that I
would have had more chances of success if I just tried to follow the JNI code,
and in particular the
<a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys/tree/jni/android_hardware_fm.cpp?h=LA.UM.7.9.r1-11400-sm6150.0"><code>android_hardware_fm.cpp</code></a>
file. I'm not sure why this code is not using the C structure types defined in
the headers provided by the helium library, and instead redefines all the
constants and accesses the character buffers by offsets — it might be just for
historical reasons — but in any case I decided to follow along.</p>
<h4>The <code>fm-bridge</code> program</h4>
<p>Since we have a rather net separation between the Ubuntu Touch and the Android
worlds (the Android services are running inside an LXC container, with all
their Android libs and dependencies), one should not attempt to write an Ubuntu
process that loads the Android libraries, because the libc used in Android is
different, so things are likely not to work. But we can have Ubuntu and Android
processes communicate over a socket or other kind of IPC; so, what I decided to
go for, is writing a small C program that will live in the Android side, it
will talk to the FM radio (via <code>helium_fm</code>), and accept commands / give replies
via its <code>stdin</code> / <code>stdout</code>.</p>
<p>I unimaginatively called it “<code>fm-bridge</code>”, and you can look at its horrible
code <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/fm-bridge">here</a>. Really, I
just said it was terrible, so why did you look at it? I definitely need to
rewrite it from scratch, possibly using the helium headers, but as a proof of
concept this also works. Then I carefully examined the logcat output while
using the MIUI FM radio application in Android, and figured out what was the
command sequence I had to input into <code>fm-bridge</code>'s standard input in order to
have it tune onto a given frequency. I'm publishing the commands here too,
should I ever lose my notes:</p>
<div class="code"><pre class="code literal-block">enableSlimbus 1
setControl 0x8000004 1
enableSoftMute 1
setControl 0x8000029 0
setControl 0x800000c 1
setControl 0x800000d 1
setControl 0x800000e 1
setControl 0x800002b 0
setControl 0x8000007 4
setControl 0x8000006 0x40
setControl 0x8000006 0x40
setControl 0x8000011 0
setControl 0x800000f 1
getControl 0x8000010
setControl 0x8000010 0xef
setControl 0x800000f 1
setControl 0x800001b 1
setControl 0x8000012 0
setFreq 89300
setMonoStereo 1
</pre></div>

<p>I'm sure that not all of them are needed, but I'll figure out the optimal
sequence later. In order to use this program on Ubuntu Touch, I had to alter
the vendor partition to add this program, but also the <code>fm_helium.so</code> and
<code>libfm_hci.so</code> libraries (more on that below).</p>
<p>When feeding the above commands to the <code>fm-bridge</code> in Ubuntu, I saw that I was
getting a logcat output similar to the one from Android, which was mildly
comforting. No sound was comint out of the speaker or out of the earplugs, but
I was hardly expecting it all to work at the first try. And I got convinced
that the FM tuner was indeed working, because typing the command “<code>startSearch
1</code>” made a new frequency appear in the logs, proving that the tuner had found
another station and tuned onto it.</p>
<h4>Getting the sound out</h4>
<p>This was actually the easiest of the steps, thanks to the Ubuntu Touch FM radio
application we have for the Volla: its source code mentions a few pulseaudio
commands that worked perfectly in the Note 7 Pro too, despite the fact that the
underlying chipset is totally different. This should not be as surprising as it
might sound like, given that Android has a common audio API.</p>
<p>Just for my future reference, the commands are these:</p>
<div class="code"><pre class="code literal-block">pacmd set-source-port 1 input-fm_tuner
pactl load-module module-loopback source=1 sink=0
</pre></div>

<p>Ta-daaa! The radio was now playing from the phone loudspeakers! It was indeed
quite loud, and the volume buttons did not seem to have any effect on it, but
the volume can be controlled with pulseaudio:</p>
<div class="code"><pre class="code literal-block">pactl set-source-volume 1 50%
</pre></div>

<p>Of course, if we ever manage to make this into an Ubuntu Touch feature, we'll
have to find a way to make the volume respond to the volume buttons.</p>
<h4>Addind the needed files to the vendor partition</h4>
<p>The simplest approach (and the one I took initially) is that of downloading the
<code>vendor.img</code> into your PC, loop-mounting it, adding the <code>fm_helium.so</code>,
<code>libfm_hci.so</code> and <code>fm-bridge</code> files to it and then umount the partition and
reflash it (remembering to converting it from/to a sparse image before
downloading/uploading it). This approach works flawlessly, but I'm wondering if
one might incur into issues if the version of the NDK used to compile fm-bridge
is different from the one that was used to compile the other vendor binaries,
so I decided to give it a try to build the whole vendor partition myself.</p>
<p>This turned out to be a non trivial process, because I was using the Halium
tree to build the vendor image, and not the LineageOS which was used to build
the vendor image for my device: I could make an image, but it took some time
before I figured out which were the needed packages that somehow got lost
because of the Halium changes and that <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_vendor_xiaomi_violet/-/commit/495c83065c1f135d84c8e08563cece4fd4e4d3a5">had to be added to the
Makefile</a>.</p>
<p>To help my weak memory, I expanded the <a href="https://gitlab.com/ubports/community-ports/android9/xiaomi-redmi-note-7-pro/xiaomi-violet/-/blob/master/README.md">README file in the <code>violet</code>
port</a>
with the steps needed in order to build the vendor image.</p>
<h4>A system service for the FM radio</h4>
<p>While it could be possible for Ubuntu Touch applications to directly access the
FM radio device in the same way that Android applications do, this is
suboptimal for a few reasons. Even if we provided a shared library to deal with
the various radio chipset implementations, the application would either need to
be unconfined, or we'd had to provide an ever-changing AppArmor profile that
peeks new holes every time that a new device implementation is added (and what
if this implemenation uses a generic kernel device, which could be used for
other goals too?) and in any case we'd have to make this policy restricted,
since the RDS data provided by the radio stations would reveal the user
location (well, the city at least) to the application. Not to talk about
concurrent access to the radio device if two applications attempt to use it.</p>
<p>Therefore, my proposition (and what I'll implement, if I'll live long enough or
if someone doesn't beat me to it) is to have a system service deal with the
various hardware differences and expose a D-Bus API that will be hooked up as a
QRadioTunerControl plugin, so that Qt applications will be able to just use the
QtMultimedia APIs to access the radio.</p>
<p>The service would also need to talk to the trust-store, to let the user decide
whether the application should really be granted access to the FM receiver (and
when using the turst-store, this decision is remembered, and revocable from the
System Settings's Security panel). Of course we'll also need to add a
<code>fm-radio</code> AppArmor policy to let applications use this service.</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ec57b5deca284c57b511eca0c2d36ee6d6c5e5c5e5&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ec57b5deca284c57b511eca0c2d36ee6d6c5e5c5e5/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ec57b5deca284c57b511eca0c2d36ee6d6c5e5c5e5&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ec57b5deca284c57b511eca0c2d36ee6d6c5e5c5e5/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Tue, 07 Dec 2021 16:41:26 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ec57b5deca284c57b511eca0c2d36ee6d6c5e5c5e5</guid>
        </item>
        <item>
            <title>QHtmlParser: writing an HTML parser with your brain switched off</title>
            <link>http://mardy.it/blog/2021/10/qhtmlparser-writing-an-html-parser-with-your-brain-switched-off.html</link>
            <description><![CDATA[
<p>While developing <a href="https://gitlab.com/mardy/mitubo">MiTubo</a> I've recently felt
the need of parsing HTML pages: the first problem I wanted to solve was
implementing proper RSS feed detection when the user entered a website URL into
MiTubo's search box, so that MiTubo would parse the site's HTML, look for
<code>&lt;link rel="alternate"...&gt;</code> URLs in the <code>HEAD</code> section, and let the user
subscribe to any video feeds found there.</p>
<p>A quick search in the internet did not provide a clear answer: I found <a href="https://github.com/cutelyst/html-qt">a Qt
HTML parser in (stalled) development</a>, and
a few other C++ or C parsers (among the latters,
<a href="https://github.com/lexbor/lexbor/tree/master/source/lexbor/html">lexbor</a>
is the most inspiring), but all of them seem to take the approach of parsing
the HTML file into a DOM tree, while I was hoping to find a lightweight
SAX-like parser. Pretty much like Python's
<a href="https://docs.python.org/3/library/html.parser.html">html.parser</a>.</p>
<p>Anyway, I don't remember how it happened, but at a certain point I found myself
looking at <code>html.parser</code> source code, and I was surprised to see how compact it
was (apart, of course, for the long list of character references for the HTML
entities!). Upon a closer look, it also appeared that the code was not making
much use of Python's dynamic typing, so, I thought, maybe I could give it a try
to rewrite that into a Qt class. And a few hours later
<a href="https://gitlab.com/mardy/qhtmlparser">QHtmlParser</a> was born.</p>
<p>As this post's title suggests, the process of rewriting <code>html.parser</code> with Qt
was quite straightforward, and the nice thing about it is that I didn't have to
spend any time reading the HTML standard or trying to figure out how to
implement the parser: I just had to translate Python code into C++ code, and
thanks to the nice API of QString (which in many ways resembles Python's — or
vice versa) this was not too hard. I even left most of the original code
comments untouched, and reused quite a few tests from the test suite.</p>
<p>It was time well spent. :-)</p>
<p>If you think you might need an HTML parser for your Qt application, you are
welcome to give it a try. It's not a library, just a set of files that you can
import into your project; for the time being I only have a build file for
<a href="https://doc.qt.io/qbs/overview.html">QBS</a>, but I'll happily accept
contributions to make it easier to use QHtmlParser with projects built using
other build systems. You can see
<a href="https://gitlab.com/mardy/mitubo/-/commit/531bd4e8b0d354aad5bb3e749073ddf16f6fe625">here</a>
the changes I made in MiTubo to start using it and detect RSS feed in a
webpage's HEAD.</p>
<p>That's all for now. And in case you missed the link before, you can find
QHtmlParser <a href="https://gitlab.com/mardy/qhtmlparser">here</a>.</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1ec2a224501942c2a2211eca2429f96a21b14611461&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1ec2a224501942c2a2211eca2429f96a21b14611461/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1ec2a224501942c2a2211eca2429f96a21b14611461&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1ec2a224501942c2a2211eca2429f96a21b14611461/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 10 Oct 2021 19:57:28 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1ec2a224501942c2a2211eca2429f96a21b14611461</guid>
        </item>
        <item>
            <title>Ubuntu Touch porting notes for the Redmi Note 7 Pro, part 2</title>
            <link>http://mardy.it/blog/2021/02/ubuntu-touch-porting-notes-for-the-redmi-note-7-pro-part-2.html</link>
            <description><![CDATA[
<p>This is the second part of my porting odyssey; for the first part, follow <a href="http://mardy.it/blog/2021/01/ubuntu-touch-porting-notes-for-the-redmi-note-7-pro.html">this
link</a>.</p>
<p>The good news is that I've done some progress; the bad news is that there are
still plenty of issues, and solving them involves deep diving into nearly all
components and technologies that make up the core of an Android device, so
completing the porting is going to take quite some time. On the other hand, I'm
learning a lot of new stuff, and I might be able to share it by writing some
documentation. And, who knows, maybe work on some other device port.</p>
<p>Anyway, enough with the introduction! Let's see what progress I've been doing
so far.</p>
<h3>The new device tree</h3>
<p>While asking for help to debug the audio issue I was facing (more about that
later), I was also told that the <code>lavender</code> tree, which I was using as a
reference, was obsolete. The new one was <a href="https://gitlab.com/ubports/community-ports/android9/xiaomi-redmi-note-7/xiaomi-lavender">in
gitlab</a>,
and was build with a totally different system, described
<a href="https://github.com/ubports/porting-notes/wiki/GitLab-CI-builds-for-devices-based-on-halium_arm64-(Halium-9)">here</a>.</p>
<p>So, I picked the <code>lavender</code> tree and adapted it for <code>violet</code>: I changed the
<code>deviceinfo</code> file to point to my kernel tree, use my kernel configuration, and
use the same boot command line as before. By the way, <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/halium-xiaomi-violet">here's my current "new"
device
tree</a>. The
build failed, with errors like:</p>
<div class="code"><pre class="code literal-block">In function 'memcpy',
    inlined from 'proc_ipc_auto_msgmni.part.1' at /home/mardy/projects/port/xiaomi-violet/bd/downloads/android_kernel_xiaomi_violet/ipc/ipc_sysctl.c:82:2:
/home/mardy/projects/port/xiaomi-violet/bd/downloads/android_kernel_xiaomi_violet/include/linux/string.h:340:4: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object passed as 2nd parameter
    __read_overflow2();
    ^
</pre></div>

<p>I then replayed the kernel build using the old system, and noticed that it was
using clang as the compiler; so I changed the related flag in the <code>deviceinfo</code>
file, and the build went past that point. It failed later, though:</p>
<div class="code"><pre class="code literal-block">/home/mardy/projects/port/xiaomi-violet/bd/downloads/android_kernel_xiaomi_violet/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c:1498:26: error: cast to smaller integer type 'eSapStatus' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast]
                bss_complete-&gt;status = (eSapStatus) context;
                                       ^~~~~~~~~~~~~~~~~~~~
</pre></div>

<p>I ended up editing the Kbuild file in the module source directory, and
<a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_kernel_xiaomi_violet/-/commit/58ee86d2faa154e40faa5787d4166384b3e41ee3">removed</a>
the <code>-Werror</code> from there (as well in another place that failed a bit later).
This made the build proceed until the end, where it failed because the device
tree file was not found:</p>
<div class="code"><pre class="code literal-block">+ cp -v /home/mardy/projects/port/xiaomi-violet/bd/downloads/KERNEL_OBJ/arch/arm64/boot/dts/qcom/sm8150-mtp-overlay.dtbo /home/mardy/projects/port/xiaomi-violet/bd/tmp/partitions/dtbo.img
cp: cannot stat '/home/mardy/projects/port/xiaomi-violet/bd/downloads/KERNEL_OBJ/arch/arm64/boot/dts/qcom/sm8150-mtp-overlay.dtbo': No such file or directory
</pre></div>

<p>I quickly realized that this was due to an error of mine: the Xiaomi <code>violet</code>
is a <code>sm6150</code>, not a <code>sm8150</code> as mentioned in my <code>deviceinfo</code> file! But what
overlay file should I use then, since there isn't a <code>sm6150-mtp-overlay.dts</code> in
my source tree? Having a loot at <a href="https://gitlab.com/ubports/community-ports/android9/xiaomi-poco-f1/xiaomi-beryllium/-/blob/master/deviceinfo">other deviceinfo
files</a>,
I saw that the <code>deviceinfo_kernel_dtb_overlay</code> line is not always there, so I
tried commenting it out, and it helped.</p>
<p>The next step was getting flashable images, of course. While the device is not
supported by the UBports system-image server, we can use use some scripts to
create a fake OTA (Over The Air update) and generate flashable images starting
from it. The steps can be read in the <code>devel-flashable</code> target of the
<code>.gitlab-ci.yml</code> file (if this step is not present, we should try to find
<a href="https://gitlab.com/ubports/community-ports/android9">another device
repository</a> which has it.
They are the following:</p>
<div class="code"><pre class="code literal-block">./build/prepare-fake-ota.sh<span class="w"> </span>out/device_violet.tar.xz<span class="w"> </span>ota
./build/system-image-from-ota.sh<span class="w"> </span>ota/ubuntu_command<span class="w"> </span>out
</pre></div>

<p>Once these commands have completed their execution, these commands will push
the images to the device:</p>
<div class="code"><pre class="code literal-block">fastboot<span class="w"> </span>flash<span class="w"> </span>boot<span class="w"> </span>out/boot.img<span class="p">;</span><span class="w"> </span>fastboot<span class="w"> </span>flash<span class="w"> </span>system<span class="w"> </span>out/system.img
</pre></div>

<p>There's also <code>fastboot flash recovery out/recovery.img</code>, but I left it out
since I was not interested in the recovery image at this stage. And unless you
are ready to submit your port for inclusion into the "supported devices" list,
I'd recommend not flashing the UT recovery image since TWRP is more powerful
and will likely help you in recover your device from a broken image.</p>
<h4>Kernel command line</h4>
<p>It's important that the kernel command line contains the <code>systempart</code>
parameter. In my case, the first boot failed because the command line was
longer than 512 bytes, and this parameter was getting truncated. So one thing
to be careful about is the length of the kernel command line.</p>
<p>This was fixed by <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/halium-xiaomi-violet/-/commit/25075c7e913501e2a142143f09e1e0598ecd6380">removing some unnecessary kernel
parameters</a>
from the <code>deviceinfo</code> file.</p>
<h3>Missing thumbnails in the Gallery app, content-hub not working</h3>
<p>Another issue I noticed is that photo thumbnails were all black in the Gallery
app, and the content-hub also was not working.
I noticed a <a href="https://github.com/ubuntu-touch-lavender/kernel/commit/2d0cd516735aaa88733dfc251e1e7dce9e549197">relevant commit in the lavender kernel
tree</a>
and found a <a href="https://bugs.launchpad.net/apparmor/+bug/1620635">launchpad bug</a>
which mentioned the issues I was seeing. In the Telegram channel I was told
that patch is a <em>forward</em> port of a commit from kernel 3.4 that was present in
all of the cores devices, and that it was indeed needed to have the ContentHub
working.</p>
<p>The patch did not apply cleanly on top of my kernel tree, but luckily it was
just an offset issue: <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_kernel_xiaomi_violet/-/commit/fba5fc33aee3147146199f8a3185b10b5c85b46c">adjusting the
patch</a>
was easy, and indeed after applying it thumbnails started appearing in the
Gallery and
<a href="http://imaginario.mardy.it">Imaginario</a> could import photos again via the
ContentHub.</p>
<h3>Time and date</h3>
<p>Time was always reset to a far away date after a reboot. This is a common issue
on Qualcomm devices, and can be fixed by disabling the time service in the
Android container.</p>
<p>https://github.com/Halium/android_device_halium_halium_arm64/pull/3</p>
<p>For some reason, at a certain point my override stopped working (or, more
likely, the override never worked, but I happened to have fixed the issue
directly modifying the vendor init file). I had to copy
<code>/android/vendor/etc/init/hw/init.qcom.rc</code> into <code>/usr/share/halium-overrides/</code>,
modify it and bind mount the modified file in order to get it working.</p>
<p>This actually seems to match my understanding of the <a href="https://android.googlesource.com/platform/system/core/+/master/init/README.md#imports">Android init
documentation</a>,
because according to the path priorities a configuration file stored under
<code>/system/</code> will never be able to override one stored under <code>/vendor</code>.</p>
<h3>Fixing the audio configuration</h3>
<p>Audio was not working at all. The sound indicator icon was not shown, only the
raw (unstranslated) "indicator-sound" text was shown in the panel. <code>pulseaudio</code>
was not running. Trying to run it manually (as the phablet user, since
pulseaudio is run in the user session) led to this:</p>
<div class="code"><pre class="code literal-block">phablet@ubuntu-phablet:~$ pulseaudio -n -vvv -F /etc/pulse/touch-android9.pa
I: [pulseaudio] main.c: setrlimit(RLIMIT_NICE, (31, 31)) failed: Operation not permitted
I: [pulseaudio] main.c: setrlimit(RLIMIT_RTPRIO, (9, 9)) failed: Operation not permitted
...
D: [pulseaudio] cli-command.c: Parsing script '/etc/pulse/touch-android9.pa'
D: [pulseaudio] database-tdb.c: Opened TDB database '/home/phablet/.config/pulse/ubuntu-phablet-stream-volumes.tdb'
I: [pulseaudio] module-stream-restore.c: Successfully opened database file '/home/phablet/.config/pulse/ubuntu-phablet-stream-volumes'.
...
D: [pulseaudio] module.c: Checking for existence of '/usr/lib/pulse-8.0/modules/module-droid-card-28.so': success
I: [pulseaudio] module-droid-card.c: Create new droid-card
D: [pulseaudio] droid-util.c: No configuration provided for opening module with id primary
I: [pulseaudio] config-parser-xml.c: Failed to open file (/odm/etc/audio_policy_configuration.xml): No such file or directory
D: [pulseaudio] droid-config.c: Failed to parse configuration from /odm/etc/audio_policy_configuration.xml
D: [pulseaudio] config-parser-xml.c: Read /vendor/etc/audio/audio_policy_configuration.xml ...
D: [pulseaudio] config-parser-xml.c: New module: "primary"
W: [pulseaudio] config-parser-xml.c: [/vendor/etc/audio/audio_policy_configuration.xml:78] Could not find element attribute "samplingRates"
E: [pulseaudio] config-parser-xml.c: [/vendor/etc/audio/audio_policy_configuration.xml:78] Failed to parse element &lt;profile&gt;
E: [pulseaudio] config-parser-xml.c: parsing aborted at line 78
D: [pulseaudio] droid-config.c: Failed to parse configuration from /vendor/etc/audio/audio_policy_configuration.xml
D: [pulseaudio] config-parser-xml.c: Read /vendor/etc/audio_policy_configuration.xml ...
D: [pulseaudio] config-parser-xml.c: New module: "primary"
W: [pulseaudio] config-parser-xml.c: [/vendor/etc/audio_policy_configuration.xml:78] Could not find element attribute "samplingRates"
E: [pulseaudio] config-parser-xml.c: [/vendor/etc/audio_policy_configuration.xml:78] Failed to parse element &lt;profile&gt;
E: [pulseaudio] config-parser-xml.c: parsing aborted at line 78
D: [pulseaudio] droid-config.c: Failed to parse configuration from /vendor/etc/audio_policy_configuration.xml
I: [pulseaudio] config-parser-legacy.c: Failed to open config file (/vendor/etc/audio_policy.conf): No such file or directory
D: [pulseaudio] droid-config.c: Failed to parse configuration from /vendor/etc/audio_policy.conf
I: [pulseaudio] config-parser-xml.c: Failed to open file (/system/etc/audio_policy_configuration.xml): No such file or directory
D: [pulseaudio] droid-config.c: Failed to parse configuration from /system/etc/audio_policy_configuration.xml
I: [pulseaudio] config-parser-legacy.c: Failed to open config file (/system/etc/audio_policy.conf): No such file or directory
D: [pulseaudio] droid-config.c: Failed to parse configuration from /system/etc/audio_policy.conf
E: [pulseaudio] droid-config.c: Failed to parse any configuration.
...
</pre></div>

<p>Indeed, line 78 of <code>/vendor/etc/audio_policy_configuration.xml</code> had an error,
where a property was spelt like <code>simplingRate</code> instead of <code>samplingRate</code>.
However, the "vendor" partition is read-only, so I couldn't change that file
directly. Another option could have been creating a fixed copy of the file and
place it with <code>/system/etc/audio_policy_configuration.xml</code>, but the "system" is
also read-only (there are ways to modify these partitions, of course, but I
couldn't find a clean way to do it from the device tree scripts. So I went for
the bind-mount approach: I would ship the fixed file in some other directory of
the file-system, and then modify the <code>/etc/init/mount-android.conf</code> file (this
is the job that upstart executes before starting the Android LXC container) to
bind-mount the file onto <code>/vendor/etc/audio_policy_configuration.xml</code>.</p>
<p>This worked, but my joy was short-lived: audio was coming up only once every 5
boots or so. I will not list here all the things I tried, as they were plenty
of them; and more than once I went to sleep happy and convinced of having fixed
the issue for good, until the next day the device booted without audio. It was
clearly a timing issue occurring in the early boot, because one thing I clearly
noticed very early on is that in those cases when the audio was booting, the
following lines appeared in the kernel log:</p>
<div class="code"><pre class="code literal-block">[    7.130057] wcd937x_codec wcd937x-codec: msm_cdc_dt_parse_vreg_info: cdc-vdd-ldo-rxtx: vol=[1800000 1800000]uV, curr=[25000]uA, ond 0
[    7.130068] wcd937x_codec wcd937x-codec: msm_cdc_dt_parse_vreg_info: cdc-vddpx-1: vol=[1800000 1800000]uV, curr=[10000]uA, ond 0
[    7.130076] wcd937x_codec wcd937x-codec: msm_cdc_dt_parse_vreg_info: cdc-vdd-mic-bias: vol=[3296000 3296000]uV, curr=[25000]uA, ond 0
[    7.130084] wcd937x_codec wcd937x-codec: msm_cdc_dt_parse_vreg_info: cdc-vdd-buck: vol=[1800000 1800000]uV, curr=[650000]uA, ond 1
[    7.137759] wcd937x_codec wcd937x-codec: bound wcd937x-slave.1170224 (ops cleanup_module [wcd937x_slave_dlkm])
[    7.138065] wcd937x_codec wcd937x-codec: bound wcd937x-slave.1170223 (ops cleanup_module [wcd937x_slave_dlkm])
</pre></div>

<p>I started adding some printk to the kernel driver, and modified
it slightly to register itself with the <code>module_driver()</code> macro instead of the
simpler, but logless, <code>module_platform_driver()</code>. This showed that the driver
was always loaded at about 7 seconds, but the <code>platform_driver_register()</code>
method only called the driver's bind method (<code>wcd937x_bind()</code>) in those boots
where audio was working.</p>
<p>After more debugging into <code>platform_driver_register()</code>, I stumbled upon the
<a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_kernel_xiaomi_violet/-/blob/halium-9.0/drivers/base/platform.c#L965"><code>platform_match()</code></a>
function, added some debugging message in there to print the device name and
the driver name, and observed how in those boots where audio was failing this
function was called to find a driver for the <code>wcd937x_codec</code> device <em>before</em>
the <code>wcd937x_codec</code> driver (provided by the <code>wcd937x_dlmk</code> module) was
available. So, I tried adding <code>wcd937x_dlmk</code> to
<code>/etc/modules-load.d/modules.conf</code> and this caused the driver to be loaded at
about 3 seconds, and apparently fixed the audio issue. At least, till the time
of writing this, I never had my phone boot without audio anymore.</p>
<p>Not all is fine with the audio, unfortunately: the mic records a background
noise along with the actual sounds, and the recording volume is quite low. This
also affects the call quality. On the other hand, the noise disappears when
recording happens via the earphones. But I've yet to investigate this; I hope
to give you some updates in part three.</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1eb67ffecc7d6c067ff11eb8edbb5e608a925062506&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1eb67ffecc7d6c067ff11eb8edbb5e608a925062506/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1eb67ffecc7d6c067ff11eb8edbb5e608a925062506&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1eb67ffecc7d6c067ff11eb8edbb5e608a925062506/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Thu, 04 Feb 2021 20:34:28 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1eb67ffecc7d6c067ff11eb8edbb5e608a925062506</guid>
        </item>
        <item>
            <title>Ubuntu Touch porting notes for the Redmi Note 7 Pro</title>
            <link>http://mardy.it/blog/2021/01/ubuntu-touch-porting-notes-for-the-redmi-note-7-pro.html</link>
            <description><![CDATA[
<p>In case you have a sense of <em>deja-vu</em> when reading this post, it's because
indeed this is not the first time I try porting a device to Ubuntu Touch. <a href="http://mardy.it/blog/2019/07/notes-on-porting-the-samsung-j3-to-halium-%2B-ubports.html">The
previous
attempt</a>,
however, was with another phone model (and manufacturer), and did not have a
happy ending. This time it went better, although the real ending is still far
away; but at least I have something to celebrate.</p>
<h3>The phone</h3>
<p>I made myself a Christmas present and bought a Xiaomi Redmi Note 7 Pro, a
dual-SIM phone from 2019 with 6GB of RAM and 128GB of flash storage. To be
totally honest, I bought it by mistake: the phone I really wanted to buy is the
Redmi Note 7 (without the "Pro"), because it's a modern phone that is working
reasonable well with Ubuntu Touch. The online shop where I bought it from let
me choose some options, including the RAM size, so I chose the maximum
available (6GB) without being aware that this would mean that I would be buying
the "Pro" device — the shop did not alter the item name, so I couldn't really
know. Unfortunately, the two versions are two rather different beasts, powered
by different SoC; both are produced by Qualcomm, so they are not <em>that</em>
different, but it's enough to make the installation of Ubuntu Touch impossible.</p>
<p>But between the choice of retuning the phone to the shop and begin a new
porting adventure, I stood firm and went for the latter. Hopefully I won't
regret it (if everything goes bad, I can still use it with LineageOS, which
runs perfectly on it).</p>
<p>Moreover, there already exist a port of Ubuntu Touch for this phone, which
actually works reasonably well (I tried it briefly, and many things were
working), but the author claims to be a novice and indeed did not follow the
best git practices when working on the source code, so it's hard to understand
what was changed and why. But if you are looking for a quick way to get Ubuntu
Touch working on this phone, you are welcome to have a look <a href="https://t.me/note7prom">at this Telegram
channel</a>.</p>
<p>What follows are the raw notes of my attempts. They are here so that search
engines can index the error messages and the various logs, and hopefully help
someone hitting similar errors on other devices to find his way out.</p>
<h3>Getting Halium and the device source code</h3>
<p>Installed the dependencies like in the first step. <code>repo</code> was not found in the
Ubuntu 20.04 archives, but I had it installed anyway due to my work on a Yocto
device.</p>
<p>Since my device has Android 9 on it, I went for Halium 9:</p>
<div class="code"><pre class="code literal-block">repo<span class="w"> </span>init<span class="w"> </span>-u<span class="w"> </span>git://github.com/Halium/android.git<span class="w"> </span>-b<span class="w"> </span>halium-9.0<span class="w"> </span>--depth<span class="o">=</span><span class="m">1</span>
repo<span class="w"> </span>sync<span class="w"> </span>-c<span class="w"> </span>-j<span class="w"> </span><span class="m">16</span>
</pre></div>

<p>The official LineageOS repository for the Xiaomi Redmi Note 7 Pro is
<a href="https://github.com/LineageOS/android_device_xiaomi_violet">android_device_xiaomi_violet</a>,
but the <a href="https://download.lineageos.org/violet">page with the official build</a>
has been taken down (some DMCA violation, <a href="https://forum.xda-developers.com/t/rom-official-9-0-0-violet-lineageos-16-0-wrappedkey-fbe.3951524/post-81799135">if you believe the
 forums</a>)
and no development has been happening since last year. A <a href="https://forum.xda-developers.com/t/unofficial-rom-10-0-9-0-lineageos-17-1-16-0-violet-q-pie.4050059/">more active forum
thread</a>
uses another repository which seems to be receiving more frequent updates, so I
chose to base my port on that.</p>
<p>I actually tested that LineageOS image on my phone, and verified that all the
hardware was working properly.</p>
<p>Initially, I created forks of the relevant repository under my own gitlab
account, but then I though (especially looking at the <a href="https://github.com/ubuntu-touch-lavender">Note 7 port</a>)
that creating a group just for this port would make people's life easier,
because they wouldn't need to navigate through my 1000 personal projects
to find what is relevant for this port. So, I created these forks:</p>
<ul>
<li><a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_device_xiaomi_violet">gitlab.com/ubuntu-touch-xiaomi-violet/android_device_xiaomi_violet</a></li>
<li><a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_kernel_xiaomi_violet">gitlab.com/ubuntu-touch-xiaomi-violet/android_kernel_xiaomi_violet</a></li>
<li><a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_vendor_xiaomi_violet">gitlab.com/ubuntu-touch-xiaomi-violet/android_vendor_xiaomi_violet</a></li>
</ul>
<p>Next, created the <code>halium/devices/manifests/xiaomi_violet.xml</code> file with this content:</p>
<div class="code"><pre class="code literal-block"><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;manifest&gt;</span>
<span class="w">    </span><span class="cm">&lt;!-- Remotes --&gt;</span>
<span class="w">    </span><span class="nt">&lt;remote</span><span class="w"> </span><span class="na">name=</span><span class="s">"ubuntu-touch-xiaomi-violet"</span>
<span class="w">            </span><span class="na">fetch=</span><span class="s">"https://gitlab.com/ubuntu-touch-xiaomi-violet"</span>
<span class="w">            </span><span class="na">revision=</span><span class="s">"halium-9.0"</span><span class="nt">/&gt;</span>

<span class="w">    </span><span class="cm">&lt;!-- Device Tree --&gt;</span>
<span class="w">    </span><span class="nt">&lt;project</span><span class="w"> </span><span class="na">path=</span><span class="s">"device/xiaomi/violet"</span>
<span class="w">             </span><span class="na">name=</span><span class="s">"android_device_xiaomi_violet"</span>
<span class="w">             </span><span class="na">remote=</span><span class="s">"ubuntu-touch-xiaomi-violet"</span><span class="w"> </span><span class="nt">/&gt;</span>

<span class="w">    </span><span class="cm">&lt;!-- Kernel --&gt;</span>
<span class="w">    </span><span class="nt">&lt;project</span><span class="w"> </span><span class="na">path=</span><span class="s">"kernel/xiaomi/violet"</span>
<span class="w">             </span><span class="na">name=</span><span class="s">"android_kernel_xiaomi_violet"</span>
<span class="w">             </span><span class="na">remote=</span><span class="s">"ubuntu-touch-xiaomi-violet"</span><span class="w"> </span><span class="nt">/&gt;</span>

<span class="w">    </span><span class="cm">&lt;!-- Proprietary/Vendor blobs --&gt;</span>
<span class="w">    </span><span class="nt">&lt;project</span><span class="w"> </span><span class="na">path=</span><span class="s">"vendor/xiaomi/violet"</span>
<span class="w">             </span><span class="na">name=</span><span class="s">"android_vendor_xiaomi_violet"</span>
<span class="w">             </span><span class="na">remote=</span><span class="s">"ubuntu-touch-xiaomi-violet"</span><span class="w"> </span><span class="nt">/&gt;</span>
<span class="nt">&lt;/manifest&gt;</span>
</pre></div>

<p>Fetching all the sources mentioned in the manifest:</p>
<div class="code"><pre class="code literal-block">./halium/devices/setup violet
</pre></div>

<p>Full output:</p>
<div class="code"><pre class="code literal-block">*****************************************
I: Configuring for device xiaomi_violet
*****************************************
Fetching projects: 100% (393/393), done.
hardware/qcom/audio-caf/apq8084: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8916: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8952: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8960: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8974: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8994: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8996: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/msm8998: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/sdm845: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio-caf/sm8150: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/audio/default: Shared project LineageOS/android_hardware_qcom_audio found, disabling pruning.
hardware/qcom/display: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/apq8084: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8916: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8952: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8960: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8974: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8994: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8996: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/msm8998: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/sdm845: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/display-caf/sm8150: Shared project LineageOS/android_hardware_qcom_display found, disabling pruning.
hardware/qcom/media: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/apq8084: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8916: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8952: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8960: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8974: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8994: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8996: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/msm8998: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/sdm845: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/qcom/media-caf/sm8150: Shared project LineageOS/android_hardware_qcom_media found, disabling pruning.
hardware/ril: Shared project LineageOS/android_hardware_ril found, disabling pruning.
hardware/ril-caf: Shared project LineageOS/android_hardware_ril found, disabling pruning.
hardware/qcom/wlan: Shared project LineageOS/android_hardware_qcom_wlan found, disabling pruning.
hardware/qcom/wlan-caf: Shared project LineageOS/android_hardware_qcom_wlan found, disabling pruning.
hardware/qcom/bt: Shared project LineageOS/android_hardware_qcom_bt found, disabling pruning.
hardware/qcom/bt-caf: Shared project LineageOS/android_hardware_qcom_bt found, disabling pruning.
Updating files: 100% (67031/67031), done.nel/testsUpdating files:  36% (24663/67031)
lineage/scripts/: discarding 1 commits
Updating files: 100% (1406/1406), done.ineageOS/android_vendor_qcom_opensource_thermal-engineUpdating files:  47% (666/1406)
Checking out projects: 100% (392/392), done.
*******************************************
I: Refreshing device vendor repository: device/xiaomi/violet
I: Processing proprietary blob file: device/xiaomi/violet/./proprietary-files.txt
I: Processing fstab file: device/xiaomi/violet/./rootdir/etc/fstab.qcom
I: Removing components relying on SettingsLib from: device/xiaomi/violet
*******************************************
</pre></div>

<h3>Starting the build</h3>
<p>Setting up the environment:</p>
<div class="code"><pre class="code literal-block">$ source build/envsetup.sh
including device/xiaomi/violet/vendorsetup.sh
including vendor/lineage/vendorsetup.sh
$
</pre></div>

<p>Running the breakfast command:</p>
<div class="code"><pre class="code literal-block">$ breakfast violet
including vendor/lineage/vendorsetup.sh
Trying dependencies-only mode on a non-existing device tree?

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=9
LINEAGE_VERSION=16.0-20210109-UNOFFICIAL-violet
TARGET_PRODUCT=lineage_violet
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=kryo300
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv8-a
TARGET_2ND_CPU_VARIANT=cortex-a75
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.4.0-58-generic-x86_64-Ubuntu-20.04.1-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=PQ3A.190801.002
OUT_DIR=/home/mardy/projects/port/halium/out
PRODUCT_SOONG_NAMESPACES= hardware/qcom/audio-caf/sm8150 hardware/qcom/display-caf/sm8150 hardware/qcom/media-caf/sm8150
============================================
</pre></div>

<h4>Building the kernel</h4>
<p>The configuration needs to be adapted for Halium.  Locating the kernel config:</p>
<div class="code"><pre class="code literal-block">$ grep "TARGET_KERNEL_CONFIG" device/xiaomi/violet/BoardConfig.mk 
TARGET_KERNEL_CONFIG := vendor/violet-perf_defconfig
$
</pre></div>

<p>Getting the Mer checker tool and running it:</p>
<div class="code"><pre class="code literal-block">git clone https://github.com/mer-hybris/mer-kernel-check
cd mer-kernel-check
./mer_verify_kernel_config ../kernel/xiaomi/violet/arch/arm64/configs/vendor/violet-perf_defconfig
</pre></div>

<p>Prints lots of warnings, starting with:</p>
<div class="code"><pre class="code literal-block">WARNING: kernel version missing, some reports maybe misleading
</pre></div>

<p>To help the tool, we need to let him know the kernel version. It can be seen at
the beginning of the kernel Makefile, located in
<code>../kernel/xiaomi/violet/Makefile</code>; in my case it was</p>
<div class="code"><pre class="code literal-block">VERSION = 4
PATCHLEVEL = 14
SUBLEVEL = 83
EXTRAVERSION =
</pre></div>

<p>So I edited the configuration file
<code>../kernel/xiaomi/violet/arch/arm64/configs/vendor/violet-perf_defconfig</code> and
added this line at the beginning:</p>
<div class="code"><pre class="code literal-block"># Version 4.14.83
</pre></div>

<p>then ran the checker tool again. This time the output was a long list of kernel
options that needed to be fixed, but as I went asking for some explanation in
the Telegram channel for Ubuntu Touch porters, I was told that I could/should
skip this test and instead use the <code>check-kernel-config</code> tool <a href="https://raw.githubusercontent.com/Halium/halium-boot/halium-9.0/check-kernel-config">from
Halium</a>.
I downloaded it, made it executable (<code>chmod +x check-kernel-config</code>) and ran
it:</p>
<div class="code"><pre class="code literal-block">./check-kernel-config kernel/xiaomi/violet/arch/arm64/configs/vendor/violet-perf_defconfig
[...lots of red and green lines...]
Config file checked, found 288 errors that I did not fix.
</pre></div>

<p>I ran it again with the <code>-w</code> option, and it reportedly fixed 287 errors. Weird,
does that mean that an error was still left? I ran the tool again (without
<code>-w</code>), and it reported 2 errors. Ran it once more in write mode, and if fixed
them. So, one might need to run it twice.</p>
<p>Next, added the line</p>
<div class="code"><pre class="code literal-block">BOARD_KERNEL_CMDLINE += console=tty0
</pre></div>

<p>in <code>device/xiaomi/violet/BoardConfig.mk</code>. One more thing that needs to be done
before starting the build is <a href="https://docs.ubports.com/en/latest/porting/halium_7-1/Building.html#fix-mount-points">fixing the mount
points</a>,
so I opened <code>device/xiaomi/violet/rootdir/etc/fstab.qcom</code> and changed the type
of the userdata partition from <code>f2fs</code> to <code>ext4</code>. There were no lines with the
<code>context</code> option, so that was the only change I needed to do.</p>
<p>At this point, while browsing throught the documentation, I found a link to
<a href="https://github.com/ubports/porting-notes/wiki/Halium-9">this page</a> which
contains some notes on Halium 9 porting, which are substantially different from
the official porting guide in halium.org (which I was already told in Telegram
to be obsolete in several points).</p>
<p>So, following the instructions from this new link I ran</p>
<div class="code"><pre class="code literal-block">hybris-patches/apply-patches.sh --mb
</pre></div>

<p>which completed successfully.</p>
<p>Then, continuing following the points from this page, I edited <code>device/xiaomi/violet/lineage_violet.mk</code>, commented out the lines</p>
<div class="code"><pre class="code literal-block"><span class="k">$(</span><span class="nv">call</span> <span class="nv">inherit-product</span>, <span class="k">$(</span><span class="nv">SRC_TARGET_DIR</span><span class="k">)</span>/<span class="nv">product</span>/<span class="nv">full_base_telephony.mk</span><span class="k">)</span>
<span class="c"># ...</span>
<span class="k">$(</span><span class="nv">call</span> <span class="nv">inherit-product</span>, <span class="nv">vendor</span>/<span class="nv">lineage</span>/<span class="nv">config</span>/<span class="nv">common_full_phone.mk</span><span class="k">)</span>
</pre></div>

<p>and replaced the first one with a similar line pointing to <code>halium.mk</code>. For the
record, a <code>find</code> revealed that the <code>SRC_TARGET_DIR</code> variable in my case was
<code>build/make/target/</code>. It contained also the <code>halium.mk</code> file, which was created
by the hybris patches before. As for removing the Java dependencies, I cound't
find any modules similar to those listed <a href="https://github.com/ubports-on-fxtec-pro1/proprietary_vendor_idealte/commit/65cfe7583aaa886709b6142d8b79c276a3028ad9">in this
commit</a>
in any of the makefiles in my source tree, so I just started the build:</p>
<div class="code"><pre class="code literal-block"><span class="nb">source</span><span class="w"> </span>build/envsetup.sh<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>breakfast<span class="w"> </span>violet
make<span class="w"> </span>halium-boot
</pre></div>

<p>This failed the first time with the compiler being killed (out of memory, most
likely), but it succeeded on the second run. There was a suspicious warning,
though:</p>
<div class="code"><pre class="code literal-block">drivers/input/touchscreen/Kconfig:1290:warning: multi-line strings not supported
</pre></div>

<p>And indeed my <code>kernel/xiaomi/violet/drivers/input/touchscreen/Kconfig</code> had this line:</p>
<div class="code"><pre class="code literal-block">source "drivers/input/touchscreen/ft8719_touch_f7b/Kconfig
</pre></div>

<p>(notice the unterminated string quote). I don't know if this had any impact on
the build, but just to be on the safe side I added the missing quote and
rebuilt.</p>
<h4>Building the system image</h4>
<p>Running</p>
<div class="code"><pre class="code literal-block">make systemimage
</pre></div>

<p>failed pretty soon:</p>
<div class="code"><pre class="code literal-block">ninja: error: '/home/mardy/projects/port/halium/out/soong/host/linux-x86/framework/turbine.jar', needed by '/home/mardy/projects/port/halium/out/soong/.intermediates/libcore/core-oj/android_common/turbine/core-oj.jar', missing and no known rule to make it
</pre></div>

<p>The error is due to all the Java-related stuff that I should have disabled but
couldn't find. So, I tried to have a look at the <a href="https://github.com/ubuntu-touch-lavender/android_device_xiaomi_lavender/commit/ad640e121d0dc75017f31d860332327f8acd5d36">changes made on another
xiaomi
device</a>
(<code>lavender</code>, the Redmi note 7, which might not be that different, I thought)
and started editing <code>device/xiaomi/violet/device.mk</code> and removing a couple of
Android packages. Eventually the build proceeded, just to stop at a python
error:</p>
<div class="code"><pre class="code literal-block">  File "build/make/tools/check_radio_versions.py", line 56
    print "*** Error opening \"%s.sha1\"; can't verify %s" % (fn, key)
          ^
SyntaxError: invalid syntax
</pre></div>

<p>Yes, it's the python3 vs python2 issue, since in my system <code>python</code> is python
version 3. In order to fix it, I created a virtual environment:</p>
<div class="code"><pre class="code literal-block">virtualenv --python 2.7 ../python27  # adjust the path to your prefs
source ../python27/bin/activate
</pre></div>

<p>Remember that the second line must be run every time you'll need to setup the
Halium build environment (that is, every time you run <code>breakfast</code>).</p>
<p>The build then proceeded for several minutes, until it failed due to some unresolved symbols:</p>
<div class="code"><pre class="code literal-block">prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/aarch64-linux-android/bin/ld.gold: error: /home/mardy/projects/port/halium/out/target/product/violet/obj/STATIC_LIBRARIES/lib_driver_cmd_qcwcn_intermediates/lib_driver_cmd_qcwcn.a: member at 7694 is not an ELF object
external/wpa_supplicant_8/hostapd/src/drivers/driver_nl80211.c:7936: error: undefined reference to 'wpa_driver_set_p2p_ps'
/home/mardy/projects/port/halium/out/target/product/violet/obj/EXECUTABLES/hostapd_intermediates/src/drivers/driver_nl80211.o:driver_nl80211.c:wpa_driver_nl80211_ops: error: undefined reference to 'wpa_driver_set_ap_wps_p2p_ie'
/home/mardy/projects/port/halium/out/target/product/violet/obj/EXECUTABLES/hostapd_intermediates/src/drivers/driver_nl80211.o:driver_nl80211.c:wpa_driver_nl80211_ops: error: undefined reference to 'wpa_driver_get_p2p_noa'
/home/mardy/projects/port/halium/out/target/product/violet/obj/EXECUTABLES/hostapd_intermediates/src/drivers/driver_nl80211.o:driver_nl80211.c:wpa_driver_nl80211_ops: error: undefined reference to 'wpa_driver_set_p2p_noa'
/home/mardy/projects/port/halium/out/target/product/violet/obj/EXECUTABLES/hostapd_intermediates/src/drivers/driver_nl80211.o:driver_nl80211.c:wpa_driver_nl80211_ops: error: undefined reference to 'wpa_driver_nl80211_driver_cmd'
</pre></div>

<p>As people told me in the Telegram channel, this driver is not used since "our
<code>wpa_supplicant</code> talks to kernel directly". OK, so I simply disabled the
driver, copying again from the <a href="https://github.com/ubuntu-touch-lavender/android_device_xiaomi_lavender/commit/ad640e121d0dc75017f31d860332327f8acd5d36"><code>lavender</code> Halium
changes</a>:
commented out the <code>BOARD_WLAN_DEVICE := qcwcn</code> line (and all lines referring
this variable) from <code>device/xiaomi/violet/BoardConfig.mk</code> and ran <code>make
systemimage</code> again. This time, surprisingly, it all worked.</p>
<h4>Try it out</h4>
<p>I first tried to flash the kernel only. I rebooted into fastboot, and on my PC ran this:</p>
<div class="code"><pre class="code literal-block">cout
fastboot<span class="w"> </span>flash<span class="w"> </span>boot<span class="w"> </span>halium-boot.img
</pre></div>

<p>I then rebooted my phone, but after showing the boot logo for a few seconds it
would jump to the fastboot screen. Indeed, flashing the previous kernel would
restore the normal boot, so there had to be something wrong with my own kernel.</p>
<p>While looking at what the problem could be, I noticed that in the <code>lavender</code>
port the author did not modify the lineageos kernel config file in place, but
instead created a new one and changed the <code>BoardConfig.mk</code> file to point to his
new copy. Since it sounded like a good idea, I did the same and created
<code>kernel/xiaomi/violet/arch/arm64/configs/vendor/violet_halium_defconfig</code> for
the Halium changes. And then the line in the board config file became</p>
<div class="code"><pre class="code literal-block">TARGET_KERNEL_CONFIG := vendor/violet_halium_defconfig
</pre></div>

<p>I then continued investigating the boot issue, and I was told that it might
have been due to an Android option, <code>skip_initramfs</code>, which is set by the
bootloader and causes our Halium boot to fail. The fix is to just disable this
option in the kernel, by editing <code>init/initramfs.c</code> and change the
<code>skip_initramfs_param</code> function to always set the <code>do_skip_initramfs</code> variable
to <code>0</code>, rather than to <code>1</code>. After doing this, the boot proceeded to show the
Ubuntu splash screen with the five dots being lit, but it didn't proceed from
there.</p>
<h5>Setting up the udev rules</h5>
<p>Even in this state, the device was detected by my host PC and these lines
appeared in the system log:</p>
<div class="code"><pre class="code literal-block">kernel: usb 1-3: new high-speed USB device number 26 using xhci_hcd
kernel: usb 1-3: New USB device found, idVendor=0fce, idProduct=7169, bcdDevice= 4.14
kernel: usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
kernel: usb 1-3: Product: Unknown
kernel: usb 1-3: Manufacturer: GNU/Linux Device
kernel: usb 1-3: SerialNumber: GNU/Linux Device on usb0 10.15.19.82
</pre></div>

<p>Indeed, I guess the reason I could do this without even flashing my systemimage
is because I had first flashed another UT system image from another porter. I'm
not sure if I'd had the same results with my own image. Anyway, the USB
networking was there, so I connected and ran the following commands to generate
the udev rules:</p>
<div class="code"><pre class="code literal-block">ssh<span class="w"> </span>phablet@10.15.19.82
<span class="c1"># used 0000 as password</span>
sudo<span class="w"> </span>-i
<span class="c1"># same password again</span>
<span class="nb">cd</span><span class="w"> </span>/home/phablet
<span class="nv">DEVICE</span><span class="o">=</span>violet
cat<span class="w"> </span>/var/lib/lxc/android/rootfs/ueventd*.rc<span class="w"> </span>/vendor/ueventd*.rc<span class="w"> </span><span class="se">\</span>
<span class="w">        </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>^/dev<span class="w"> </span><span class="se">\</span>
<span class="w">        </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^\/dev\///'</span><span class="w"> </span><span class="se">\</span>
<span class="w">        </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">'{printf "ACTION==\"add\", KERNEL==\"%s\", OWNER=\"%s\", GROUP=\"%s\", MODE=\"%s\"\n",$1,$3,$4,$2}'</span><span class="w"> </span><span class="se">\</span>
<span class="w">        </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/\r//'</span><span class="w"> </span><span class="se">\</span>
<span class="w">        </span>&gt;70-<span class="nv">$DEVICE</span>.rules
</pre></div>

<p>I then copied (with <code>scp</code>) this file to my host PC, and I moved it to
<code>device/xiaomi/violet/ubuntu/70-violet.rules</code> (I had to create the <code>ubuntu</code>
directory first). Then I edited the <code>device/xiaomi/violet/device.mk</code> file and
added these lines at the end:</p>
<div class="code"><pre class="code literal-block"><span class="c">### Ubuntu Touch ###</span>
<span class="nv">PRODUCT_COPY_FILES</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="se">\</span>
<span class="w">    </span><span class="k">$(</span>LOCAL_PATH<span class="k">)</span>/ubuntu/70-violet.rules:system/halium/lib/udev/rules.d/70-android.rules
<span class="c">### End Ubuntu Touch ###</span>
</pre></div>

<p>It was now time to try my own system image. I rebooted my device into TWRP, I
cloned the <a href="https://gitlab.com/JBBgameich/halium-install">halium-install
repository</a> into my halium build
dir, downloaded <a href="https://ci.ubports.com/job/xenial-hybris-android9-rootfs-arm64/107/">a rootfs for
Halium9</a>,
and ran</p>
<div class="code"><pre class="code literal-block">./halium-install/halium-install<span class="w"> </span>-p<span class="w"> </span>ut<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>~/Downloads/ubuntu-touch-android9-arm64.tar.gz<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>out/target/product/violet/system.img
</pre></div>

<p>The first time this failed because the <code>simg2img</code> tool was not installed. The
second time it proceeded to create the image, asked me for a password for the
phablet user (gave "0000") and pushed the image onto the device, into the
<code>/data/</code> partition. I then rebooted.</p>
<h5>My first Ubuntu Touch image</h5>
<p>Upon reboot, the usual splash screen appeared, followed by several seconds of
black screen. It definitely didn't look right, but at least it proved that
<em>something</em> had been flashed. After some more seconds, to my big surprise, the
Ubuntu boot screen appeared, just with a smaller logo than how it used to be
before, which also confimed that my system image was being used — in fact, I
did not adjust the <code>GRID_UNIT_PX</code> variable before. Since this was an easy fix,
I chose to focus on that, rather than fix the boot issues (indeed, my device
did not move on from the Ubuntu boot screen). SSH was working.</p>
<p>I took the scaling.conf file from the <a href="https://github.com/ubuntu-touch-lavender/android_device_xiaomi_lavender/commit/e02875e15a09e96635d32aaf9427fcd057d7a9ae">lavender
changes</a>,
put it in <code>device/xiaomi/violet/ubuntu/</code> and added this line in the
<code>PRODUCT_COPY_FILES</code> in <code>device.mk</code>:</p>
<div class="code"><pre class="code literal-block">$(LOCAL_PATH)/ubuntu/scaling.conf:system/halium/etc/ubuntu-touch-session.d/android.conf
</pre></div>

<p>I initially used <code>system/ubuntu/etc/...</code> as the target destination for the
config file, like in the lavender commit, but this didn't work out for me. Then
I changed the path to start with <code>system/halium/</code>, like it's mentioned in the
ubports documentation, but it apparently had no effect either.</p>
<p>After a couple of days spent trying to understand why my files were not
appearing under <code>/etc</code>, it turned out that the device was not using my system
image at all: with <code>halium-install</code> I had my image installed in
<code>/userdata/system.img</code>, while the correct path for Halium 9 devices is
<code>/userdata/android-rootfs.img</code>. I was told that the option <code>-s</code> of
<code>halium-install</code> would do the trick. Instead of re-running the script, I took
the shortcut of renaming <code>/userdata/system.img</code> to
<code>/userdata/android-rootfs.img</code> and after rebooting I could see that the Ubuntu
logo was displayed at the correct size. And indeed my system image was being
used.</p>
<p>So I started to debug why unity8 didn't start. The logs terminated with this line:</p>
<div class="code"><pre class="code literal-block">terminate called after throwing an instance of 'std::runtime_error'
  what():  org.freedesktop.DBus.Error.NoReply: Message recipient disconnected from message bus without replying
initctl: Event failed
</pre></div>

<p>It means, that unity8 did not handle correctly the situation where another
D-Bus service crashed while handing a call from unity8. The problem now was how
to figure out which service it was. I ran <code>dbus-monitor</code> and restarted unity8
(<code>initctl start unity8</code>), then examined the dbus logs; I saw the point where
unity8 got disconnected from the bus, but before that point I didn't find any
failed D-Bus calls. So it had to be the system bus. I did exactly the same
steps, just this time after running <code>dbus-monitor --system</code> as root, I found
the place where unity8 got disconnected, and found this D-bus error shortly
before that:</p>
<div class="code"><pre class="code literal-block">method call time=1605676421.968667 sender=:1.306 -&gt; destination=com.ubuntu.biometryd.Service serial=3 path=/default_device; interface=com.ubuntu.biometryd.Device; member=Identifier
method return time=1605676421.970222 sender=:1.283 -&gt; destination=:1.306 serial=4 reply_serial=3
   object path "/default_device/identifier"
...
method call time=1605676421.974218 sender=:1.283 -&gt; destination=org.freedesktop.DBus serial=6 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetConnectionAppArmorSecurityContext
   string ":1.306"
error time=1605676421.974278 sender=org.freedesktop.DBus -&gt; destination=:1.283 error_name=org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown reply_serial=6
   string "Could not determine security context for ':1.306'"
...
signal time=1605676421.989074 sender=org.freedesktop.DBus -&gt; destination=:1.283 serial=6 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
   string "com.ubuntu.biometryd.Service"
...
error time=1605676421.989302 sender=org.freedesktop.DBus -&gt; destination=:1.306 error_name=org.freedesktop.DBus.Error.NoReply reply_serial=4
   string "Message recipient disconnected from message bus without replying"
</pre></div>

<p>So, it looks like unity8 (<code>:1.306</code>) made a request to biometryd, who asked the
D-Bus daemon what was the AppArmor label of the caller, but since I didn't
backport the D-Bus mediation patches for AppArmor, the label could not be
resolved. <code>biometryd</code> decided to crash instead of properly handling the error,
and so did unity8.</p>
<p>So I backported the AppArmor patches. I took them from the <a href="https://kernel.ubuntu.com/git/jj/linux-apparmor-backports/log/?h=v4.15%2b-apparmor-backport-to-v4.14-presquash">Canonical kernel
repo</a>,
but they did not apply cleanly because they are meant to be applied on top of a
pristine 4.14 branch, whereas the Android kernel had already some AppArmor
security fixes backported from later releases. So I set and quickly inspected
the contents of each patch, and found out that a couple of them had already
been applied, and the last patch had to be applied as the first (yeah, it's
hard to explain, but it all depends on other patches that Android has
backported from newer kernels). Anyway, after rebuilding the kernel and
reflashing it, my phone could finally boot to unity8!</p>
<h3>Conclusion (of the first episode)</h3>
<p>The actual porting, as I've been told, starts here. What has been documented
here are only the very first steps of the bring-up; what awaits me now is to
make all the hardware subsystems work properly, and this, according to people
more experienced in porting, is the harder part.</p>
<p>So far, very few things work, to the point that it's faster to me to list the
things that <em>do work</em>; it's safe to assume that all what is not listed here is
not working:</p>
<ul>
<li>Mir, with graphics and input: Unity8 starts and is usable</li>
<li>Camera: can take photos; video recording start but an error appears when the
  stop button is pressed</li>
<li>Flashlight</li>
<li>Fingerprint reader: surprisingly, this worked out of the box</li>
<li>Screen brightness (though it can be changed only manually)</li>
</ul>
<p>For all the rest, please keep an eye on this blog: I'll write, when I make some
progress!</p><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1eb590a08aa9788590a11eb98f5bd3b52003c683c68&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1eb590a08aa9788590a11eb98f5bd3b52003c683c68/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1eb590a08aa9788590a11eb98f5bd3b52003c683c68&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1eb590a08aa9788590a11eb98f5bd3b52003c683c68/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 17 Jan 2021 19:15:01 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1eb590a08aa9788590a11eb98f5bd3b52003c683c68</guid>
        </item>
        <item>
            <title>Qbs and code coverage reports</title>
            <link>http://mardy.it/blog/2019/07/qbs-and-code-coverage-reports.html</link>
            <description><![CDATA[
<div><p>You know that I'm not an <em>early adopter</em>. That's why it was only a couple of
weeks ago when I decided to give <a href="https://doc.qt.io/qbs/">Qbs</a> a try, by using
the good old <a href="https://www.mardy.it/mappero/">Mappero</a> (and its spin-off,
<a href="https://www.mardy.it/mappero-geotagger/">Mappero Geotagger</a>) as a test bench.
Yes, I know that the Qt company is not going to maintain Qbs anymore in the
future, but the little I knew about Qbs was enough to convince me that it's a
project worth supporting. So, better late than never -- and hopefully the
community (me included) will do a good job in keeping Qbs thriving.</p>
<p>Having Mappero build with Qbs was the simplest thing ever. The only issue I met
was in building the unit tests, because I'm used to set the <code>rpath</code> on test
executables in order to make it easy to run them uninstalled, and with <code>qmake</code>
I achieved that with this:</p>
<pre class="code literal-block"><span></span><code><span class="nv">QMAKE_RPATHDIR</span> <span class="o">=</span> <span class="nv">$$</span><span class="o">{</span>QMAKE_LIBDIR<span class="o">}</span>
</code></pre>


<p>In turns out that with Qbs you can do it in almost the same way, but for some
reason I couldn't figure it out and I even <a href="https://bugreports.qt.io/browse/QBS-1455">reported a
bug</a> to which I got some nice
suggestions, before eventually settling on this:</p>
<pre class="code literal-block"><span></span><code><span class="kr">import</span> <span class="nx">qbs</span> <span class="mf">1.0</span>

<span class="nx">Test</span> <span class="p">{</span>
    <span class="k">name:</span> <span class="s2">"path-test"</span>

    <span class="k">files:</span> <span class="p">[</span>
        <span class="s2">"path-test.cpp"</span><span class="p">,</span>
        <span class="s2">"path-test.h"</span><span class="p">,</span>
        <span class="s2">"paths.qrc"</span><span class="p">,</span>
    <span class="p">]</span>

    <span class="nx">Depends</span> <span class="p">{</span> <span class="k">name:</span> <span class="s2">"Mappero"</span> <span class="p">}</span>
    <span class="k">cpp.rpaths:</span> <span class="nx">cpp</span><span class="p">.</span><span class="nx">libraryPaths</span>    <span class="c1">// &lt;-- this does the trick!</span>
<span class="p">}</span>
</code></pre>


<p>It's surprisingly similar to how it's done in qmake, so it's not clear even to
me why I didn't guess that immediately. Anyway, that was literally my only
problem, and you can see the whole set of Qbs files I wrote by having a look at
<a href="https://gitlab.com/mardy/mappero/commit/2a19b59f018cd0517d37eadd24d1aa1780140e4b">this
commit</a>.</p>
<p>Given how easy the migration was, I thought I should also try to add a code
coverage report; that's not something I had in my qmake build either, but it's
something I really want to have in all my newer projects.</p>
<h3>Teaching Qbs to make a code coverage report</h3>
<p>Unfortunately, my search for examples on how to have Qbs prepare a coverage
report was mostly insuccessful, but thanks to some amazing help from Christian
in the #qbs IRC channel, this was not hard to achieve. So, I hope to be of some
help myself too, by sharing how this works.</p>
<p>First of all, it must be said that Qbs doesn't know anything about code
coverage, at all. However, it's possible (and often easy) to extend Qbs by
adding your own <code>Product</code> with its own set of build rules, so here's the
<code>CoverageReport</code> item for Mappero (though, it should be general enough to be
reusable in your own project):</p>
<pre class="code literal-block"><span></span><code><span class="kr">import</span> <span class="nx">qbs</span>

<span class="nx">Product</span> <span class="p">{</span>
    <span class="k">name:</span> <span class="s2">"coverage"</span>

    <span class="nx">property</span> <span class="nx">string</span> <span class="k">outputDirectory:</span> <span class="s2">"coverage-html"</span>
    <span class="nx">property</span> <span class="nx">stringList</span> <span class="k">extractPatterns:</span> <span class="p">[]</span>

    <span class="k">builtByDefault:</span> <span class="kc">false</span>
    <span class="k">files:</span> <span class="p">[</span><span class="s2">"**"</span><span class="p">]</span>
    <span class="k">type:</span> <span class="p">[</span><span class="s2">"coverage.html"</span><span class="p">]</span>

    <span class="nx">Depends</span> <span class="p">{</span> <span class="k">productTypes:</span> <span class="p">[</span><span class="s2">"autotest-result"</span><span class="p">]</span> <span class="p">}</span>

    <span class="nx">Rule</span> <span class="p">{</span>
        <span class="k">multiplex:</span> <span class="kc">true</span>
        <span class="k">explicitlyDependsOnFromDependencies:</span> <span class="p">[</span><span class="s2">"autotest-result"</span><span class="p">]</span>
        <span class="k">outputFileTags:</span> <span class="s2">"coverage.html"</span>
        <span class="k">requiresInputs:</span> <span class="kc">false</span>
        <span class="k">prepare:</span> <span class="p">{</span>
            <span class="kd">var</span> <span class="nx">commands</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="kd">var</span> <span class="nx">captureCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="p">[</span>
                <span class="s2">"--directory"</span><span class="p">,</span> <span class="nx">project</span><span class="p">.</span><span class="nx">sourceDirectory</span><span class="p">,</span>
                <span class="s2">"--capture"</span><span class="p">,</span>
                <span class="s2">"--output-file"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span>
                <span class="s2">"--no-checksum"</span><span class="p">,</span>
                <span class="s2">"--compat-libtool"</span><span class="p">,</span>
            <span class="p">]);</span>
            <span class="nx">captureCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Collecting coverage data"</span><span class="p">;</span>
            <span class="nx">captureCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
            <span class="nx">captureCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
            <span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">captureCmd</span><span class="p">);</span>

            <span class="kd">var</span> <span class="nx">extractArgs</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"--extract"</span><span class="p">);</span>
                <span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"coverage.info"</span><span class="p">);</span>
                <span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"-o"</span><span class="p">);</span>
                <span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"coverage.info"</span><span class="p">);</span>
                <span class="kd">var</span> <span class="nx">extractCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="nx">extractArgs</span><span class="p">);</span>
                <span class="nx">extractCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Extracting coverage data"</span><span class="p">;</span>
                <span class="nx">extractCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
                <span class="nx">extractCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
                <span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">extractCmd</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="kd">var</span> <span class="nx">filterCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="p">[</span>
                <span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'moc_*.cpp'</span><span class="p">,</span>
                <span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'qrc_*.cpp'</span><span class="p">,</span>
                <span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'*/tests/*'</span><span class="p">,</span>
                <span class="s2">"-o"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span>
            <span class="p">]);</span>
            <span class="nx">filterCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Filtering coverage data"</span><span class="p">;</span>
            <span class="nx">filterCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
            <span class="nx">filterCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
            <span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">filterCmd</span><span class="p">);</span>

            <span class="kd">var</span> <span class="nx">genhtmlCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"genhtml"</span><span class="p">,</span> <span class="p">[</span>
                <span class="s2">"--prefix"</span><span class="p">,</span> <span class="nx">project</span><span class="p">.</span><span class="nx">sourceDirectory</span><span class="p">,</span>
                <span class="s2">"--output-directory"</span><span class="p">,</span> <span class="nx">product</span><span class="p">.</span><span class="nx">outputDirectory</span><span class="p">,</span>
                <span class="s2">"--title"</span><span class="p">,</span> <span class="s2">"Code coverage"</span><span class="p">,</span>
                <span class="s2">"--legend"</span><span class="p">,</span>
                <span class="s2">"--show-details"</span><span class="p">,</span>
                <span class="s2">"coverage.info"</span><span class="p">,</span>
            <span class="p">]);</span>
            <span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Generate HTML coverage report"</span><span class="p">;</span>
            <span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
            <span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
            <span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">genhtmlCmd</span><span class="p">);</span>

            <span class="k">return</span> <span class="nx">commands</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>


<p>The most important thing here are the references to the <code>autotest-result</code> tag:
this is the tag used by the <code>AutotestRunner</code> Qbs item, which is responsible for
running the unit tests. Referencing its product's tag in the <code>Depends</code> item and
in the <code>explicitlyDependsOnFromDependencies</code> properties ensures that "building"
our product will cause the unit tests to run. Other needed bits are the
<code>requiresInputs: false</code> property, which means that our rule doesn't have any
required inputs, and the <code>builtByDefault: false</code> property, which says that our
coverage report should not be generated when just typing <code>qbs</code>. Instead, to run
the tests and get the code coverage report one will have to request it
explicitly, by typing</p>
<pre class="code literal-block"><span></span><code><span class="err">qbs -p coverage</span>
</code></pre>


<p>The <code>prepare</code> property of the <code>Rule</code> is where the commands to generate the code
coverage report are defined. Here we can use the <code>Command</code> item to invoke
external programs, and we return a list of such items, so that the commands
will be executed in sequence. Note that here I'm using <code>lcov</code> and expecting to
find the coverage data produced by <code>gcov</code>, so this is probably not portable
outside of Linux/gcc.</p>
<p>Using the <code>CoverageReport</code> item is quite easy: you just need to declare it, and
specify which paths contain the coverage data that you are interested in
(otherwise, lcov will collect data from all object files that it find under the
build directory, which might not be what you desire):</p>
<pre class="code literal-block"><span></span><code>    <span class="nx">CoverageReport</span> <span class="p">{</span>
        <span class="k">condition:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span>
        <span class="k">extractPatterns:</span> <span class="p">[</span> <span class="s1">'*/src/*.cpp'</span><span class="p">,</span> <span class="s1">'*/lib/*.cpp'</span> <span class="p">]</span>
    <span class="p">}</span>
</code></pre>


<p>There's little more than that to be done. Of course, you need to find a way to
pass the <code>--coverage</code> option to gcc when building your products, and for this I
created a small <code>buildconfig</code> module in
<code>qbs/modules/buildconfig/BuildConfig.qbs</code> which I depend on in all products
which I wish to build with coverage enabled:</p>
<pre class="code literal-block"><span></span><code><span class="kr">import</span> <span class="nx">qbs</span>

<span class="nx">Module</span> <span class="p">{</span>
    <span class="k">cpp.cxxFlags:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span> <span class="o">?</span> <span class="p">[</span><span class="s2">"--coverage"</span><span class="p">]</span> <span class="o">:</span> <span class="kc">undefined</span>
    <span class="k">cpp.dynamicLibraries:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span> <span class="o">?</span> <span class="p">[</span><span class="s2">"gcov"</span><span class="p">]</span> <span class="o">:</span> <span class="kc">undefined</span>

    <span class="nx">Depends</span> <span class="p">{</span> <span class="k">name:</span> <span class="s2">"cpp"</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre>


<p>If all this looks scary, you should probably have a look at the diff which
shows <a href="https://gitlab.com/mardy/mappero/commit/ee04f6a453a935db653095c45bfe57af6a0ce508">how I added code coverage reporting to
qbs</a>:
hopefully you'll find that it's not that complex, after all.</p>
<p>I hope that Qbs users will find this interesting, and possibly improving my
setup. Ideally we should try to get something like this part of Qbs itself, but
portability outside of Linux / gcc is going to be an issue.</p></div><span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e99c39ac45c7da9c3911e98a3a37a5e1a937693769&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e99c39ac45c7da9c3911e98a3a37a5e1a937693769/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e99c39ac45c7da9c3911e98a3a37a5e1a937693769&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e99c39ac45c7da9c3911e98a3a37a5e1a937693769/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Mon, 01 Jul 2019 13:42:20 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e99c39ac45c7da9c3911e98a3a37a5e1a937693769</guid>
        </item>
        <item>
            <title>A critical view on the blockchain</title>
            <link>http://mardy.it/blog/2019/04/a-critical-view-on-the-blockchain.html</link>
            <description><![CDATA[
<div><p>At the beginning of this month I participated to the
<a href="https://foss-north.se">foss-north</a> conference, in Gothenburg, and took the
stage to give a short presentation of the blockchain technology. Given that my
talk was somehow critical of the blockchain (or rather, of the projects using
it without due reason) I was prepared to receive a wave of negative remarks,
assuming that all the hype surrounding this technology would have infected a
good part of my audience as well. I was therefore positively surprised when
several people came to me afterwords to express their appreciation for my
speech, appreciation that now makes me confident enough to share the video of
the presentation here too:</p>
<p></p><center>
<iframe width="560" height="315" src="https://www.youtube.com/embed/5VcdC3A-ezg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</center>
<p>I want to publicly thank <a href="http://www.thelins.se/johan/blog/">Johan Thelin</a> and
all the other foss-north staff and volunteers who organized such a successful
conference. They also managed to get the video recordings out in a surprisingly
short time. Indeed, the above video is taken from the <a href="https://www.youtube.com/channel/UCQvR8lgE9rishcKT_hZT6eQ">foss-north
YouTube channel</a>,
which I recommend you to visit as there were a lot of good talks at the
conference; the topics were so varied, that I'm sure you'll find at least a
couple of talks of your interest.</p></div><span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e966db615f1a7a66db11e982f4f37f62fd695a695a&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e966db615f1a7a66db11e982f4f37f62fd695a695a/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e966db615f1a7a66db11e982f4f37f62fd695a695a&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e966db615f1a7a66db11e982f4f37f62fd695a695a/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Wed, 24 Apr 2019 19:59:45 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e966db615f1a7a66db11e982f4f37f62fd695a695a</guid>
        </item>
        <item>
            <title>Ubports at the LinuxPiter conference</title>
            <link>http://mardy.it/blog/2019/03/ubports-at-the-linuxpiter-conference.html</link>
            <description><![CDATA[
<div><p>Last November I was invited to talk at the <a class="reference external" href="https://linuxpiter.com/">LinuxPiter</a> conference. I held a presentation of the <a class="reference external" href="https://ubports.com/">Ubports
project</a>, to which I still contribute in my little
spare time.</p>
<p>The video recording from the conference has finally been published:</p>
<div class="youtube-video align-center">
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/_gWTiVPahT0?rel=0&amp;wmode=transparent" frameborder="0" allow="encrypted-media" allowfullscreen></iframe>
</div><p>(there's also a <a class="reference external" href="https://www.youtube.com/watch?v=pYiqOzZZg-w">version in Russian</a>)</p>
<p>There was not a big audience, to be honest, but those that were there expressed
a lot of interest in the project.</p></div><span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e945b0296a7f3e45b011e98aacf76b108d15221522&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e945b0296a7f3e45b011e98aacf76b108d15221522/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e945b0296a7f3e45b011e98aacf76b108d15221522&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e945b0296a7f3e45b011e98aacf76b108d15221522/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Wed, 13 Mar 2019 16:07:23 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e945b0296a7f3e45b011e98aacf76b108d15221522</guid>
        </item>
        <item>
            <title>Mappero: public source code, CLA, Qt5 port</title>
            <link>http://blog.mardy.it/2013/11/mappero-public-source-code-cla-qt5-port.html</link>
            <description><![CDATA[
<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://www.mardy.it/mappero">Mappero</a> has always been distributed under a GPL licence. However, since when I started selling <a href="http://www.mardy.it/mappero-geotagger">Mappero Geotagger</a> (which is built from the same source), I decided not to publish the source code in a public repository, but only to provide it to those who made an explicit request to obtain it.<br />
<br />
I spent some time reconsidering the matter, and I've finally decided to let the source code live in a <a href="https://gitlab.com/mardy/mappero">public repository</a>. I also setup a <a href="http://lists.mardy.it/listinfo.cgi/mappero-mardy.it">mailing list</a> for it. And indeed I welcome code contributions, however there's a small catch: a <a href="http://en.wikipedia.org/wiki/Contributor_License_Agreement">CLA</a>. While Mappero is distributed under the GPLv3 licence, <i>I request that all contributors send me an e-mail in which they give me the right to re-licence their contribution under any licence published by the Free Software Foundation</i>.<br />
<br />
Since I believe that the busiest time for my involvement with <a href="http://blog.mardy.it/2013/11/speculo-or-shared-memory-made-easy.html">speculo</a> has passed, I expect to be able to spend some more time developing Mappero. The qt5 port is more or less working, but most of the cool features are missing, so it's little more than a map viewer at the moment (Mappero Geotagger, however, is fully working under Qt5!).<br />
<center>
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/QeAT6LFrpp4" width="560"></iframe></center>
<br />
Here you can see Mappero running on an Ubuntu Touch powered Nexus 4. Pinch zooming and GPS are not yet working, but I promise they'll be there in less than a week. Also I found a nasty bug which can cause the application to crash when downloading map tiles, and I'll fix it ASAP (I'm mentioning it just so that I won't be flooded with identical bug reports now :-) ).</div>
<span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e344a25f96b22244a211e399758b05128eae94ae94&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e344a25f96b22244a211e399758b05128eae94ae94/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e344a25f96b22244a211e399758b05128eae94ae94&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e344a25f96b22244a211e399758b05128eae94ae94/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 03 Nov 2013 17:55:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e344a25f96b22244a211e399758b05128eae94ae94</guid>
        </item>
        <item>
            <title>speculo, or shared memory made easy</title>
            <link>http://blog.mardy.it/2013/11/speculo-or-shared-memory-made-easy.html</link>
            <description><![CDATA[
<div dir="ltr" style="text-align: left;" trbidi="on">
The last few months I've been dedicating most of my (very little) free time to a new project: <tt>speculo</tt>, a library which implements IPC (Inter-Process Communication) on top of shared memory. Since developers appreciate conciseness and minimalism, here's a description of <tt>speculo</tt> in a few bullet points:<br />
<ul style="text-align: left;">
<li>written in C</li>
<li>POSIX (tested in Linux and FreeBSD) </li>
<li>small (~850 LOC)</li>
<li>well commented (~400 lines) </li>
<li>good test coverage</li>
<li>zerocopy</li>
<li>lockless </li>
<li>one writer, many readers</li>
<li>data is written and read in chunks of arbitrary size </li>
<li>a data chunk becomes visible to the readers as soon as the writer commits it </li>
<li>data chunks can have an expiration time </li>
<li>data chunks can be obsoleted by a newer copy</li>
<li>garbage collector </li>
<li>no file descriptors are permanently kept open</li>
<li>no change notification</li>
</ul>
But here I probably need to write some paragraphs to explain a couple of points.&nbsp; Except for a few memory addresses which hold the state of the memory area and which are atomically updated and guarded with memory barriers, <i>all the data written to the shared memory object is immutable</i>. This in particular guarantees that readers have a consistent access to the data, which will not change under their eyes. Data chunks are only appended, which means that the shared memory object can only grow. However, data chunks can be marked as expired (if they have an expiration time associated with them) or obsoleted (if a new chunk is said to replace their contents), which means that not all of the data which is written in the SHM object is actually valid. The readers' functions know this, and skip over the invalid data.<br />
At some point the garbage collector will kick in, when the conditions specified by the writer are met or when the SHM area is completely full. All the chunks which are still valid will be copied over to a new SHM object, and then the SHM objects will be atomically switched. Readers will be able to complete their ongoing reads, and transparently move on to the new SHM object as they request to read a new data chunk.<br />
<br />
The above means that speculo can be used in at least two ways:<br />
<ul style="text-align: left;">
<li>to implement a data stream: the writer fills the shared memory area with short-lived data chunks</li>
<li>sharing changeable blocks of data</li>
</ul>
The first use-case doesn't need much of an explanation; it's usual message passing between a writer and some readers. The second use-case means having a writer expose one or more blocks of data to the readers; if the data gets updated, readers can re-read it and obtain the latest version.<br />
<br />
On the minus side, <tt>speculo</tt> doesn't implement any mechanism of change notification: when the writer writes a new data chunk, or updates an existing one, readers won't be notified of it (though they will get the new data, if they access the shared memory area). This was done intentionally, because the scope of <tt>speculo</tt> is just to make using shared memory a little easier, and to integrate with existing IPC mechanisms, such as sockets or D-Bus (<a href="http://www.freedesktop.org/wiki/Software/DBusP2P/">or even new IPC mechanisms</a>).<br />
<br />
The project is in such a state where the declared functionality is working, though I wouldn't swear about its complete reliability (more tests are needed). The current API is not fixed in stone, and on the contrary I'm thinking of a couple of changes to apply. Also, after seeing the implementation of <tt>shm_open</tt> in <a href="http://eglibc.org/cgi-bin/viewvc.cgi/trunk/libc/sysdeps/unix/sysv/linux/shm_open.c?revision=22177&amp;view=markup">Linux</a> and <a href="http://nixdoc.net/man-pages/FreeBSD/man3/shm_open.3.html">FreeBSD</a>, I'm seriously considering dropping the usage of it in favour of plain <tt>open</tt>, which would then allow for per-user namespaces. So, I think this is a good time to join the project, to shape it the way it can be useful to the largest number of people.<br />
<br />
Last but not least, the link to the project page: <a href="https://gitlab.com/mardy/speculo">https://gitlab.com/mardy/speculo</a><br />
There is not much documentation in the wiki yet; I recommend checking out the code and running <tt>make doc</tt> to build the HTML documentation (requires doxygen). To run the tests, use <tt>make check</tt> (requires pkg-config and <a href="http://check.sourceforge.net/">check</a>).<br />
A mailing list is up <a href="http://lists.mardy.it/listinfo.cgi/speculo-mardy.it">here</a>.</div>
<span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e343c8c2bff47e43c811e3ae33598a764ffe4ffe4f&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e343c8c2bff47e43c811e3ae33598a764ffe4ffe4f/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e343c8c2bff47e43c811e3ae33598a764ffe4ffe4f&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e343c8c2bff47e43c811e3ae33598a764ffe4ffe4f/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sat, 02 Nov 2013 15:41:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e343c8c2bff47e43c811e3ae33598a764ffe4ffe4f</guid>
        </item>
        <item>
            <title>An always new wallpaper for your N900</title>
            <link>http://blog.mardy.it/2011/06/always-new-wallpaper-for-your-n900.html</link>
            <description><![CDATA[
<p>With the 0.9 version of <a href="http://www.mardy.it/oculo">oculo</a>, your N900 homescreen gets one level up: beautiful wallpapers that will never be the same. Well, whether they are beautiful really depends on you: you decide what tiny part of the World Wide Web should be rendered in there!</p><br />
<center><br />
<iframe width="560" height="349" src="http://www.youtube.com/embed/XeZhF00P1hs?rel=0" frameborder="0" allowfullscreen></iframe><br />
</center><br />
<p>Of course you are not forced to have Oculo manage your wallpapers. :-) Oculo can still render the web content into a homescreen widget, and you can run multiple instances of it, in different modes. Also, you can have Oculo render only some of your homescreen views, while keeping the rest static.</p><br />
<p>Version 0.9 of Oculo is in the <tt>extras-testing</tt> repository, and you can directly <a href="http://repository.maemo.org/extras-devel/pool/fremantle/non-free/o/oculo/oculo_0.9_armel.deb">download it from here</a>. Be warned that I just tested the widget for a couple of minutes, so anything bad can happen. :-)</p><span class="net_nemein_favourites">12 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=3e0eb9f09f4b11e0ba2dc7240c5aa106a106&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/3e0eb9f09f4b11e0ba2dc7240c5aa106a106/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=3e0eb9f09f4b11e0ba2dc7240c5aa106a106&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/3e0eb9f09f4b11e0ba2dc7240c5aa106a106/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sat, 25 Jun 2011 19:12:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-3e0eb9f09f4b11e0ba2dc7240c5aa106a106</guid>
        </item>
        <item>
            <title>Oculo is now available in the Extras repository!</title>
            <link>http://blog.mardy.it/2011/05/oculo-is-now-available-in-extras.html</link>
            <description><![CDATA[
Just a quick note: <a href="http://www.mardy.it/oculo">Oculo</a> 0.8 is now in the <a href="http://wiki.maemo.org/Extras">Maemo Extras repository</a>. Known issues with the CSSU have now been resolved, and the update interval is now configurable.<span class="net_nemein_favourites">7 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=7669ca1a7ed011e086e403e06757c333c333&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/7669ca1a7ed011e086e403e06757c333c333/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=7669ca1a7ed011e086e403e06757c333c333&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/7669ca1a7ed011e086e403e06757c333c333/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 15 May 2011 11:05:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-7669ca1a7ed011e086e403e06757c333c333</guid>
        </item>
        <item>
            <title>Oculo: dynamic web content to your N900 home screen</title>
            <link>http://blog.mardy.it/2011/05/oculo-dynamic-web-content-to-your-n900.html</link>
            <description><![CDATA[
<p>Latest news, sport results, stock market quotes, currency conversions, web comics, picture of the day... The internet is filled with dynamic content that you might want to bring into your phone homescreen, but often you don't have a widget that supports the site you are interested in. But now, cry no more! <a href="http://maemo.org/packages/view/oculo/">Oculo</a> is a homescreen widget for the <a href="http://maemo.nokia.com/n900">Nokia N900</a> which can take any web site and render its contents into your homescreen. Not only it can render a complete web-page, you can also choose which specific parts of a web page you are interested in!</p>

<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mardy.it/archivos/imagines/oculo.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" width="400" src="http://www.mardy.it/archivos/imagines/oculo.png" /></a><br>
The mandatory screenshot. Three instances of Oculo: Flickr! explore, Google local news, Yahoo! finance.</div>



<p>As I'm writing this, Oculo 0.7 is in the <a href="http://wiki.maemo.org/Extras-testing">Maemo extras-testing repository</a>; I'm using it without problems in my N900, but it's still rather buggy, so if you try and find some problems, don't hesitate to report them. Unfortunately, it is already known that <b>Oculo will not be visible if you are running the <a href="http://wiki.maemo.org/Community_SSU">community SSU</a></b>; this is apparently a <a href="http://talk.maemo.org/showthread.php?p=998003">problem with the CSSU and Qt home widgets</a> which I'm investigating. Also, since the configuration procedure might not be as intuitive as it could be, I've created a video which shows how to configure it:</p>
<center><iframe width="560" height="349" src="http://www.youtube.com/embed/g-ShrSkq0r8?rel=0" frameborder="0" allowfullscreen></iframe></center>

<h4>History and technical aspects</h4>

<p>The idea of developing Oculo (which means &ldquo;eye&rdquo; in <a href="http://www.interlingua.com/">interlingua</a>) came to me a few months ago, when I noticed that Radek, a colleague of mine, was checking the daily menu of our canteen in the intranet pages. I ironically suggested him that he should write a maemo home widget showing the daily menu, so he could have it always visible on his phone. The fact that I considered &ldquo;silly&rdquo; the idea of writing a homescreen widget just for that goal suddenly brought up the idea of Oculo: giving the user the possibility to put in his homescreen whatever web content he desires.</p>
<p>Using Qt and QWebKit to render the web page contents into an image was unbelievably simple, and boosted my motivation in developing the widget. In a couple of days I already got something that was usable to me; but as <a href="http://www.mardy.it/mappero">Mappero</a> users know, my usability standards are quite low :-), and this time I realized that I couldn't just publish Oculo in that state. So I went on developing the configuration dialog, tried hard to improve the graphical appearance of the widget (which still looks bad, but you haven't seen how it was before :-p) and solve some performance issues. The biggest of which was the <i>memory consumption</i> of the widget due to keeping QWebKit loaded in memory; this has now been solved by moving the configuration phase and the web content retrieval/rendering into a separate process, which is running only when needed. The homescreen widget itself is just a container for the image.

<h4>Future developments</h4>

<p>A quick roadmap of what should be coming for Oculo:</p>
<ul>
<li>Minimum interval between updates will be configurable (this is trivial and will be coming very soon)</li>
<li>Speed improvements: try not to load external content which will not be rendered</li>
<li>Share configurations between users; let users upload/download their configuration to a central server &mdash; this will make the configuration much easier</li>
<li>Port Oculo to MeeGo (to be investigated)</li>
<li>Port Oculo to Linux desktops</li>
<li>If <a href="http://labs.qt.nokia.com/2011/02/28/necessitas/">Qt on Android</a> can be used to develop home screen widget, an Android port might also be possible.</li>
</ul>

<p>That's all for now! Go and try Oculo out, and let me know your impressions. :-)</p><span class="net_nemein_favourites">13 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=8111aea873e811e09edaf39384a566d766d7&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/8111aea873e811e09edaf39384a566d766d7/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=8111aea873e811e09edaf39384a566d766d7&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/8111aea873e811e09edaf39384a566d766d7/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 01 May 2011 14:17:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-8111aea873e811e09edaf39384a566d766d7</guid>
        </item>
        <item>
            <title>Committed to Linux</title>
            <link>http://blog.mardy.it/2011/02/committed-to-linux.html</link>
            <description><![CDATA[
<p>
As a Nokia employee working on MeeGo, I feel that my career is going to be deeply affected by the  recently announced <a href="http://www.nokia.com/press/press-releases/showpressrelease?newsid=1488004">Nokia strategy</a>. I'm not going to comment on the value of the business decisions; of course I have my opinions about that too, but what I feel more important now is the future of MeeGo, and Linux-based platforms in general, inside Nokia.<br />
The announcement mentions MeeGo only marginally, as a <em>“longer-term market exploration”</em>, and ends the paragraph with <em>&ldquo;Nokia <b>still</b> plans to ship a MeeGo-related product later this year&rdquo;</em>. This sounds to me like: we won't market any MeeGo devices in parallel with Windows Phone ones, not to hinder the latter's success, but we'll release the MeeGo product we're currently working on before downscaling MeeGo back into the R&D division.</p>
<p>No matter how wrong my interpretation might be, let's try to collect a few facts:
<ul>
<li><b>MeeGo is ready, it's not an R&D project</b>: a MeeGo phone <em>will</em> be released
<li>Nokia's primary platform for the middle/long term is Windows Mobile</li>
<li>Meego will become, within Nokia, an R&D project at best
</ul>
<p>I feel confused and fooled. Business logics are floating several metres above my head, and I cannot understand what's the point of saying that MeeGo will be an R&D project when it's not. To me, it's like taking a teenager and trying to squeeze him into a baby's cradle. Either you kill him more or less explicitly, or you take him out, let him grow and give him a chance to be a hero. We are going to have the best phone in the market this year. It might not be perfect, as the N900 clearly wasn't, but all the premises for a brilliant future are there. And people will love it, as they loved the N900 despite it being far away from the quality standards we aspired to achieve and despite a zero-digits investment on marketing. Maemo won, against all odds.</p>
<p>
One thing is clear: Nokia is not committed to Linux and the platform for the future Nokia devices is not going to be Linux-based, at least in the middle term. Because if it were, I can't see a reason why it couldn't be MeeGo.</p>
<p>
If I try to imagine my future career in Nokia, I see myself either working on applications or R&D projects on top of Windows Mobile, or trying to squeeze the teenager into the cradle, and maybe put him into the refrigerator and periodically check that he doesn't die, because hey, he's our far future hope.<br/>
So, what do I have against Windows Mobile? Simple: it's closed source software. And it doesn't matter if the software I develop is open-source; on the contrary, <b>if I had to choose between developing open-source software on top of a closed platform and developing closed-source software on top of an open-source platform, I'd much rather go for the second option</b>: because with the first one I'd still be using and promoting a closed platform, and unless you are developing a cross-platform application or framework, you'd be doing very little good to the open source world.</p>
<p>
Summing up. I really wish that Nokia took one step back and revised their plan. Not because I ask it of course, but because the loyal customers, the developers and the investors are asking it. And give a clear statement on what is the future of MeeGo, Linux and open-source within Nokia. Meanwhile, <b><a href="http://www.mardy.it/archivos/AlbertoMardeganCVe.pdf">my CV has been updated</a></b> and has appeared on this blog's navigation menu for anyone to read. Companies committed to Linux are welcome to <a href="mailto:mardy.tardi@gmail.com">contact me</a> for proposing a job or even a shorter term collaboration. It would be wonderful if I was given a chance to continue working on MeeGo, <a href="http://old.nabble.com/%22DBus-Embedded%22---a-clean-break-tt30716929.html#a30810229">work on some cool ideas</a>, work to introduce the Accounts & SingleSignOn framework to more Linux distributions and open-source OSes. Or actually, anything where I would be given a chance to develop on top of open-source software.<br/>
Proposals from Nokia are welcome as well.</p>
<p style="padding-top: 1em"><i>Note: in this blog post I'm talking only about MeeGo because it's what's affecting me most, and I wanted to keep the post to the point. It doesn't mean that I don't care about Symbian's future and Qt deployment.</i></p><span class="net_nemein_favourites">38 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=d4c716d236ad11e0983eafe5f95c6dbd6dbd&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/d4c716d236ad11e0983eafe5f95c6dbd6dbd/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=d4c716d236ad11e0983eafe5f95c6dbd6dbd&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/d4c716d236ad11e0983eafe5f95c6dbd6dbd/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sat, 12 Feb 2011 15:02:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-d4c716d236ad11e0983eafe5f95c6dbd6dbd</guid>
        </item>
        <item>
            <title>Google Maps routing: the day after</title>
            <link>http://blog.mardy.it/2010/08/google-maps-routing-day-after.html</link>
            <description><![CDATA[
<p>Just one day after releasing mappero 3.0+beta11, another version is out. Today's hot dish is the Google Maps <i>address disambiguation</i> dialog:</p>

<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mardy.it/archivos/imagines/mappero-google-disambiguation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://www.mardy.it/archivos/imagines/mappero-google-disambiguation.png" width="400" /></a></div>

<p>It sometimes happens (especially to people living in Italy) that the address you need exists in different cities. &ldquo;Via Roma&rdquo;, for instance, is one very common street name in Italy, so if you are searching for it in Google Maps web interface you won't get a route, but instead you'll get a list of possible matches. And so far, in such a situation Mappero would have spit out the infamous &ldquo;Invalid source or destination.&rdquo; error message.<br/>
In today's release the situation is improved, because when we get a disambiguation request from Google Maps, Mappero shows the screen above and lets you pick your destination. This should hopefully save you some time when typing addresses.</p>
<p>I still have a few unclear points about Google Maps behaviour, because sometimes the reply is different from what we get via web, and it seems that it doesn't always honour our request for local results only. So, if someone is familiar with <a href="http://mapki.com/wiki/Google_Map_Parameters">Google Maps parameters</a> and knows how to get the destination address resolved using a local search, please let me know and as a reward I'll append your name to all street names returned by Mappero. ;-)</p>
<p>By the way, the main reason for releasing this today was that this version also fixes the problem when libmappero doesn't get automatically upgraded along with Mappero. Also, the fact of having received a huge donation stimulated me to do something in return. :-)</p>
<br/>
<p>Oh! I hope that now you won't be expecting a new release every day! But in case you do, here is how <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DLKNAWDRW4WVG">you can make it happen</a>.</p><span class="net_nemein_favourites">13 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=a1123f5e9d6211df96a28b0bda45be56be56&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/a1123f5e9d6211df96a28b0bda45be56be56/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=a1123f5e9d6211df96a28b0bda45be56be56&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/a1123f5e9d6211df96a28b0bda45be56be56/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Alberto Mardegan &lt;mardy@users.sourceforge.net&gt;</author>
            <category>feed:04088ede8ecf981676b12f87999d25d2</category>
            <pubDate>Sun, 01 Aug 2010 13:51:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-a1123f5e9d6211df96a28b0bda45be56be56</guid>
        </item>
    </channel>
</rss>
