read_buffer and read_1024   Leave a comment

Just for fun, below is an implementation for the read_buffer problem. The problem asks for an implementation of a function that reads chars to a user provided buffer of arbitrary size, using an already implemented buffer reading function, which however can only read to a buffer of fixed size (1024 in this example).

First Implementation

#include <cstring>      // std::memcpy
#include <algorithm>    // std::min

// read up to 1024 chars into buf. return number chars actually written into buf.
// if return value is less than 1024, the source underneath is exhausted at this time.
size_t read_1024(char* buf);    // implemented elsewhere.

// just a better name for the constant 1024
const size_t BUF_LEN = 1024;

// read to user provided buf of at most buf_len chars. return number chars actually written into buf.
size_t read_buffer(char* buf, size_t buf_len)
{
    static char s_buf[BUF_LEN]; // cache for read_1024.
    static size_t s_offset = 0; // unread chars start here in cache.
    static size_t s_count = 0;  // number of unread chars in cache.

    // policy-dependent. you may want it to crash for nullptr instead of guarding against this.
    if (nullptr == buf)
        return size_t(0);

    size_t total_read_count = 0;// how many chars already read into buf
    bool exhausted = false;     // if source of read_1024 is exhausted and no more chars available
    while (total_read_count < buf_len)
    {
        if (s_count>0)
        {   // if there are left over unread chars in cache, use those first.
            size_t copy_count = (std::min)(buf_len - total_read_count, s_count);
            std::memcpy(buf + total_read_count, s_buf + s_offset, copy_count);
            total_read_count += copy_count;
            s_offset += copy_count;
            s_count -= copy_count;
            if (exhausted)
                break;  // exhausted. stop.
        }
        else
        {   // now must read afresh using read_1024
            if (buf_len - total_read_count >= BUF_LEN)
            {
                // all chars can go to user buffer directly bypassing cache
                size_t read_count = read_1024(buf + total_read_count);
                total_read_count += read_count;
                if (read_count < BUF_LEN)
                    break;  // exhausted. stop.
            }
            else
            {
                // must use cache, or it may write beyond user buf boundary
                size_t read_count = read_1024(s_buf);
                s_offset = 0;
                s_count = read_count;
                if (read_count < BUF_LEN)
                {
                    exhausted = true;
                    if (read_count == 0)
                        break;  // exhausted and nothing in cache. stop.
                    // otherwise, let it read from left over cache, in code above.
                }
            }
        }
    }
    return total_read_count;
}

The read_buffer function implemented above:

  • it reads properly if user buffer is equal to or larger than 1024 chars;
  • it reads properly without buffer overflow if user buffer is less than 1024 chars;
  • no chars are lost between read_buffer calls.

Refactored Implementation

This is a little bit refactored version that puts code around cache into a class template buffer_cache, such that the read_buffer code is clearer:

#include <cassert>      // assert
#include <cstring>      // std::memcpy
#include <algorithm>    // std::min

// cache object
// Size_:       the fixe size of cache
// FixedReader: the function to fill fixed cache
template<size_t Size_, size_t(*FixedReader)(char*)>
struct buffer_cache
{
    static const size_t Size = Size_;

    // user can call fixed reader directly
    static size_t read_raw(char* buf) { return FixedReader(buf); }

    // construct an empty cache
    buffer_cache() : count_(0) {}

    // if cache is empty
    bool empty() const { return count_ == 0; }

    // read cache and write user provided buffer. return chars written.
    size_t read(char* buffer, size_t len)
    {
        size_t copy_count = (std::min)(len, count_);
        std::memcpy(buffer, buf_ + offset_, copy_count);
        count_ -= copy_count;
        offset_ += copy_count;
        return copy_count;
    }

    // try to fill cache using the fixed reader. return chars filled.
    size_t try_fill()
    {
        assert(empty());
        size_t read_count = FixedReader(buf_);
        if (read_count>0)
        {
            count_ = read_count;
            offset_ = 0;
        }
        return read_count;
    }

private:
    size_t	count_;     // number of unread chars in cache.
    size_t  offset_;    // unread chars start here in cache.
    char 	buf_[Size]; // cache
};

// read up to 1024 chars into buf. return number chars actually written into buf.
// if return value is less than 1024, the source underneath is exhausted at this time.
size_t read_1024(char* buf);

// read to user provided buf of at most buf_len chars. return number chars actually written into buf.
size_t read_buffer(char* buf, size_t buf_len)
{
    using BufferCache = buffer_cache<1024, read_1024>; // only need to change to other size here
    static BufferCache s_cache;

    // policy-dependent. you may want it to crash for nullptr instead of guarding against this.
    if (!buf)
        return size_t(0);

    size_t total_read_count = 0;// how many chars already read into buf

    // first pick up cache chars left over by last call.
    if (!s_cache.empty())
        total_read_count += s_cache.read(buf, buf_len);

    while (total_read_count < buf_len)
    {
        if (buf_len - total_read_count >= BufferCache::Size)
        {
            // all chars can go to user buffer directly bypassing cache, since it's big enough
            size_t read_count = BufferCache::read_raw(buf + total_read_count);
            total_read_count += read_count;
            if (read_count < BufferCache::Size)
                break;  // source exhausted.
        }
        else
        {
            // must use cache, or it may write beyond user buffer boundary
            s_cache.try_fill();
            total_read_count += s_cache.read(buf + total_read_count, buf_len - total_read_count);
            break;  // 
        }
    }
    return total_read_count;
}

Compared to the previous version, it is easy to change the buffer length from 1024 to others in one line where BufferCache is aliased.

Test Code

Below is a simple test program.

#include <cassert>
#include <cstring>
#include <algorithm>

#include <vector>
#include <cstdlib>
#include <iostream>

// simulating the source of chars:
std::vector<char>   g_storage;
size_t              g_pos;

size_t read_1024(char* buf)
{
    size_t count = 1024;
    if (g_pos + count > g_storage.size())
        count = g_storage.size() - g_pos;
    if (count>0)
    {
        std::memcpy(buf, &g_storage[g_pos], count);
        g_pos += count;
    }
    return count;
}

// you need to implement this function:
size_t read_buffer(char* buf, size_t buf_len);

bool test(size_t len)
{
    // generate test data stream.
    g_pos = 0;
    g_storage.clear();
    g_storage.reserve(len);
    for (size_t i = 0; i < len; ++i)
        g_storage.push_back((char)(std::rand() % 256));

    // make a copy of data stream as ground truth.
    std::vector<char> truth = g_storage;

    // to make a few read_buffer() calls with random sizes until the stream is exhausted.
    size_t base = len / 10; // rough read size.
    if (base < 512)
        base = 512;
    std::vector<char> read_chars;   // user buffer
    read_chars.resize(len + 1);
    size_t read_count = 0;
    while (true)
    {
        size_t rc = std::rand() % base;
        if (rc < 1)
            rc = 1;
        size_t rr = read_buffer(&read_chars[read_count], rc);
        std::cout << "    try to read = " << rc << ", actual read = " << rr << "\n";
        read_count += rr;
        if (rr == 0 || rr < rc)
            break;  // exhausted, no more chars to read.
    }

    bool ok = false;
    if (read_count != len)
        std::cout << "  FAIL: mismatch read size: expected=" << len << ", actual=" << read_count;
    else
    {
        read_chars.resize(read_count);
        if (read_chars != truth)
            std::cout << "  FAIL: mismatch read contents";
        else
        {
            std::cout << "  OK. stream matching, size = " << read_count;
            ok = true;
        }
    }
    return ok;
}

int main(int argc, char* argv[])
{
    size_t repeat = 10;
    size_t test_sz[] = { 0, 11, 522, 1024, 3001, 9273, 89704, 123458, 334526 };
    for (size_t i = 0; i < repeat; ++i)
    {
        for (size_t j = 0; j < sizeof(test_sz) / sizeof(test_sz[0]); ++j)
        {
            size_t sz = test_sz[j];
            std::cout << "Test stream size = " << sz << "\n";
            bool ok = test(sz);
            std::cout << std::endl;
            if (!ok)
                return -1;
        }
    }
    return 0;
}

Plug in read_buffer implementation, the test program can check if the implementation is good.

Please note that the code above is not safe in multi-threading use, because it uses static variable to hold cached chars without protection.

Posted March 1, 2015 by binglongx in C++

Tagged with , , , , , , ,

Reinstall Google Play on Motorola DEFY XT for Republic Wireless   1 comment

My Motorola DEFY XT for Republic Wireless crashed yesterday. It would freeze right after booting when it showed “Contacting Network …”. If I remove the SD card, it booted normally. I inserted into the phone again it did not boot. I inserted the SD card into my PC, and PC could initially see the drive, but copying files out of it was extremely slow (like 5KB/s) and finally hung. The SD card was faulty, and I could not recover some useful files, such as downloaded files.

DEFY XT has very limited 388MB Internal storage (i.e., /data). The Internal storage is used to store user installed apps (apks), and user specific data files for system and user apps. The user app apks can be found in the /data/app directory. The data files associated with apps can be found in /data/data/<apk_name>. For example, more than 100MB was used for WeChat data in /data/data/com.tencent.mm, including chat history and others. /data/dalvik-cache can take a lot of space too, as it houses the dex files for the apps. Some of the dex files can be removed to save some space. For example, I deleted the dex file for Google+ because I did not use Google+ on the phone. It is easy to browse around if you have ES File Explorer installed. In the end, it is quite easy to get “insufficient space” error when trying to install more apps. I installed Link2SD and an SD card with 2nd partition to offload apks to the SD card, so I was able to install quite some apps on the phone.

Now that the SD card was gone, a lot of offloaded apps on my phone could not run, because the Link2SD linked apks were no longer accessible from the phone. To accommodate the big data footprint of WeChat, I had even linked Google Play Services and Google Play Store. The trouble was that without Play Store, I could not reinstall other missing apps!

Initially I thought Link2SD moved the Play Store app in /system/app. If the apk was removed from system partition, even factory reset would not be able to revive it, see Factory Reset what is it, and why would you.

Luckily I had another DEFY XT phone with almost the same configuration. Play Store worked fine on that phone, so I was able to download and install ES File Explorer easily. Using ES File Explorer itself, I copied its own apk file to the problematic phone. I could run ES File Explorer on both phones and compare the apk files side by side.

It was easy to find out that the stock Play Store in DEFY XT is /system/app/Phonesky.apk. However the faulty phone had the same apk at the same location. Obviously this was not used. Then I looked at /data/app. Here I saw the difference. The good phone had a newer Play Store /data/app/com.android.vending-2.apk (11.16MB); while the other one had a dummy 0-byte /data/app/com.android.vending-1.apk, which was a symbolic link to actual apk on SD card 2nd partition managed by Link2SD (now non-existing). I also found Google Play Services /data/app/com.google.android.gms-2.apk (27.64MB) on the good phone, which I assumed necessary for Google Play to work.

The next step was simple. I just copied the two apk files from the good phone to the crippled one, and installed them. Launching Play Store right after installation did not work (“application stopped unexpectedly”), but a reboot fixed the problem. I think it should also work if I download the Play Store apk off the internet, see How to download & install the Google Play Store manually.

With Play Store recovered, I was able to install more apps and fix other problems in the phone.

Reference:

How To Install Any App As A System App On Android [Guide]

SM-22301 Shower Radio User Manual   Leave a comment

I cannot find the user manual of SM-22301 Shower Radio over the internet, so I post a scan here.

image

Posted February 21, 2015 by binglongx in Home

Tagged with , , , , ,

Dropbox Referral Program For 500MB Extra Free Bonus Space   Leave a comment

Dropbox is a cloud storage service. It is like a remote online drive that you can put your files there. It is slower than your local hard drive, but it is super reliable. A basic personal account is free to open, and it has 2GB free space.

I have been using Dropbox for quite a few years. There are many nice features of it. For me, the most convenient feature of Dropbox is automatic uploading of photos that I take on my mobile phone. I just install the Dropbox app on my Android phone, and set up the automatic uploading. Whenever I take a picture, it would be backed up to my online Dropbox account automatically. It saved a lot of photos when my microSD card in my phone went wrong some time ago.

If you open an account at Dropbox right now, you get 2GB free space. However, if you create a Dropbox account through a referral link from an existing Dropbox user, you will get extra 500MB space, i.e., 2.5GB total free space. The existing user will also get 500MB extra space for free.

If you so happen to need a Dropbox account, you can use my referral link https://db.tt/4WHpE8bR. To get the 500MB extra space, you need to:

  • Use the referral link to create a new Dropbox account; and
  • Install the Dropbox desktop application on a Windows, Linux or Mac computer; and
  • Sign in to the installed application with the newly created Dropbox account.

That’s it. You will see 2.5GB (instead of 2.0GB) space available in your Dropbox account. And thanks, this will also add 500MB to my Dropbox account. If you need more space, you can publish your referral link to earn bonus space.

Please note that, for this to work, you have to install the Dropbox desktop application on a desktop computer. Installing the Dropbox app on your Android or iOS phone or tablet does NOT qualify for the referral program.

For details, you can also check with Dropbox Referral Program.

Megacubo: A Broadcast Tuner Application on Windows   Leave a comment

Megacubo is featured as the Staff Pick project of February 2015 at SourceForge. The Windows application allows users to watch hundreds of live TV channels and listen to many radio stations on a PC with internet connection.

Excited to learn this in my SourceForge February newsletter, I headed to SF to download and install the application. After downloading megacubo_setup_f.exe, I was really surprised by the way the installer looks. It basically wants to install a lot of fishy bloatware. I checked its SourceForge reviews. It received straight 1-star negative reviews in past 2 months, mostly complaining attempts to install bloatware and language issues.

It is however unfair as I find out that Megacubo is not that bad. The installations of bloatware can be declined during Megacubo setup without affecting the functionalities of the installed application. With some help from free online tools on the internet, I was able to navigate in Megacubo and turn the Portuguese UI into English. Below is a summary.

Install Bloatware-Free Megacubo

The key here is to read each page carefully, and decline the bloatware offers in the installation process, even though sometimes the Decline button may not be very obvious.

Megacubo Setup Wizard shows the Welcome window:

image

Click “Next”, it shows the License Agreement window:

image

Click “Accept”, it now asks if you want to install Binkiland Browser.

image

Most people would believe this is bloatware. Click “Decline” at the bottom left corner. It now asks if you want to install Optimizer Pro.

image

Again I think Optimizer Pro is unnecessary for most people. Choose “Decline”. Finally, it starts to install Megacubo:

image

Turn UI Language From Portuguese To English

When Megacubo runs for the first time, it shows a message box to let you choose Yes or No. The problem is that the message is in Portuguese and I do not know any Portuguese. Worse, the text is not selectable, so I cannot copy it and use Google Translate.

This was what I did. I capture the window while it is on focus using Alt-PrtScrn (a Windows feature), then paste the captured image to IrfanView. In IrfanView, I cropped the text portion of the window. I did not take a snapshot of the message box window, but this was the text portion of that window:

image

I saved that portion to a .jpg file on my local hard drive. Then I used online Free OCR tool to convert the image into Portuguese text, which was:

Deseja ativar o "Controle dos Pais"?
Com o "Controle dos Pais" você pode configurar uma senha
que passará a ser pedida sempre que qualquer usuário_acessar qualquer
conteúdo inadequado para menores. Respondendo NAO os canais com
conteúdo adulto abriram livremente sem pedir senha para acesso.

This was relatively easy job for any OCR tool as the input image was perfectly distortion and noise free. Now Google Translate took it and translated into English:

Want to activate the "Parental Control"?
With the "Parental Controls" you can con fi gure a password
which will be requested whenever any usuário_acessar any
adult content. Responding NOT channels with
adult content freely opened without asking password for access.

From here it is obvious what you want to do with the Yes or No choice. In fact, below is the same message box in English (just that you will not see the English version in most situations):

image

After you dismiss the message box, you arrive at the main UI of Megacubo. It is however Portuguese:

image

If you are like me, and don’t read Portuguese, you want to change to use the English UI. Click the Settings icon and choose the Language menu item:

image

In the dialog box, choose “English”:

image

Megacubo will restart and show the English UI! See below:

image

Choose TV/radio channels here:

image

And you can also see the Options | Change Language menu item that was used above, the English version (in case you want to go back to Portuguese…):

image

When watching TV, sometimes there are Portuguese ads popup windows blocking the TV contents. Normally, you can click the “Fechar e tocar” button on the ads window to dismiss it (according to Google Translate, it means “close and touch”, I bet it is just “click to close”).

Conclusion

It is possible to install Megacubo without any bloatware, and use it with its English UI. As a free TV application, Megacubo has decent quality on the channels that I tried.

However, a lot of TV channels and radio stations in Megacubo are Portuguese. Sometimes when you quit Megacubo, it may fire up a marketing web page in your default web browser – not a big problem for me.

Install ecobee Smart Si Thermostat   Leave a comment

My local utility company was providing free smart thermostats to promote electricity and gas use reduction. I signed up at their website. Today the technician came over and installed two smart thermostats. This post is simply records of the replacement for future reference.

The old thermostat installed by the home builder:

image

After removing the panel, the wall-mounted part of the old thermostat:

image

It’s basically a connector to the wires from the forced air unit and a battery compartment. The close-up of wires and connector:

image

The wires are color coded following the letters on the case. The technician snipped the wires such that I can see the original wiring now. According to the technician:

  • Yellow (Y): turn on  AC
  • White (W): turn on heater
  • Green (G): turn on fan
  • Red (R): power
  • Cyan (C): ground

The new thermostat back piece installed and wired:

image

The letters are a little bit different for the new thermostat. More details about thermostat signals and wiring can be found here.

The new thermostat, ecobee Smart Si Thermostat:

image

This was before it’s programmed to use Wi-Fi and connected to the Internet. After creating a web portal account at ecobee.com and registering the thermostat, it would pull weather information and show in the right column:

image

Smart Si can also connect to the electrical meter of my utility company near the breaker panel through ZigBee, and show the graphs of electricity usage on its little screen. Please follow the user manual.

The thermostat can be viewed and controlled in the web portal from anywhere. There is also ecobee3 app in Google Play Store for Android phones that allows viewing and controlling the thermostat even one is not home.

Water Leaking from AVB in Irrigation Valve   Leave a comment

At a friend’s home, one of the irrigation anti-siphon valves leaks water. When the zone is turned on, the water leaks from the AVB (Atmospheric Vacuum Breaker) part of the valve.

There are two reasons that this can happen:

  1. The valve side (the side with solenoid and electric wires, i.e., the inlet side) of the valve is faulty. When the valve is turned on, it does not let enough water through. When water arrives at the AVB side (outlet side), it does not have enough pressure to close the vacuum poppet valve to close the air entrance in AVB. The water will just leave from the air path and leak from AVB.
  2. The vacuum poppet is stuck in AVB, so even the solenoid controlled valve works fine, the normal water pressure still cannot push close the vacuum poppet in AVB, and water just leaks from AVB.

Some related discussions can be found here: http://www.plbg.com/forum/read.php?1,376766

Depending on how difficult it is to open up the valve/AVB, to locate the faulty parts, and the availability of repair parts, it might be possible to repair the faulty parts with valve in place. This can potentially save digging, cutting or unscrewing the pipes.

If above seems too uncertain, it might be better to just replace the whole valve. This depends on the availability of space clearance, replacement valve, whether it’s installed on a riser and so on. A previous post mentions an interesting approach to save the risers when replacing the valve.

Follow

Get every new post delivered to your Inbox.

Join 47 other followers