5

I bought a decibel meter off amazon recently (http://www.amazon.com/Sound-Measure-Tester-Pressure-Decibel/dp/B00CPKSE38/ref=sr_1_1?ie=UTF8&qid=1436376590&sr=8-1&keywords=wensn) which outputs db measurements to a microsd card. I opened the sd card's content on my computer and encountered four separate *.wsn files, two of which I created and the other two apparently made by the manufacturer in testing perhaps. Anyway, did a google search for the .wsn file extension and can't find anything but something called a "whoopsie skin file" which doesn't appear to be what I'm looking for. Can anyone help me find a way to parse this file? I imagine it simply contains a table of information with two columns (db level and time)

Here's the link to a sample of the file. It is time series data for just a couple of seconds from the decibel meter. https://drive.google.com/file/d/0B0yWXI3LgLr4ME1DeUs4SDFMX1E/view?usp=sharing

Update: The db measurement device's manufacturer is "wensn", which clearly accounts for the file name extension. I've found two leads so far:

but both are for parsing usb streams of *.tmp files from the device, rather than the static wsn files. I'm guessing I could utilize this code to parse the wsn files, but I don't know how to do that yet. Honestly I'm in way over my head at this point.

I first posted this question meta.stackexchange, you can find that discussion here. The expected output data is columnar, time and decibel level, as seems to be indicated here.

Update 2: I think there may be a way to decode this file using the 'sigrok' utility, which is used to read all sorts of serial outputs from scientific sensors.

2
  • Out of curiosity, how do you know that it's been hacked? – Carcigenicate Jul 9 '15 at 2:44
  • I am not currently pursuing the amateur noise study project because the damned device cut off and the data was only for a few seconds, then all of a sudden the noise study was moot for other business reasons. I still have the equipment and may try to do a study again. I will mark the correct answer as the one that leads to me cracking the puzzle. Until then, this question appears to be helping a lot of people and that is good – boulder_ruby Nov 4 '15 at 22:51
7

This is a hex dump of your sample file:

00000000  1F DA 51 A0 19 5A 52 A0  19 DA 52 A0 28 5A 53 A0  ..Q..ZR...R.(ZS.
00000010  28 DA 53 A0 24 5A 54 A0  1A DA 54 A0 2A 5A 55 A0  (.S.$ZT...T.*ZU.
00000020  26 DA 55 A0 26 5A 56 A0  08 DA 56 A0 47 5A 57 A0  &.U.&ZV...V.GZW.
00000030  35 DA 57 A0 32 5A 58 A0  3B DA 58 A0              5.W.2ZX.;.X.

As you can see, the file clearly has a pattern where 4 bytes seem to repeat: - Byte one goes up and down, and might have to do with the sound level - Byte two alternates between DA and 5A - note DA is just a 5A with the highest bit set - Byte three seems to be slowly ascending, maybe a time indicator - Byte four is A0 and might be the high order byte of the time.

However, without any information about the sound level that has been recorded, or some expected values from the raw bytes, every guess is quite hard to verify. It would be really helpful if you could use the software that comes with the device, open the file with it, and tell us whatever the software makes of that data.

Btw, the german vendor Voelkner (they are reputable and i bought from them on several occasions) has a german/english PDF manual of the product, which refers to www.omnitronic.com for the newest version. That web site forwards to a shop that sold the product, doesn't have it in stock anymore, but still has a download page for manual and software. The product looks slightly different, but has the same overall layout and key positions, so there is reason to assume it's the same electronics in a slightly different plastic case, and the software might work for you and even be better than whatever came with your device - the amazon reviews says the software is in chinese and lacks a driver; the zip on "my" download page includes a "Vista Driver" folder and an installer that seems to support english.

3

This is the file in hex format (done with vi and :%!xxd; I added the column numbers myself):

          0 1  2 3  4 5  6 7  8 9  a b  c d  e f
0000000: 1fda 51a0 195a 52a0 19da 52a0 285a 53a0  ..Q..ZR...R.(ZS.
0000010: 28da 53a0 245a 54a0 1ada 54a0 2a5a 55a0  (.S.$ZT...T.*ZU.
0000020: 26da 55a0 265a 56a0 08da 56a0 475a 57a0  &.U.&ZV...V.GZW.
0000030: 35da 57a0 325a 58a0 3bda 58a0 0a         5.W.2ZX.;.X..

As you can see the bytes with odd indexes are all da, a0, 5a, a0, with a period of 8 bytes (half a line). This doesn't look like the data on the usb stream, so that link or the Python project are probably not going to help you much:

enter image description here

Furthermore, there seems to be a counter in columns 2 and a: 51, 52, 53, ... The bytes in columns 6 and a are the same. The bytes in column e and 2 are also the same, but with 2 difference, showing us that this part is not very well aligned. A nicer alignment to further reverse engineer would be to shift column e to the leftmost position or so.

You could get a larger sample to see if da, a0 and 5a are constants or that they are part of the counter, or possibly something else. For example, it could also be that they are actually part of the measurement, but seem to be constant here because the sound level on the moment of measurement was constant.

In any case, it seems at this point that only columns 0, 4, 8 and c carry data. Once you have confirmed that hypothesis (by looking at more data), you could start generating sounds and see how the data you see relates to the sounds you generate.

Considering that the manufacturer uses its own name as an extension, it is unlikely this file has some common-used table format, so I can't give you more tips than this.

A note about the hex editor. As said, I used vi with xxd (i.e. open the file in vi and then :%!xxd). However, there are plenty of hex editors, also for Windows. I don't know of any that allows you to shift the start column, which would be useful to check alignment.

3

Your file seems to go like:

51A0
52A0
52A0
53A0
53A0

_

52A0 = 20:02:36
53A0 = 20:02:38 in dos time

If its dos time it would make sense why every pattern(51A0, 52A0) is shown 2 times since dos time doesnt accept odd numbers as seconds.

Theory 1:

I dont think anything natural such as sound would go DA,5A,DA,5A,DA,5A,DA,5A,DA,5A.

So I assume that DA shows the lower part and 5A is the higher part. (DA=+0 and 5A=+1)

5A 52 A0 = 20:02:36
DA 52 A0 = 20:02:37
5A 53 A0 = 20:02:38
DA 53 A0 = 20:02:39

I'm dont know alot about measuring sound but I can make assumptions based on the first byte too. But this maybe wrong since you didnt give any information about the sound you captured.

1st byte is Max: 0x47(71) Min: 0x8(8) on your file.

On the amazon page it says (30 ~ 130 Db)

8 wouldnt fit those ranges so I assume the first byte is an offset.

130-30=100 -> 0 > x > 100.

Every 4 byte has this information:

struct Frame{
  char SoundOffset;
  char TimeOffset;
  char DosTime[2];
}

I wrote a sample code for your data.

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <string>
#include <iostream>  
#include <fstream>
#include <iostream>

using namespace std;


struct DosTime{
    int hour, minute, second;
    DosTime(char a1, char a2){
        char y[2] = { a1, a2 };
        INT16 * b = (INT16*)y;
        second = 2 * (*b & 31);
        minute = (*b & 2016) >> 5;
        hour = (*b & 63488) >> 11;
    }
    DosTime(){
        hour = 0;
        minute = 0;
        second = 0;
    }
};
struct Frame{
    char SoundOffset;
    char TimeOffset;
    char DosTime[2];
};
struct ConvertedFrame{
    int soundDB;
    DosTime time;
    void print(){
        cout << "Sound Level: " << soundDB << " dB @ ";
        cout.fill('0'); cout.width(2); cout << time.hour;
        cout << ":";
        cout.fill('0'); cout.width(2); cout << time.minute;
        cout << ":";
        cout.fill('0'); cout.width(2); cout << time.second;
        cout << endl;
    }
};
int main(int argc, char* argv[])
{

    int bytecount = 0;

    ifstream inFile;
    inFile.open("FG8U0235.wsn", ios::in | ios::binary | ios::ate);
    inFile.seekg(0, ios::end);
    bytecount = inFile.tellg();
    inFile.seekg(0, ios::beg);

    char * buffer = new char[bytecount];
    inFile.read(buffer, bytecount);

    ConvertedFrame * frames = new ConvertedFrame[bytecount / 4];
    for (int i = 0; i < bytecount; i += 4){
        ConvertedFrame _con;
        Frame f;
        memcpy(&f, &buffer[i], 4);
        DosTime _t = DosTime(f.DosTime[0], f.DosTime[1]);
        if (f.TimeOffset == '\xDA')
            _t.second++;
        _con.time = _t;
        _con.soundDB = ((int)f.SoundOffset) + 30;
        frames[i / 4] = _con;
        _con.print();
    }
    system("pause");
    return 0;

}

Which outputs:

Sound Level: 61 dB @ 20:02:35
Sound Level: 55 dB @ 20:02:36
Sound Level: 55 dB @ 20:02:37
Sound Level: 70 dB @ 20:02:36
Sound Level: 70 dB @ 20:02:39
Sound Level: 66 dB @ 20:02:40
Sound Level: 56 dB @ 20:02:41
Sound Level: 72 dB @ 20:02:42
Sound Level: 68 dB @ 20:02:43
Sound Level: 68 dB @ 20:02:44
Sound Level: 38 dB @ 20:02:45
Sound Level: 101 dB @ 20:02:46
Sound Level: 83 dB @ 20:02:47
Sound Level: 80 dB @ 20:02:48
Sound Level: 89 dB @ 20:02:49

Theory 2:

On the site you gave us (http://opensource.ebswift.com/RaspiMonitor/wensn/), there was this function (dB = (byte1 + ((byte2 & 3) * 256)) * 0.1 + 30) that made me think that maybe the 2nd byte is actually not the timeoffset but the 2nd byte for the dB.

This makes dB Float instead of Integer which would make much more sense. Also the output I got from the 2nd theory felt much better so I assume this is the correct answer.

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <string>
#include <fstream>
#include <iostream>

using namespace std;

struct DosTime{
    int hour, minute, second;
    INT16 data;
    DosTime(char a1, char a2){
        char y[2] = { a1, a2 };
        INT16 * b = (INT16*)y;
        second = 2 * (*b & 31);
        minute = (*b & 2016) >> 5;
        hour = (*b & 63488) >> 11;
        data = *b;
    }
    DosTime(){
        hour = 0;
        minute = 0;
        second = 0;
    }
};
struct Frame{
    char SoundOffset;
    char precisionOffset;
    char DosTime[2];
};
struct ConvertedFrame{
    float soundDB;
    DosTime time;
    void print(){
        cout << "Sound Level: ";
        cout << soundDB;
        if ((((int)soundDB) - soundDB) == 0) cout << ".0";
        cout << " dB @ ";
        cout.fill('0'); cout.width(2); cout << time.hour;
        cout << ":";
        cout.fill('0'); cout.width(2); cout << time.minute;
        cout << ":";
        cout.fill('0'); cout.width(2); cout << time.second;
        cout << endl;
    }
};
int main(int argc, char* argv[])
{
    int bytecount = 0;

    ifstream inFile;
    inFile.open("FG8U0235.wsn", ios::in | ios::binary | ios::ate);
    inFile.seekg(0, ios::end);
    bytecount = inFile.tellg();
    inFile.seekg(0, ios::beg);

    char * buffer = new char[bytecount];
    inFile.read(buffer, bytecount);


    ConvertedFrame * frames = new ConvertedFrame[bytecount / 4];


    INT16 lastTime = 0;
    for (int i = 0; i < bytecount; i += 4){
        ConvertedFrame _con;
        Frame f;
        memcpy(&f, &buffer[i], 4);
        DosTime _t = DosTime(f.DosTime[0], f.DosTime[1]);
        if (lastTime == _t.data) _t.second++;
        lastTime = _t.data;
        _con.time = _t;
        _con.soundDB = (f.SoundOffset + ((f.precisionOffset & 3) * 256)) * 0.1 + 30;
        frames[i / 4] = _con;
        _con.print();
    }
    system("pause");
    return 0;

}

Output:

Sound Level: 84.3 dB @ 20:02:34
Sound Level: 83.7 dB @ 20:02:36
Sound Level: 83.7 dB @ 20:02:37
Sound Level: 85.2 dB @ 20:02:38
Sound Level: 85.2 dB @ 20:02:39
Sound Level: 84.8 dB @ 20:02:40
Sound Level: 83.8 dB @ 20:02:41
Sound Level: 85.4 dB @ 20:02:42
Sound Level: 85.0 dB @ 20:02:43
Sound Level: 85.0 dB @ 20:02:44
Sound Level: 82.0 dB @ 20:02:45
Sound Level: 88.3 dB @ 20:02:46
Sound Level: 86.5 dB @ 20:02:47
Sound Level: 86.2 dB @ 20:02:48
Sound Level: 87.1 dB @ 20:02:49

Notes: To find which one is the correct one you need to write dB into a paper or something and then compare with the output you get from both codes.

Also you need to do the cleanup of ConvertedFrame * frames and char * buffer if you use this code and want to prevent memory leaks. I wrote this code pretty fast @ 4 am just to test the theory.

1

I have buy a decibel meter Koolertron SL1361 from Amazon and it's produce files *.wsn, but software don't work so I use this notes to understand. The last theory 2 it's right, every sample data is 4 bytes long.

Assuming that the 32 bit(four byte) is named bit31-0, here my decode:

Bit 31-24 & 17-16 Value in Db (10 bits), must be divide by 10 and after add 30 to obtain the correct value Bit 22 filter mode 0=Fast 1=Slow Bit 21 filter mode 0=A 1=C Bit 12-8 & 23 = seconds Bit 7-3 = hours bit 2-0 & 15-13 = minutes

They are coding in positive binary.

Everything works.

0

Obvious and easy solution if you just can't get any documentation: Do you have any software that reads these files? Something that probably displays them in some useful, probably graphic format?

If so, reverse engineer the loading section of this program. String search in the program for "wsn" references to help zero in on where they are probably loaded..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.